Merge branch 'dev_native' of https://github.com/prusa3d/Slic3r into dev_native

This commit is contained in:
bubnikv 2018-10-26 16:25:47 +02:00
commit 135ee60db4
2184 changed files with 237093 additions and 26 deletions

View file

@ -146,7 +146,7 @@ void SparseLUImpl<Scalar,StorageIndex>::panel_bmod(const Index m, const Index w,
Index ldl = internal::first_multiple<Index>(nrow, PacketSize);
Index offset = (PacketSize-internal::first_default_aligned(B.data(), PacketSize)) % PacketSize;
MappedMatrixBlock L(tempv.data()+w*ldu+offset, nrow, u_cols, OuterStride<>(ldl));
auto L = MappedMatrixBlock(tempv.data()+w*ldu+offset, nrow, u_cols, OuterStride<>(ldl));
L.setZero();
internal::sparselu_gemm<Scalar>(L.rows(), L.cols(), B.cols(), B.data(), B.outerStride(), U.data(), U.outerStride(), L.data(), L.outerStride());

1075
src/igl/AABB.cpp Normal file

File diff suppressed because it is too large Load diff

413
src/igl/AABB.h Normal file
View file

@ -0,0 +1,413 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_AABB_H
#define IGL_AABB_H
#include "Hit.h"
#include "igl_inline.h"
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <vector>
namespace igl
{
// Implementation of semi-general purpose axis-aligned bounding box hierarchy.
// The mesh (V,Ele) is stored and managed by the caller and each routine here
// simply takes it as references (it better not change between calls).
//
// It's a little annoying that the Dimension is a template parameter and not
// picked up at run time from V. This leads to duplicated code for 2d/3d (up to
// dim).
template <typename DerivedV, int DIM>
class AABB
{
public:
typedef typename DerivedV::Scalar Scalar;
typedef Eigen::Matrix<Scalar,1,DIM> RowVectorDIMS;
typedef Eigen::Matrix<Scalar,DIM,1> VectorDIMS;
typedef Eigen::Matrix<Scalar,Eigen::Dynamic,DIM> MatrixXDIMS;
// Shared pointers are slower...
AABB * m_left;
AABB * m_right;
Eigen::AlignedBox<Scalar,DIM> m_box;
// -1 non-leaf
int m_primitive;
//Scalar m_low_sqr_d;
//int m_depth;
AABB():
m_left(NULL), m_right(NULL),
m_box(), m_primitive(-1)
//m_low_sqr_d(std::numeric_limits<double>::infinity()),
//m_depth(0)
{}
// http://stackoverflow.com/a/3279550/148668
AABB(const AABB& other):
m_left(other.m_left ? new AABB(*other.m_left) : NULL),
m_right(other.m_right ? new AABB(*other.m_right) : NULL),
m_box(other.m_box),
m_primitive(other.m_primitive)
//m_low_sqr_d(other.m_low_sqr_d),
//m_depth(std::max(
// m_left ? m_left->m_depth + 1 : 0,
// m_right ? m_right->m_depth + 1 : 0))
{
}
// copy-swap idiom
friend void swap(AABB& first, AABB& second)
{
// Enable ADL
using std::swap;
swap(first.m_left,second.m_left);
swap(first.m_right,second.m_right);
swap(first.m_box,second.m_box);
swap(first.m_primitive,second.m_primitive);
//swap(first.m_low_sqr_d,second.m_low_sqr_d);
//swap(first.m_depth,second.m_depth);
}
// Pass-by-value (aka copy)
AABB& operator=(AABB other)
{
swap(*this,other);
return *this;
}
AABB(AABB&& other):
// initialize via default constructor
AABB()
{
swap(*this,other);
}
// Seems like there should have been an elegant solution to this using
// the copy-swap idiom above:
IGL_INLINE void deinit()
{
m_primitive = -1;
m_box = Eigen::AlignedBox<Scalar,DIM>();
delete m_left;
m_left = NULL;
delete m_right;
m_right = NULL;
}
~AABB()
{
deinit();
}
// Build an Axis-Aligned Bounding Box tree for a given mesh and given
// serialization of a previous AABB tree.
//
// Inputs:
// V #V by dim list of mesh vertex positions.
// Ele #Ele by dim+1 list of mesh indices into #V.
// bb_mins max_tree by dim list of bounding box min corner positions
// bb_maxs max_tree by dim list of bounding box max corner positions
// elements max_tree list of element or (not leaf id) indices into Ele
// i recursive call index {0}
template <
typename DerivedEle,
typename Derivedbb_mins,
typename Derivedbb_maxs,
typename Derivedelements>
IGL_INLINE void init(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const Eigen::MatrixBase<Derivedbb_mins> & bb_mins,
const Eigen::MatrixBase<Derivedbb_maxs> & bb_maxs,
const Eigen::MatrixBase<Derivedelements> & elements,
const int i = 0);
// Wrapper for root with empty serialization
template <typename DerivedEle>
IGL_INLINE void init(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele);
// Build an Axis-Aligned Bounding Box tree for a given mesh.
//
// Inputs:
// V #V by dim list of mesh vertex positions.
// Ele #Ele by dim+1 list of mesh indices into #V.
// SI #Ele by dim list revealing for each coordinate where Ele's
// barycenters would be sorted: SI(e,d) = i --> the dth coordinate of
// the barycenter of the eth element would be placed at position i in a
// sorted list.
// I #I list of indices into Ele of elements to include (for recursive
// calls)
//
template <typename DerivedEle, typename DerivedSI, typename DerivedI>
IGL_INLINE void init(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const Eigen::MatrixBase<DerivedSI> & SI,
const Eigen::MatrixBase<DerivedI>& I);
// Return whether at leaf node
IGL_INLINE bool is_leaf() const;
// Find the indices of elements containing given point: this makes sense
// when Ele is a co-dimension 0 simplex (tets in 3D, triangles in 2D).
//
// Inputs:
// V #V by dim list of mesh vertex positions. **Should be same as used to
// construct mesh.**
// Ele #Ele by dim+1 list of mesh indices into #V. **Should be same as used to
// construct mesh.**
// q dim row-vector query position
// first whether to only return first element containing q
// Returns:
// list of indices of elements containing q
template <typename DerivedEle, typename Derivedq>
IGL_INLINE std::vector<int> find(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const Eigen::MatrixBase<Derivedq> & q,
const bool first=false) const;
// If number of elements m then total tree size should be 2*h where h is
// the deepest depth 2^ceil(log(#Ele*2-1))
IGL_INLINE int subtree_size() const;
// Serialize this class into 3 arrays (so we can pass it pack to matlab)
//
// Outputs:
// bb_mins max_tree by dim list of bounding box min corner positions
// bb_maxs max_tree by dim list of bounding box max corner positions
// elements max_tree list of element or (not leaf id) indices into Ele
// i recursive call index into these arrays {0}
template <
typename Derivedbb_mins,
typename Derivedbb_maxs,
typename Derivedelements>
IGL_INLINE void serialize(
Eigen::PlainObjectBase<Derivedbb_mins> & bb_mins,
Eigen::PlainObjectBase<Derivedbb_maxs> & bb_maxs,
Eigen::PlainObjectBase<Derivedelements> & elements,
const int i = 0) const;
// Compute squared distance to a query point
//
// Inputs:
// V #V by dim list of vertex positions
// Ele #Ele by dim list of simplex indices
// p dim-long query point
// Outputs:
// i facet index corresponding to smallest distances
// c closest point
// Returns squared distance
//
// Known bugs: currently assumes Elements are triangles regardless of
// dimension.
template <typename DerivedEle>
IGL_INLINE Scalar squared_distance(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const RowVectorDIMS & p,
int & i,
Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
//private:
// Compute squared distance to a query point
//
// Inputs:
// V #V by dim list of vertex positions
// Ele #Ele by dim list of simplex indices
// p dim-long query point
// low_sqr_d lower bound on squared distance, specified maximum squared
// distance
// up_sqr_d current upper bounded on squared distance, current minimum
// squared distance (only consider distances less than this), see
// output.
// Outputs:
// up_sqr_d updated current minimum squared distance
// i facet index corresponding to smallest distances
// c closest point
// Returns squared distance
//
// Known bugs: currently assumes Elements are triangles regardless of
// dimension.
template <typename DerivedEle>
IGL_INLINE Scalar squared_distance(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const RowVectorDIMS & p,
const Scalar low_sqr_d,
const Scalar up_sqr_d,
int & i,
Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
// Default low_sqr_d
template <typename DerivedEle>
IGL_INLINE Scalar squared_distance(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const RowVectorDIMS & p,
const Scalar up_sqr_d,
int & i,
Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
// All hits
template <typename DerivedEle>
IGL_INLINE bool intersect_ray(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const RowVectorDIMS & origin,
const RowVectorDIMS & dir,
std::vector<igl::Hit> & hits) const;
// First hit
template <typename DerivedEle>
IGL_INLINE bool intersect_ray(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const RowVectorDIMS & origin,
const RowVectorDIMS & dir,
igl::Hit & hit) const;
//private:
template <typename DerivedEle>
IGL_INLINE bool intersect_ray(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const RowVectorDIMS & origin,
const RowVectorDIMS & dir,
const Scalar min_t,
igl::Hit & hit) const;
public:
// Compute the squared distance from all query points in P to the
// _closest_ points on the primitives stored in the AABB hierarchy for
// the mesh (V,Ele).
//
// Inputs:
// V #V by dim list of vertex positions
// Ele #Ele by dim list of simplex indices
// P #P by dim list of query points
// Outputs:
// sqrD #P list of squared distances
// I #P list of indices into Ele of closest primitives
// C #P by dim list of closest points
template <
typename DerivedEle,
typename DerivedP,
typename DerivedsqrD,
typename DerivedI,
typename DerivedC>
IGL_INLINE void squared_distance(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const Eigen::MatrixBase<DerivedP> & P,
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
Eigen::PlainObjectBase<DerivedI> & I,
Eigen::PlainObjectBase<DerivedC> & C) const;
// Compute the squared distance from all query points in P already stored
// in its own AABB hierarchy to the _closest_ points on the primitives
// stored in the AABB hierarchy for the mesh (V,Ele).
//
// Inputs:
// V #V by dim list of vertex positions
// Ele #Ele by dim list of simplex indices
// other AABB hierarchy of another set of primitives (must be points)
// other_V #other_V by dim list of query points
// other_Ele #other_Ele by ss list of simplex indices into other_V
// (must be simple list of points: ss == 1)
// Outputs:
// sqrD #P list of squared distances
// I #P list of indices into Ele of closest primitives
// C #P by dim list of closest points
template <
typename DerivedEle,
typename Derivedother_V,
typename Derivedother_Ele,
typename DerivedsqrD,
typename DerivedI,
typename DerivedC>
IGL_INLINE void squared_distance(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const AABB<Derivedother_V,DIM> & other,
const Eigen::MatrixBase<Derivedother_V> & other_V,
const Eigen::MatrixBase<Derivedother_Ele> & other_Ele,
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
Eigen::PlainObjectBase<DerivedI> & I,
Eigen::PlainObjectBase<DerivedC> & C) const;
private:
template <
typename DerivedEle,
typename Derivedother_V,
typename Derivedother_Ele,
typename DerivedsqrD,
typename DerivedI,
typename DerivedC>
IGL_INLINE Scalar squared_distance_helper(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const AABB<Derivedother_V,DIM> * other,
const Eigen::MatrixBase<Derivedother_V> & other_V,
const Eigen::MatrixBase<Derivedother_Ele>& other_Ele,
const Scalar up_sqr_d,
Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
Eigen::PlainObjectBase<DerivedI> & I,
Eigen::PlainObjectBase<DerivedC> & C) const;
// Compute the squared distance to the primitive in this node: assumes
// that this is indeed a leaf node.
//
// Inputs:
// V #V by dim list of vertex positions
// Ele #Ele by dim list of simplex indices
// p dim-long query point
// sqr_d current minimum distance for this query, see output
// i current index into Ele of closest point, see output
// c dim-long current closest point, see output
// Outputs:
// sqr_d minimum of initial value and squared distance to this
// primitive
// i possibly updated index into Ele of closest point
// c dim-long possibly updated closest point
template <typename DerivedEle>
IGL_INLINE void leaf_squared_distance(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const RowVectorDIMS & p,
const Scalar low_sqr_d,
Scalar & sqr_d,
int & i,
Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
// Default low_sqr_d
template <typename DerivedEle>
IGL_INLINE void leaf_squared_distance(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedEle> & Ele,
const RowVectorDIMS & p,
Scalar & sqr_d,
int & i,
Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
// If new distance (sqr_d_candidate) is less than current distance
// (sqr_d), then update this distance and its associated values
// _in-place_:
//
// Inputs:
// p dim-long query point (only used in DEBUG mode)
// sqr_d candidate minimum distance for this query, see output
// i candidate index into Ele of closest point, see output
// c dim-long candidate closest point, see output
// sqr_d current minimum distance for this query, see output
// i current index into Ele of closest point, see output
// c dim-long current closest point, see output
// Outputs:
// sqr_d minimum of initial value and squared distance to this
// primitive
// i possibly updated index into Ele of closest point
// c dim-long possibly updated closest point
IGL_INLINE void set_min(
const RowVectorDIMS & p,
const Scalar sqr_d_candidate,
const int i_candidate,
const RowVectorDIMS & c_candidate,
Scalar & sqr_d,
int & i,
Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
}
#ifndef IGL_STATIC_LIBRARY
# include "AABB.cpp"
#endif
#endif

36
src/igl/ARAPEnergyType.h Normal file
View file

@ -0,0 +1,36 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ARAPENERGYTYPE_H
#define IGL_ARAPENERGYTYPE_H
namespace igl
{
// ARAP_ENERGY_TYPE_SPOKES "As-rigid-as-possible Surface Modeling" by [Sorkine and
// Alexa 2007], rotations defined at vertices affecting incident edges,
// default
// ARAP_ENERGY_TYPE_SPOKES-AND-RIMS Adapted version of "As-rigid-as-possible Surface
// Modeling" by [Sorkine and Alexa 2007] presented in section 4.2 of or
// "A simple geometric model for elastic deformation" by [Chao et al.
// 2010], rotations defined at vertices affecting incident edges and
// opposite edges
// ARAP_ENERGY_TYPE_ELEMENTS "A local-global approach to mesh parameterization" by
// [Liu et al. 2010] or "A simple geometric model for elastic
// deformation" by [Chao et al. 2010], rotations defined at elements
// (triangles or tets)
// ARAP_ENERGY_TYPE_DEFAULT Choose one automatically: spokes and rims
// for surfaces, elements for planar meshes and tets (not fully
// supported)
enum ARAPEnergyType
{
ARAP_ENERGY_TYPE_SPOKES = 0,
ARAP_ENERGY_TYPE_SPOKES_AND_RIMS = 1,
ARAP_ENERGY_TYPE_ELEMENTS = 2,
ARAP_ENERGY_TYPE_DEFAULT = 3,
NUM_ARAP_ENERGY_TYPES = 4
};
}
#endif

130
src/igl/AtA_cached.cpp Normal file
View file

@ -0,0 +1,130 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "AtA_cached.h"
#include <iostream>
#include <vector>
#include <utility>
template <typename Scalar>
IGL_INLINE void igl::AtA_cached_precompute(
const Eigen::SparseMatrix<Scalar>& A,
igl::AtA_cached_data& data,
Eigen::SparseMatrix<Scalar>& AtA)
{
// 1 Compute At (this could be avoided, but performance-wise it will not make a difference)
std::vector<std::vector<int> > Col_RowPtr;
std::vector<std::vector<int> > Col_IndexPtr;
Col_RowPtr.resize(A.cols());
Col_IndexPtr.resize(A.cols());
for (unsigned k=0; k<A.outerSize(); ++k)
{
unsigned outer_index = *(A.outerIndexPtr()+k);
unsigned next_outer_index = (k+1 == A.outerSize()) ? A.nonZeros() : *(A.outerIndexPtr()+k+1);
for (unsigned l=outer_index; l<next_outer_index; ++l)
{
int col = k;
int row = *(A.innerIndexPtr()+l);
int value_index = l;
assert(col < A.cols());
assert(col >= 0);
assert(row < A.rows());
assert(row >= 0);
assert(value_index >= 0);
assert(value_index < A.nonZeros());
Col_RowPtr[col].push_back(row);
Col_IndexPtr[col].push_back(value_index);
}
}
Eigen::SparseMatrix<Scalar> At = A.transpose();
At.makeCompressed();
AtA = At * A;
AtA.makeCompressed();
assert(AtA.isCompressed());
// If weights are not provided, use 1
if (data.W.size() == 0)
data.W = Eigen::VectorXd::Ones(A.rows());
assert(data.W.size() == A.rows());
data.I_outer.reserve(AtA.outerSize());
data.I_row.reserve(2*AtA.nonZeros());
data.I_col.reserve(2*AtA.nonZeros());
data.I_w.reserve(2*AtA.nonZeros());
// 2 Construct the rules
for (unsigned k=0; k<AtA.outerSize(); ++k)
{
unsigned outer_index = *(AtA.outerIndexPtr()+k);
unsigned next_outer_index = (k+1 == AtA.outerSize()) ? AtA.nonZeros() : *(AtA.outerIndexPtr()+k+1);
for (unsigned l=outer_index; l<next_outer_index; ++l)
{
int col = k;
int row = *(AtA.innerIndexPtr()+l);
int value_index = l;
assert(col < AtA.cols());
assert(col >= 0);
assert(row < AtA.rows());
assert(row >= 0);
assert(value_index >= 0);
assert(value_index < AtA.nonZeros());
data.I_outer.push_back(data.I_row.size());
// Find correspondences
unsigned i=0;
unsigned j=0;
while (i<Col_RowPtr[row].size() && j<Col_RowPtr[col].size())
{
if (Col_RowPtr[row][i] == Col_RowPtr[col][j])
{
data.I_row.push_back(Col_IndexPtr[row][i]);
data.I_col.push_back(Col_IndexPtr[col][j]);
data.I_w.push_back(Col_RowPtr[col][j]);
++i;
++j;
} else
if (Col_RowPtr[row][i] > Col_RowPtr[col][j])
++j;
else
++i;
}
}
}
data.I_outer.push_back(data.I_row.size()); // makes it more efficient to iterate later on
igl::AtA_cached(A,data,AtA);
}
template <typename Scalar>
IGL_INLINE void igl::AtA_cached(
const Eigen::SparseMatrix<Scalar>& A,
const igl::AtA_cached_data& data,
Eigen::SparseMatrix<Scalar>& AtA)
{
for (unsigned i=0; i<data.I_outer.size()-1; ++i)
{
*(AtA.valuePtr() + i) = 0;
for (unsigned j=data.I_outer[i]; j<data.I_outer[i+1]; ++j)
*(AtA.valuePtr() + i) += *(A.valuePtr() + data.I_row[j]) * data.W[data.I_w[j]] * *(A.valuePtr() + data.I_col[j]);
}
}
#ifdef IGL_STATIC_LIBRARY
template void igl::AtA_cached<double>(Eigen::SparseMatrix<double, 0, int> const&, igl::AtA_cached_data const&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::AtA_cached_precompute<double>(Eigen::SparseMatrix<double, 0, int> const&, igl::AtA_cached_data&, Eigen::SparseMatrix<double, 0, int>&);
#endif

70
src/igl/AtA_cached.h Normal file
View file

@ -0,0 +1,70 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ATA_CACHED_H
#define IGL_ATA_CACHED_H
#include "igl_inline.h"
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
#include <Eigen/Dense>
#include <Eigen/Sparse>
namespace igl
{
struct AtA_cached_data
{
// Weights
Eigen::VectorXd W;
// Flatten composition rules
std::vector<int> I_row;
std::vector<int> I_col;
std::vector<int> I_w;
// For each entry of AtA, points to the beginning
// of the composition rules
std::vector<int> I_outer;
};
// Computes At * W * A, where A is sparse and W is diagonal. Divides the
// construction in two phases, one
// for fixing the sparsity pattern, and one to populate it with values. Compared to
// evaluating it directly, this version is slower for the first time (since it requires a
// precomputation), but faster to the subsequent evaluations.
//
// Input:
// A m x n sparse matrix
// data stores the precomputed sparsity pattern, data.W contains the optional diagonal weights (stored as a dense vector). If W is not provided, it is replaced by the identity.
// Outputs:
// AtA m by m matrix computed as AtA * W * A
//
// Example:
// AtA_data = igl::AtA_cached_data();
// AtA_data.W = W;
// if (s.AtA.rows() == 0)
// igl::AtA_cached_precompute(s.A,s.AtA_data,s.AtA);
// else
// igl::AtA_cached(s.A,s.AtA_data,s.AtA);
template <typename Scalar>
IGL_INLINE void AtA_cached_precompute(
const Eigen::SparseMatrix<Scalar>& A,
AtA_cached_data& data,
Eigen::SparseMatrix<Scalar>& AtA
);
template <typename Scalar>
IGL_INLINE void AtA_cached(
const Eigen::SparseMatrix<Scalar>& A,
const AtA_cached_data& data,
Eigen::SparseMatrix<Scalar>& AtA
);
}
#ifndef IGL_STATIC_LIBRARY
# include "AtA_cached.cpp"
#endif
#endif

18
src/igl/C_STR.h Normal file
View file

@ -0,0 +1,18 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_C_STR_H
#define IGL_C_STR_H
// http://stackoverflow.com/a/2433143/148668
// Suppose you have a function:
// void func(const char * c);
// Then you can write:
// func(C_STR("foo"<<1<<"bar"));
#include <sstream>
#include <string>
#define C_STR(X) static_cast<std::ostringstream&>(std::ostringstream().flush() << X).str().c_str()
#endif

359
src/igl/Camera.h Normal file
View file

@ -0,0 +1,359 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_CAMERA_H
#define IGL_CAMERA_H
// you're idiot, M$!
#if defined(_WIN32)
#undef far
#undef near
#endif
#include <Eigen/Geometry>
#include <Eigen/Core>
#include <PI.h>
#define IGL_CAMERA_MIN_ANGLE 5.0
namespace igl
{
// A simple camera class. The camera stores projection parameters (field of
// view angle, aspect ratio, near and far clips) as well as a rigid
// transformation *of the camera as if it were also a scene object*. Thus, the
// **inverse** of this rigid transformation is the modelview transformation.
class Camera
{
public:
// On windows you might need: -fno-delayed-template-parsing
//static constexpr double IGL_CAMERA_MIN_ANGLE = 5.;
// m_angle Field of view angle in degrees {45}
// m_aspect Aspect ratio {1}
// m_near near clipping plane {1e-2}
// m_far far clipping plane {100}
// m_at_dist distance of looking at point {1}
// m_orthographic whether to use othrographic projection {false}
// m_rotation_conj Conjugate of rotation part of rigid transformation of
// camera {identity}. Note: we purposefully store the conjugate because
// this is what TW_TYPE_QUAT4D is expecting.
// m_translation Translation part of rigid transformation of camera
// {(0,0,1)}
double m_angle, m_aspect, m_near, m_far, m_at_dist;
bool m_orthographic;
Eigen::Quaterniond m_rotation_conj;
Eigen::Vector3d m_translation;
public:
inline Camera();
inline virtual ~Camera(){}
// Return projection matrix that takes relative camera coordinates and
// transforms it to viewport coordinates
//
// Note:
//
// if(m_angle > 0)
// {
// gluPerspective(m_angle,m_aspect,m_near,m_at_dist+m_far);
// }else
// {
// gluOrtho(-0.5*aspect,0.5*aspect,-0.5,0.5,m_at_dist+m_near,m_far);
// }
//
// Is equivalent to
//
// glMultMatrixd(projection().data());
//
inline Eigen::Matrix4d projection() const;
// Return an Affine transformation (rigid actually) that
// takes relative coordinates and tramsforms them into world 3d
// coordinates: moves the camera into the scene.
inline Eigen::Affine3d affine() const;
// Return an Affine transformation (rigid actually) that puts the takes a
// world 3d coordinate and transforms it into the relative camera
// coordinates: moves the scene in front of the camera.
//
// Note:
//
// gluLookAt(
// eye()(0), eye()(1), eye()(2),
// at()(0), at()(1), at()(2),
// up()(0), up()(1), up()(2));
//
// Is equivalent to
//
// glMultMatrixd(camera.inverse().matrix().data());
//
// See also: affine, eye, at, up
inline Eigen::Affine3d inverse() const;
// Returns world coordinates position of center or "eye" of camera.
inline Eigen::Vector3d eye() const;
// Returns world coordinate position of a point "eye" is looking at.
inline Eigen::Vector3d at() const;
// Returns world coordinate unit vector of "up" vector
inline Eigen::Vector3d up() const;
// Return top right corner of unit plane in relative coordinates, that is
// (w/2,h/2,1)
inline Eigen::Vector3d unit_plane() const;
// Move dv in the relative coordinate frame of the camera (move the FPS)
//
// Inputs:
// dv (x,y,z) displacement vector
//
inline void dolly(const Eigen::Vector3d & dv);
// "Scale zoom": Move `eye`, but leave `at`
//
// Input:
// s amount to scale distance to at
inline void push_away(const double s);
// Aka "Hitchcock", "Vertigo", "Spielberg" or "Trombone" zoom:
// simultaneously dolly while changing angle so that `at` not only stays
// put in relative coordinates but also projected coordinates. That is
//
// Inputs:
// da change in angle in degrees
inline void dolly_zoom(const double da);
// Turn around eye so that rotation is now q
//
// Inputs:
// q new rotation as quaternion
inline void turn_eye(const Eigen::Quaterniond & q);
// Orbit around at so that rotation is now q
//
// Inputs:
// q new rotation as quaternion
inline void orbit(const Eigen::Quaterniond & q);
// Rotate and translate so that camera is situated at "eye" looking at "at"
// with "up" pointing up.
//
// Inputs:
// eye (x,y,z) coordinates of eye position
// at (x,y,z) coordinates of at position
// up (x,y,z) coordinates of up vector
inline void look_at(
const Eigen::Vector3d & eye,
const Eigen::Vector3d & at,
const Eigen::Vector3d & up);
// Needed any time Eigen Structures are used as class members
// http://eigen.tuxfamily.org/dox-devel/group__TopicStructHavingEigenMembers.html
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
}
// Implementation
#include "PI.h"
#include "EPS.h"
#include <cmath>
#include <iostream>
#include <cassert>
inline igl::Camera::Camera():
m_angle(45.0),m_aspect(1),m_near(1e-2),m_far(100),m_at_dist(1),
m_orthographic(false),
m_rotation_conj(1,0,0,0),
m_translation(0,0,1)
{
}
inline Eigen::Matrix4d igl::Camera::projection() const
{
Eigen::Matrix4d P;
using namespace std;
const double far = m_at_dist + m_far;
const double near = m_near;
// http://stackoverflow.com/a/3738696/148668
if(m_orthographic)
{
const double f = 0.5;
const double left = -f*m_aspect;
const double right = f*m_aspect;
const double bottom = -f;
const double top = f;
const double tx = (right+left)/(right-left);
const double ty = (top+bottom)/(top-bottom);
const double tz = (far+near)/(far-near);
const double z_fix = 0.5 /m_at_dist / tan(m_angle*0.5 * (igl::PI/180.) );
P<<
z_fix*2./(right-left), 0, 0, -tx,
0, z_fix*2./(top-bottom), 0, -ty,
0, 0, -z_fix*2./(far-near), -tz,
0, 0, 0, 1;
}else
{
const double yScale = tan(PI*0.5 - 0.5*m_angle*PI/180.);
// http://stackoverflow.com/a/14975139/148668
const double xScale = yScale/m_aspect;
P<<
xScale, 0, 0, 0,
0, yScale, 0, 0,
0, 0, -(far+near)/(far-near), -1,
0, 0, -2.*near*far/(far-near), 0;
P = P.transpose().eval();
}
return P;
}
inline Eigen::Affine3d igl::Camera::affine() const
{
using namespace Eigen;
Affine3d t = Affine3d::Identity();
t.rotate(m_rotation_conj.conjugate());
t.translate(m_translation);
return t;
}
inline Eigen::Affine3d igl::Camera::inverse() const
{
using namespace Eigen;
Affine3d t = Affine3d::Identity();
t.translate(-m_translation);
t.rotate(m_rotation_conj);
return t;
}
inline Eigen::Vector3d igl::Camera::eye() const
{
using namespace Eigen;
return affine() * Vector3d(0,0,0);
}
inline Eigen::Vector3d igl::Camera::at() const
{
using namespace Eigen;
return affine() * (Vector3d(0,0,-1)*m_at_dist);
}
inline Eigen::Vector3d igl::Camera::up() const
{
using namespace Eigen;
Affine3d t = Affine3d::Identity();
t.rotate(m_rotation_conj.conjugate());
return t * Vector3d(0,1,0);
}
inline Eigen::Vector3d igl::Camera::unit_plane() const
{
// Distance of center pixel to eye
const double d = 1.0;
const double a = m_aspect;
const double theta = m_angle*PI/180.;
const double w =
2.*sqrt(-d*d/(a*a*pow(tan(0.5*theta),2.)-1.))*a*tan(0.5*theta);
const double h = w/a;
return Eigen::Vector3d(w*0.5,h*0.5,-d);
}
inline void igl::Camera::dolly(const Eigen::Vector3d & dv)
{
m_translation += dv;
}
inline void igl::Camera::push_away(const double s)
{
using namespace Eigen;
#ifndef NDEBUG
Vector3d old_at = at();
#endif
const double old_at_dist = m_at_dist;
m_at_dist = old_at_dist * s;
dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
}
inline void igl::Camera::dolly_zoom(const double da)
{
using namespace std;
using namespace Eigen;
#ifndef NDEBUG
Vector3d old_at = at();
#endif
const double old_angle = m_angle;
if(old_angle + da < IGL_CAMERA_MIN_ANGLE)
{
m_orthographic = true;
}else if(old_angle + da > IGL_CAMERA_MIN_ANGLE)
{
m_orthographic = false;
}
if(!m_orthographic)
{
m_angle += da;
m_angle = min(89.,max(IGL_CAMERA_MIN_ANGLE,m_angle));
// change in distance
const double s =
(2.*tan(old_angle/2./180.*igl::PI)) /
(2.*tan(m_angle/2./180.*igl::PI)) ;
const double old_at_dist = m_at_dist;
m_at_dist = old_at_dist * s;
dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
}
}
inline void igl::Camera::turn_eye(const Eigen::Quaterniond & q)
{
using namespace Eigen;
Vector3d old_eye = eye();
// eye should be fixed
//
// eye_1 = R_1 * t_1 = eye_0
// t_1 = R_1' * eye_0
m_rotation_conj = q.conjugate();
m_translation = m_rotation_conj * old_eye;
assert((old_eye - eye()).squaredNorm() < DOUBLE_EPS);
}
inline void igl::Camera::orbit(const Eigen::Quaterniond & q)
{
using namespace Eigen;
Vector3d old_at = at();
// at should be fixed
//
// at_1 = R_1 * t_1 - R_1 * z = at_0
// t_1 = R_1' * (at_0 + R_1 * z)
m_rotation_conj = q.conjugate();
m_translation =
m_rotation_conj *
(old_at +
m_rotation_conj.conjugate() * Vector3d(0,0,1) * m_at_dist);
assert((old_at - at()).squaredNorm() < DOUBLE_EPS);
}
inline void igl::Camera::look_at(
const Eigen::Vector3d & eye,
const Eigen::Vector3d & at,
const Eigen::Vector3d & up)
{
using namespace Eigen;
using namespace std;
// http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
// Normalize vector from at to eye
Vector3d F = eye-at;
m_at_dist = F.norm();
F.normalize();
// Project up onto plane orthogonal to F and normalize
assert(up.cross(F).norm() > DOUBLE_EPS && "(eye-at) x up ≈ 0");
const Vector3d proj_up = (up-(up.dot(F))*F).normalized();
Quaterniond a,b;
a.setFromTwoVectors(Vector3d(0,0,-1),-F);
b.setFromTwoVectors(a*Vector3d(0,1,0),proj_up);
m_rotation_conj = (b*a).conjugate();
m_translation = m_rotation_conj * eye;
//cout<<"m_at_dist: "<<m_at_dist<<endl;
//cout<<"proj_up: "<<proj_up.transpose()<<endl;
//cout<<"F: "<<F.transpose()<<endl;
//cout<<"eye(): "<<this->eye().transpose()<<endl;
//cout<<"at(): "<<this->at().transpose()<<endl;
//cout<<"eye()-at(): "<<(this->eye()-this->at()).normalized().transpose()<<endl;
//cout<<"eye-this->eye(): "<<(eye-this->eye()).squaredNorm()<<endl;
assert( (eye-this->eye()).squaredNorm() < DOUBLE_EPS);
//assert((F-(this->eye()-this->at()).normalized()).squaredNorm() <
// DOUBLE_EPS);
assert( (at-this->at()).squaredNorm() < DOUBLE_EPS);
//assert( (proj_up-this->up()).squaredNorm() < DOUBLE_EPS);
}
#endif

30
src/igl/EPS.cpp Normal file
View file

@ -0,0 +1,30 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "EPS.h"
template <> IGL_INLINE float igl::EPS()
{
return igl::FLOAT_EPS;
}
template <> IGL_INLINE double igl::EPS()
{
return igl::DOUBLE_EPS;
}
template <> IGL_INLINE float igl::EPS_SQ()
{
return igl::FLOAT_EPS_SQ;
}
template <> IGL_INLINE double igl::EPS_SQ()
{
return igl::DOUBLE_EPS_SQ;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
#endif

32
src/igl/EPS.h Normal file
View file

@ -0,0 +1,32 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_EPS_H
#define IGL_EPS_H
#include "igl_inline.h"
namespace igl
{
// Define a standard value for double epsilon
const double DOUBLE_EPS = 1.0e-14;
const double DOUBLE_EPS_SQ = 1.0e-28;
const float FLOAT_EPS = 1.0e-7;
const float FLOAT_EPS_SQ = 1.0e-14;
// Function returning EPS for corresponding type
template <typename S_type> IGL_INLINE S_type EPS();
template <typename S_type> IGL_INLINE S_type EPS_SQ();
// Template specializations for float and double
template <> IGL_INLINE float EPS<float>();
template <> IGL_INLINE double EPS<double>();
template <> IGL_INLINE float EPS_SQ<float>();
template <> IGL_INLINE double EPS_SQ<double>();
}
#ifndef IGL_STATIC_LIBRARY
# include "EPS.cpp"
#endif
#endif

View file

@ -0,0 +1,158 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "HalfEdgeIterator.h"
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::HalfEdgeIterator(
const Eigen::PlainObjectBase<DerivedF>& _F,
const Eigen::PlainObjectBase<DerivedFF>& _FF,
const Eigen::PlainObjectBase<DerivedFFi>& _FFi,
int _fi,
int _ei,
bool _reverse
)
: fi(_fi), ei(_ei), reverse(_reverse), F(_F), FF(_FF), FFi(_FFi)
{}
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE void igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::flipF()
{
if (isBorder())
return;
int fin = (FF)(fi,ei);
int ein = (FFi)(fi,ei);
fi = fin;
ei = ein;
reverse = !reverse;
}
// Change Edge
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE void igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::flipE()
{
if (!reverse)
ei = (ei+2)%3; // ei-1
else
ei = (ei+1)%3;
reverse = !reverse;
}
// Change Vertex
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE void igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::flipV()
{
reverse = !reverse;
}
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::isBorder()
{
return (FF)(fi,ei) == -1;
}
/*!
* Returns the next edge skipping the border
* _________
* /\ c | b /\
* / \ | / \
* / d \ | / a \
* /______\|/______\
* v
* In this example, if a and d are of-border and the pos is iterating counterclockwise, this method iterate through the faces incident on vertex v,
* producing the sequence a, b, c, d, a, b, c, ...
*/
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::NextFE()
{
if ( isBorder() ) // we are on a border
{
do
{
flipF();
flipE();
} while (!isBorder());
flipE();
return false;
}
else
{
flipF();
flipE();
return true;
}
}
// Get vertex index
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE int igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::Vi()
{
assert(fi >= 0);
assert(fi < F.rows());
assert(ei >= 0);
assert(ei <= 2);
if (!reverse)
return (F)(fi,ei);
else
return (F)(fi,(ei+1)%3);
}
// Get face index
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE int igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::Fi()
{
return fi;
}
// Get edge index
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE int igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::Ei()
{
return ei;
}
template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::operator==(HalfEdgeIterator& p2)
{
return
(
(fi == p2.fi) &&
(ei == p2.ei) &&
(reverse == p2.reverse) &&
(F == p2.F) &&
(FF == p2.FF) &&
(FFi == p2.FFi)
);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, int, int, bool);
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Ei();
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Ei();
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::Ei();
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::Fi();
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::NextFE();
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Vi();
template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipE();
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipF();
template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipV();
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::operator==(igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
#endif

114
src/igl/HalfEdgeIterator.h Normal file
View file

@ -0,0 +1,114 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_HALFEDGEITERATOR_H
#define IGL_HALFEDGEITERATOR_H
#include <Eigen/Core>
#include <vector>
#include <igl/igl_inline.h>
// This file violates many of the libigl style guidelines.
namespace igl
{
// HalfEdgeIterator - Fake halfedge for fast and easy navigation
// on triangle meshes with vertex_triangle_adjacency and
// triangle_triangle adjacency
//
// Note: this is different to classical Half Edge data structure.
// Instead, it follows cell-tuple in [Brisson, 1989]
// "Representing geometric structures in d dimensions: topology and order."
// This class can achieve local navigation similar to half edge in OpenMesh
// But the logic behind each atom operation is different.
// So this should be more properly called TriangleTupleIterator.
//
// Each tuple contains information on (face, edge, vertex)
// and encoded by (face, edge \in {0,1,2}, bool reverse)
//
// Inputs:
// F #F by 3 list of "faces"
// FF #F by 3 list of triangle-triangle adjacency.
// FFi #F by 3 list of FF inverse. For FF and FFi, refer to
// "triangle_triangle_adjacency.h"
// Usages:
// FlipF/E/V changes solely one actual face/edge/vertex resp.
// NextFE iterates through one-ring of a vertex robustly.
//
template <
typename DerivedF,
typename DerivedFF,
typename DerivedFFi>
class HalfEdgeIterator
{
public:
// Init the HalfEdgeIterator by specifying Face,Edge Index and Orientation
IGL_INLINE HalfEdgeIterator(
const Eigen::PlainObjectBase<DerivedF>& _F,
const Eigen::PlainObjectBase<DerivedFF>& _FF,
const Eigen::PlainObjectBase<DerivedFFi>& _FFi,
int _fi,
int _ei,
bool _reverse = false
);
// Change Face
IGL_INLINE void flipF();
// Change Edge
IGL_INLINE void flipE();
// Change Vertex
IGL_INLINE void flipV();
IGL_INLINE bool isBorder();
/*!
* Returns the next edge skipping the border
* _________
* /\ c | b /\
* / \ | / \
* / d \ | / a \
* /______\|/______\
* v
* In this example, if a and d are of-border and the pos is iterating
counterclockwise, this method iterate through the faces incident on vertex
v,
* producing the sequence a, b, c, d, a, b, c, ...
*/
IGL_INLINE bool NextFE();
// Get vertex index
IGL_INLINE int Vi();
// Get face index
IGL_INLINE int Fi();
// Get edge index
IGL_INLINE int Ei();
IGL_INLINE bool operator==(HalfEdgeIterator& p2);
private:
int fi;
int ei;
bool reverse;
// All the same type? This is likely to break.
const Eigen::PlainObjectBase<DerivedF> & F;
const Eigen::PlainObjectBase<DerivedFF> & FF;
const Eigen::PlainObjectBase<DerivedFFi> & FFi;
};
}
#ifndef IGL_STATIC_LIBRARY
# include "HalfEdgeIterator.cpp"
#endif
#endif

25
src/igl/Hit.h Normal file
View file

@ -0,0 +1,25 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
// 2014 Christian Schüller <schuellchr@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_HIT_H
#define IGL_HIT_H
namespace igl
{
// Reimplementation of the embree::Hit struct from embree1.0
//
// TODO: template on floating point type
struct Hit
{
int id; // primitive id
int gid; // geometry id
float u,v; // barycentric coordinates
float t; // distance = direction*t to intersection
};
}
#endif

28
src/igl/IO Normal file
View file

@ -0,0 +1,28 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_IO
#define IGL_IO
// Input and output functions
#include "read_triangle_mesh.h"
#include "readDMAT.h"
#include "readMESH.h"
#include "readNODE.h"
#include "readOBJ.h"
#include "readOFF.h"
#include "readTGF.h"
#include "readWRL.h"
#include "readCSV.h"
#include "file_contents_as_string.h"
#include "write_triangle_mesh.h"
#include "writeDMAT.h"
#include "writeMESH.h"
#include "writeOBJ.h"
#include "writeOFF.h"
#include "writeTGF.h"
#endif

117
src/igl/IndexComparison.h Normal file
View file

@ -0,0 +1,117 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_INDEXCOMPARISON_H
#define IGL_INDEXCOMPARISON_H
#include <iostream>
namespace igl{
// Comparison struct used by sort
// http://bytes.com/topic/c/answers/132045-sort-get-index
// For use with functions like std::sort
template<class T> struct IndexLessThan
{
IndexLessThan(const T arr) : arr(arr) {}
bool operator()(const size_t a, const size_t b) const
{
return arr[a] < arr[b];
}
const T arr;
};
// For use with functions like std::unique
template<class T> struct IndexEquals
{
IndexEquals(const T arr) : arr(arr) {}
bool operator()(const size_t a, const size_t b) const
{
return arr[a] == arr[b];
}
const T arr;
};
// For use with functions like std::sort
template<class T> struct IndexVectorLessThan
{
IndexVectorLessThan(const T & vec) : vec ( vec) {}
bool operator()(const size_t a, const size_t b) const
{
return vec(a) < vec(b);
}
const T & vec;
};
// For use with functions like std::sort
template<class T> struct IndexDimLessThan
{
IndexDimLessThan(const T & mat,const int & dim, const int & j) :
mat(mat),
dim(dim),
j(j)
{}
bool operator()(const size_t a, const size_t b) const
{
if(dim == 1)
{
return mat(a,j) < mat(b,j);
}else
{
return mat(j,a) < mat(j,b);
}
}
const T & mat;
const int & dim;
const int & j;
};
// For use with functions like std::sort
template<class T> struct IndexRowLessThan
{
IndexRowLessThan(const T & mat) : mat ( mat) {}
bool operator()(const size_t a, const size_t b) const
{
const int cols = mat.cols();
// Lexicographical order
for(int j = 0;j<cols;j++)
{
if(mat(a,j) > mat(b,j))
{
return false;
} else if(mat(a,j) < mat(b,j))
{
return true;
}
}
// equality is false
return false;
}
const T & mat;
};
// For use with functions like std::sort
template<class T> struct IndexRowEquals
{
IndexRowEquals(const T & mat) : mat ( mat) {}
bool operator()(const size_t a, const size_t b) const
{
const int cols = mat.cols();
// Lexicographical order
for(int j = 0;j<cols;j++)
{
if(mat(a,j) != mat(b,j))
{
return false;
}
}
return true;
}
const T & mat;
};
}
#endif

61
src/igl/LinSpaced.h Normal file
View file

@ -0,0 +1,61 @@
#ifndef IGL_LINSPACED_H
#define IGL_LINSPACED_H
#include <Eigen/Core>
// This function is not intended to be a permanent function of libigl. Rather
// it is a "drop-in" workaround for documented bug in Eigen:
// http://eigen.tuxfamily.org/bz/show_bug.cgi?id=1383
//
// Replace:
//
// Eigen::VectorXi::LinSpaced(size,low,high);
//
// With:
//
// igl::LinSpaced<Eigen::VectorXi>(size,low,high);
//
// Specifcally, this version will _always_ return an empty vector if size==0,
// regardless of the values for low and high. If size != 0, then this simply
// returns the result of Eigen::Derived::LinSpaced.
//
// Until this bug is fixed, we should also avoid calls to the member function
// `.setLinSpaced`. This means replacing:
//
// a.setLinSpaced(size,low,high);
//
// with
//
// a = igl::LinSpaced<decltype(a) >(size,low,high);
//
namespace igl
{
template <typename Derived>
//inline typename Eigen::DenseBase< Derived >::RandomAccessLinSpacedReturnType
inline Derived LinSpaced(
typename Derived::Index size,
const typename Derived::Scalar & low,
const typename Derived::Scalar & high);
}
// Implementation
template <typename Derived>
//inline typename Eigen::DenseBase< Derived >::RandomAccessLinSpacedReturnType
inline Derived
igl::LinSpaced(
typename Derived::Index size,
const typename Derived::Scalar & low,
const typename Derived::Scalar & high)
{
if(size == 0)
{
// Force empty vector with correct "RandomAccessLinSpacedReturnType" type.
return Derived::LinSpaced(0,0,1);
}else if(high < low)
{
return low-Derived::LinSpaced(size,low-low,low-high).array();
}else{
return Derived::LinSpaced(size,low,high);
}
}
#endif

23
src/igl/MeshBooleanType.h Normal file
View file

@ -0,0 +1,23 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_MESH_BOOLEAN_TYPE_H
#define IGL_MESH_BOOLEAN_TYPE_H
namespace igl
{
enum MeshBooleanType
{
MESH_BOOLEAN_TYPE_UNION = 0,
MESH_BOOLEAN_TYPE_INTERSECT = 1,
MESH_BOOLEAN_TYPE_MINUS = 2,
MESH_BOOLEAN_TYPE_XOR = 3,
MESH_BOOLEAN_TYPE_RESOLVE = 4,
NUM_MESH_BOOLEAN_TYPES = 5
};
};
#endif

27
src/igl/NormalType.h Normal file
View file

@ -0,0 +1,27 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_NORMALTYPE_H
#define IGL_NORMALTYPE_H
namespace igl
{
// PER_VERTEX_NORMALS Normals computed per vertex based on incident faces
// PER_FACE_NORMALS Normals computed per face
// PER_CORNER_NORMALS Normals computed per corner (aka wedge) based on
// incident faces without sharp edge
enum NormalType
{
PER_VERTEX_NORMALS,
PER_FACE_NORMALS,
PER_CORNER_NORMALS
};
# define NUM_NORMAL_TYPE 3
}
#endif

22
src/igl/ONE.h Normal file
View file

@ -0,0 +1,22 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ONE_H
#define IGL_ONE_H
namespace igl
{
// Often one needs a reference to a dummy variable containing one as its
// value, for example when using AntTweakBar's
// TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ONE);
const char CHAR_ONE = 1;
const int INT_ONE = 1;
const unsigned int UNSIGNED_INT_ONE = 1;
const double DOUBLE_ONE = 1;
const float FLOAT_ONE = 1;
}
#endif

19
src/igl/PI.h Normal file
View file

@ -0,0 +1,19 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_PI_H
#define IGL_PI_H
namespace igl
{
// Use standard mathematical constants' M_PI if available
#ifdef M_PI
const double PI = M_PI;
#else
const double PI = 3.1415926535897932384626433832795;
#endif
}
#endif

55
src/igl/REDRUM.h Normal file
View file

@ -0,0 +1,55 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_REDRUM_H
#define IGL_REDRUM_H
// Q: These should probably be inside the igl namespace. What's the correct
// way to do that?
// A: I guess the right way is to not use a macro but a proper function with
// streams as input and output.
// ANSI color codes for formatting iostream style output
#ifdef IGL_REDRUM_NOOP
// Bold Red, etc.
#define NORUM(X) X
#define REDRUM(X) X
#define GREENRUM(X) X
#define YELLOWRUM(X) X
#define BLUERUM(X) X
#define MAGENTARUM(X) X
#define CYANRUM(X) X
// Regular Red, etc.
#define REDGIN(X) X
#define GREENGIN(X) X
#define YELLOWGIN(X) X
#define BLUEGIN(X) X
#define MAGENTAGIN(X) X
#define CYANGIN(X) X
#else
// Bold Red, etc.
#define NORUM(X) ""<<X<<""
#define REDRUM(X) "\e[1m\e[31m"<<X<<"\e[m"
#define GREENRUM(X) "\e[1m\e[32m"<<X<<"\e[m"
#define YELLOWRUM(X) "\e[1m\e[33m"<<X<<"\e[m"
#define BLUERUM(X) "\e[1m\e[34m"<<X<<"\e[m"
#define MAGENTARUM(X) "\e[1m\e[35m"<<X<<"\e[m"
#define CYANRUM(X) "\e[1m\e[36m"<<X<<"\e[m"
// Regular Red, etc.
#define REDGIN(X) "\e[31m"<<X<<"\e[m"
#define GREENGIN(X) "\e[32m"<<X<<"\e[m"
#define YELLOWGIN(X) "\e[33m"<<X<<"\e[m"
#define BLUEGIN(X) "\e[34m"<<X<<"\e[m"
#define MAGENTAGIN(X) "\e[35m"<<X<<"\e[m"
#define CYANGIN(X) "\e[36m"<<X<<"\e[m"
#endif
#endif

18
src/igl/STR.h Normal file
View file

@ -0,0 +1,18 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_STR_H
#define IGL_STR_H
// http://stackoverflow.com/a/2433143/148668
#include <string>
#include <sstream>
// Suppose you have a function:
// void func(std::string c);
// Then you can write:
// func(STR("foo"<<1<<"bar"));
#define STR(X) static_cast<std::ostringstream&>(std::ostringstream().flush() << X).str()
#endif

View file

@ -0,0 +1,128 @@
//#####################################################################
// Copyright (c) 2010-2011, Eftychios Sifakis.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//#####################################################################
//###########################################################
// Compute the Givens half-angle, construct the Givens quaternion and the rotation sine/cosine (for the full angle)
//###########################################################
#ifdef _WIN32
#undef max
#undef min
#endif
ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=SANPIVOT.f*SANPIVOT.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(VANPIVOT,VANPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(VANPIVOT,VANPIVOT);)
ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=(Ssh.f>=Ssmall_number.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_cmpge_ps(Vsh,Vsmall_number);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_cmp_ps(Vsh,Vsmall_number, _CMP_GE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_cmpge_ps(Vsh,Vsmall_number);)
ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Ssh.ui&SANPIVOT.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_and_ps(Vsh,VANPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_and_ps(Vsh,VANPIVOT);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vtmp5,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vtmp5,Vtmp5);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Stmp5.f-SAPIVOT.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_sub_ps(Vtmp5,VAPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_sub_ps(Vtmp5,VAPIVOT);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.f=std::max(Sch.f,SAPIVOT.f);) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_max_ps(Vch,VAPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_max_ps(Vch,VAPIVOT);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.f=std::max(Sch.f,Ssmall_number.f);) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_max_ps(Vch,Vsmall_number);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_max_ps(Vch,Vsmall_number);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=(SAPIVOT.f>=Stmp5.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_cmpge_ps(VAPIVOT,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_cmp_ps(VAPIVOT,Vtmp5, _CMP_GE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_cmpge_ps(VAPIVOT,Vtmp5);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vch,Vch);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=rsqrt(Stmp2.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_rsqrt_ps(Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_rsqrt_ps(Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp1.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp1,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp1,Vone_half);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp4);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp3);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp2.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp2,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp2,Vtmp3);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vtmp1,Vtmp4);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f-Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_sub_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_sub_ps(Vtmp1,Vtmp3);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vtmp1,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Sch.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_add_ps(Vch,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_add_ps(Vch,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=~Stmp5.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_andnot_ps(Vtmp5,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=Vch;)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=~Stmp5.ui&Sch.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_andnot_ps(Vtmp5,Vch);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_blendv_ps(Vsh,Vch,Vtmp5);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Stmp5.ui&Sch.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_and_ps(Vtmp5,Vch);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_blendv_ps(Vtmp1,Vsh,Vtmp5);)
ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Stmp5.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_and_ps(Vtmp5,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Sch.ui|Stmp1.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_or_ps(Vch,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Ssh.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_or_ps(Vsh,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vch,Vch);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=rsqrt(Stmp2.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_rsqrt_ps(Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_rsqrt_ps(Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp1.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp1,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp1,Vone_half);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp4);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp3);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp2.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp2,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp2,Vtmp3);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vtmp1,Vtmp4);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f-Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_sub_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_sub_ps(Vtmp1,Vtmp3);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Sch.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_mul_ps(Vch,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_mul_ps(Vch,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Ssh.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vsh,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vsh,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vch,Vch);)ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vsh,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Sc.f-Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_sub_ps(Vc,Vs);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_sub_ps(Vc,Vs);)
ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ssh.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vsh,Vch);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vsh,Vch);)
ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ss.f+Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_add_ps(Vs,Vs);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_add_ps(Vs,Vs);)
//###########################################################
// Rotate matrix A
//###########################################################
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SA11.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VA11);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VA11);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SA21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VA21);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VA21);)
ENABLE_SCALAR_IMPLEMENTATION(SA11.f=Sc.f*SA11.f;) ENABLE_SSE_IMPLEMENTATION(VA11=_mm_mul_ps(Vc,VA11);) ENABLE_AVX_IMPLEMENTATION(VA11=_mm256_mul_ps(Vc,VA11);)
ENABLE_SCALAR_IMPLEMENTATION(SA21.f=Sc.f*SA21.f;) ENABLE_SSE_IMPLEMENTATION(VA21=_mm_mul_ps(Vc,VA21);) ENABLE_AVX_IMPLEMENTATION(VA21=_mm256_mul_ps(Vc,VA21);)
ENABLE_SCALAR_IMPLEMENTATION(SA11.f=SA11.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VA11=_mm_add_ps(VA11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VA11=_mm256_add_ps(VA11,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(SA21.f=SA21.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VA21=_mm_sub_ps(VA21,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VA21=_mm256_sub_ps(VA21,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SA12.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VA12);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VA12);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SA22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VA22);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VA22);)
ENABLE_SCALAR_IMPLEMENTATION(SA12.f=Sc.f*SA12.f;) ENABLE_SSE_IMPLEMENTATION(VA12=_mm_mul_ps(Vc,VA12);) ENABLE_AVX_IMPLEMENTATION(VA12=_mm256_mul_ps(Vc,VA12);)
ENABLE_SCALAR_IMPLEMENTATION(SA22.f=Sc.f*SA22.f;) ENABLE_SSE_IMPLEMENTATION(VA22=_mm_mul_ps(Vc,VA22);) ENABLE_AVX_IMPLEMENTATION(VA22=_mm256_mul_ps(Vc,VA22);)
ENABLE_SCALAR_IMPLEMENTATION(SA12.f=SA12.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VA12=_mm_add_ps(VA12,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VA12=_mm256_add_ps(VA12,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(SA22.f=SA22.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VA22=_mm_sub_ps(VA22,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VA22=_mm256_sub_ps(VA22,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SA13.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VA13);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VA13);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SA23.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VA23);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VA23);)
ENABLE_SCALAR_IMPLEMENTATION(SA13.f=Sc.f*SA13.f;) ENABLE_SSE_IMPLEMENTATION(VA13=_mm_mul_ps(Vc,VA13);) ENABLE_AVX_IMPLEMENTATION(VA13=_mm256_mul_ps(Vc,VA13);)
ENABLE_SCALAR_IMPLEMENTATION(SA23.f=Sc.f*SA23.f;) ENABLE_SSE_IMPLEMENTATION(VA23=_mm_mul_ps(Vc,VA23);) ENABLE_AVX_IMPLEMENTATION(VA23=_mm256_mul_ps(Vc,VA23);)
ENABLE_SCALAR_IMPLEMENTATION(SA13.f=SA13.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VA13=_mm_add_ps(VA13,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VA13=_mm256_add_ps(VA13,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(SA23.f=SA23.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VA23=_mm_sub_ps(VA23,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VA23=_mm256_sub_ps(VA23,Vtmp1);)
//###########################################################
// Update matrix U
//###########################################################
#ifdef COMPUTE_U_AS_MATRIX
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SU11.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VU11);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VU11);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SU12.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VU12);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VU12);)
ENABLE_SCALAR_IMPLEMENTATION(SU11.f=Sc.f*SU11.f;) ENABLE_SSE_IMPLEMENTATION(VU11=_mm_mul_ps(Vc,VU11);) ENABLE_AVX_IMPLEMENTATION(VU11=_mm256_mul_ps(Vc,VU11);)
ENABLE_SCALAR_IMPLEMENTATION(SU12.f=Sc.f*SU12.f;) ENABLE_SSE_IMPLEMENTATION(VU12=_mm_mul_ps(Vc,VU12);) ENABLE_AVX_IMPLEMENTATION(VU12=_mm256_mul_ps(Vc,VU12);)
ENABLE_SCALAR_IMPLEMENTATION(SU11.f=SU11.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VU11=_mm_add_ps(VU11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VU11=_mm256_add_ps(VU11,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(SU12.f=SU12.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VU12=_mm_sub_ps(VU12,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VU12=_mm256_sub_ps(VU12,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SU21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VU21);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VU21);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SU22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VU22);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VU22);)
ENABLE_SCALAR_IMPLEMENTATION(SU21.f=Sc.f*SU21.f;) ENABLE_SSE_IMPLEMENTATION(VU21=_mm_mul_ps(Vc,VU21);) ENABLE_AVX_IMPLEMENTATION(VU21=_mm256_mul_ps(Vc,VU21);)
ENABLE_SCALAR_IMPLEMENTATION(SU22.f=Sc.f*SU22.f;) ENABLE_SSE_IMPLEMENTATION(VU22=_mm_mul_ps(Vc,VU22);) ENABLE_AVX_IMPLEMENTATION(VU22=_mm256_mul_ps(Vc,VU22);)
ENABLE_SCALAR_IMPLEMENTATION(SU21.f=SU21.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VU21=_mm_add_ps(VU21,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VU21=_mm256_add_ps(VU21,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(SU22.f=SU22.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VU22=_mm_sub_ps(VU22,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VU22=_mm256_sub_ps(VU22,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SU31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VU31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VU31);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SU32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VU32);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VU32);)
ENABLE_SCALAR_IMPLEMENTATION(SU31.f=Sc.f*SU31.f;) ENABLE_SSE_IMPLEMENTATION(VU31=_mm_mul_ps(Vc,VU31);) ENABLE_AVX_IMPLEMENTATION(VU31=_mm256_mul_ps(Vc,VU31);)
ENABLE_SCALAR_IMPLEMENTATION(SU32.f=Sc.f*SU32.f;) ENABLE_SSE_IMPLEMENTATION(VU32=_mm_mul_ps(Vc,VU32);) ENABLE_AVX_IMPLEMENTATION(VU32=_mm256_mul_ps(Vc,VU32);)
ENABLE_SCALAR_IMPLEMENTATION(SU31.f=SU31.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VU31=_mm_add_ps(VU31,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VU31=_mm256_add_ps(VU31,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(SU32.f=SU32.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VU32=_mm_sub_ps(VU32,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VU32=_mm256_sub_ps(VU32,Vtmp1);)
#endif

View file

@ -0,0 +1,118 @@
//#####################################################################
// Copyright (c) 2010-2011, Eftychios Sifakis.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//#####################################################################
//###########################################################
// Compute the Givens angle (and half-angle)
//###########################################################
ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=SS21.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(VS21,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(VS21,Vone_half);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=SS11.f-SS22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_sub_ps(VS11,VS22);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_sub_ps(VS11,VS22);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=(Stmp2.f>=Stiny_number.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_cmpge_ps(Vtmp2,Vtiny_number);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmp_ps(Vtmp2,Vtiny_number, _CMP_GE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmpge_ps(Vtmp2,Vtiny_number);)
ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Stmp1.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_and_ps(Vtmp1,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_and_ps(Vtmp1,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Stmp1.ui&Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_and_ps(Vtmp1,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_blendv_ps(Vone,Vtmp5,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=~Stmp1.ui&Sone.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_andnot_ps(Vtmp1,Vone);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Sch.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_or_ps(Vch,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vsh,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vch,Vch);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_add_ps(Vtmp1,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=rsqrt(Stmp3.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_rsqrt_ps(Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_rsqrt_ps(Vtmp3);)
#ifdef USE_ACCURATE_RSQRT_IN_JACOBI_CONJUGATION
ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Stmp4.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vtmp4,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vtmp4,Vone_half);)
ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp4.f*Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vtmp4,Vs);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vtmp4,Vs);)
ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp4.f*Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vtmp4,Vc);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vtmp4,Vc);)
ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp3.f*Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vtmp3,Vc);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vtmp3,Vc);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f+Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_add_ps(Vtmp4,Vs);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_add_ps(Vtmp4,Vs);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f-Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_sub_ps(Vtmp4,Vc);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_sub_ps(Vtmp4,Vc);)
#endif
ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Stmp4.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vtmp4,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vtmp4,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Stmp4.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_mul_ps(Vtmp4,Vch);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_mul_ps(Vtmp4,Vch);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sfour_gamma_squared.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vfour_gamma_squared,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vfour_gamma_squared,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=(Stmp2.f<=Stmp1.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_cmple_ps(Vtmp2,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmp_ps(Vtmp2,Vtmp1, _CMP_LE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmple_ps(Vtmp2,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=Ssine_pi_over_eight.ui&Stmp1.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_and_ps(Vsine_pi_over_eight,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_blendv_ps(Vsh,Vsine_pi_over_eight,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=~Stmp1.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_andnot_ps(Vtmp1,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Ssh.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_or_ps(Vsh,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=Scosine_pi_over_eight.ui&Stmp1.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_and_ps(Vcosine_pi_over_eight,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_blendv_ps(Vch,Vcosine_pi_over_eight,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=~Stmp1.ui&Sch.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_andnot_ps(Vtmp1,Vch);)
ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Sch.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_or_ps(Vch,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vsh,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vch,Vch);)
ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp2.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_sub_ps(Vtmp2,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_sub_ps(Vtmp2,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Sch.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vch,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vch,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ss.f+Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_add_ps(Vs,Vs);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_add_ps(Vs,Vs);)
//###########################################################
// Perform the actual Givens conjugation
//###########################################################
#ifndef USE_ACCURATE_RSQRT_IN_JACOBI_CONJUGATION
ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_add_ps(Vtmp1,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(SS33.f=SS33.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS33=_mm_mul_ps(VS33,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS33=_mm256_mul_ps(VS33,Vtmp3);)
ENABLE_SCALAR_IMPLEMENTATION(SS31.f=SS31.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS31=_mm_mul_ps(VS31,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS31=_mm256_mul_ps(VS31,Vtmp3);)
ENABLE_SCALAR_IMPLEMENTATION(SS32.f=SS32.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS32=_mm_mul_ps(VS32,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS32=_mm256_mul_ps(VS32,Vtmp3);)
ENABLE_SCALAR_IMPLEMENTATION(SS33.f=SS33.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS33=_mm_mul_ps(VS33,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS33=_mm256_mul_ps(VS33,Vtmp3);)
#endif
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SS31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VS31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VS31);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SS32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VS32);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VS32);)
ENABLE_SCALAR_IMPLEMENTATION(SS31.f=Sc.f*SS31.f;) ENABLE_SSE_IMPLEMENTATION(VS31=_mm_mul_ps(Vc,VS31);) ENABLE_AVX_IMPLEMENTATION(VS31=_mm256_mul_ps(Vc,VS31);)
ENABLE_SCALAR_IMPLEMENTATION(SS32.f=Sc.f*SS32.f;) ENABLE_SSE_IMPLEMENTATION(VS32=_mm_mul_ps(Vc,VS32);) ENABLE_AVX_IMPLEMENTATION(VS32=_mm256_mul_ps(Vc,VS32);)
ENABLE_SCALAR_IMPLEMENTATION(SS31.f=Stmp2.f+SS31.f;) ENABLE_SSE_IMPLEMENTATION(VS31=_mm_add_ps(Vtmp2,VS31);) ENABLE_AVX_IMPLEMENTATION(VS31=_mm256_add_ps(Vtmp2,VS31);)
ENABLE_SCALAR_IMPLEMENTATION(SS32.f=SS32.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VS32=_mm_sub_ps(VS32,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VS32=_mm256_sub_ps(VS32,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,Vs);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,Vs);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=SS22.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(VS22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(VS22,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=SS11.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(VS11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(VS11,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sc.f*Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vc,Vc);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vc,Vc);)
ENABLE_SCALAR_IMPLEMENTATION(SS11.f=SS11.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(VS11=_mm_mul_ps(VS11,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(VS11=_mm256_mul_ps(VS11,Vtmp4);)
ENABLE_SCALAR_IMPLEMENTATION(SS22.f=SS22.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(VS22=_mm_mul_ps(VS22,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(VS22=_mm256_mul_ps(VS22,Vtmp4);)
ENABLE_SCALAR_IMPLEMENTATION(SS11.f=SS11.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VS11=_mm_add_ps(VS11,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VS11=_mm256_add_ps(VS11,Vtmp1);)
ENABLE_SCALAR_IMPLEMENTATION(SS22.f=SS22.f+Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS22=_mm_add_ps(VS22,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS22=_mm256_add_ps(VS22,Vtmp3);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f-Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_sub_ps(Vtmp4,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_sub_ps(Vtmp4,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=SS21.f+SS21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(VS21,VS21);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(VS21,VS21);)
ENABLE_SCALAR_IMPLEMENTATION(SS21.f=SS21.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(VS21=_mm_mul_ps(VS21,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(VS21=_mm256_mul_ps(VS21,Vtmp4);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sc.f*Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vc,Vs);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vc,Vs);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp2.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vtmp2,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vtmp2,Vtmp4);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp5.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_mul_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_mul_ps(Vtmp5,Vtmp4);)
ENABLE_SCALAR_IMPLEMENTATION(SS11.f=SS11.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VS11=_mm_add_ps(VS11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VS11=_mm256_add_ps(VS11,Vtmp2);)
ENABLE_SCALAR_IMPLEMENTATION(SS21.f=SS21.f-Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(VS21=_mm_sub_ps(VS21,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(VS21=_mm256_sub_ps(VS21,Vtmp5);)
ENABLE_SCALAR_IMPLEMENTATION(SS22.f=SS22.f-Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VS22=_mm_sub_ps(VS22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VS22=_mm256_sub_ps(VS22,Vtmp2);)
//###########################################################
// Compute the cumulative rotation, in quaternion form
//###########################################################
ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ssh.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vsh,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vsh,Vqvvx);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vqvvy);)
ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Ssh.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vsh,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vsh,Vqvvz);)
ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Ssh.f*Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vsh,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vsh,Vqvs);)
ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sch.f*Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_mul_ps(Vch,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_mul_ps(Vch,Vqvs);)
ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=Sch.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=_mm_mul_ps(Vch,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vqvvx=_mm256_mul_ps(Vch,Vqvvx);)
ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=Sch.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=_mm_mul_ps(Vch,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vqvvy=_mm256_mul_ps(Vch,Vqvvy);)
ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=Sch.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=_mm_mul_ps(Vch,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vqvvz=_mm256_mul_ps(Vch,Vqvvz);)
ENABLE_SCALAR_IMPLEMENTATION(SQVVZ.f=SQVVZ.f+Ssh.f;) ENABLE_SSE_IMPLEMENTATION(VQVVZ=_mm_add_ps(VQVVZ,Vsh);) ENABLE_AVX_IMPLEMENTATION(VQVVZ=_mm256_add_ps(VQVVZ,Vsh);)
ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sqvs.f-STMP3.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_sub_ps(Vqvs,VTMP3);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_sub_ps(Vqvs,VTMP3);)
ENABLE_SCALAR_IMPLEMENTATION(SQVVX.f=SQVVX.f+STMP2.f;) ENABLE_SSE_IMPLEMENTATION(VQVVX=_mm_add_ps(VQVVX,VTMP2);) ENABLE_AVX_IMPLEMENTATION(VQVVX=_mm256_add_ps(VQVVX,VTMP2);)
ENABLE_SCALAR_IMPLEMENTATION(SQVVY.f=SQVVY.f-STMP1.f;) ENABLE_SSE_IMPLEMENTATION(VQVVY=_mm_sub_ps(VQVVY,VTMP1);) ENABLE_AVX_IMPLEMENTATION(VQVVY=_mm256_sub_ps(VQVVY,VTMP1);)

View file

@ -0,0 +1,137 @@
//#####################################################################
// Copyright (c) 2010-2011, Eftychios Sifakis.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//#####################################################################
//###########################################################
// Local variable declarations
//###########################################################
#ifdef PRINT_DEBUGGING_OUTPUT
#ifdef USE_SSE_IMPLEMENTATION
float buf[4];
float A11,A21,A31,A12,A22,A32,A13,A23,A33;
float S11,S21,S31,S22,S32,S33;
#ifdef COMPUTE_V_AS_QUATERNION
float QVS,QVVX,QVVY,QVVZ;
#endif
#ifdef COMPUTE_V_AS_MATRIX
float V11,V21,V31,V12,V22,V32,V13,V23,V33;
#endif
#ifdef COMPUTE_U_AS_QUATERNION
float QUS,QUVX,QUVY,QUVZ;
#endif
#ifdef COMPUTE_U_AS_MATRIX
float U11,U21,U31,U12,U22,U32,U13,U23,U33;
#endif
#endif
#ifdef USE_AVX_IMPLEMENTATION
float buf[8];
float A11,A21,A31,A12,A22,A32,A13,A23,A33;
float S11,S21,S31,S22,S32,S33;
#ifdef COMPUTE_V_AS_QUATERNION
float QVS,QVVX,QVVY,QVVZ;
#endif
#ifdef COMPUTE_V_AS_MATRIX
float V11,V21,V31,V12,V22,V32,V13,V23,V33;
#endif
#ifdef COMPUTE_U_AS_QUATERNION
float QUS,QUVX,QUVY,QUVZ;
#endif
#ifdef COMPUTE_U_AS_MATRIX
float U11,U21,U31,U12,U22,U32,U13,U23,U33;
#endif
#endif
#endif
const float Four_Gamma_Squared=sqrt(8.)+3.;
const float Sine_Pi_Over_Eight=.5*sqrt(2.-sqrt(2.));
const float Cosine_Pi_Over_Eight=.5*sqrt(2.+sqrt(2.));
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sfour_gamma_squared;) ENABLE_SSE_IMPLEMENTATION(__m128 Vfour_gamma_squared;) ENABLE_AVX_IMPLEMENTATION(__m256 Vfour_gamma_squared;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ssine_pi_over_eight;) ENABLE_SSE_IMPLEMENTATION(__m128 Vsine_pi_over_eight;) ENABLE_AVX_IMPLEMENTATION(__m256 Vsine_pi_over_eight;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Scosine_pi_over_eight;) ENABLE_SSE_IMPLEMENTATION(__m128 Vcosine_pi_over_eight;) ENABLE_AVX_IMPLEMENTATION(__m256 Vcosine_pi_over_eight;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sone_half;) ENABLE_SSE_IMPLEMENTATION(__m128 Vone_half;) ENABLE_AVX_IMPLEMENTATION(__m256 Vone_half;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sone;) ENABLE_SSE_IMPLEMENTATION(__m128 Vone;) ENABLE_AVX_IMPLEMENTATION(__m256 Vone;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stiny_number;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtiny_number;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtiny_number;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ssmall_number;) ENABLE_SSE_IMPLEMENTATION(__m128 Vsmall_number;) ENABLE_AVX_IMPLEMENTATION(__m256 Vsmall_number;)
ENABLE_SCALAR_IMPLEMENTATION(Sfour_gamma_squared.f=Four_Gamma_Squared;) ENABLE_SSE_IMPLEMENTATION(Vfour_gamma_squared=_mm_set1_ps(Four_Gamma_Squared);) ENABLE_AVX_IMPLEMENTATION(Vfour_gamma_squared=_mm256_set1_ps(Four_Gamma_Squared);)
ENABLE_SCALAR_IMPLEMENTATION(Ssine_pi_over_eight.f=Sine_Pi_Over_Eight;) ENABLE_SSE_IMPLEMENTATION(Vsine_pi_over_eight=_mm_set1_ps(Sine_Pi_Over_Eight);) ENABLE_AVX_IMPLEMENTATION(Vsine_pi_over_eight=_mm256_set1_ps(Sine_Pi_Over_Eight);)
ENABLE_SCALAR_IMPLEMENTATION(Scosine_pi_over_eight.f=Cosine_Pi_Over_Eight;) ENABLE_SSE_IMPLEMENTATION(Vcosine_pi_over_eight=_mm_set1_ps(Cosine_Pi_Over_Eight);) ENABLE_AVX_IMPLEMENTATION(Vcosine_pi_over_eight=_mm256_set1_ps(Cosine_Pi_Over_Eight);)
ENABLE_SCALAR_IMPLEMENTATION(Sone_half.f=.5;) ENABLE_SSE_IMPLEMENTATION(Vone_half=_mm_set1_ps(.5);) ENABLE_AVX_IMPLEMENTATION(Vone_half=_mm256_set1_ps(.5);)
ENABLE_SCALAR_IMPLEMENTATION(Sone.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vone=_mm_set1_ps(1.);) ENABLE_AVX_IMPLEMENTATION(Vone=_mm256_set1_ps(1.);)
ENABLE_SCALAR_IMPLEMENTATION(Stiny_number.f=1.e-20;) ENABLE_SSE_IMPLEMENTATION(Vtiny_number=_mm_set1_ps(1.e-20);) ENABLE_AVX_IMPLEMENTATION(Vtiny_number=_mm256_set1_ps(1.e-20);)
ENABLE_SCALAR_IMPLEMENTATION(Ssmall_number.f=1.e-12;) ENABLE_SSE_IMPLEMENTATION(Vsmall_number=_mm_set1_ps(1.e-12);) ENABLE_AVX_IMPLEMENTATION(Vsmall_number=_mm256_set1_ps(1.e-12);)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa11;) ENABLE_SSE_IMPLEMENTATION(__m128 Va11;) ENABLE_AVX_IMPLEMENTATION(__m256 Va11;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa21;) ENABLE_SSE_IMPLEMENTATION(__m128 Va21;) ENABLE_AVX_IMPLEMENTATION(__m256 Va21;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa31;) ENABLE_SSE_IMPLEMENTATION(__m128 Va31;) ENABLE_AVX_IMPLEMENTATION(__m256 Va31;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa12;) ENABLE_SSE_IMPLEMENTATION(__m128 Va12;) ENABLE_AVX_IMPLEMENTATION(__m256 Va12;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa22;) ENABLE_SSE_IMPLEMENTATION(__m128 Va22;) ENABLE_AVX_IMPLEMENTATION(__m256 Va22;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa32;) ENABLE_SSE_IMPLEMENTATION(__m128 Va32;) ENABLE_AVX_IMPLEMENTATION(__m256 Va32;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa13;) ENABLE_SSE_IMPLEMENTATION(__m128 Va13;) ENABLE_AVX_IMPLEMENTATION(__m256 Va13;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa23;) ENABLE_SSE_IMPLEMENTATION(__m128 Va23;) ENABLE_AVX_IMPLEMENTATION(__m256 Va23;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa33;) ENABLE_SSE_IMPLEMENTATION(__m128 Va33;) ENABLE_AVX_IMPLEMENTATION(__m256 Va33;)
#ifdef COMPUTE_V_AS_MATRIX
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv11;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv11;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv11;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv21;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv21;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv21;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv31;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv31;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv31;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv12;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv12;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv12;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv22;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv22;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv22;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv32;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv32;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv32;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv13;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv13;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv13;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv23;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv23;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv23;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv33;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv33;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv33;)
#endif
#ifdef COMPUTE_V_AS_QUATERNION
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvs;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvs;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvs;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvx;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvx;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvx;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvy;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvy;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvy;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvz;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvz;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvz;)
#endif
#ifdef COMPUTE_U_AS_MATRIX
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su11;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu11;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu11;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su21;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu21;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu21;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su31;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu31;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu31;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su12;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu12;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu12;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su22;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu22;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu22;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su32;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu32;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu32;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su13;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu13;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu13;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su23;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu23;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu23;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su33;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu33;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu33;)
#endif
#ifdef COMPUTE_U_AS_QUATERNION
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squs;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqus;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqus;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squvx;) ENABLE_SSE_IMPLEMENTATION(__m128 Vquvx;) ENABLE_AVX_IMPLEMENTATION(__m256 Vquvx;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squvy;) ENABLE_SSE_IMPLEMENTATION(__m128 Vquvy;) ENABLE_AVX_IMPLEMENTATION(__m256 Vquvy;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squvz;) ENABLE_SSE_IMPLEMENTATION(__m128 Vquvz;) ENABLE_AVX_IMPLEMENTATION(__m256 Vquvz;)
#endif
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sc;) ENABLE_SSE_IMPLEMENTATION(__m128 Vc;) ENABLE_AVX_IMPLEMENTATION(__m256 Vc;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sch;) ENABLE_SSE_IMPLEMENTATION(__m128 Vch;) ENABLE_AVX_IMPLEMENTATION(__m256 Vch;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ssh;) ENABLE_SSE_IMPLEMENTATION(__m128 Vsh;) ENABLE_AVX_IMPLEMENTATION(__m256 Vsh;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp1;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp1;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp1;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp2;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp2;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp2;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp3;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp3;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp3;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp4;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp4;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp4;)
ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp5;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp5;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp5;)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,78 @@
//#####################################################################
// Copyright (c) 2010-2011, Eftychios Sifakis.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//#####################################################################
#ifdef PRINT_DEBUGGING_OUTPUT
#include <iomanip>
#include <iostream>
#endif
// Prevent warnings
#ifdef ENABLE_SCALAR_IMPLEMENTATION
# undef ENABLE_SCALAR_IMPLEMENTATION
#endif
#ifdef ENABLE_SSE_IMPLEMENTATION
# undef ENABLE_SSE_IMPLEMENTATION
#endif
#ifdef ENABLE_AVX_IMPLEMENTATION
# undef ENABLE_AVX_IMPLEMENTATION
#endif
#ifdef USE_SCALAR_IMPLEMENTATION
#define ENABLE_SCALAR_IMPLEMENTATION(X) X
#else
#define ENABLE_SCALAR_IMPLEMENTATION(X)
#endif
#ifdef USE_SSE_IMPLEMENTATION
#define ENABLE_SSE_IMPLEMENTATION(X) X
#else
#define ENABLE_SSE_IMPLEMENTATION(X)
#endif
#ifdef USE_AVX_IMPLEMENTATION
#include <immintrin.h>
#define ENABLE_AVX_IMPLEMENTATION(X) X
#else
// Stefan: removed include. Why does it import MMX instructions, shouldn't this be under the #ifdef USE_SSE_IMPLEMENTATION above?
//#include <xmmintrin.h>
#define ENABLE_AVX_IMPLEMENTATION(X)
#endif
#ifdef USE_SCALAR_IMPLEMENTATION
// Alec: Why is this using sse intrinsics if it's supposed to be the scalar
// implementation?
#ifdef __SSE__
#include <mmintrin.h>
// Changed to inline
inline float rsqrt(const float f)
{
float buf[4];
buf[0]=f;
__m128 v=_mm_loadu_ps(buf);
v=_mm_rsqrt_ss(v);
_mm_storeu_ps(buf,v);
return buf[0];
}
#else
#include <cmath>
inline float rsqrt(const float f)
{
return 1./sqrtf(f);
}
#endif
#endif

23
src/igl/SolverStatus.h Normal file
View file

@ -0,0 +1,23 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_SOLVER_STATUS_H
#define IGL_SOLVER_STATUS_H
namespace igl
{
enum SolverStatus
{
// Good
SOLVER_STATUS_CONVERGED = 0,
// OK
SOLVER_STATUS_MAX_ITER = 1,
// Bad
SOLVER_STATUS_ERROR = 2,
NUM_SOLVER_STATUSES = 3,
};
};
#endif

70
src/igl/SortableRow.h Normal file
View file

@ -0,0 +1,70 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_SORTABLE_ROW_H
#define IGL_SORTABLE_ROW_H
// Simple class to contain a rowvector which allows rowwise sorting and
// reordering
#include <Eigen/Core>
namespace igl
{
// Templates:
// T should be a matrix that implements .size(), and operator(int i)
template <typename T>
class SortableRow
{
public:
T data;
public:
SortableRow():data(){};
SortableRow(const T & data):data(data){};
bool operator<(const SortableRow & that) const
{
// Get reference so that I can use parenthesis
const SortableRow<T> & THIS = *this;
// Lexicographical
int minc = (THIS.data.size() < that.data.size()?
THIS.data.size() : that.data.size());
// loop over columns
for(int i = 0;i<minc;i++)
{
if(THIS.data(i) == that.data(i))
{
continue;
}
return THIS.data(i) < that.data(i);
}
// All characters the same, comes done to length
return THIS.data.size()<that.data.size();
};
bool operator==(const SortableRow & that) const
{
// Get reference so that I can use parenthesis
const SortableRow<T> & THIS = *this;
if(THIS.data.size() != that.data.size())
{
return false;
}
for(int i = 0;i<THIS.data.size();i++)
{
if(THIS.data(i) != that.data(i))
{
return false;
}
}
return true;
};
bool operator!=(const SortableRow & that) const
{
return !(*this == that);
};
};
}
#endif

179
src/igl/Timer.h Normal file
View file

@ -0,0 +1,179 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
// High Resolution Timer.
//
// Resolution on Mac (clock tick)
// Resolution on Linux (1 us not tested)
// Resolution on Windows (clock tick not tested)
#ifndef IGL_TIMER_H
#define IGL_TIMER_H
#ifdef WIN32 // Windows system specific
#include <windows.h>
#elif __APPLE__ // Unix based system specific
#include <mach/mach_time.h> // for mach_absolute_time
#else
#include <sys/time.h>
#endif
#include <cstddef>
namespace igl
{
class Timer
{
public:
// default constructor
Timer():
stopped(0),
#ifdef WIN32
frequency(),
startCount(),
endCount()
#elif __APPLE__
startCount(0),
endCount(0)
#else
startCount(),
endCount()
#endif
{
#ifdef WIN32
QueryPerformanceFrequency(&frequency);
startCount.QuadPart = 0;
endCount.QuadPart = 0;
#elif __APPLE__
startCount = 0;
endCount = 0;
#else
startCount.tv_sec = startCount.tv_usec = 0;
endCount.tv_sec = endCount.tv_usec = 0;
#endif
stopped = 0;
}
// default destructor
~Timer()
{
}
#ifdef __APPLE__
//Raw mach_absolute_times going in, difference in seconds out
double subtractTimes( uint64_t endTime, uint64_t startTime )
{
uint64_t difference = endTime - startTime;
static double conversion = 0.0;
if( conversion == 0.0 )
{
mach_timebase_info_data_t info;
kern_return_t err = mach_timebase_info( &info );
//Convert the timebase into seconds
if( err == 0 )
conversion = 1e-9 * (double) info.numer / (double) info.denom;
}
return conversion * (double) difference;
}
#endif
// start timer
void start()
{
stopped = 0; // reset stop flag
#ifdef WIN32
QueryPerformanceCounter(&startCount);
#elif __APPLE__
startCount = mach_absolute_time();
#else
gettimeofday(&startCount, NULL);
#endif
}
// stop the timer
void stop()
{
stopped = 1; // set timer stopped flag
#ifdef WIN32
QueryPerformanceCounter(&endCount);
#elif __APPLE__
endCount = mach_absolute_time();
#else
gettimeofday(&endCount, NULL);
#endif
}
// get elapsed time in second
double getElapsedTime()
{
return this->getElapsedTimeInSec();
}
// get elapsed time in second (same as getElapsedTime)
double getElapsedTimeInSec()
{
return this->getElapsedTimeInMicroSec() * 0.000001;
}
// get elapsed time in milli-second
double getElapsedTimeInMilliSec()
{
return this->getElapsedTimeInMicroSec() * 0.001;
}
// get elapsed time in micro-second
double getElapsedTimeInMicroSec()
{
double startTimeInMicroSec = 0;
double endTimeInMicroSec = 0;
#ifdef WIN32
if(!stopped)
QueryPerformanceCounter(&endCount);
startTimeInMicroSec =
startCount.QuadPart * (1000000.0 / frequency.QuadPart);
endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart);
#elif __APPLE__
if (!stopped)
endCount = mach_absolute_time();
return subtractTimes(endCount,startCount)/1e-6;
#else
if(!stopped)
gettimeofday(&endCount, NULL);
startTimeInMicroSec =
(startCount.tv_sec * 1000000.0) + startCount.tv_usec;
endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec;
#endif
return endTimeInMicroSec - startTimeInMicroSec;
}
private:
// stop flag
int stopped;
#ifdef WIN32
// ticks per second
LARGE_INTEGER frequency;
LARGE_INTEGER startCount;
LARGE_INTEGER endCount;
#elif __APPLE__
uint64_t startCount;
uint64_t endCount;
#else
timeval startCount;
timeval endCount;
#endif
};
}
#endif // TIMER_H_DEF

69
src/igl/Viewport.h Normal file
View file

@ -0,0 +1,69 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_VIEWPORT_H
#define IGL_VIEWPORT_H
namespace igl
{
// Simple Viewport class for an opengl context. Handles reshaping and mouse.
struct Viewport
{
int x,y,width,height;
// Constructors
Viewport(
const int x=0,
const int y=0,
const int width=0,
const int height=0):
x(x),
y(y),
width(width),
height(height)
{
};
virtual ~Viewport(){}
void reshape(
const int x,
const int y,
const int width,
const int height)
{
this->x = x;
this->y = y;
this->width = width;
this->height = height;
};
// Given mouse_x,mouse_y on the entire window return mouse_x, mouse_y in
// this viewport.
//
// Inputs:
// my mouse y-coordinate
// wh window height
// Returns y-coordinate in viewport
int mouse_y(const int my,const int wh)
{
return my - (wh - height - y);
}
// Inputs:
// mx mouse x-coordinate
// Returns x-coordinate in viewport
int mouse_x(const int mx)
{
return mx - x;
}
// Returns whether point (mx,my) is in extend of Viewport
bool inside(const int mx, const int my) const
{
return
mx >= x && my >= y &&
mx < x+width && my < y+height;
}
};
}
#endif

377
src/igl/WindingNumberAABB.h Normal file
View file

@ -0,0 +1,377 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
// # MUTUAL DEPENDENCY ISSUE FOR HEADER ONLY VERSION
// MUST INCLUDE winding_number.h first before guard:
#include "winding_number.h"
#ifndef IGL_WINDINGNUMBERAABB_H
#define IGL_WINDINGNUMBERAABB_H
#include "WindingNumberTree.h"
namespace igl
{
template <
typename Point,
typename DerivedV,
typename DerivedF >
class WindingNumberAABB : public WindingNumberTree<Point,DerivedV,DerivedF>
{
protected:
Point min_corner;
Point max_corner;
typename DerivedV::Scalar total_positive_area;
public:
enum SplitMethod
{
CENTER_ON_LONGEST_AXIS = 0,
MEDIAN_ON_LONGEST_AXIS = 1,
NUM_SPLIT_METHODS = 2
} split_method;
public:
inline WindingNumberAABB():
total_positive_area(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
split_method(MEDIAN_ON_LONGEST_AXIS)
{}
inline WindingNumberAABB(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
inline WindingNumberAABB(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F);
// Initialize some things
inline void set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
inline void init();
inline bool inside(const Point & p) const;
inline virtual void grow();
// Compute min and max corners
inline void compute_min_max_corners();
inline typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
inline typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
};
}
// Implementation
#include "winding_number.h"
#include "barycenter.h"
#include "median.h"
#include "doublearea.h"
#include "per_face_normals.h"
#include <limits>
#include <vector>
#include <iostream>
// Minimum number of faces in a hierarchy element (this is probably dependent
// on speed of machine and compiler optimization)
#ifndef WindingNumberAABB_MIN_F
# define WindingNumberAABB_MIN_F 100
#endif
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F)
{
igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(V,F);
init();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::init()
{
using namespace Eigen;
assert(max_corner.size() == 3);
assert(min_corner.size() == 3);
compute_min_max_corners();
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,1> dblA;
doublearea(this->getV(),this->getF(),dblA);
total_positive_area = dblA.sum()/2.0;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberAABB<Point,DerivedV,DerivedF>::WindingNumberAABB(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F):
WindingNumberTree<Point,DerivedV,DerivedF>(V,F),
min_corner(),
max_corner(),
total_positive_area(
std::numeric_limits<typename DerivedV::Scalar>::infinity()),
split_method(MEDIAN_ON_LONGEST_AXIS)
{
init();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberAABB<Point,DerivedV,DerivedF>::WindingNumberAABB(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F):
WindingNumberTree<Point,DerivedV,DerivedF>(parent,F),
min_corner(),
max_corner(),
total_positive_area(
std::numeric_limits<typename DerivedV::Scalar>::infinity()),
split_method(MEDIAN_ON_LONGEST_AXIS)
{
init();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
{
using namespace std;
using namespace Eigen;
// Clear anything that already exists
this->delete_children();
//cout<<"cap.rows(): "<<this->getcap().rows()<<endl;
//cout<<"F.rows(): "<<this->getF().rows()<<endl;
// Base cases
if(
this->getF().rows() <= (WindingNumberAABB_MIN_F>0?WindingNumberAABB_MIN_F:0) ||
(this->getcap().rows() - 2) >= this->getF().rows())
{
// Don't grow
return;
}
// Compute longest direction
int max_d = -1;
typename DerivedV::Scalar max_len =
-numeric_limits<typename DerivedV::Scalar>::infinity();
for(int d = 0;d<min_corner.size();d++)
{
if( (max_corner[d] - min_corner[d]) > max_len )
{
max_len = (max_corner[d] - min_corner[d]);
max_d = d;
}
}
// Compute facet barycenters
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic> BC;
barycenter(this->getV(),this->getF(),BC);
// Blerg, why is selecting rows so difficult
typename DerivedV::Scalar split_value;
// Split in longest direction
switch(split_method)
{
case MEDIAN_ON_LONGEST_AXIS:
// Determine median
median(BC.col(max_d),split_value);
break;
default:
assert(false);
case CENTER_ON_LONGEST_AXIS:
split_value = 0.5*(max_corner[max_d] + min_corner[max_d]);
break;
}
//cout<<"c: "<<0.5*(max_corner[max_d] + min_corner[max_d])<<" "<<
// "m: "<<split_value<<endl;;
vector<int> id( this->getF().rows());
for(int i = 0;i<this->getF().rows();i++)
{
if(BC(i,max_d) <= split_value)
{
id[i] = 0; //left
}else
{
id[i] = 1; //right
}
}
const int lefts = (int) count(id.begin(),id.end(),0);
const int rights = (int) count(id.begin(),id.end(),1);
if(lefts == 0 || rights == 0)
{
// badly balanced base case (could try to recut)
return;
}
assert(lefts+rights == this->getF().rows());
DerivedF leftF(lefts, this->getF().cols());
DerivedF rightF(rights,this->getF().cols());
int left_i = 0;
int right_i = 0;
for(int i = 0;i<this->getF().rows();i++)
{
if(id[i] == 0)
{
leftF.row(left_i++) = this->getF().row(i);
}else if(id[i] == 1)
{
rightF.row(right_i++) = this->getF().row(i);
}else
{
assert(false);
}
}
assert(right_i == rightF.rows());
assert(left_i == leftF.rows());
// Finally actually grow children and Recursively grow
WindingNumberAABB<Point,DerivedV,DerivedF> * leftWindingNumberAABB =
new WindingNumberAABB<Point,DerivedV,DerivedF>(*this,leftF);
leftWindingNumberAABB->grow();
this->children.push_back(leftWindingNumberAABB);
WindingNumberAABB<Point,DerivedV,DerivedF> * rightWindingNumberAABB =
new WindingNumberAABB<Point,DerivedV,DerivedF>(*this,rightF);
rightWindingNumberAABB->grow();
this->children.push_back(rightWindingNumberAABB);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline bool igl::WindingNumberAABB<Point,DerivedV,DerivedF>::inside(const Point & p) const
{
assert(p.size() == max_corner.size());
assert(p.size() == min_corner.size());
for(int i = 0;i<p.size();i++)
{
//// Perfect matching is **not** robust
//if( p(i) < min_corner(i) || p(i) >= max_corner(i))
// **MUST** be conservative
if( p(i) < min_corner(i) || p(i) > max_corner(i))
{
return false;
}
}
return true;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::compute_min_max_corners()
{
using namespace std;
// initialize corners
for(int d = 0;d<min_corner.size();d++)
{
min_corner[d] = numeric_limits<typename Point::Scalar>::infinity();
max_corner[d] = -numeric_limits<typename Point::Scalar>::infinity();
}
this->center = Point(0,0,0);
// Loop over facets
for(int i = 0;i<this->getF().rows();i++)
{
for(int j = 0;j<this->getF().cols();j++)
{
for(int d = 0;d<min_corner.size();d++)
{
min_corner[d] =
this->getV()(this->getF()(i,j),d) < min_corner[d] ?
this->getV()(this->getF()(i,j),d) : min_corner[d];
max_corner[d] =
this->getV()(this->getF()(i,j),d) > max_corner[d] ?
this->getV()(this->getF()(i,j),d) : max_corner[d];
}
// This is biased toward vertices incident on more than one face, but
// perhaps that's good
this->center += this->getV().row(this->getF()(i,j));
}
}
// Average
this->center.array() /= this->getF().size();
//cout<<"min_corner: "<<this->min_corner.transpose()<<endl;
//cout<<"Center: "<<this->center.transpose()<<endl;
//cout<<"max_corner: "<<this->max_corner.transpose()<<endl;
//cout<<"Diag center: "<<((this->max_corner + this->min_corner)*0.5).transpose()<<endl;
//cout<<endl;
this->radius = (max_corner-min_corner).norm()/2.0;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberAABB<Point,DerivedV,DerivedF>::max_abs_winding_number(const Point & p) const
{
using namespace std;
// Only valid if not inside
if(inside(p))
{
return numeric_limits<typename DerivedV::Scalar>::infinity();
}
// Q: we know the total positive area so what's the most this could project
// to? Remember it could be layered in the same direction.
return numeric_limits<typename DerivedV::Scalar>::infinity();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberAABB<Point,DerivedV,DerivedF>::max_simple_abs_winding_number(
const Point & p) const
{
using namespace std;
using namespace Eigen;
// Only valid if not inside
if(inside(p))
{
return numeric_limits<typename DerivedV::Scalar>::infinity();
}
// Max simple is the same as sum of positive winding number contributions of
// bounding box
// begin precomputation
//MatrixXd BV((int)pow(2,3),3);
typedef
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
MatrixXS;
typedef
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
MatrixXF;
MatrixXS BV((int)(1<<3),3);
BV <<
min_corner[0],min_corner[1],min_corner[2],
min_corner[0],min_corner[1],max_corner[2],
min_corner[0],max_corner[1],min_corner[2],
min_corner[0],max_corner[1],max_corner[2],
max_corner[0],min_corner[1],min_corner[2],
max_corner[0],min_corner[1],max_corner[2],
max_corner[0],max_corner[1],min_corner[2],
max_corner[0],max_corner[1],max_corner[2];
MatrixXF BF(2*2*3,3);
BF <<
0,6,4,
0,2,6,
0,3,2,
0,1,3,
2,7,6,
2,3,7,
4,6,7,
4,7,5,
0,4,5,
0,5,1,
1,5,7,
1,7,3;
MatrixXS BFN;
per_face_normals(BV,BF,BFN);
// end of precomputation
// Only keep those with positive dot products
MatrixXF PBF(BF.rows(),BF.cols());
int pbfi = 0;
Point p2c = 0.5*(min_corner+max_corner)-p;
for(int i = 0;i<BFN.rows();i++)
{
if(p2c.dot(BFN.row(i)) > 0)
{
PBF.row(pbfi++) = BF.row(i);
}
}
PBF.conservativeResize(pbfi,PBF.cols());
return igl::winding_number(BV,PBF,p);
}
#endif

View file

@ -0,0 +1,23 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_WINDINGNUMBERMETHOD_H
#define IGL_WINDINGNUMBERMETHOD_H
namespace igl
{
// EXACT_WINDING_NUMBER_METHOD exact hierarchical evaluation
// APPROX_SIMPLE_WINDING_NUMBER_METHOD poor approximation
// APPROX_CACHE_WINDING_NUMBER_METHOD another poor approximation
enum WindingNumberMethod
{
EXACT_WINDING_NUMBER_METHOD = 0,
APPROX_SIMPLE_WINDING_NUMBER_METHOD = 1,
APPROX_CACHE_WINDING_NUMBER_METHOD = 2,
NUM_WINDING_NUMBER_METHODS = 3
};
}
#endif

503
src/igl/WindingNumberTree.h Normal file
View file

@ -0,0 +1,503 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_WINDINGNUMBERTREE_H
#define IGL_WINDINGNUMBERTREE_H
#include <list>
#include <map>
#include <Eigen/Dense>
#include "WindingNumberMethod.h"
namespace igl
{
// Space partitioning tree for computing winding number hierarchically.
//
// Templates:
// Point type for points in space, e.g. Eigen::Vector3d
template <
typename Point,
typename DerivedV,
typename DerivedF >
class WindingNumberTree
{
public:
// Method to use (see enum above)
//static double min_max_w;
static std::map<
std::pair<const WindingNumberTree*,const WindingNumberTree*>,
typename DerivedV::Scalar>
cached;
// This is only need to fill in references, it should never actually be touched
// and shouldn't cause race conditions. (This is a hack, but I think it's "safe")
static DerivedV dummyV;
protected:
WindingNumberMethod method;
const WindingNumberTree * parent;
std::list<WindingNumberTree * > children;
typedef
Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
MatrixXS;
typedef
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
MatrixXF;
//// List of boundary edges (recall edges are vertices in 2d)
//const Eigen::MatrixXi boundary;
// Base mesh vertices
DerivedV & V;
// Base mesh vertices with duplicates removed
MatrixXS SV;
// Facets in this bounding volume
MatrixXF F;
// Tessellated boundary curve
MatrixXF cap;
// Upper Bound on radius of enclosing ball
typename DerivedV::Scalar radius;
// (Approximate) center (of mass)
Point center;
public:
inline WindingNumberTree();
// For root
inline WindingNumberTree(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
// For chilluns
inline WindingNumberTree(
const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & F);
inline virtual ~WindingNumberTree();
inline void delete_children();
inline virtual void set_mesh(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F);
// Set method
inline void set_method( const WindingNumberMethod & m);
public:
inline const DerivedV & getV() const;
inline const MatrixXF & getF() const;
inline const MatrixXF & getcap() const;
// Grow the Tree recursively
inline virtual void grow();
// Determine whether a given point is inside the bounding
//
// Inputs:
// p query point
// Returns true if the point p is inside this bounding volume
inline virtual bool inside(const Point & p) const;
// Compute the (partial) winding number of a given point p
// According to method
//
// Inputs:
// p query point
// Returns winding number
inline typename DerivedV::Scalar winding_number(const Point & p) const;
// Same as above, but always computes winding number using exact method
// (sum over every facet)
inline typename DerivedV::Scalar winding_number_all(const Point & p) const;
// Same as above, but always computes using sum over tessllated boundary
inline typename DerivedV::Scalar winding_number_boundary(const Point & p) const;
//// Same as winding_number above, but if max_simple_abs_winding_number is
//// less than some threshold min_max_w just return 0 (colloquially the "fast
//// multipole method)
////
////
//// Inputs:
//// p query point
//// min_max_w minimum max simple w to be processed
//// Returns approximate winding number
//double winding_number_approx_simple(
// const Point & p,
// const double min_max_w);
// Print contents of Tree
//
// Optional input:
// tab tab to show depth
inline void print(const char * tab="");
// Determine max absolute winding number
//
// Inputs:
// p query point
// Returns max winding number of
inline virtual typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
// Same as above, but stronger assumptions on (V,F). Assumes (V,F) is a
// simple polyhedron
inline virtual typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
// Compute or read cached winding number for point p with respect to mesh
// in bounding box, recursing according to approximation criteria
//
// Inputs:
// p query point
// that WindingNumberTree containing mesh w.r.t. which we're computing w.n.
// Returns cached winding number
inline virtual typename DerivedV::Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const;
};
}
// Implementation
#include "WindingNumberTree.h"
#include "winding_number.h"
#include "triangle_fan.h"
#include "exterior_edges.h"
#include <igl/PI.h>
#include <igl/remove_duplicate_vertices.h>
#include <iostream>
#include <limits>
//template <typename Point, typename DerivedV, typename DerivedF>
//WindingNumberMethod WindingNumberTree<Point,DerivedV,DerivedF>::method = EXACT_WINDING_NUMBER_METHOD;
//template <typename Point, typename DerivedV, typename DerivedF>
//double WindingNumberTree<Point,DerivedV,DerivedF>::min_max_w = 0;
template <typename Point, typename DerivedV, typename DerivedF>
std::map< std::pair<const igl::WindingNumberTree<Point,DerivedV,DerivedF>*,const igl::WindingNumberTree<Point,DerivedV,DerivedF>*>, typename DerivedV::Scalar>
igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached;
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree():
method(EXACT_WINDING_NUMBER_METHOD),
parent(NULL),
V(dummyV),
SV(),
F(),
//boundary(igl::boundary_facets<Eigen::MatrixXi,Eigen::MatrixXi>(F))
cap(),
radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
center(0,0,0)
{
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
const Eigen::MatrixBase<DerivedV> & _V,
const Eigen::MatrixBase<DerivedF> & _F):
method(EXACT_WINDING_NUMBER_METHOD),
parent(NULL),
V(dummyV),
SV(),
F(),
//boundary(igl::boundary_facets<Eigen::MatrixXi,Eigen::MatrixXi>(F))
cap(),
radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
center(0,0,0)
{
set_mesh(_V,_F);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(
const Eigen::MatrixBase<DerivedV> & _V,
const Eigen::MatrixBase<DerivedF> & _F)
{
using namespace std;
// Remove any exactly duplicate vertices
// Q: Can this ever increase the complexity of the boundary?
// Q: Would we gain even more by remove almost exactly duplicate vertices?
MatrixXF SF,SVI,SVJ;
igl::remove_duplicate_vertices(_V,_F,0.0,SV,SVI,SVJ,F);
triangle_fan(igl::exterior_edges(F),cap);
V = SV;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
const igl::WindingNumberTree<Point,DerivedV,DerivedF> & parent,
const Eigen::MatrixBase<DerivedF> & _F):
method(parent.method),
parent(&parent),
V(parent.V),
SV(),
F(_F),
cap(triangle_fan(igl::exterior_edges(_F)))
{
}
template <typename Point, typename DerivedV, typename DerivedF>
inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::~WindingNumberTree()
{
delete_children();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::delete_children()
{
using namespace std;
// Delete children
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
while(cit != children.end())
{
// clear the memory of this item
delete (* cit);
// erase from list, returns next element in iterator
cit = children.erase(cit);
}
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_method(const WindingNumberMethod & m)
{
this->method = m;
for(auto child : children)
{
child->set_method(m);
}
}
template <typename Point, typename DerivedV, typename DerivedF>
inline const DerivedV & igl::WindingNumberTree<Point,DerivedV,DerivedF>::getV() const
{
return V;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline const typename igl::WindingNumberTree<Point,DerivedV,DerivedF>::MatrixXF&
igl::WindingNumberTree<Point,DerivedV,DerivedF>::getF() const
{
return F;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline const typename igl::WindingNumberTree<Point,DerivedV,DerivedF>::MatrixXF&
igl::WindingNumberTree<Point,DerivedV,DerivedF>::getcap() const
{
return cap;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::grow()
{
// Don't grow
return;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline bool igl::WindingNumberTree<Point,DerivedV,DerivedF>::inside(const Point & /*p*/) const
{
return true;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p) const
{
using namespace std;
//cout<<"+"<<boundary.rows();
// If inside then we need to be careful
if(inside(p))
{
// If not a leaf then recurse
if(children.size()>0)
{
// Recurse on each child and accumulate
typename DerivedV::Scalar sum = 0;
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
cit != children.end();
cit++)
{
switch(method)
{
case EXACT_WINDING_NUMBER_METHOD:
sum += (*cit)->winding_number(p);
break;
case APPROX_SIMPLE_WINDING_NUMBER_METHOD:
case APPROX_CACHE_WINDING_NUMBER_METHOD:
//if((*cit)->max_simple_abs_winding_number(p) > min_max_w)
//{
sum += (*cit)->winding_number(p);
//}
break;
default:
assert(false);
break;
}
}
return sum;
}else
{
return winding_number_all(p);
}
}else{
// Otherwise we can just consider boundary
// Q: If we using the "multipole" method should we also subdivide the
// boundary case?
if((cap.rows() - 2) < F.rows())
{
switch(method)
{
case EXACT_WINDING_NUMBER_METHOD:
return winding_number_boundary(p);
case APPROX_SIMPLE_WINDING_NUMBER_METHOD:
{
typename DerivedV::Scalar dist = (p-center).norm();
// Radius is already an overestimate of inside
if(dist>1.0*radius)
{
return 0;
}else
{
return winding_number_boundary(p);
}
}
case APPROX_CACHE_WINDING_NUMBER_METHOD:
{
return parent->cached_winding_number(*this,p);
}
default: assert(false);break;
}
}else
{
// doesn't pay off to use boundary
return winding_number_all(p);
}
}
return 0;
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_all(const Point & p) const
{
return igl::winding_number(V,F,p);
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_boundary(const Point & p) const
{
using namespace Eigen;
using namespace std;
return igl::winding_number(V,cap,p);
}
//template <typename Point, typename DerivedV, typename DerivedF>
//inline double igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_approx_simple(
// const Point & p,
// const double min_max_w)
//{
// using namespace std;
// if(max_simple_abs_winding_number(p) > min_max_w)
// {
// return winding_number(p);
// }else
// {
// cout<<"Skipped! "<<max_simple_abs_winding_number(p)<<"<"<<min_max_w<<endl;
// return 0;
// }
//}
template <typename Point, typename DerivedV, typename DerivedF>
inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::print(const char * tab)
{
using namespace std;
// Print all facets
cout<<tab<<"["<<endl<<F<<endl<<"]";
// Print children
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
cit != children.end();
cit++)
{
cout<<","<<endl;
(*cit)->print((string(tab)+"").c_str());
}
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::max_abs_winding_number(const Point & /*p*/) const
{
return std::numeric_limits<typename DerivedV::Scalar>::infinity();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::max_simple_abs_winding_number(
const Point & /*p*/) const
{
using namespace std;
return numeric_limits<typename DerivedV::Scalar>::infinity();
}
template <typename Point, typename DerivedV, typename DerivedF>
inline typename DerivedV::Scalar
igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
const igl::WindingNumberTree<Point,DerivedV,DerivedF> & that,
const Point & p) const
{
using namespace std;
// Simple metric for `is_far`
//
// this that
// --------
// ----- / | \ .
// / r \ / R \ .
// | p ! | | ! |
// \_____/ \ /
// \________/
//
//
// a = angle formed by trapazoid formed by raising sides with lengths r and R
// at respective centers.
//
// a = atan2(R-r,d), where d is the distance between centers
// That should be bigger (what about parent? what about sister?)
bool is_far = this->radius<that.radius;
if(is_far)
{
typename DerivedV::Scalar a = atan2(
that.radius - this->radius,
(that.center - this->center).norm());
assert(a>0);
is_far = (a<PI/8.0);
}
if(is_far)
{
// Not implemented yet
pair<const WindingNumberTree*,const WindingNumberTree*> this_that(this,&that);
// Need to compute it for first time?
if(cached.count(this_that)==0)
{
cached[this_that] =
that.winding_number_boundary(this->center);
}
return cached[this_that];
}else if(children.size() == 0)
{
// not far and hierarchy ended too soon: can't use cache
return that.winding_number_boundary(p);
}else
{
for(
typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
cit != children.end();
cit++)
{
if((*cit)->inside(p))
{
return (*cit)->cached_winding_number(that,p);
}
}
// Not inside any children? This can totally happen because bounding boxes
// are set to bound contained facets. So sibilings may overlap and their
// union may not contain their parent (though, their union is certainly a
// subset of their parent).
assert(false);
}
return 0;
}
// Explicit instantiation of static variable
template <
typename Point,
typename DerivedV,
typename DerivedF >
DerivedV igl::WindingNumberTree<Point,DerivedV,DerivedF>::dummyV;
#endif

21
src/igl/ZERO.h Normal file
View file

@ -0,0 +1,21 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ZERO_H
#define IGL_ZERO_H
namespace igl
{
// Often one needs a reference to a dummy variable containing zero as its
// value, for example when using AntTweakBar's
// TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ZERO);
const char CHAR_ZERO = 0;
const int INT_ZERO = 0;
const unsigned int UNSIGNED_INT_ZERO = 0;
const double DOUBLE_ZERO = 0;
const float FLOAT_ZERO = 0;
}
#endif

370
src/igl/active_set.cpp Executable file
View file

@ -0,0 +1,370 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "active_set.h"
#include "min_quad_with_fixed.h"
#include "slice.h"
#include "slice_into.h"
#include "cat.h"
//#include "matlab_format.h"
#include <iostream>
#include <limits>
#include <algorithm>
template <
typename AT,
typename DerivedB,
typename Derivedknown,
typename DerivedY,
typename AeqT,
typename DerivedBeq,
typename AieqT,
typename DerivedBieq,
typename Derivedlx,
typename Derivedux,
typename DerivedZ
>
IGL_INLINE igl::SolverStatus igl::active_set(
const Eigen::SparseMatrix<AT>& A,
const Eigen::PlainObjectBase<DerivedB> & B,
const Eigen::PlainObjectBase<Derivedknown> & known,
const Eigen::PlainObjectBase<DerivedY> & Y,
const Eigen::SparseMatrix<AeqT>& Aeq,
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
const Eigen::SparseMatrix<AieqT>& Aieq,
const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
const Eigen::PlainObjectBase<Derivedlx> & p_lx,
const Eigen::PlainObjectBase<Derivedux> & p_ux,
const igl::active_set_params & params,
Eigen::PlainObjectBase<DerivedZ> & Z
)
{
//#define ACTIVE_SET_CPP_DEBUG
#if defined(ACTIVE_SET_CPP_DEBUG) && !defined(_MSC_VER)
# warning "ACTIVE_SET_CPP_DEBUG"
#endif
using namespace Eigen;
using namespace std;
SolverStatus ret = SOLVER_STATUS_ERROR;
const int n = A.rows();
assert(n == A.cols() && "A must be square");
// Discard const qualifiers
//if(B.size() == 0)
//{
// B = DerivedB::Zero(n,1);
//}
assert(n == B.rows() && "B.rows() must match A.rows()");
assert(B.cols() == 1 && "B must be a column vector");
assert(Y.cols() == 1 && "Y must be a column vector");
assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.cols() == n);
assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.rows() == Beq.rows());
assert((Aeq.size() == 0 && Beq.size() == 0) || Beq.cols() == 1);
assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.cols() == n);
assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.rows() == Bieq.rows());
assert((Aieq.size() == 0 && Bieq.size() == 0) || Bieq.cols() == 1);
Eigen::Matrix<typename Derivedlx::Scalar,Eigen::Dynamic,1> lx;
Eigen::Matrix<typename Derivedux::Scalar,Eigen::Dynamic,1> ux;
if(p_lx.size() == 0)
{
lx = Derivedlx::Constant(
n,1,-numeric_limits<typename Derivedlx::Scalar>::max());
}else
{
lx = p_lx;
}
if(p_ux.size() == 0)
{
ux = Derivedux::Constant(
n,1,numeric_limits<typename Derivedux::Scalar>::max());
}else
{
ux = p_ux;
}
assert(lx.rows() == n && "lx must have n rows");
assert(ux.rows() == n && "ux must have n rows");
assert(ux.cols() == 1 && "lx must be a column vector");
assert(lx.cols() == 1 && "ux must be a column vector");
assert((ux.array()-lx.array()).minCoeff() > 0 && "ux(i) must be > lx(i)");
if(Z.size() != 0)
{
// Initial guess should have correct size
assert(Z.rows() == n && "Z must have n rows");
assert(Z.cols() == 1 && "Z must be a column vector");
}
assert(known.cols() == 1 && "known must be a column vector");
// Number of knowns
const int nk = known.size();
// Initialize active sets
typedef int BOOL;
#define TRUE 1
#define FALSE 0
Matrix<BOOL,Dynamic,1> as_lx = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
Matrix<BOOL,Dynamic,1> as_ux = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
Matrix<BOOL,Dynamic,1> as_ieq = Matrix<BOOL,Dynamic,1>::Constant(Aieq.rows(),1,FALSE);
// Keep track of previous Z for comparison
DerivedZ old_Z;
old_Z = DerivedZ::Constant(
n,1,numeric_limits<typename DerivedZ::Scalar>::max());
int iter = 0;
while(true)
{
#ifdef ACTIVE_SET_CPP_DEBUG
cout<<"Iteration: "<<iter<<":"<<endl;
cout<<" pre"<<endl;
#endif
// FIND BREACHES OF CONSTRAINTS
int new_as_lx = 0;
int new_as_ux = 0;
int new_as_ieq = 0;
if(Z.size() > 0)
{
for(int z = 0;z < n;z++)
{
if(Z(z) < lx(z))
{
new_as_lx += (as_lx(z)?0:1);
//new_as_lx++;
as_lx(z) = TRUE;
}
if(Z(z) > ux(z))
{
new_as_ux += (as_ux(z)?0:1);
//new_as_ux++;
as_ux(z) = TRUE;
}
}
if(Aieq.rows() > 0)
{
DerivedZ AieqZ;
AieqZ = Aieq*Z;
for(int a = 0;a<Aieq.rows();a++)
{
if(AieqZ(a) > Bieq(a))
{
new_as_ieq += (as_ieq(a)?0:1);
as_ieq(a) = TRUE;
}
}
}
#ifdef ACTIVE_SET_CPP_DEBUG
cout<<" new_as_lx: "<<new_as_lx<<endl;
cout<<" new_as_ux: "<<new_as_ux<<endl;
#endif
const double diff = (Z-old_Z).squaredNorm();
#ifdef ACTIVE_SET_CPP_DEBUG
cout<<"diff: "<<diff<<endl;
#endif
if(diff < params.solution_diff_threshold)
{
ret = SOLVER_STATUS_CONVERGED;
break;
}
old_Z = Z;
}
const int as_lx_count = std::count(as_lx.data(),as_lx.data()+n,TRUE);
const int as_ux_count = std::count(as_ux.data(),as_ux.data()+n,TRUE);
const int as_ieq_count =
std::count(as_ieq.data(),as_ieq.data()+as_ieq.size(),TRUE);
#ifndef NDEBUG
{
int count = 0;
for(int a = 0;a<as_ieq.size();a++)
{
if(as_ieq(a))
{
assert(as_ieq(a) == TRUE);
count++;
}
}
assert(as_ieq_count == count);
}
#endif
// PREPARE FIXED VALUES
Derivedknown known_i;
known_i.resize(nk + as_lx_count + as_ux_count,1);
DerivedY Y_i;
Y_i.resize(nk + as_lx_count + as_ux_count,1);
{
known_i.block(0,0,known.rows(),known.cols()) = known;
Y_i.block(0,0,Y.rows(),Y.cols()) = Y;
int k = nk;
// Then all lx
for(int z = 0;z < n;z++)
{
if(as_lx(z))
{
known_i(k) = z;
Y_i(k) = lx(z);
k++;
}
}
// Finally all ux
for(int z = 0;z < n;z++)
{
if(as_ux(z))
{
known_i(k) = z;
Y_i(k) = ux(z);
k++;
}
}
assert(k==Y_i.size());
assert(k==known_i.size());
}
//cout<<matlab_format((known_i.array()+1).eval(),"known_i")<<endl;
// PREPARE EQUALITY CONSTRAINTS
VectorXi as_ieq_list(as_ieq_count,1);
// Gather active constraints and resp. rhss
DerivedBeq Beq_i;
Beq_i.resize(Beq.rows()+as_ieq_count,1);
Beq_i.head(Beq.rows()) = Beq;
{
int k =0;
for(int a=0;a<as_ieq.size();a++)
{
if(as_ieq(a))
{
assert(k<as_ieq_list.size());
as_ieq_list(k)=a;
Beq_i(Beq.rows()+k,0) = Bieq(k,0);
k++;
}
}
assert(k == as_ieq_count);
}
// extract active constraint rows
SparseMatrix<AeqT> Aeq_i,Aieq_i;
slice(Aieq,as_ieq_list,1,Aieq_i);
// Append to equality constraints
cat(1,Aeq,Aieq_i,Aeq_i);
min_quad_with_fixed_data<AT> data;
#ifndef NDEBUG
{
// NO DUPES!
Matrix<BOOL,Dynamic,1> fixed = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
for(int k = 0;k<known_i.size();k++)
{
assert(!fixed[known_i(k)]);
fixed[known_i(k)] = TRUE;
}
}
#endif
DerivedZ sol;
if(known_i.size() == A.rows())
{
// Everything's fixed?
#ifdef ACTIVE_SET_CPP_DEBUG
cout<<" everything's fixed."<<endl;
#endif
Z.resize(A.rows(),Y_i.cols());
slice_into(Y_i,known_i,1,Z);
sol.resize(0,Y_i.cols());
assert(Aeq_i.rows() == 0 && "All fixed but linearly constrained");
}else
{
#ifdef ACTIVE_SET_CPP_DEBUG
cout<<" min_quad_with_fixed_precompute"<<endl;
#endif
if(!min_quad_with_fixed_precompute(A,known_i,Aeq_i,params.Auu_pd,data))
{
cerr<<"Error: min_quad_with_fixed precomputation failed."<<endl;
if(iter > 0 && Aeq_i.rows() > Aeq.rows())
{
cerr<<" *Are you sure rows of [Aeq;Aieq] are linearly independent?*"<<
endl;
}
ret = SOLVER_STATUS_ERROR;
break;
}
#ifdef ACTIVE_SET_CPP_DEBUG
cout<<" min_quad_with_fixed_solve"<<endl;
#endif
if(!min_quad_with_fixed_solve(data,B,Y_i,Beq_i,Z,sol))
{
cerr<<"Error: min_quad_with_fixed solve failed."<<endl;
ret = SOLVER_STATUS_ERROR;
break;
}
//cout<<matlab_format((Aeq*Z-Beq).eval(),"cr")<<endl;
//cout<<matlab_format(Z,"Z")<<endl;
#ifdef ACTIVE_SET_CPP_DEBUG
cout<<" post"<<endl;
#endif
// Computing Lagrange multipliers needs to be adjusted slightly if A is not symmetric
assert(data.Auu_sym);
}
// Compute Lagrange multiplier values for known_i
SparseMatrix<AT> Ak;
// Slow
slice(A,known_i,1,Ak);
DerivedB Bk;
slice(B,known_i,Bk);
MatrixXd Lambda_known_i = -(0.5*Ak*Z + 0.5*Bk);
// reverse the lambda values for lx
Lambda_known_i.block(nk,0,as_lx_count,1) =
(-1*Lambda_known_i.block(nk,0,as_lx_count,1)).eval();
// Extract Lagrange multipliers for Aieq_i (always at back of sol)
VectorXd Lambda_Aieq_i(Aieq_i.rows(),1);
for(int l = 0;l<Aieq_i.rows();l++)
{
Lambda_Aieq_i(Aieq_i.rows()-1-l) = sol(sol.rows()-1-l);
}
// Remove from active set
for(int l = 0;l<as_lx_count;l++)
{
if(Lambda_known_i(nk + l) < params.inactive_threshold)
{
as_lx(known_i(nk + l)) = FALSE;
}
}
for(int u = 0;u<as_ux_count;u++)
{
if(Lambda_known_i(nk + as_lx_count + u) <
params.inactive_threshold)
{
as_ux(known_i(nk + as_lx_count + u)) = FALSE;
}
}
for(int a = 0;a<as_ieq_count;a++)
{
if(Lambda_Aieq_i(a) < params.inactive_threshold)
{
as_ieq(as_ieq_list(a)) = FALSE;
}
}
iter++;
//cout<<iter<<endl;
if(params.max_iter>0 && iter>=params.max_iter)
{
ret = SOLVER_STATUS_MAX_ITER;
break;
}
}
return ret;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif

111
src/igl/active_set.h Normal file
View file

@ -0,0 +1,111 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ACTIVE_SET_H
#define IGL_ACTIVE_SET_H
#include "igl_inline.h"
#include "SolverStatus.h"
#include <Eigen/Core>
#include <Eigen/Sparse>
namespace igl
{
struct active_set_params;
// Known Bugs: rows of [Aeq;Aieq] **must** be linearly independent. Should be
// using QR decomposition otherwise:
// http://www.okstate.edu/sas/v8/sashtml/ormp/chap5/sect32.htm
//
// ACTIVE_SET Minimize quadratic energy
//
// 0.5*Z'*A*Z + Z'*B + C with constraints
//
// that Z(known) = Y, optionally also subject to the constraints Aeq*Z = Beq,
// and further optionally subject to the linear inequality constraints that
// Aieq*Z <= Bieq and constant inequality constraints lx <= x <= ux
//
// Inputs:
// A n by n matrix of quadratic coefficients
// B n by 1 column of linear coefficients
// known list of indices to known rows in Z
// Y list of fixed values corresponding to known rows in Z
// Aeq meq by n list of linear equality constraint coefficients
// Beq meq by 1 list of linear equality constraint constant values
// Aieq mieq by n list of linear inequality constraint coefficients
// Bieq mieq by 1 list of linear inequality constraint constant values
// lx n by 1 list of lower bounds [] implies -Inf
// ux n by 1 list of upper bounds [] implies Inf
// params struct of additional parameters (see below)
// Z if not empty, is taken to be an n by 1 list of initial guess values
// (see output)
// Outputs:
// Z n by 1 list of solution values
// Returns true on success, false on error
//
// Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2
// secs, igl/min_quad_with_fixed.h 7.1 secs
//
template <
typename AT,
typename DerivedB,
typename Derivedknown,
typename DerivedY,
typename AeqT,
typename DerivedBeq,
typename AieqT,
typename DerivedBieq,
typename Derivedlx,
typename Derivedux,
typename DerivedZ
>
IGL_INLINE igl::SolverStatus active_set(
const Eigen::SparseMatrix<AT>& A,
const Eigen::PlainObjectBase<DerivedB> & B,
const Eigen::PlainObjectBase<Derivedknown> & known,
const Eigen::PlainObjectBase<DerivedY> & Y,
const Eigen::SparseMatrix<AeqT>& Aeq,
const Eigen::PlainObjectBase<DerivedBeq> & Beq,
const Eigen::SparseMatrix<AieqT>& Aieq,
const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
const Eigen::PlainObjectBase<Derivedlx> & lx,
const Eigen::PlainObjectBase<Derivedux> & ux,
const igl::active_set_params & params,
Eigen::PlainObjectBase<DerivedZ> & Z
);
};
#include "EPS.h"
struct igl::active_set_params
{
// Input parameters for active_set:
// Auu_pd whether Auu is positive definite {false}
// max_iter Maximum number of iterations (0 = Infinity, {100})
// inactive_threshold Threshold on Lagrange multiplier values to determine
// whether to keep constraints active {EPS}
// constraint_threshold Threshold on whether constraints are violated (0
// is perfect) {EPS}
// solution_diff_threshold Threshold on the squared norm of the difference
// between two consecutive solutions {EPS}
bool Auu_pd;
int max_iter;
double inactive_threshold;
double constraint_threshold;
double solution_diff_threshold;
active_set_params():
Auu_pd(false),
max_iter(100),
inactive_threshold(igl::DOUBLE_EPS),
constraint_threshold(igl::DOUBLE_EPS),
solution_diff_threshold(igl::DOUBLE_EPS)
{};
};
#ifndef IGL_STATIC_LIBRARY
# include "active_set.cpp"
#endif
#endif

168
src/igl/adjacency_list.cpp Normal file
View file

@ -0,0 +1,168 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "adjacency_list.h"
#include "verbose.h"
#include <algorithm>
template <typename Index, typename IndexVector>
IGL_INLINE void igl::adjacency_list(
const Eigen::PlainObjectBase<Index> & F,
std::vector<std::vector<IndexVector> >& A,
bool sorted)
{
A.clear();
A.resize(F.maxCoeff()+1);
// Loop over faces
for(int i = 0;i<F.rows();i++)
{
// Loop over this face
for(int j = 0;j<F.cols();j++)
{
// Get indices of edge: s --> d
int s = F(i,j);
int d = F(i,(j+1)%F.cols());
A.at(s).push_back(d);
A.at(d).push_back(s);
}
}
// Remove duplicates
for(int i=0; i<(int)A.size();++i)
{
std::sort(A[i].begin(), A[i].end());
A[i].erase(std::unique(A[i].begin(), A[i].end()), A[i].end());
}
// If needed, sort every VV
if (sorted)
{
// Loop over faces
// for every vertex v store a set of ordered edges not incident to v that belongs to triangle incident on v.
std::vector<std::vector<std::vector<int> > > SR;
SR.resize(A.size());
for(int i = 0;i<F.rows();i++)
{
// Loop over this face
for(int j = 0;j<F.cols();j++)
{
// Get indices of edge: s --> d
int s = F(i,j);
int d = F(i,(j+1)%F.cols());
// Get index of opposing vertex v
int v = F(i,(j+2)%F.cols());
std::vector<int> e(2);
e[0] = d;
e[1] = v;
SR[s].push_back(e);
}
}
for(int v=0; v<(int)SR.size();++v)
{
std::vector<IndexVector>& vv = A.at(v);
std::vector<std::vector<int> >& sr = SR[v];
std::vector<std::vector<int> > pn = sr;
// Compute previous/next for every element in sr
for(int i=0;i<(int)sr.size();++i)
{
int a = sr[i][0];
int b = sr[i][1];
// search for previous
int p = -1;
for(int j=0;j<(int)sr.size();++j)
if(sr[j][1] == a)
p = j;
pn[i][0] = p;
// search for next
int n = -1;
for(int j=0;j<(int)sr.size();++j)
if(sr[j][0] == b)
n = j;
pn[i][1] = n;
}
// assume manifoldness (look for beginning of a single chain)
int c = 0;
for(int j=0; j<=(int)sr.size();++j)
if (pn[c][0] != -1)
c = pn[c][0];
if (pn[c][0] == -1) // border case
{
// finally produce the new vv relation
for(int j=0; j<(int)sr.size();++j)
{
vv[j] = sr[c][0];
if (pn[c][1] != -1)
c = pn[c][1];
}
vv.back() = sr[c][1];
}
else
{
// finally produce the new vv relation
for(int j=0; j<(int)sr.size();++j)
{
vv[j] = sr[c][0];
c = pn[c][1];
}
}
}
}
}
template <typename Index>
IGL_INLINE void igl::adjacency_list(
const std::vector<std::vector<Index> > & F,
std::vector<std::vector<Index> >& A)
{
A.clear();
A.resize(F.maxCoeff()+1);
// Loop over faces
for(int i = 0;i<F.size();i++)
{
// Loop over this face
for(int j = 0;j<F[i].size();j++)
{
// Get indices of edge: s --> d
int s = F(i,j);
int d = F(i,(j+1)%F[i].size());
A.at(s).push_back(d);
A.at(d).push_back(s);
}
}
// Remove duplicates
for(int i=0; i<(int)A.size();++i)
{
std::sort(A[i].begin(), A[i].end());
A[i].erase(std::unique(A[i].begin(), A[i].end()), A[i].end());
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::adjacency_list<Eigen::Matrix<int, -1, 2, 0, -1, 2>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
// generated by autoexplicit.sh
template void igl::adjacency_list<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
template void igl::adjacency_list<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
#endif

51
src/igl/adjacency_list.h Normal file
View file

@ -0,0 +1,51 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ADJACENCY_LIST_H
#define IGL_ADJACENCY_LIST_H
#include "igl_inline.h"
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <vector>
namespace igl
{
// Constructs the graph adjacency list of a given mesh (V,F)
// Templates:
// T should be a eigen sparse matrix primitive type like int or double
// Inputs:
// F #F by dim list of mesh faces (must be triangles)
// sorted flag that indicates if the list should be sorted counter-clockwise
// Outputs:
// A vector<vector<T> > containing at row i the adjacent vertices of vertex i
//
// Example:
// // Mesh in (V,F)
// vector<vector<double> > A;
// adjacency_list(F,A);
//
// See also: edges, cotmatrix, diag
template <typename Index, typename IndexVector>
IGL_INLINE void adjacency_list(
const Eigen::PlainObjectBase<Index> & F,
std::vector<std::vector<IndexVector> >& A,
bool sorted = false);
// Variant that accepts polygonal faces.
// Each element of F is a set of indices of a polygonal face.
template <typename Index>
IGL_INLINE void adjacency_list(
const std::vector<std::vector<Index> > & F,
std::vector<std::vector<Index> >& A);
}
#ifndef IGL_STATIC_LIBRARY
# include "adjacency_list.cpp"
#endif
#endif

View file

@ -0,0 +1,74 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "adjacency_matrix.h"
#include "verbose.h"
#include <vector>
template <typename DerivedF, typename T>
IGL_INLINE void igl::adjacency_matrix(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::SparseMatrix<T>& A)
{
using namespace std;
using namespace Eigen;
typedef typename DerivedF::Scalar Index;
typedef Triplet<T> IJV;
vector<IJV > ijv;
ijv.reserve(F.size()*2);
// Loop over **simplex** (i.e., **not quad**)
for(int i = 0;i<F.rows();i++)
{
// Loop over this **simplex**
for(int j = 0;j<F.cols();j++)
for(int k = j+1;k<F.cols();k++)
{
// Get indices of edge: s --> d
Index s = F(i,j);
Index d = F(i,k);
ijv.push_back(IJV(s,d,1));
ijv.push_back(IJV(d,s,1));
}
}
const Index n = F.maxCoeff()+1;
A.resize(n,n);
switch(F.cols())
{
case 3:
A.reserve(6*(F.maxCoeff()+1));
break;
case 4:
A.reserve(26*(F.maxCoeff()+1));
break;
}
A.setFromTriplets(ijv.begin(),ijv.end());
// Force all non-zeros to be one
// Iterate over outside
for(int k=0; k<A.outerSize(); ++k)
{
// Iterate over inside
for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
{
assert(it.value() != 0);
A.coeffRef(it.row(),it.col()) = 1;
}
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, bool>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<bool, 0, int>&);
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<int, 0, int>&);
#endif

View file

@ -0,0 +1,51 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ADJACENCY_MATRIX_H
#define IGL_ADJACENCY_MATRIX_H
#include "igl_inline.h"
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
#include <Eigen/Dense>
#include <Eigen/Sparse>
namespace igl
{
// Constructs the graph adjacency matrix of a given mesh (V,F)
// Templates:
// T should be a eigen sparse matrix primitive type like int or double
// Inputs:
// F #F by dim list of mesh simplices
// Outputs:
// A max(F) by max(F) cotangent matrix, each row i corresponding to V(i,:)
//
// Example:
// // Mesh in (V,F)
// Eigen::SparseMatrix<double> A;
// adjacency_matrix(F,A);
// // sum each row
// SparseVector<double> Asum;
// sum(A,1,Asum);
// // Convert row sums into diagonal of sparse matrix
// SparseMatrix<double> Adiag;
// diag(Asum,Adiag);
// // Build uniform laplacian
// SparseMatrix<double> U;
// U = A-Adiag;
//
// See also: edges, cotmatrix, diag
template <typename DerivedF, typename T>
IGL_INLINE void adjacency_matrix(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::SparseMatrix<T>& A);
}
#ifndef IGL_STATIC_LIBRARY
# include "adjacency_matrix.cpp"
#endif
#endif

26
src/igl/all.cpp Normal file
View file

@ -0,0 +1,26 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "all.h"
#include "redux.h"
template <typename AType, typename DerivedB>
IGL_INLINE void igl::all(
const Eigen::SparseMatrix<AType> & A,
const int dim,
Eigen::PlainObjectBase<DerivedB>& B)
{
typedef typename DerivedB::Scalar Scalar;
igl::redux(A,dim,[](Scalar a, Scalar b){ return a && b!=0;},B);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
#endif

36
src/igl/all.h Normal file
View file

@ -0,0 +1,36 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ALL_H
#define IGL_ALL_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <Eigen/Sparse>
namespace igl
{
// For Dense matrices use: A.rowwise().all() or A.colwise().all()
//
// Inputs:
// A m by n sparse matrix
// dim dimension along which to check for all (1 or 2)
// Output:
// B n-long vector (if dim == 1)
// or
// B m-long vector (if dim == 2)
//
template <typename AType, typename DerivedB>
IGL_INLINE void all(
const Eigen::SparseMatrix<AType> & A,
const int dim,
Eigen::PlainObjectBase<DerivedB>& B);
}
#ifndef IGL_STATIC_LIBRARY
# include "all.cpp"
#endif
#endif

26
src/igl/all_edges.cpp Normal file
View file

@ -0,0 +1,26 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "all_edges.h"
#include "oriented_facets.h"
template <typename DerivedF, typename DerivedE>
IGL_INLINE void igl::all_edges(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedE> & E)
{
return oriented_facets(F,E);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::all_edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::all_edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
template void igl::all_edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
template void igl::all_edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::all_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
#endif

38
src/igl/all_edges.h Normal file
View file

@ -0,0 +1,38 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ALL_EDGES_H
#define IGL_ALL_EDGES_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
{
// Deprecated: call oriented_facets instead.
//
// ALL_EDGES Determines all "directed edges" of a given set of simplices. For
// a manifold mesh, this computes all of the half-edges
//
// Inputs:
// F #F by simplex_size list of "faces"
// Outputs:
// E #E by simplex_size-1 list of edges
//
// Note: this is not the same as igl::edges because this includes every
// directed edge including repeats (meaning interior edges on a surface will
// show up once for each direction and non-manifold edges may appear more than
// once for each direction).
template <typename DerivedF, typename DerivedE>
IGL_INLINE void all_edges(
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedE> & E);
}
#ifndef IGL_STATIC_LIBRARY
# include "all_edges.cpp"
#endif
#endif

View file

@ -0,0 +1,39 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "all_pairs_distances.h"
#include <Eigen/Dense>
template <typename Mat>
IGL_INLINE void igl::all_pairs_distances(
const Mat & V,
const Mat & U,
const bool squared,
Mat & D)
{
// dimension should be the same
assert(V.cols() == U.cols());
// resize output
D.resize(V.rows(),U.rows());
for(int i = 0;i<V.rows();i++)
{
for(int j=0;j<U.rows();j++)
{
D(i,j) = (V.row(i)-U.row(j)).squaredNorm();
if(!squared)
{
D(i,j) = sqrt(D(i,j));
}
}
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::all_pairs_distances<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, bool, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
#endif

View file

@ -0,0 +1,41 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ALL_PAIRS_DISTANCES_H
#define IGL_ALL_PAIRS_DISTANCES_H
#include "igl_inline.h"
namespace igl
{
// ALL_PAIRS_DISTANCES compute distances between each point i in V and point j
// in U
//
// D = all_pairs_distances(V,U)
//
// Templates:
// Mat matrix class like MatrixXd
// Inputs:
// V #V by dim list of points
// U #U by dim list of points
// squared whether to return squared distances
// Outputs:
// D #V by #U matrix of distances, where D(i,j) gives the distance or
// squareed distance between V(i,:) and U(j,:)
//
template <typename Mat>
IGL_INLINE void all_pairs_distances(
const Mat & V,
const Mat & U,
const bool squared,
Mat & D);
}
#ifndef IGL_STATIC_LIBRARY
# include "all_pairs_distances.cpp"
#endif
#endif

View file

@ -0,0 +1,137 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "ambient_occlusion.h"
#include "random_dir.h"
#include "ray_mesh_intersect.h"
#include "EPS.h"
#include "Hit.h"
#include "parallel_for.h"
#include <functional>
#include <vector>
#include <algorithm>
template <
typename DerivedP,
typename DerivedN,
typename DerivedS >
IGL_INLINE void igl::ambient_occlusion(
const std::function<
bool(
const Eigen::Vector3f&,
const Eigen::Vector3f&)
> & shoot_ray,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S)
{
using namespace Eigen;
const int n = P.rows();
// Resize output
S.resize(n,1);
// Embree seems to be parallel when constructing but not when tracing rays
const MatrixXf D = random_dir_stratified(num_samples).cast<float>();
const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p)
{
const Vector3f origin = P.row(p).template cast<float>();
const Vector3f normal = N.row(p).template cast<float>();
int num_hits = 0;
for(int s = 0;s<num_samples;s++)
{
Vector3f d = D.row(s);
if(d.dot(normal) < 0)
{
// reverse ray
d *= -1;
}
if(shoot_ray(origin,d))
{
num_hits++;
}
}
S(p) = (double)num_hits/(double)num_samples;
};
parallel_for(n,inner,1000);
}
template <
typename DerivedV,
int DIM,
typename DerivedF,
typename DerivedP,
typename DerivedN,
typename DerivedS >
IGL_INLINE void igl::ambient_occlusion(
const igl::AABB<DerivedV,DIM> & aabb,
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S)
{
const auto & shoot_ray = [&aabb,&V,&F](
const Eigen::Vector3f& _s,
const Eigen::Vector3f& dir)->bool
{
Eigen::Vector3f s = _s+1e-4*dir;
igl::Hit hit;
return aabb.intersect_ray(
V,
F,
s .cast<typename DerivedV::Scalar>().eval(),
dir.cast<typename DerivedV::Scalar>().eval(),
hit);
};
return ambient_occlusion(shoot_ray,P,N,num_samples,S);
}
template <
typename DerivedV,
typename DerivedF,
typename DerivedP,
typename DerivedN,
typename DerivedS >
IGL_INLINE void igl::ambient_occlusion(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S)
{
if(F.rows() < 100)
{
// Super naive
const auto & shoot_ray = [&V,&F](
const Eigen::Vector3f& _s,
const Eigen::Vector3f& dir)->bool
{
Eigen::Vector3f s = _s+1e-4*dir;
igl::Hit hit;
return ray_mesh_intersect(s,dir,V,F,hit);
};
return ambient_occlusion(shoot_ray,P,N,num_samples,S);
}
AABB<DerivedV,3> aabb;
aabb.init(V,F);
return ambient_occlusion(aabb,V,F,P,N,num_samples,S);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
// generated by autoexplicit.sh
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
// generated by autoexplicit.sh
template void igl::ambient_occlusion<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif

View file

@ -0,0 +1,80 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_AMBIENT_OCCLUSION_H
#define IGL_AMBIENT_OCCLUSION_H
#include "igl_inline.h"
#include "AABB.h"
#include <Eigen/Core>
#include <functional>
namespace igl
{
// Compute ambient occlusion per given point
//
// Inputs:
// shoot_ray function handle that outputs hits of a given ray against a
// mesh (embedded in function handles as captured variable/data)
// P #P by 3 list of origin points
// N #P by 3 list of origin normals
// Outputs:
// S #P list of ambient occlusion values between 1 (fully occluded) and
// 0 (not occluded)
//
template <
typename DerivedP,
typename DerivedN,
typename DerivedS >
IGL_INLINE void ambient_occlusion(
const std::function<
bool(
const Eigen::Vector3f&,
const Eigen::Vector3f&)
> & shoot_ray,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S);
// Inputs:
// AABB axis-aligned bounding box hierarchy around (V,F)
template <
typename DerivedV,
int DIM,
typename DerivedF,
typename DerivedP,
typename DerivedN,
typename DerivedS >
IGL_INLINE void ambient_occlusion(
const igl::AABB<DerivedV,DIM> & aabb,
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S);
// Inputs:
// V #V by 3 list of mesh vertex positions
// F #F by 3 list of mesh face indices into V
template <
typename DerivedV,
typename DerivedF,
typename DerivedP,
typename DerivedN,
typename DerivedS >
IGL_INLINE void ambient_occlusion(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const Eigen::PlainObjectBase<DerivedP> & P,
const Eigen::PlainObjectBase<DerivedN> & N,
const int num_samples,
Eigen::PlainObjectBase<DerivedS> & S);
};
#ifndef IGL_STATIC_LIBRARY
# include "ambient_occlusion.cpp"
#endif
#endif

View file

@ -0,0 +1,20 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "angular_distance.h"
#include <igl/EPS.h>
#include <igl/PI.h>
IGL_INLINE double igl::angular_distance(
const Eigen::Quaterniond & A,
const Eigen::Quaterniond & B)
{
assert(fabs(A.norm()-1)<FLOAT_EPS && "A should be unit norm");
assert(fabs(B.norm()-1)<FLOAT_EPS && "B should be unit norm");
//// acos is always in [0,2*pi)
//return acos(fabs(A.dot(B)));
return fmod(2.*acos(A.dot(B)),2.*PI);
}

View file

@ -0,0 +1,30 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ANGULAR_DISTANCE_H
#define IGL_ANGULAR_DISTANCE_H
#include "igl_inline.h"
#include <Eigen/Geometry>
namespace igl
{
// The "angular distance" between two unit quaternions is the angle of the
// smallest rotation (treated as an Axis and Angle) that takes A to B.
//
// Inputs:
// A unit quaternion
// B unit quaternion
// Returns angular distance
IGL_INLINE double angular_distance(
const Eigen::Quaterniond & A,
const Eigen::Quaterniond & B);
}
#ifndef IGL_STATIC_LIBRARY
#include "angular_distance.cpp"
#endif
#endif

View file

@ -0,0 +1,934 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "ReAntTweakBar.h"
#include <cstdio>
#include <cstring>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <map>
// GLOBAL WRAPPERS
namespace
{
std::map<
TwType,std::pair<const char *,std::vector<TwEnumVal> >
> ReTw_custom_types;
}
IGL_INLINE TwType igl::anttweakbar::ReTwDefineEnum(
const char *name,
const TwEnumVal *enumValues,
unsigned int nbValues)
{
using namespace std;
// copy enum valus into vector
std::vector<TwEnumVal> enum_vals;
enum_vals.resize(nbValues);
for(unsigned int j = 0; j<nbValues;j++)
{
enum_vals[j] = enumValues[j];
}
TwType type = TwDefineEnum(name,enumValues,nbValues);
ReTw_custom_types[type] =
std::pair<const char *,std::vector<TwEnumVal> >(name,enum_vals);
return type;
}
IGL_INLINE TwType igl::anttweakbar::ReTwDefineEnumFromString(
const char * _Name,
const char * _EnumString)
{
// Taken directly from TwMgr.cpp, just replace TwDefineEnum with
// ReTwDefineEnum
using namespace std;
{
if (_EnumString == NULL)
return ReTwDefineEnum(_Name, NULL, 0);
// split enumString
stringstream EnumStream(_EnumString);
string Label;
vector<string> Labels;
while( getline(EnumStream, Label, ',') ) {
// trim Label
size_t Start = Label.find_first_not_of(" \n\r\t");
size_t End = Label.find_last_not_of(" \n\r\t");
if( Start==string::npos || End==string::npos )
Label = "";
else
Label = Label.substr(Start, (End-Start)+1);
// store Label
Labels.push_back(Label);
}
// create TwEnumVal array
vector<TwEnumVal> Vals(Labels.size());
for( int i=0; i<(int)Labels.size(); i++ )
{
Vals[i].Value = i;
// Wrong:
//Vals[i].Label = Labels[i].c_str();
// Allocate char on heap
// http://stackoverflow.com/a/10050258/148668
char * c_label = new char[Labels[i].length()+1];
std::strcpy(c_label, Labels[i].c_str());
Vals[i].Label = c_label;
}
const TwType type =
ReTwDefineEnum(_Name, Vals.empty() ?
NULL :
&(Vals[0]), (unsigned int)Vals.size());
return type;
}
}
namespace
{
struct ReTwTypeString
{
TwType type;
const char * type_str;
};
#define RETW_NUM_DEFAULT_TYPE_STRINGS 23
ReTwTypeString ReTwDefaultTypeStrings[RETW_NUM_DEFAULT_TYPE_STRINGS] =
{
{TW_TYPE_UNDEF,"TW_TYPE_UNDEF"},
{TW_TYPE_BOOLCPP,"TW_TYPE_BOOLCPP"},
{TW_TYPE_BOOL8,"TW_TYPE_BOOL8"},
{TW_TYPE_BOOL16,"TW_TYPE_BOOL16"},
{TW_TYPE_BOOL32,"TW_TYPE_BOOL32"},
{TW_TYPE_CHAR,"TW_TYPE_CHAR"},
{TW_TYPE_INT8,"TW_TYPE_INT8"},
{TW_TYPE_UINT8,"TW_TYPE_UINT8"},
{TW_TYPE_INT16,"TW_TYPE_INT16"},
{TW_TYPE_UINT16,"TW_TYPE_UINT16"},
{TW_TYPE_INT32,"TW_TYPE_INT32"},
{TW_TYPE_UINT32,"TW_TYPE_UINT32"},
{TW_TYPE_FLOAT,"TW_TYPE_FLOAT"},
{TW_TYPE_DOUBLE,"TW_TYPE_DOUBLE"},
{TW_TYPE_COLOR32,"TW_TYPE_COLOR32"},
{TW_TYPE_COLOR3F,"TW_TYPE_COLOR3F"},
{TW_TYPE_COLOR4F,"TW_TYPE_COLOR4F"},
{TW_TYPE_CDSTRING,"TW_TYPE_CDSTRING"},
{TW_TYPE_STDSTRING,"TW_TYPE_STDSTRING"},
{TW_TYPE_QUAT4F,"TW_TYPE_QUAT4F"},
{TW_TYPE_QUAT4D,"TW_TYPE_QUAT4D"},
{TW_TYPE_DIR3F,"TW_TYPE_DIR3F"},
{TW_TYPE_DIR3D,"TW_TYPE_DIR3D"}
};
}
IGL_INLINE igl::anttweakbar::ReTwBar::ReTwBar():
bar(NULL),
name(),
rw_items(),cb_items()
{
}
IGL_INLINE igl::anttweakbar::ReTwBar::ReTwBar(
const igl::anttweakbar::ReTwBar & that):
bar(that.bar),
name(that.name),
rw_items(that.rw_items),
cb_items(that.cb_items)
{
}
IGL_INLINE igl::anttweakbar::ReTwBar &
igl::anttweakbar::ReTwBar::operator=(const igl::anttweakbar::ReTwBar & that)
{
// check for self assignment
if(this != &that)
{
bar = that.bar;
rw_items = that.rw_items;
cb_items = that.cb_items;
}
return *this;
}
// BAR WRAPPERS
IGL_INLINE void igl::anttweakbar::ReTwBar::TwNewBar(const char * _name)
{
this->bar = ::TwNewBar(_name);
// Alec: This causes trouble (not sure why) in multiple applications
// (medit, puppet) Probably there is some sort of memory corrpution.
// this->name = _name;
// Suspiciously this also fails:
//this->name = "foobar";
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddVarRW(
const char *name,
TwType type,
void *var,
const char *def,
const bool record)
{
int ret = ::TwAddVarRW(this->bar,name,type,var,def);
if(ret && record)
{
rw_items.push_back(ReTwRWItem(name,type,var));
}
return ret;
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddVarCB(
const char *name,
TwType type,
TwSetVarCallback setCallback,
TwGetVarCallback getCallback,
void *clientData,
const char *def,
const bool record)
{
int ret =
::TwAddVarCB(this->bar,name,type,setCallback,getCallback,clientData,def);
if(ret && record)
{
cb_items.push_back(ReTwCBItem(name,type,setCallback,getCallback,clientData));
}
return ret;
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddVarRO(
const char *name,
TwType type,
void *var,
const char *def)
{
int ret = ::TwAddVarRO(this->bar,name,type,var,def);
// Read only variables are not recorded
//if(ret)
//{
// rw_items.push_back(ReTwRWItem(name,type,var));
//}
return ret;
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddButton(
const char *name,
TwButtonCallback buttonCallback,
void *clientData,
const char *def)
{
int ret =
::TwAddButton(this->bar,name,buttonCallback,clientData,def);
// buttons are not recorded
//if(ret)
//{
// cb_items.push_back(ReTwCBItem(name,type,setCallback,getCallback,clientData));
//}
return ret;
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwSetParam(
const char *varName,
const char *paramName,
TwParamValueType paramValueType,
unsigned int inValueCount,
const void *inValues)
{
// For now just pass these along
return
::TwSetParam(
this->bar,
varName,
paramName,
paramValueType,
inValueCount,
inValues);
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwGetParam(
const char *varName,
const char *paramName,
TwParamValueType paramValueType,
unsigned int outValueMaxCount,
void *outValues)
{
return
::TwGetParam(
this->bar,
varName,
paramName,
paramValueType,
outValueMaxCount,
outValues);
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwRefreshBar()
{
return ::TwRefreshBar(this->bar);
}
IGL_INLINE int igl::anttweakbar::ReTwBar::TwTerminate()
{
//std::cout<<"TwTerminate"<<std::endl;
int r = ::TwTerminate();
//std::cout<<" "<<r<<std::endl;
return r;
}
IGL_INLINE bool igl::anttweakbar::ReTwBar::save(const char *file_name)
{
FILE * fp;
if(file_name == NULL)
{
fp = stdout;
}else
{
fp = fopen(file_name,"w");
}
if(fp == NULL)
{
printf("ERROR: not able to open %s for writing...\n",file_name);
return false;
}
// Print all RW variables
for(
std::vector<ReTwRWItem>::iterator it = rw_items.begin();
it != rw_items.end();
it++)
{
std::string s = (*it).name;
const char * name = s.c_str();
TwType type = (*it).type;
void * var = (*it).var;
fprintf(fp,"%s: %s\n",
name,
get_value_as_string(var,type).c_str());
}
char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE];
// Print all CB variables
for(
std::vector<ReTwCBItem>::iterator it = cb_items.begin();
it != cb_items.end();
it++)
{
const char * name = it->name.c_str();
TwType type = it->type;
//TwSetVarCallback setCallback = it->setCallback;
TwGetVarCallback getCallback = it->getCallback;
void * clientData = it->clientData;
// I'm not sure how to do what I want to do. getCallback needs to be sure
// that it can write to var. So var needs to point to a valid and big
// enough chunk of memory
getCallback(var,clientData);
fprintf(fp,"%s: %s\n",
name,
get_value_as_string(var,type).c_str());
}
fprintf(fp,"\n");
if(file_name != NULL)
{
fclose(fp);
}
// everything succeeded
return true;
}
IGL_INLINE std::string igl::anttweakbar::ReTwBar::get_value_as_string(
void * var,
TwType type)
{
std::stringstream sstr;
switch(type)
{
case TW_TYPE_BOOLCPP:
{
sstr << "TW_TYPE_BOOLCPP" << " ";
sstr << *(static_cast<bool*>(var));
break;
}
case TW_TYPE_QUAT4D:
{
sstr << "TW_TYPE_QUAT4D" << " ";
// Q: Why does casting to double* work? shouldn't I have to cast to
// double**?
double * q = static_cast<double*>(var);
sstr << std::setprecision(15) << q[0] << " " << q[1] << " " << q[2] << " " << q[3];
break;
}
case TW_TYPE_QUAT4F:
{
sstr << "TW_TYPE_QUAT4F" << " ";
// Q: Why does casting to float* work? shouldn't I have to cast to
// float**?
float * q = static_cast<float*>(var);
sstr << q[0] << " " << q[1] << " " << q[2] << " " << q[3];
break;
}
case TW_TYPE_COLOR4F:
{
sstr << "TW_TYPE_COLOR4F" << " ";
float * c = static_cast<float*>(var);
sstr << c[0] << " " << c[1] << " " << c[2] << " " << c[3];
break;
}
case TW_TYPE_COLOR3F:
{
sstr << "TW_TYPE_COLOR3F" << " ";
float * c = static_cast<float*>(var);
sstr << c[0] << " " << c[1] << " " << c[2];
break;
}
case TW_TYPE_DIR3D:
{
sstr << "TW_TYPE_DIR3D" << " ";
double * d = static_cast<double*>(var);
sstr << std::setprecision(15) << d[0] << " " << d[1] << " " << d[2];
break;
}
case TW_TYPE_DIR3F:
{
sstr << "TW_TYPE_DIR3F" << " ";
float * d = static_cast<float*>(var);
sstr << d[0] << " " << d[1] << " " << d[2];
break;
}
case TW_TYPE_BOOL32:
{
sstr << "TW_TYPE_BOOL32" << " ";
sstr << *(static_cast<int*>(var));
break;
}
case TW_TYPE_UINT8:
{
sstr << "TW_TYPE_UINT8" << " ";
// Cast to int so that it's human readable
sstr << (int)*(static_cast<unsigned char*>(var));
break;
}
case TW_TYPE_INT32:
{
sstr << "TW_TYPE_INT32" << " ";
sstr << *(static_cast<int*>(var));
break;
}
case TW_TYPE_UINT32:
{
sstr << "TW_TYPE_UINT32" << " ";
sstr << *(static_cast<unsigned int*>(var));
break;
}
case TW_TYPE_FLOAT:
{
sstr << "TW_TYPE_FLOAT" << " ";
sstr << *(static_cast<float*>(var));
break;
}
case TW_TYPE_DOUBLE:
{
sstr << "TW_TYPE_DOUBLE" << " ";
sstr << std::setprecision(15) << *(static_cast<double*>(var));
break;
}
case TW_TYPE_STDSTRING:
{
sstr << "TW_TYPE_STDSTRING" << " ";
std::string *destPtr = static_cast<std::string *>(var);
sstr << destPtr->c_str();
break;
}
default:
{
using namespace std;
std::map<TwType,std::pair<const char *,std::vector<TwEnumVal> > >::const_iterator iter =
ReTw_custom_types.find(type);
if(iter != ReTw_custom_types.end())
{
sstr << (*iter).second.first << " ";
int enum_val = *(static_cast<int*>(var));
// try find display name for enum value
std::vector<TwEnumVal>::const_iterator eit = (*iter).second.second.begin();
bool found = false;
for(;eit<(*iter).second.second.end();eit++)
{
if(enum_val == eit->Value)
{
sstr << eit->Label;
found = true;
break;
}
}
if(!found)
{
sstr << "ERROR_ENUM_VALUE_NOT_DEFINED";
}
}else
{
sstr << "ERROR_TYPE_NOT_SUPPORTED";
}
break;
}
}
return sstr.str();
}
IGL_INLINE bool igl::anttweakbar::ReTwBar::load(const char *file_name)
{
FILE * fp;
fp = fopen(file_name,"r");
if(fp == NULL)
{
printf("ERROR: not able to open %s for reading...\n",file_name);
return false;
}
// go through file line by line
char line[REANTTWEAKBAR_MAX_LINE];
bool still_comments;
char name[REANTTWEAKBAR_MAX_WORD];
char type_str[REANTTWEAKBAR_MAX_WORD];
char value_str[REANTTWEAKBAR_MAX_WORD];
// line number
int j = 0;
bool finished = false;
while(true)
{
// Eat comments
still_comments = true;
while(still_comments)
{
if(fgets(line,REANTTWEAKBAR_MAX_LINE,fp) == NULL)
{
finished = true;
break;
}
// Blank lines and lines that begin with # are comments
still_comments = (line[0] == '#' || line[0] == '\n');
j++;
}
if(finished)
{
break;
}
sscanf(line,"%[^:]: %s %[^\n]",name,type_str,value_str);
//printf("%s: %s %s\n",name, type_str,value_str);
TwType type;
if(!type_from_string(type_str,type))
{
printf("ERROR: %s type not found... Skipping...\n",type_str);
continue;
}
set_value_from_string(name,type,value_str);
}
fclose(fp);
// everything succeeded
return true;
}
IGL_INLINE bool igl::anttweakbar::ReTwBar::type_from_string(
const char *type_str, TwType & type)
{
// first check default types
for(int j = 0; j < RETW_NUM_DEFAULT_TYPE_STRINGS; j++)
{
if(strcmp(type_str,ReTwDefaultTypeStrings[j].type_str) == 0)
{
type = ReTwDefaultTypeStrings[j].type;
return true;
break;
}
}
// then check custom types
std::map<
TwType,std::pair<const char *,std::vector<TwEnumVal> >
>::const_iterator iter =
ReTw_custom_types.begin();
for(;iter != ReTw_custom_types.end(); iter++)
{
if(strcmp((*iter).second.first,type_str)==0)
{
type = (*iter).first;
return true;
}
}
return false;
}
bool igl::anttweakbar::ReTwBar::set_value_from_string(
const char * name,
TwType type,
const char * value_str)
{
void * value = NULL;
// possible value slots
int i;
float v;
double dv;
float f[4];
double d[4];
bool b;
unsigned int u;
unsigned char uc;
std::string s;
// First try to get value from default types
switch(type)
{
case TW_TYPE_BOOLCPP:
{
int ib;
if(sscanf(value_str," %d",&ib) == 1)
{
b = ib!=0;
value = &b;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_QUAT4D:
//case TW_TYPE_COLOR4D:
{
if(sscanf(value_str," %lf %lf %lf %lf",&d[0],&d[1],&d[2],&d[3]) == 4)
{
value = &d;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_QUAT4F:
case TW_TYPE_COLOR4F:
{
if(sscanf(value_str," %f %f %f %f",&f[0],&f[1],&f[2],&f[3]) == 4)
{
value = &f;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
//case TW_TYPE_COLOR3D:
case TW_TYPE_DIR3D:
{
if(sscanf(value_str," %lf %lf %lf",&d[0],&d[1],&d[2]) == 3)
{
value = &d;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_COLOR3F:
case TW_TYPE_DIR3F:
{
if(sscanf(value_str," %f %f %f",&f[0],&f[1],&f[2]) == 3)
{
value = &f;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_UINT8:
{
if(sscanf(value_str," %d",&i) == 1)
{
// Cast to unsigned char
uc = (unsigned char) i;
value = &uc;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_BOOL32:
case TW_TYPE_INT32:
{
if(sscanf(value_str," %d",&i) == 1)
{
value = &i;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_UINT32:
{
if(sscanf(value_str," %u",&u) == 1)
{
value = &u;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_FLOAT:
{
if(sscanf(value_str," %f",&v) == 1)
{
value = &v;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_DOUBLE:
{
if(sscanf(value_str," %lf",&dv) == 1)
{
value = &dv;
}else
{
printf("ERROR: Bad value format...\n");
return false;
}
break;
}
case TW_TYPE_STDSTRING:
{
s = value_str;
value = &s;
break;
}
default:
// Try to find type in custom enum types
std::map<TwType,std::pair<const char *,std::vector<TwEnumVal> > >::const_iterator iter =
ReTw_custom_types.find(type);
if(iter != ReTw_custom_types.end())
{
std::vector<TwEnumVal>::const_iterator eit = (*iter).second.second.begin();
bool found = false;
for(;eit<(*iter).second.second.end();eit++)
{
if(strcmp(value_str,eit->Label) == 0)
{
i = eit->Value;
value = &i;
found = true;
break;
}
}
if(!found)
{
printf("ERROR_ENUM_VALUE_NOT_DEFINED");
}
}else
{
printf("ERROR_TYPE_NOT_SUPPORTED\n");
}
break;
}
// Find variable based on name
// First look in RW items
bool item_found = false;
for(
std::vector<ReTwRWItem>::iterator it = rw_items.begin();
it != rw_items.end();
it++)
{
if(it->name == name)
{
void * var = it->var;
switch(type)
{
case TW_TYPE_BOOLCPP:
{
bool * bvar = static_cast<bool*>(var);
bool * bvalue = static_cast<bool*>(value);
*bvar = *bvalue;
break;
}
case TW_TYPE_QUAT4D:
//case TW_TYPE_COLOR4D:
{
double * dvar = static_cast<double*>(var);
double * dvalue = static_cast<double*>(value);
dvar[0] = dvalue[0];
dvar[1] = dvalue[1];
dvar[2] = dvalue[2];
dvar[3] = dvalue[3];
break;
}
case TW_TYPE_QUAT4F:
case TW_TYPE_COLOR4F:
{
float * fvar = static_cast<float*>(var);
float * fvalue = static_cast<float*>(value);
fvar[0] = fvalue[0];
fvar[1] = fvalue[1];
fvar[2] = fvalue[2];
fvar[3] = fvalue[3];
break;
}
//case TW_TYPE_COLOR3D:
case TW_TYPE_DIR3D:
{
double * dvar = static_cast<double*>(var);
double * dvalue = static_cast<double*>(value);
dvar[0] = dvalue[0];
dvar[1] = dvalue[1];
dvar[2] = dvalue[2];
break;
}
case TW_TYPE_COLOR3F:
case TW_TYPE_DIR3F:
{
float * fvar = static_cast<float*>(var);
float * fvalue = static_cast<float*>(value);
fvar[0] = fvalue[0];
fvar[1] = fvalue[1];
fvar[2] = fvalue[2];
break;
}
case TW_TYPE_UINT8:
{
unsigned char * ucvar = static_cast<unsigned char*>(var);
unsigned char * ucvalue = static_cast<unsigned char*>(value);
*ucvar = *ucvalue;
break;
}
case TW_TYPE_BOOL32:
case TW_TYPE_INT32:
{
int * ivar = static_cast<int*>(var);
int * ivalue = static_cast<int*>(value);
*ivar = *ivalue;
break;
}
case TW_TYPE_UINT32:
{
unsigned int * uvar = static_cast<unsigned int*>(var);
unsigned int * uvalue = static_cast<unsigned int*>(value);
*uvar = *uvalue;
break;
}
case TW_TYPE_FLOAT:
{
float * fvar = static_cast<float*>(var);
float * fvalue = static_cast<float*>(value);
*fvar = *fvalue;
break;
}
case TW_TYPE_DOUBLE:
{
double * dvar = static_cast<double*>(var);
double * fvalue = static_cast<double*>(value);
*dvar = *fvalue;
break;
}
case TW_TYPE_STDSTRING:
{
std::string * svar = static_cast<std::string*>(var);
std::string * svalue = static_cast<std::string*>(value);
*svar = *svalue;
break;
}
default:
// Try to find type in custom enum types
std::map<TwType,std::pair<const char *,std::vector<TwEnumVal> > >::iterator iter =
ReTw_custom_types.find(type);
if(iter != ReTw_custom_types.end())
{
int * ivar = static_cast<int*>(var);
std::vector<TwEnumVal>::iterator eit = (*iter).second.second.begin();
bool found = false;
for(;eit<(*iter).second.second.end();eit++)
{
if(strcmp(value_str,eit->Label) == 0)
{
*ivar = eit->Value;
found = true;
break;
}
}
if(!found)
{
printf("ERROR_ENUM_VALUE_NOT_DEFINED");
}
}else
{
printf("ERROR_TYPE_NOT_SUPPORTED\n");
}
break;
}
item_found = true;
break;
}
}
// Try looking in CB items
if(!item_found)
{
for(
std::vector<ReTwCBItem>::iterator it = cb_items.begin();
it != cb_items.end();
it++)
{
if(it->name==name)
{
it->setCallback(value,it->clientData);
item_found = true;
break;
}
}
}
if(!item_found)
{
printf("ERROR: item '%s' not found\n",name);
}
return true;
}
IGL_INLINE const std::vector<igl::anttweakbar::ReTwRWItem> &
igl::anttweakbar::ReTwBar::get_rw_items()
{
return rw_items;
}
IGL_INLINE const std::vector<igl::anttweakbar::ReTwCBItem> &
igl::anttweakbar::ReTwBar::get_cb_items()
{
return cb_items;
}

View file

@ -0,0 +1,286 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ANTTWEAKBAR_REANTTWEAKBAR_H
#define IGL_ANTTWEAKBAR_REANTTWEAKBAR_H
#include "../igl_inline.h"
// ReAntTweakBar is a minimal wrapper for the AntTweakBar library that allows
// "bars" to be saved and load from disk. Changing your existing app that uses
// AntTweakBar to use ReAntTweakBar is trivial.
//
// Many (but not all) variable types are supported. I'll try to keep track them
// here:
// TW_TYPE_BOOLCPP
// TW_TYPE_QUAT4F
// TW_TYPE_QUAT4D
// TW_TYPE_COLOR4F
// TW_TYPE_COLOR4D
// TW_TYPE_COLOR3F
// TW_TYPE_DIR3F
// TW_TYPE_DIR3D
// TW_TYPE_BOOL32
// TW_TYPE_INT32
// TW_TYPE_UINT32
// TW_TYPE_FLOAT
// TW_TYPE_DOUBLE
// TW_TYPE_UINT8
// and
// custom TwTypes made with TwDefineEnum
//
// I'm working on adding the rest on an as-needed basis. Adding a new type only
// requires changes in a few places...
//
//
//
// This allows the user to have a non-global, static installation of
// AntTweakBar
#include <AntTweakBar.h>
// Instead of including AntTweakBar.h, just define the necessary types
// Types used:
// - TwType
// - TwEnumVal
// - TwSetVarCallback
// - TwGetVarCallback
// - TwBar
// - TwButtonCallback
#include <vector>
#include <string>
#define REANTTWEAKBAR_MAX_CB_VAR_SIZE 1000
// Max line size for reading files
#define REANTTWEAKBAR_MAX_LINE 1000
#define REANTTWEAKBAR_MAX_WORD 100
namespace igl
{
namespace anttweakbar
{
TwType ReTwDefineEnum(
const char *name,
const TwEnumVal *enumValues,
unsigned int nbValues);
TwType ReTwDefineEnumFromString(const char * name,const char * enumString);
struct ReTwRWItem
{
//const char * name;
std::string name;
TwType type;
void * var;
// Default constructor
IGL_INLINE ReTwRWItem(
const std::string _name,
TwType _type,
void *_var):
name(_name),
type(_type),
var(_var)
{
}
// Shallow copy constructor
// I solemnly swear it's OK to copy var this way
// Q: Is it really?
IGL_INLINE ReTwRWItem(const ReTwRWItem & that):
name(that.name),
type(that.type),
var(that.var)
{
}
// Shallow assignment
// I solemnly swear it's OK to copy var this way
IGL_INLINE ReTwRWItem & operator=(const ReTwRWItem & that)
{
if(this != &that)
{
this->name = that.name;
this->type = that.type;
this->var = that.var;
}
return *this;
}
};
struct ReTwCBItem
{
//const char * name;
std::string name;
TwType type;
TwSetVarCallback setCallback;
TwGetVarCallback getCallback;
void * clientData;
// Default constructor
IGL_INLINE ReTwCBItem(
const std::string _name,
TwType _type,
TwSetVarCallback _setCallback,
TwGetVarCallback _getCallback,
void * _clientData):
name(_name),
type(_type),
setCallback(_setCallback),
getCallback(_getCallback),
clientData(_clientData)
{
}
// Shallow copy
// I solemnly swear it's OK to copy clientData this way
IGL_INLINE ReTwCBItem(const ReTwCBItem & that):
name(that.name),
type(that.type),
setCallback(that.setCallback),
getCallback(that.getCallback),
clientData(that.clientData)
{
}
// Shallow assignment
// I solemnly swear it's OK to copy clientData this way
IGL_INLINE ReTwCBItem & operator=(const ReTwCBItem & that)
{
if(this != &that)
{
name = that.name;
type = that.type;
setCallback = that.setCallback;
getCallback = that.getCallback;
clientData = that.clientData;
}
return *this;
}
};
class ReTwBar
{
// VARIABLES
// Should be private, but seeing as I'm not going to implement all of the
// AntTweakBar public functions right away, I'll expose this so that at
// anytime AntTweakBar functions can be called directly on the bar
public:
TwBar * bar;
std::string name;
protected:
std::vector<ReTwRWItem> rw_items;
std::vector<ReTwCBItem> cb_items;
public:
// Default constructor with explicit initialization
IGL_INLINE ReTwBar();
private:
// Copy constructor does shallow copy
IGL_INLINE ReTwBar(const ReTwBar & that);
// Assignment operator does shallow assignment
IGL_INLINE ReTwBar &operator=(const ReTwBar & that);
// WRAPPERS FOR ANTTWEAKBAR FUNCTIONS
public:
IGL_INLINE void TwNewBar(const char *_name);
IGL_INLINE int TwAddVarRW(
const char *name,
TwType type,
void *var,
const char *def,
const bool record=true);
IGL_INLINE int TwAddVarCB(
const char *name,
TwType type,
TwSetVarCallback setCallback,
TwGetVarCallback getCallback,
void *clientData,
const char *def,
const bool record=true);
// Wrappers for convenience (not recorded, just passed on)
IGL_INLINE int TwAddVarRO(const char *name, TwType type, void *var, const char *def);
IGL_INLINE int TwAddButton(
const char *name,
TwButtonCallback buttonCallback,
void *clientData,
const char *def);
IGL_INLINE int TwSetParam(
const char *varName,
const char *paramName,
TwParamValueType paramValueType,
unsigned int inValueCount,
const void *inValues);
IGL_INLINE int TwGetParam(
const char *varName,
const char *paramName,
TwParamValueType paramValueType,
unsigned int outValueMaxCount,
void *outValues);
IGL_INLINE int TwRefreshBar();
IGL_INLINE int TwTerminate();
// IO FUNCTIONS
public:
// Save current items to file
// Input:
// file_name name of file to save data to, can be null which means print
// to stdout
// Return:
// true only if there were no (fatal) errors
IGL_INLINE bool save(const char *file_name);
std::string get_value_as_string(
void * var,
TwType type);
// Load into current items from file
// Input:
// file_name name of input file to load
// Return:
// true only if there were no (fatal) errors
IGL_INLINE bool load(const char *file_name);
// Get TwType from string
// Input
// type_str string of type
// Output
// type TwType converted from string
// Returns
// true only if string matched a valid type
IGL_INLINE bool type_from_string(const char *type_str, TwType & type);
// I realize that I mix std::string and const char * all over the place.
// What can you do...
IGL_INLINE bool set_value_from_string(
const char * name,
TwType type,
const char * value_str);
IGL_INLINE const std::vector<ReTwRWItem> & get_rw_items();
IGL_INLINE const std::vector<ReTwCBItem> & get_cb_items();
};
}
}
// List of TwBar functions
//TW_API TwBar * TW_CALL TwNewBar(const char *barName);
//TW_API int TW_CALL TwDeleteBar(TwBar *bar);
//TW_API int TW_CALL TwDeleteAllBars();
//TW_API int TW_CALL TwSetTopBar(const TwBar *bar);
//TW_API TwBar * TW_CALL TwGetTopBar();
//TW_API int TW_CALL TwSetBottomBar(const TwBar *bar);
//TW_API TwBar * TW_CALL TwGetBottomBar();
//TW_API const char * TW_CALL TwGetBarName(TwBar *bar);
//TW_API int TW_CALL TwGetBarCount();
//TW_API TwBar * TW_CALL TwGetBarByIndex(int barIndex);
//TW_API TwBar * TW_CALL TwGetBarByName(const char *barName);
//TW_API int TW_CALL TwRefreshBar(TwBar *bar);
//TW_API int TW_CALL TwTerminate();
//
//TW_API int TW_CALL TwAddVarRW(TwBar *bar, const char *name, TwType type, void *var, const char *def);
//TW_API int TW_CALL TwAddVarRO(TwBar *bar, const char *name, TwType type, const void *var, const char *def);
//TW_API int TW_CALL TwAddVarCB(TwBar *bar, const char *name, TwType type, TwSetVarCallback setCallback, TwGetVarCallback getCallback, void *clientData, const char *def);
//TW_API int TW_CALL TwAddButton(TwBar *bar, const char *name, TwButtonCallback callback, void *clientData, const char *def);
//TW_API int TW_CALL TwAddSeparator(TwBar *bar, const char *name, const char *def);
//TW_API int TW_CALL TwRemoveVar(TwBar *bar, const char *name);
//TW_API int TW_CALL TwRemoveAllVars(TwBar *bar);
// Until AntTweakBar dependency folder exists, this is header-only
#ifndef IGL_STATIC_LIBRARY
# include "ReAntTweakBar.cpp"
#endif
#endif

View file

@ -0,0 +1,81 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "cocoa_key_to_anttweakbar_key.h"
#include <AntTweakBar.h>
IGL_INLINE int igl::anttweakbar::cocoa_key_to_anttweakbar_key(int key)
{
// I've left commented the AntTweakBar key codes that correspond to keys I
// don't have on my keyboard. Please fill this in if you have those keys
switch(key)
{
case 127:
return TW_KEY_BACKSPACE;
case 9:
return TW_KEY_TAB;
//TW_KEY_CLEAR = 0x0c,
case 3://ENTER
case 13:
return TW_KEY_RETURN;
case 27:
return TW_KEY_ESCAPE;
case 32:
return TW_KEY_SPACE;
// IN A GLUT APP 40 is (
//case 40:
case 63272:
return TW_KEY_DELETE;
case 63232:
return TW_KEY_UP;
case 63233:
return TW_KEY_DOWN;
case 63235:
return TW_KEY_RIGHT;
case 63234:
return TW_KEY_LEFT;
//TW_KEY_INSERT,
//TW_KEY_HOME,
//TW_KEY_END,
//TW_KEY_PAGE_UP,
//TW_KEY_PAGE_DOWN,
case 63236:
return TW_KEY_F1;
case 63237:
return TW_KEY_F2;
case 63238:
return TW_KEY_F3;
case 63239:
return TW_KEY_F4;
case 63240:
return TW_KEY_F5;
case 63241:
return TW_KEY_F6;
case 63242:
return TW_KEY_F7;
case 63243:
return TW_KEY_F8;
case 63244:
return TW_KEY_F9;
case 63245:
return TW_KEY_F10;
case 63246:
return TW_KEY_F11;
case 63247:
return TW_KEY_F12;
case 63248:
return TW_KEY_F13;
case 63249:
return TW_KEY_F14;
case 63250:
return TW_KEY_F15;
default:
break;
}
return key;
}

View file

@ -0,0 +1,31 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ANTTWEAKBAR_COCOA_KEY_TO_ANTTWEAKBAR_KEY_H
#define IGL_ANTTWEAKBAR_COCOA_KEY_TO_ANTTWEAKBAR_KEY_H
#include "../igl_inline.h"
namespace igl
{
namespace anttweakbar
{
// Convert an unsigned char (like that from Cocoa apps) to AntTweakBar key
// code.
// See also: TranslateKey() in TwMgr.cpp in AntTweakBar source
// Inputs:
// key unsigned char key from keyboard
// Returns int of new key code
IGL_INLINE int cocoa_key_to_anttweakbar_key(int key);
}
}
#ifndef IGL_STATIC_LIBRARY
# include "cocoa_key_to_anttweakbar_key.cpp"
#endif
#endif

26
src/igl/any.cpp Normal file
View file

@ -0,0 +1,26 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "any.h"
#include "redux.h"
template <typename AType, typename DerivedB>
IGL_INLINE void igl::any(
const Eigen::SparseMatrix<AType> & A,
const int dim,
Eigen::PlainObjectBase<DerivedB>& B)
{
typedef typename DerivedB::Scalar Scalar;
igl::redux(A,dim,[](Scalar a, Scalar b){ return a || b!=0;},B);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::any<bool, Eigen::Array<bool, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, int, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&);
#endif

35
src/igl/any.h Normal file
View file

@ -0,0 +1,35 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ANY_H
#define IGL_ANY_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <Eigen/Sparse>
namespace igl
{
// For Dense matrices use: A.rowwise().any() or A.colwise().any()
//
// Inputs:
// A m by n sparse matrix
// dim dimension along which to check for any (1 or 2)
// Output:
// B n-long vector (if dim == 1)
// or
// B m-long vector (if dim == 2)
//
template <typename AType, typename DerivedB>
IGL_INLINE void any(
const Eigen::SparseMatrix<AType> & A,
const int dim,
Eigen::PlainObjectBase<DerivedB>& B);
}
#ifndef IGL_STATIC_LIBRARY
# include "any.cpp"
#endif
#endif

20
src/igl/any_of.cpp Normal file
View file

@ -0,0 +1,20 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "any_of.h"
#include <Eigen/Core>
template <typename Mat>
IGL_INLINE bool igl::any_of(const Mat & S)
{
return std::any_of(S.data(),S.data()+S.size(),[](bool s){return s;});
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::any_of<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
#endif

26
src/igl/any_of.h Normal file
View file

@ -0,0 +1,26 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ANY_OF_H
#define IGL_ANY_OF_H
#include "igl_inline.h"
namespace igl
{
// Wrapper for STL `any_of` for matrix types
//
// Inputs:
// S matrix
// Returns whether any entries are true
//
// Seems that Eigen (now) implements this for `Eigen::Array`
template <typename Mat>
IGL_INLINE bool any_of(const Mat & S);
}
#ifndef IGL_STATIC_LIBRARY
# include "any_of.cpp"
#endif
#endif

312
src/igl/arap.cpp Normal file
View file

@ -0,0 +1,312 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "arap.h"
#include "colon.h"
#include "cotmatrix.h"
#include "massmatrix.h"
#include "group_sum_matrix.h"
#include "covariance_scatter_matrix.h"
#include "speye.h"
#include "mode.h"
#include "project_isometrically_to_plane.h"
#include "slice.h"
#include "arap_rhs.h"
#include "repdiag.h"
#include "columnize.h"
#include "fit_rotations.h"
#include <cassert>
#include <iostream>
template <
typename DerivedV,
typename DerivedF,
typename Derivedb>
IGL_INLINE bool igl::arap_precomputation(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const int dim,
const Eigen::PlainObjectBase<Derivedb> & b,
ARAPData & data)
{
using namespace std;
using namespace Eigen;
typedef typename DerivedV::Scalar Scalar;
// number of vertices
const int n = V.rows();
data.n = n;
assert((b.size() == 0 || b.maxCoeff() < n) && "b out of bounds");
assert((b.size() == 0 || b.minCoeff() >=0) && "b out of bounds");
// remember b
data.b = b;
//assert(F.cols() == 3 && "For now only triangles");
// dimension
//const int dim = V.cols();
assert((dim == 3 || dim ==2) && "dim should be 2 or 3");
data.dim = dim;
//assert(dim == 3 && "Only 3d supported");
// Defaults
data.f_ext = MatrixXd::Zero(n,data.dim);
assert(data.dim <= V.cols() && "solve dim should be <= embedding");
bool flat = (V.cols() - data.dim)==1;
DerivedV plane_V;
DerivedF plane_F;
typedef SparseMatrix<Scalar> SparseMatrixS;
SparseMatrixS ref_map,ref_map_dim;
if(flat)
{
project_isometrically_to_plane(V,F,plane_V,plane_F,ref_map);
repdiag(ref_map,dim,ref_map_dim);
}
const PlainObjectBase<DerivedV>& ref_V = (flat?plane_V:V);
const PlainObjectBase<DerivedF>& ref_F = (flat?plane_F:F);
SparseMatrixS L;
cotmatrix(V,F,L);
ARAPEnergyType eff_energy = data.energy;
if(eff_energy == ARAP_ENERGY_TYPE_DEFAULT)
{
switch(F.cols())
{
case 3:
if(data.dim == 3)
{
eff_energy = ARAP_ENERGY_TYPE_SPOKES_AND_RIMS;
}else
{
eff_energy = ARAP_ENERGY_TYPE_ELEMENTS;
}
break;
case 4:
eff_energy = ARAP_ENERGY_TYPE_ELEMENTS;
break;
default:
assert(false);
}
}
// Get covariance scatter matrix, when applied collects the covariance
// matrices used to fit rotations to during optimization
covariance_scatter_matrix(ref_V,ref_F,eff_energy,data.CSM);
if(flat)
{
data.CSM = (data.CSM * ref_map_dim.transpose()).eval();
}
assert(data.CSM.cols() == V.rows()*data.dim);
// Get group sum scatter matrix, when applied sums all entries of the same
// group according to G
SparseMatrix<double> G_sum;
if(data.G.size() == 0)
{
if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
{
speye(F.rows(),G_sum);
}else
{
speye(n,G_sum);
}
}else
{
// groups are defined per vertex, convert to per face using mode
if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
{
Eigen::Matrix<int,Eigen::Dynamic,1> GG;
MatrixXi GF(F.rows(),F.cols());
for(int j = 0;j<F.cols();j++)
{
Matrix<int,Eigen::Dynamic,1> GFj;
slice(data.G,F.col(j),GFj);
GF.col(j) = GFj;
}
mode<int>(GF,2,GG);
data.G=GG;
}
//printf("group_sum_matrix()\n");
group_sum_matrix(data.G,G_sum);
}
SparseMatrix<double> G_sum_dim;
repdiag(G_sum,data.dim,G_sum_dim);
assert(G_sum_dim.cols() == data.CSM.rows());
data.CSM = (G_sum_dim * data.CSM).eval();
arap_rhs(ref_V,ref_F,data.dim,eff_energy,data.K);
if(flat)
{
data.K = (ref_map_dim * data.K).eval();
}
assert(data.K.rows() == data.n*data.dim);
SparseMatrix<double> Q = (-L).eval();
if(data.with_dynamics)
{
const double h = data.h;
assert(h != 0);
SparseMatrix<double> M;
massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,data.M);
const double dw = (1./data.ym)*(h*h);
SparseMatrix<double> DQ = dw * 1./(h*h)*data.M;
Q += DQ;
// Dummy external forces
data.f_ext = MatrixXd::Zero(n,data.dim);
data.vel = MatrixXd::Zero(n,data.dim);
}
return min_quad_with_fixed_precompute(
Q,b,SparseMatrix<double>(),true,data.solver_data);
}
template <
typename Derivedbc,
typename DerivedU>
IGL_INLINE bool igl::arap_solve(
const Eigen::PlainObjectBase<Derivedbc> & bc,
ARAPData & data,
Eigen::PlainObjectBase<DerivedU> & U)
{
using namespace Eigen;
using namespace std;
assert(data.b.size() == bc.rows());
if(bc.size() > 0)
{
assert(bc.cols() == data.dim && "bc.cols() match data.dim");
}
const int n = data.n;
int iter = 0;
if(U.size() == 0)
{
// terrible initial guess.. should at least copy input mesh
#ifndef NDEBUG
cerr<<"arap_solve: Using terrible initial guess for U. Try U = V."<<endl;
#endif
U = MatrixXd::Zero(data.n,data.dim);
}else
{
assert(U.cols() == data.dim && "U.cols() match data.dim");
}
// changes each arap iteration
MatrixXd U_prev = U;
// doesn't change for fixed with_dynamics timestep
MatrixXd U0;
if(data.with_dynamics)
{
U0 = U_prev;
}
while(iter < data.max_iter)
{
U_prev = U;
// enforce boundary conditions exactly
for(int bi = 0;bi<bc.rows();bi++)
{
U.row(data.b(bi)) = bc.row(bi);
}
const auto & Udim = U.replicate(data.dim,1);
assert(U.cols() == data.dim);
// As if U.col(2) was 0
MatrixXd S = data.CSM * Udim;
// THIS NORMALIZATION IS IMPORTANT TO GET SINGLE PRECISION SVD CODE TO WORK
// CORRECTLY.
S /= S.array().abs().maxCoeff();
const int Rdim = data.dim;
MatrixXd R(Rdim,data.CSM.rows());
if(R.rows() == 2)
{
fit_rotations_planar(S,R);
}else
{
fit_rotations(S,true,R);
//#ifdef __SSE__ // fit_rotations_SSE will convert to float if necessary
// fit_rotations_SSE(S,R);
//#else
// fit_rotations(S,true,R);
//#endif
}
//for(int k = 0;k<(data.CSM.rows()/dim);k++)
//{
// R.block(0,dim*k,dim,dim) = MatrixXd::Identity(dim,dim);
//}
// Number of rotations: #vertices or #elements
int num_rots = data.K.cols()/Rdim/Rdim;
// distribute group rotations to vertices in each group
MatrixXd eff_R;
if(data.G.size() == 0)
{
// copy...
eff_R = R;
}else
{
eff_R.resize(Rdim,num_rots*Rdim);
for(int r = 0;r<num_rots;r++)
{
eff_R.block(0,Rdim*r,Rdim,Rdim) =
R.block(0,Rdim*data.G(r),Rdim,Rdim);
}
}
MatrixXd Dl;
if(data.with_dynamics)
{
assert(data.M.rows() == n &&
"No mass matrix. Call arap_precomputation if changing with_dynamics");
const double h = data.h;
assert(h != 0);
//Dl = 1./(h*h*h)*M*(-2.*V0 + Vm1) - fext;
// data.vel = (V0-Vm1)/h
// h*data.vel = (V0-Vm1)
// -h*data.vel = -V0+Vm1)
// -V0-h*data.vel = -2V0+Vm1
const double dw = (1./data.ym)*(h*h);
Dl = dw * (1./(h*h)*data.M*(-U0 - h*data.vel) - data.f_ext);
}
VectorXd Rcol;
columnize(eff_R,num_rots,2,Rcol);
VectorXd Bcol = -data.K * Rcol;
assert(Bcol.size() == data.n*data.dim);
for(int c = 0;c<data.dim;c++)
{
VectorXd Uc,Bc,bcc,Beq;
Bc = Bcol.block(c*n,0,n,1);
if(data.with_dynamics)
{
Bc += Dl.col(c);
}
if(bc.size()>0)
{
bcc = bc.col(c);
}
min_quad_with_fixed_solve(
data.solver_data,
Bc,bcc,Beq,
Uc);
U.col(c) = Uc;
}
iter++;
}
if(data.with_dynamics)
{
// Keep track of velocity for next time
data.vel = (U-U0)/data.h;
}
return true;
}
#ifdef IGL_STATIC_LIBRARY
template bool igl::arap_solve<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::ARAPData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template bool igl::arap_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, igl::ARAPData&);
#endif

104
src/igl/arap.h Normal file
View file

@ -0,0 +1,104 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ARAP_H
#define IGL_ARAP_H
#include "igl_inline.h"
#include "min_quad_with_fixed.h"
#include "ARAPEnergyType.h"
#include <Eigen/Core>
#include <Eigen/Sparse>
namespace igl
{
struct ARAPData
{
// n #V
// G #V list of group indices (1 to k) for each vertex, such that vertex i
// is assigned to group G(i)
// energy type of energy to use
// with_dynamics whether using dynamics (need to call arap_precomputation
// after changing)
// f_ext #V by dim list of external forces
// vel #V by dim list of velocities
// h dynamics time step
// ym ~Young's modulus smaller is softer, larger is more rigid/stiff
// max_iter maximum inner iterations
// K rhs pre-multiplier
// M mass matrix
// solver_data quadratic solver data
// b list of boundary indices into V
// dim dimension being used for solving
int n;
Eigen::VectorXi G;
ARAPEnergyType energy;
bool with_dynamics;
Eigen::MatrixXd f_ext,vel;
double h;
double ym;
int max_iter;
Eigen::SparseMatrix<double> K,M;
Eigen::SparseMatrix<double> CSM;
min_quad_with_fixed_data<double> solver_data;
Eigen::VectorXi b;
int dim;
ARAPData():
n(0),
G(),
energy(ARAP_ENERGY_TYPE_DEFAULT),
with_dynamics(false),
f_ext(),
h(1),
ym(1),
max_iter(10),
K(),
CSM(),
solver_data(),
b(),
dim(-1) // force this to be set by _precomputation
{
};
};
// Compute necessary information to start using an ARAP deformation
//
// Inputs:
// V #V by dim list of mesh positions
// F #F by simplex-size list of triangle|tet indices into V
// dim dimension being used at solve time. For deformation usually dim =
// V.cols(), for surface parameterization V.cols() = 3 and dim = 2
// b #b list of "boundary" fixed vertex indices into V
// Outputs:
// data struct containing necessary precomputation
template <
typename DerivedV,
typename DerivedF,
typename Derivedb>
IGL_INLINE bool arap_precomputation(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedF> & F,
const int dim,
const Eigen::PlainObjectBase<Derivedb> & b,
ARAPData & data);
// Inputs:
// bc #b by dim list of boundary conditions
// data struct containing necessary precomputation and parameters
// U #V by dim initial guess
template <
typename Derivedbc,
typename DerivedU>
IGL_INLINE bool arap_solve(
const Eigen::PlainObjectBase<Derivedbc> & bc,
ARAPData & data,
Eigen::PlainObjectBase<DerivedU> & U);
};
#ifndef IGL_STATIC_LIBRARY
#include "arap.cpp"
#endif
#endif

884
src/igl/arap_dof.cpp Normal file
View file

@ -0,0 +1,884 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "arap_dof.h"
#include "cotmatrix.h"
#include "massmatrix.h"
#include "speye.h"
#include "repdiag.h"
#include "repmat.h"
#include "slice.h"
#include "colon.h"
#include "is_sparse.h"
#include "mode.h"
#include "is_symmetric.h"
#include "group_sum_matrix.h"
#include "arap_rhs.h"
#include "covariance_scatter_matrix.h"
#include "fit_rotations.h"
#include "verbose.h"
#include "print_ijv.h"
#include "get_seconds_hires.h"
//#include "MKLEigenInterface.h"
#include "min_quad_dense.h"
#include "get_seconds.h"
#include "columnize.h"
// defined if no early exit is supported, i.e., always take a fixed number of iterations
#define IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
// A careful derivation of this implementation is given in the corresponding
// matlab function arap_dof.m
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool igl::arap_dof_precomputation(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const LbsMatrixType & M,
const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
ArapDOFData<LbsMatrixType, SSCALAR> & data)
{
using namespace Eigen;
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
// number of mesh (domain) vertices
int n = V.rows();
// cache problem size
data.n = n;
// dimension of mesh
data.dim = V.cols();
assert(data.dim == M.rows()/n);
assert(data.dim*n == M.rows());
if(data.dim == 3)
{
// Check if z-coordinate is all zeros
if(V.col(2).minCoeff() == 0 && V.col(2).maxCoeff() == 0)
{
data.effective_dim = 2;
}
}else
{
data.effective_dim = data.dim;
}
// Number of handles
data.m = M.cols()/data.dim/(data.dim+1);
assert(data.m*data.dim*(data.dim+1) == M.cols());
//assert(m == C.rows());
//printf("n=%d; dim=%d; m=%d;\n",n,data.dim,data.m);
// Build cotangent laplacian
SparseMatrix<double> Lcot;
//printf("cotmatrix()\n");
cotmatrix(V,F,Lcot);
// Discrete laplacian (should be minus matlab version)
SparseMatrix<double> Lapl = -2.0*Lcot;
#ifdef EXTREME_VERBOSE
cout<<"LaplIJV=["<<endl;print_ijv(Lapl,1);cout<<endl<<"];"<<
endl<<"Lapl=sparse(LaplIJV(:,1),LaplIJV(:,2),LaplIJV(:,3),"<<
Lapl.rows()<<","<<Lapl.cols()<<");"<<endl;
#endif
// Get group sum scatter matrix, when applied sums all entries of the same
// group according to G
SparseMatrix<double> G_sum;
if(G.size() == 0)
{
speye(n,G_sum);
}else
{
// groups are defined per vertex, convert to per face using mode
Eigen::Matrix<int,Eigen::Dynamic,1> GG;
if(data.energy == ARAP_ENERGY_TYPE_ELEMENTS)
{
MatrixXi GF(F.rows(),F.cols());
for(int j = 0;j<F.cols();j++)
{
Matrix<int,Eigen::Dynamic,1> GFj;
slice(G,F.col(j),GFj);
GF.col(j) = GFj;
}
mode<int>(GF,2,GG);
}else
{
GG=G;
}
//printf("group_sum_matrix()\n");
group_sum_matrix(GG,G_sum);
}
#ifdef EXTREME_VERBOSE
cout<<"G_sumIJV=["<<endl;print_ijv(G_sum,1);cout<<endl<<"];"<<
endl<<"G_sum=sparse(G_sumIJV(:,1),G_sumIJV(:,2),G_sumIJV(:,3),"<<
G_sum.rows()<<","<<G_sum.cols()<<");"<<endl;
#endif
// Get covariance scatter matrix, when applied collects the covariance matrices
// used to fit rotations to during optimization
SparseMatrix<double> CSM;
//printf("covariance_scatter_matrix()\n");
covariance_scatter_matrix(V,F,data.energy,CSM);
#ifdef EXTREME_VERBOSE
cout<<"CSMIJV=["<<endl;print_ijv(CSM,1);cout<<endl<<"];"<<
endl<<"CSM=sparse(CSMIJV(:,1),CSMIJV(:,2),CSMIJV(:,3),"<<
CSM.rows()<<","<<CSM.cols()<<");"<<endl;
#endif
// Build the covariance matrix "constructor". This is a set of *scatter*
// matrices that when multiplied on the right by column of the transformation
// matrix entries (the degrees of freedom) L, we get a stack of dim by 1
// covariance matrix column, with a column in the stack for each rotation
// *group*. The output is a list of matrices because we construct each column
// in the stack of covariance matrices with an independent matrix-vector
// multiplication.
//
// We want to build S which is a stack of dim by dim covariance matrices.
// Thus S is dim*g by dim, where dim is the number of dimensions and g is the
// number of groups. We can precompute dim matrices CSM_M such that column i
// in S is computed as S(:,i) = CSM_M{i} * L, where L is a column of the
// skinning transformation matrix values. To be clear, the covariance matrix
// for group k is then given as the dim by dim matrix pulled from the stack:
// S((k-1)*dim + 1:dim,:)
// Apply group sum to each dimension's block of covariance scatter matrix
SparseMatrix<double> G_sum_dim;
repdiag(G_sum,data.dim,G_sum_dim);
CSM = (G_sum_dim * CSM).eval();
#ifdef EXTREME_VERBOSE
cout<<"CSMIJV=["<<endl;print_ijv(CSM,1);cout<<endl<<"];"<<
endl<<"CSM=sparse(CSMIJV(:,1),CSMIJV(:,2),CSMIJV(:,3),"<<
CSM.rows()<<","<<CSM.cols()<<");"<<endl;
#endif
//printf("CSM_M()\n");
// Precompute CSM times M for each dimension
data.CSM_M.resize(data.dim);
#ifdef EXTREME_VERBOSE
cout<<"data.CSM_M = cell("<<data.dim<<",1);"<<endl;
#endif
// span of integers from 0 to n-1
Eigen::Matrix<int,Eigen::Dynamic,1> span_n(n);
for(int i = 0;i<n;i++)
{
span_n(i) = i;
}
// span of integers from 0 to M.cols()-1
Eigen::Matrix<int,Eigen::Dynamic,1> span_mlbs_cols(M.cols());
for(int i = 0;i<M.cols();i++)
{
span_mlbs_cols(i) = i;
}
// number of groups
int k = CSM.rows()/data.dim;
for(int i = 0;i<data.dim;i++)
{
//printf("CSM_M(): Mi\n");
LbsMatrixType M_i;
//printf("CSM_M(): slice\n");
slice(M,(span_n.array()+i*n).matrix().eval(),span_mlbs_cols,M_i);
LbsMatrixType M_i_dim;
data.CSM_M[i].resize(k*data.dim,data.m*data.dim*(data.dim+1));
assert(data.CSM_M[i].cols() == M.cols());
for(int j = 0;j<data.dim;j++)
{
SparseMatrix<double> CSMj;
//printf("CSM_M(): slice\n");
slice(
CSM,
colon<int>(j*k,(j+1)*k-1),
colon<int>(j*n,(j+1)*n-1),
CSMj);
assert(CSMj.rows() == k);
assert(CSMj.cols() == n);
LbsMatrixType CSMjM_i = CSMj * M_i;
if(is_sparse(CSMjM_i))
{
// Convert to full
//printf("CSM_M(): full\n");
MatrixXd CSMjM_ifull(CSMjM_i);
// printf("CSM_M[%d]: %d %d\n",i,data.CSM_M[i].rows(),data.CSM_M[i].cols());
// printf("CSM_M[%d].block(%d*%d=%d,0,%d,%d): %d %d\n",i,j,k,CSMjM_i.rows(),CSMjM_i.cols(),
// data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).rows(),
// data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).cols());
// printf("CSM_MjMi: %d %d\n",i,CSMjM_i.rows(),CSMjM_i.cols());
// printf("CSM_MjM_ifull: %d %d\n",i,CSMjM_ifull.rows(),CSMjM_ifull.cols());
data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_ifull;
}else
{
data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_i;
}
}
#ifdef EXTREME_VERBOSE
cout<<"CSM_Mi=["<<endl<<data.CSM_M[i]<<endl<<"];"<<endl;
#endif
}
// precompute arap_rhs matrix
//printf("arap_rhs()\n");
SparseMatrix<double> K;
arap_rhs(V,F,V.cols(),data.energy,K);
//#ifdef EXTREME_VERBOSE
// cout<<"KIJV=["<<endl;print_ijv(K,1);cout<<endl<<"];"<<
// endl<<"K=sparse(KIJV(:,1),KIJV(:,2),KIJV(:,3),"<<
// K.rows()<<","<<K.cols()<<");"<<endl;
//#endif
// Precompute left muliplication by M and right multiplication by G_sum
SparseMatrix<double> G_sumT = G_sum.transpose();
SparseMatrix<double> G_sumT_dim_dim;
repdiag(G_sumT,data.dim*data.dim,G_sumT_dim_dim);
LbsMatrixType MT = M.transpose();
// If this is a bottle neck then consider reordering matrix multiplication
data.M_KG = -4.0 * (MT * (K * G_sumT_dim_dim));
//#ifdef EXTREME_VERBOSE
// cout<<"data.M_KGIJV=["<<endl;print_ijv(data.M_KG,1);cout<<endl<<"];"<<
// endl<<"data.M_KG=sparse(data.M_KGIJV(:,1),data.M_KGIJV(:,2),data.M_KGIJV(:,3),"<<
// data.M_KG.rows()<<","<<data.M_KG.cols()<<");"<<endl;
//#endif
// Precompute system matrix
//printf("A()\n");
SparseMatrix<double> A;
repdiag(Lapl,data.dim,A);
data.Q = MT * (A * M);
//#ifdef EXTREME_VERBOSE
// cout<<"QIJV=["<<endl;print_ijv(data.Q,1);cout<<endl<<"];"<<
// endl<<"Q=sparse(QIJV(:,1),QIJV(:,2),QIJV(:,3),"<<
// data.Q.rows()<<","<<data.Q.cols()<<");"<<endl;
//#endif
// Always do dynamics precomputation so we can hot-switch
//if(data.with_dynamics)
//{
// Build cotangent laplacian
SparseMatrix<double> Mass;
//printf("massmatrix()\n");
massmatrix(V,F,(F.cols()>3?MASSMATRIX_TYPE_BARYCENTRIC:MASSMATRIX_TYPE_VORONOI),Mass);
//cout<<"MIJV=["<<endl;print_ijv(Mass,1);cout<<endl<<"];"<<
// endl<<"M=sparse(MIJV(:,1),MIJV(:,2),MIJV(:,3),"<<
// Mass.rows()<<","<<Mass.cols()<<");"<<endl;
//speye(data.n,Mass);
SparseMatrix<double> Mass_rep;
repdiag(Mass,data.dim,Mass_rep);
// Multiply either side by weights matrix (should be dense)
data.Mass_tilde = MT * Mass_rep * M;
MatrixXd ones(data.dim*data.n,data.dim);
for(int i = 0;i<data.n;i++)
{
for(int d = 0;d<data.dim;d++)
{
ones(i+d*data.n,d) = 1;
}
}
data.fgrav = MT * (Mass_rep * ones);
data.fext = MatrixXS::Zero(MT.rows(),1);
//data.fgrav = MT * (ones);
//}
// This may/should be superfluous
//printf("is_symmetric()\n");
if(!is_symmetric(data.Q))
{
//printf("Fixing symmetry...\n");
// "Fix" symmetry
LbsMatrixType QT = data.Q.transpose();
LbsMatrixType Q_copy = data.Q;
data.Q = 0.5*(Q_copy+QT);
// Check that ^^^ this really worked. It doesn't always
//assert(is_symmetric(*Q));
}
//printf("arap_dof_precomputation() succeeded... so far...\n");
verbose("Number of handles: %i\n", data.m);
return true;
}
/////////////////////////////////////////////////////////////////////////
//
// STATIC FUNCTIONS (These should be removed or properly defined)
//
/////////////////////////////////////////////////////////////////////////
namespace igl
{
// returns maximal difference of 'blok' from scalar times 3x3 identity:
template <typename SSCALAR>
inline static SSCALAR maxBlokErr(const Eigen::Matrix3f &blok)
{
SSCALAR mD;
SSCALAR value = blok(0,0);
SSCALAR diff1 = fabs(blok(1,1) - value);
SSCALAR diff2 = fabs(blok(2,2) - value);
if (diff1 > diff2) mD = diff1;
else mD = diff2;
for (int v=0; v<3; v++)
{
for (int w=0; w<3; w++)
{
if (v == w)
{
continue;
}
if (mD < fabs(blok(v, w)))
{
mD = fabs(blok(v, w));
}
}
}
return mD;
}
// converts CSM_M_SSCALAR[0], CSM_M_SSCALAR[1], CSM_M_SSCALAR[2] into one
// "condensed" matrix CSM while checking we're not losing any information by
// this process; specifically, returns maximal difference from scaled 3x3
// identity blocks, which should be pretty small number
template <typename MatrixXS>
static typename MatrixXS::Scalar condense_CSM(
const std::vector<MatrixXS> &CSM_M_SSCALAR,
int numBones,
int dim,
MatrixXS &CSM)
{
const int numRows = CSM_M_SSCALAR[0].rows();
assert(CSM_M_SSCALAR[0].cols() == dim*(dim+1)*numBones);
assert(CSM_M_SSCALAR[1].cols() == dim*(dim+1)*numBones);
assert(CSM_M_SSCALAR[2].cols() == dim*(dim+1)*numBones);
assert(CSM_M_SSCALAR[1].rows() == numRows);
assert(CSM_M_SSCALAR[2].rows() == numRows);
const int numCols = (dim + 1)*numBones;
CSM.resize(numRows, numCols);
typedef typename MatrixXS::Scalar SSCALAR;
SSCALAR maxDiff = 0.0f;
for (int r=0; r<numRows; r++)
{
for (int coord=0; coord<dim+1; coord++)
{
for (int b=0; b<numBones; b++)
{
// this is just a test if we really have a multiple of 3x3 identity
Eigen::Matrix3f blok;
for (int v=0; v<3; v++)
{
for (int w=0; w<3; w++)
{
blok(v,w) = CSM_M_SSCALAR[v](r, coord*(numBones*dim) + b + w*numBones);
}
}
//SSCALAR value[3];
//for (int v=0; v<3; v++)
// CSM_M_SSCALAR[v](r, coord*(numBones*dim) + b + v*numBones);
SSCALAR mD = maxBlokErr<SSCALAR>(blok);
if (mD > maxDiff) maxDiff = mD;
// use the first value:
CSM(r, coord*numBones + b) = blok(0,0);
}
}
}
return maxDiff;
}
// splits x_0, ... , x_dim coordinates in column vector 'L' into a numBones*(dimp1) x dim matrix 'Lsep';
// assumes 'Lsep' has already been preallocated
//
// is this the same as uncolumnize? no.
template <typename MatL, typename MatLsep>
static void splitColumns(
const MatL &L,
int numBones,
int dim,
int dimp1,
MatLsep &Lsep)
{
assert(L.cols() == 1);
assert(L.rows() == dim*(dimp1)*numBones);
assert(Lsep.rows() == (dimp1)*numBones && Lsep.cols() == dim);
for (int b=0; b<numBones; b++)
{
for (int coord=0; coord<dimp1; coord++)
{
for (int c=0; c<dim; c++)
{
Lsep(coord*numBones + b, c) = L(coord*numBones*dim + c*numBones + b, 0);
}
}
}
}
// the inverse of splitColumns, i.e., takes numBones*(dimp1) x dim matrix 'Lsep' and merges the dimensions
// into columns vector 'L' (which is assumed to be already allocated):
//
// is this the same as columnize? no.
template <typename MatrixXS>
static void mergeColumns(const MatrixXS &Lsep, int numBones, int dim, int dimp1, MatrixXS &L)
{
assert(L.cols() == 1);
assert(L.rows() == dim*(dimp1)*numBones);
assert(Lsep.rows() == (dimp1)*numBones && Lsep.cols() == dim);
for (int b=0; b<numBones; b++)
{
for (int coord=0; coord<dimp1; coord++)
{
for (int c=0; c<dim; c++)
{
L(coord*numBones*dim + c*numBones + b, 0) = Lsep(coord*numBones + b, c);
}
}
}
}
// converts "Solve1" the "rotations" part of FullSolve matrix (the first part)
// into one "condensed" matrix CSolve1 while checking we're not losing any
// information by this process; specifically, returns maximal difference from
// scaled 3x3 identity blocks, which should be pretty small number
template <typename MatrixXS>
static typename MatrixXS::Scalar condense_Solve1(MatrixXS &Solve1, int numBones, int numGroups, int dim, MatrixXS &CSolve1)
{
assert(Solve1.rows() == dim*(dim + 1)*numBones);
assert(Solve1.cols() == dim*dim*numGroups);
typedef typename MatrixXS::Scalar SSCALAR;
SSCALAR maxDiff = 0.0f;
CSolve1.resize((dim + 1)*numBones, dim*numGroups);
for (int rowCoord=0; rowCoord<dim+1; rowCoord++)
{
for (int b=0; b<numBones; b++)
{
for (int colCoord=0; colCoord<dim; colCoord++)
{
for (int g=0; g<numGroups; g++)
{
Eigen::Matrix3f blok;
for (int r=0; r<3; r++)
{
for (int c=0; c<3; c++)
{
blok(r, c) = Solve1(rowCoord*numBones*dim + r*numBones + b, colCoord*numGroups*dim + c*numGroups + g);
}
}
SSCALAR mD = maxBlokErr<SSCALAR>(blok);
if (mD > maxDiff) maxDiff = mD;
CSolve1(rowCoord*numBones + b, colCoord*numGroups + g) = blok(0,0);
}
}
}
}
return maxDiff;
}
}
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool igl::arap_dof_recomputation(
const Eigen::Matrix<int,Eigen::Dynamic,1> & fixed_dim,
const Eigen::SparseMatrix<double> & A_eq,
ArapDOFData<LbsMatrixType, SSCALAR> & data)
{
using namespace Eigen;
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
LbsMatrixType * Q;
LbsMatrixType Qdyn;
if(data.with_dynamics)
{
// multiply by 1/timestep and to quadratic coefficients matrix
// Might be missing a 0.5 here
LbsMatrixType Q_copy = data.Q;
Qdyn = Q_copy + (1.0/(data.h*data.h))*data.Mass_tilde;
Q = &Qdyn;
// This may/should be superfluous
//printf("is_symmetric()\n");
if(!is_symmetric(*Q))
{
//printf("Fixing symmetry...\n");
// "Fix" symmetry
LbsMatrixType QT = (*Q).transpose();
LbsMatrixType Q_copy = *Q;
*Q = 0.5*(Q_copy+QT);
// Check that ^^^ this really worked. It doesn't always
//assert(is_symmetric(*Q));
}
}else
{
Q = &data.Q;
}
assert((int)data.CSM_M.size() == data.dim);
assert(A_eq.cols() == data.m*data.dim*(data.dim+1));
data.fixed_dim = fixed_dim;
if(fixed_dim.size() > 0)
{
assert(fixed_dim.maxCoeff() < data.m*data.dim*(data.dim+1));
assert(fixed_dim.minCoeff() >= 0);
}
#ifdef EXTREME_VERBOSE
cout<<"data.fixed_dim=["<<endl<<data.fixed_dim<<endl<<"]+1;"<<endl;
#endif
// Compute dense solve matrix (alternative of matrix factorization)
//printf("min_quad_dense_precompute()\n");
MatrixXd Qfull(*Q);
MatrixXd A_eqfull(A_eq);
MatrixXd M_Solve;
double timer0_start = get_seconds_hires();
bool use_lu = data.effective_dim != 2;
//use_lu = false;
//printf("use_lu: %s\n",(use_lu?"TRUE":"FALSE"));
min_quad_dense_precompute(Qfull, A_eqfull, use_lu,M_Solve);
double timer0_end = get_seconds_hires();
verbose("Bob timing: %.20f\n", (timer0_end - timer0_start)*1000.0);
// Precompute full solve matrix:
const int fsRows = data.m * data.dim * (data.dim + 1); // 12 * number_of_bones
const int fsCols1 = data.M_KG.cols(); // 9 * number_of_posConstraints
const int fsCols2 = A_eq.rows(); // number_of_posConstraints
data.M_FullSolve.resize(fsRows, fsCols1 + fsCols2);
// note the magical multiplicative constant "-0.5", I've no idea why it has
// to be there :)
data.M_FullSolve <<
(-0.5 * M_Solve.block(0, 0, fsRows, fsRows) * data.M_KG).template cast<SSCALAR>(),
M_Solve.block(0, fsRows, fsRows, fsCols2).template cast<SSCALAR>();
if(data.with_dynamics)
{
printf(
"---------------------------------------------------------------------\n"
"\n\n\nWITH DYNAMICS recomputation\n\n\n"
"---------------------------------------------------------------------\n"
);
// Also need to save Π1 before it gets multiplied by Ktilde (aka M_KG)
data.Pi_1 = M_Solve.block(0, 0, fsRows, fsRows).template cast<SSCALAR>();
}
// Precompute condensed matrices,
// first CSM:
std::vector<MatrixXS> CSM_M_SSCALAR;
CSM_M_SSCALAR.resize(data.dim);
for (int i=0; i<data.dim; i++) CSM_M_SSCALAR[i] = data.CSM_M[i].template cast<SSCALAR>();
SSCALAR maxErr1 = condense_CSM(CSM_M_SSCALAR, data.m, data.dim, data.CSM);
verbose("condense_CSM maxErr = %.15f (this should be close to zero)\n", maxErr1);
assert(fabs(maxErr1) < 1e-5);
// and then solveBlock1:
// number of groups
const int k = data.CSM_M[0].rows()/data.dim;
MatrixXS SolveBlock1 = data.M_FullSolve.block(0, 0, data.M_FullSolve.rows(), data.dim * data.dim * k);
SSCALAR maxErr2 = condense_Solve1(SolveBlock1, data.m, k, data.dim, data.CSolveBlock1);
verbose("condense_Solve1 maxErr = %.15f (this should be close to zero)\n", maxErr2);
assert(fabs(maxErr2) < 1e-5);
return true;
}
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool igl::arap_dof_update(
const ArapDOFData<LbsMatrixType, SSCALAR> & data,
const Eigen::Matrix<double,Eigen::Dynamic,1> & B_eq,
const Eigen::MatrixXd & L0,
const int max_iters,
const double
#ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
tol,
#else
/*tol*/,
#endif
Eigen::MatrixXd & L
)
{
using namespace Eigen;
typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
#ifdef ARAP_GLOBAL_TIMING
double timer_start = get_seconds_hires();
#endif
// number of dimensions
assert((int)data.CSM_M.size() == data.dim);
assert((int)L0.size() == (data.m)*data.dim*(data.dim+1));
assert(max_iters >= 0);
assert(tol >= 0);
// timing variables
double
sec_start,
sec_covGather,
sec_fitRotations,
//sec_rhs,
sec_prepMult,
sec_solve, sec_end;
assert(L0.cols() == 1);
#ifdef EXTREME_VERBOSE
cout<<"dim="<<data.dim<<";"<<endl;
cout<<"m="<<data.m<<";"<<endl;
#endif
// number of groups
const int k = data.CSM_M[0].rows()/data.dim;
for(int i = 0;i<data.dim;i++)
{
assert(data.CSM_M[i].rows()/data.dim == k);
}
#ifdef EXTREME_VERBOSE
cout<<"k="<<k<<";"<<endl;
#endif
// resize output and initialize with initial guess
L = L0;
#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
// Keep track of last solution
MatrixXS L_prev;
#endif
// We will be iterating on L_SSCALAR, only at the end we convert back to double
MatrixXS L_SSCALAR = L.cast<SSCALAR>();
int iters = 0;
#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
double max_diff = tol+1;
#endif
MatrixXS S(k*data.dim,data.dim);
MatrixXS R(data.dim,data.dim*k);
Eigen::Matrix<SSCALAR,Eigen::Dynamic,1> Rcol(data.dim * data.dim * k);
Matrix<SSCALAR,Dynamic,1> B_eq_SSCALAR = B_eq.cast<SSCALAR>();
Matrix<SSCALAR,Dynamic,1> B_eq_fix_SSCALAR;
Matrix<SSCALAR,Dynamic,1> L0SSCALAR = L0.cast<SSCALAR>();
slice(L0SSCALAR, data.fixed_dim, B_eq_fix_SSCALAR);
//MatrixXS rhsFull(Rcol.rows() + B_eq.rows() + B_eq_fix_SSCALAR.rows(), 1);
MatrixXS Lsep(data.m*(data.dim + 1), 3);
const MatrixXS L_part2 =
data.M_FullSolve.block(0, Rcol.rows(), data.M_FullSolve.rows(), B_eq_SSCALAR.rows()) * B_eq_SSCALAR;
const MatrixXS L_part3 =
data.M_FullSolve.block(0, Rcol.rows() + B_eq_SSCALAR.rows(), data.M_FullSolve.rows(), B_eq_fix_SSCALAR.rows()) * B_eq_fix_SSCALAR;
MatrixXS L_part2and3 = L_part2 + L_part3;
// preallocate workspace variables:
MatrixXS Rxyz(k*data.dim, data.dim);
MatrixXS L_part1xyz((data.dim + 1) * data.m, data.dim);
MatrixXS L_part1(data.dim * (data.dim + 1) * data.m, 1);
#ifdef ARAP_GLOBAL_TIMING
double timer_prepFinished = get_seconds_hires();
#endif
#ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
while(iters < max_iters)
#else
while(iters < max_iters && max_diff > tol)
#endif
{
if(data.print_timings)
{
sec_start = get_seconds_hires();
}
#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
L_prev = L_SSCALAR;
#endif
///////////////////////////////////////////////////////////////////////////
// Local step: Fix positions, fit rotations
///////////////////////////////////////////////////////////////////////////
// Gather covariance matrices
splitColumns(L_SSCALAR, data.m, data.dim, data.dim + 1, Lsep);
S = data.CSM * Lsep;
// interestingly, this doesn't seem to be so slow, but
//MKL is still 2x faster (probably due to AVX)
//#ifdef IGL_ARAP_DOF_DOUBLE_PRECISION_SOLVE
// MKL_matMatMult_double(S, data.CSM, Lsep);
//#else
// MKL_matMatMult_single(S, data.CSM, Lsep);
//#endif
if(data.print_timings)
{
sec_covGather = get_seconds_hires();
}
#ifdef EXTREME_VERBOSE
cout<<"S=["<<endl<<S<<endl<<"];"<<endl;
#endif
// Fit rotations to covariance matrices
if(data.effective_dim == 2)
{
fit_rotations_planar(S,R);
}else
{
#ifdef __SSE__ // fit_rotations_SSE will convert to float if necessary
fit_rotations_SSE(S,R);
#else
fit_rotations(S,false,R);
#endif
}
#ifdef EXTREME_VERBOSE
cout<<"R=["<<endl<<R<<endl<<"];"<<endl;
#endif
if(data.print_timings)
{
sec_fitRotations = get_seconds_hires();
}
///////////////////////////////////////////////////////////////////////////
// "Global" step: fix rotations per mesh vertex, solve for
// linear transformations at handles
///////////////////////////////////////////////////////////////////////////
// all this shuffling is retarded and not completely negligible time-wise;
// TODO: change fit_rotations_XXX so it returns R in the format ready for
// CSolveBlock1 multiplication
columnize(R, k, 2, Rcol);
#ifdef EXTREME_VERBOSE
cout<<"Rcol=["<<endl<<Rcol<<endl<<"];"<<endl;
#endif
splitColumns(Rcol, k, data.dim, data.dim, Rxyz);
if(data.print_timings)
{
sec_prepMult = get_seconds_hires();
}
L_part1xyz = data.CSolveBlock1 * Rxyz;
//#ifdef IGL_ARAP_DOF_DOUBLE_PRECISION_SOLVE
// MKL_matMatMult_double(L_part1xyz, data.CSolveBlock1, Rxyz);
//#else
// MKL_matMatMult_single(L_part1xyz, data.CSolveBlock1, Rxyz);
//#endif
mergeColumns(L_part1xyz, data.m, data.dim, data.dim + 1, L_part1);
if(data.with_dynamics)
{
// Consider reordering or precomputing matrix multiplications
MatrixXS L_part1_dyn(data.dim * (data.dim + 1) * data.m, 1);
// Eigen can't parse this:
//L_part1_dyn =
// -(2.0/(data.h*data.h)) * data.Pi_1 * data.Mass_tilde * data.L0 +
// (1.0/(data.h*data.h)) * data.Pi_1 * data.Mass_tilde * data.Lm1;
// -1.0 because we've moved these linear terms to the right hand side
//MatrixXS temp = -1.0 *
// ((-2.0/(data.h*data.h)) * data.L0.array() +
// (1.0/(data.h*data.h)) * data.Lm1.array()).matrix();
//MatrixXS temp = -1.0 *
// ( (-1.0/(data.h*data.h)) * data.L0.array() +
// (1.0/(data.h*data.h)) * data.Lm1.array()
// (-1.0/(data.h*data.h)) * data.L0.array() +
// ).matrix();
//Lvel0 = (1.0/(data.h)) * data.Lm1.array() - data.L0.array();
MatrixXS temp = -1.0 *
( (-1.0/(data.h*data.h)) * data.L0.array() +
(1.0/(data.h)) * data.Lvel0.array()
).matrix();
MatrixXd temp_d = temp.template cast<double>();
MatrixXd temp_g = data.fgrav*(data.grav_mag*data.grav_dir);
assert(data.fext.rows() == temp_g.rows());
assert(data.fext.cols() == temp_g.cols());
MatrixXd temp2 = data.Mass_tilde * temp_d + temp_g + data.fext.template cast<double>();
MatrixXS temp2_f = temp2.template cast<SSCALAR>();
L_part1_dyn = data.Pi_1 * temp2_f;
L_part1.array() = L_part1.array() + L_part1_dyn.array();
}
//L_SSCALAR = L_part1 + L_part2and3;
assert(L_SSCALAR.rows() == L_part1.rows() && L_SSCALAR.rows() == L_part2and3.rows());
for (int i=0; i<L_SSCALAR.rows(); i++)
{
L_SSCALAR(i, 0) = L_part1(i, 0) + L_part2and3(i, 0);
}
#ifdef EXTREME_VERBOSE
cout<<"L=["<<endl<<L<<endl<<"];"<<endl;
#endif
if(data.print_timings)
{
sec_solve = get_seconds_hires();
}
#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
// Compute maximum absolute difference with last iteration's solution
max_diff = (L_SSCALAR-L_prev).eval().array().abs().matrix().maxCoeff();
#endif
iters++;
if(data.print_timings)
{
sec_end = get_seconds_hires();
#ifndef WIN32
// trick to get sec_* variables to compile without warning on mac
if(false)
#endif
printf(
"\ntotal iteration time = %f "
"[local: covGather = %f, "
"fitRotations = %f, "
"global: prep = %f, "
"solve = %f, "
"error = %f [ms]]\n",
(sec_end - sec_start)*1000.0,
(sec_covGather - sec_start)*1000.0,
(sec_fitRotations - sec_covGather)*1000.0,
(sec_prepMult - sec_fitRotations)*1000.0,
(sec_solve - sec_prepMult)*1000.0,
(sec_end - sec_solve)*1000.0 );
}
}
L = L_SSCALAR.template cast<double>();
assert(L.cols() == 1);
#ifdef ARAP_GLOBAL_TIMING
double timer_finito = get_seconds_hires();
printf(
"ARAP preparation = %f, "
"all %i iterations = %f [ms]\n",
(timer_prepFinished - timer_start)*1000.0,
max_iters,
(timer_finito - timer_prepFinished)*1000.0);
#endif
return true;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::arap_dof_update<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
template bool igl::arap_dof_recomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int> const&, ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>&);
template bool igl::arap_dof_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>&);
template bool igl::arap_dof_update<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
template bool igl::arap_dof_recomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int> const&, igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>&);
template bool igl::arap_dof_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>&);
#endif

244
src/igl/arap_dof.h Normal file
View file

@ -0,0 +1,244 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ARAP_ENERGY_TYPE_DOF_H
#define IGL_ARAP_ENERGY_TYPE_DOF_H
#include "igl_inline.h"
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include "ARAPEnergyType.h"
#include <vector>
namespace igl
{
// Caller example:
//
// Once:
// arap_dof_precomputation(...)
//
// Each frame:
// while(not satisfied)
// arap_dof_update(...)
// end
template <typename LbsMatrixType, typename SSCALAR>
struct ArapDOFData;
///////////////////////////////////////////////////////////////////////////
//
// Arap DOF precomputation consists of two parts the computation. The first is
// that which depends solely on the mesh (V,F), the linear blend skinning
// weights (M) and the groups G. Then there's the part that depends on the
// previous precomputation and the list of free and fixed vertices.
//
///////////////////////////////////////////////////////////////////////////
// The code and variables differ from the description in Section 3 of "Fast
// Automatic Skinning Transformations" by [Jacobson et al. 2012]
//
// Here is a useful conversion table:
//
// [article] [code]
// S = \tilde{K} T S = CSM * Lsep
// S --> R S --> R --shuffled--> Rxyz
// Gamma_solve RT = Pi_1 \tilde{K} RT L_part1xyz = CSolveBlock1 * Rxyz
// Pi_1 \tilde{K} CSolveBlock1
// Peq = [T_full; P_pos]
// T_full B_eq_fix <--- L0
// P_pos B_eq
// Pi_2 * P_eq = Lpart2and3 = Lpart2 + Lpart3
// Pi_2_left T_full + Lpart3 = M_fullsolve(right) * B_eq_fix
// Pi_2_right P_pos Lpart2 = M_fullsolve(left) * B_eq
// T = [Pi_1 Pi_2] [\tilde{K}TRT P_eq] L = Lpart1 + Lpart2and3
//
// Precomputes the system we are going to optimize. This consists of building
// constructor matrices (to compute covariance matrices from transformations
// and to build the poisson solve right hand side from rotation matrix entries)
// and also prefactoring the poisson system.
//
// Inputs:
// V #V by dim list of vertex positions
// F #F by {3|4} list of face indices
// M #V * dim by #handles * dim * (dim+1) matrix such that
// new_V(:) = LBS(V,W,A) = reshape(M * A,size(V)), where A is a column
// vectors formed by the entries in each handle's dim by dim+1
// transformation matrix. Specifcally, A =
// reshape(permute(Astack,[3 1 2]),n*dim*(dim+1),1)
// or A = [Lxx;Lyx;Lxy;Lyy;tx;ty], and likewise for other dim
// if Astack(:,:,i) is the dim by (dim+1) transformation at handle i
// handles are ordered according to P then BE (point handles before bone
// handles)
// G #V list of group indices (1 to k) for each vertex, such that vertex i
// is assigned to group G(i)
// Outputs:
// data structure containing all necessary precomputation for calling
// arap_dof_update
// Returns true on success, false on error
//
// See also: lbs_matrix_column
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool arap_dof_precomputation(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const LbsMatrixType & M,
const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
ArapDOFData<LbsMatrixType, SSCALAR> & data);
// Should always be called after arap_dof_precomputation, but may be called in
// between successive calls to arap_dof_update, recomputes precomputation
// given that there are only changes in free and fixed
//
// Inputs:
// fixed_dim list of transformation element indices for fixed (or partailly
// fixed) handles: not necessarily the complement of 'free'
// NOTE: the constraints for fixed transformations still need to be
// present in A_eq
// A_eq dim*#constraint_points by m*dim*(dim+1) matrix of linear equality
// constraint coefficients. Each row corresponds to a linear constraint,
// so that A_eq * L = Beq says that the linear transformation entries in
// the column L should produce the user supplied positional constraints
// for each handle in Beq. The row A_eq(i*dim+d) corresponds to the
// constrain on coordinate d of position i
// Outputs:
// data structure containing all necessary precomputation for calling
// arap_dof_update
// Returns true on success, false on error
//
// See also: lbs_matrix_column
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool arap_dof_recomputation(
const Eigen::Matrix<int,Eigen::Dynamic,1> & fixed_dim,
const Eigen::SparseMatrix<double> & A_eq,
ArapDOFData<LbsMatrixType, SSCALAR> & data);
// Optimizes the transformations attached to each weight function based on
// precomputed system.
//
// Inputs:
// data precomputation data struct output from arap_dof_precomputation
// Beq dim*#constraint_points constraint values.
// L0 #handles * dim * dim+1 list of initial guess transformation entries,
// also holds fixed transformation entries for fixed handles
// max_iters maximum number of iterations
// tol stopping criteria parameter. If variables (linear transformation
// matrix entries) change by less than 'tol' the optimization terminates,
// 0.75 (weak tolerance)
// 0.0 (extreme tolerance)
// Outputs:
// L #handles * dim * dim+1 list of final optimized transformation entries,
// allowed to be the same as L
template <typename LbsMatrixType, typename SSCALAR>
IGL_INLINE bool arap_dof_update(
const ArapDOFData<LbsMatrixType,SSCALAR> & data,
const Eigen::Matrix<double,Eigen::Dynamic,1> & B_eq,
const Eigen::MatrixXd & L0,
const int max_iters,
const double tol,
Eigen::MatrixXd & L
);
// Structure that contains fields for all precomputed data or data that needs
// to be remembered at update
template <typename LbsMatrixType, typename SSCALAR>
struct ArapDOFData
{
typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
// Type of arap energy we're solving
igl::ARAPEnergyType energy;
//// LU decomposition precomptation data; note: not used by araf_dop_update
//// any more, replaced by M_FullSolve
//igl::min_quad_with_fixed_data<double> lu_data;
// List of indices of fixed transformation entries
Eigen::Matrix<int,Eigen::Dynamic,1> fixed_dim;
// List of precomputed covariance scatter matrices multiplied by lbs
// matrices
//std::vector<Eigen::SparseMatrix<double> > CSM_M;
std::vector<Eigen::MatrixXd> CSM_M;
LbsMatrixType M_KG;
// Number of mesh vertices
int n;
// Number of weight functions
int m;
// Number of dimensions
int dim;
// Effective dimensions
int effective_dim;
// List of indices into C of positional constraints
Eigen::Matrix<int,Eigen::Dynamic,1> interpolated;
std::vector<bool> free_mask;
// Full quadratic coefficients matrix before lagrangian (should be dense)
LbsMatrixType Q;
//// Solve matrix for the global step
//Eigen::MatrixXd M_Solve; // TODO: remove from here
// Full solve matrix that contains also conversion from rotations to the right hand side,
// i.e., solves Poisson transformations just from rotations and positional constraints
MatrixXS M_FullSolve;
// Precomputed condensed matrices (3x3 commutators folded to 1x1):
MatrixXS CSM;
MatrixXS CSolveBlock1;
// Print timings at each update
bool print_timings;
// Dynamics
bool with_dynamics;
// I'm hiding the extra dynamics stuff in this struct, which sort of defeats
// the purpose of this function-based coding style...
// Time step
double h;
// L0 #handles * dim * dim+1 list of transformation entries from
// previous solve
MatrixXS L0;
//// Lm1 #handles * dim * dim+1 list of transformation entries from
//// previous-previous solve
//MatrixXS Lm1;
// "Velocity"
MatrixXS Lvel0;
// #V by dim matrix of external forces
// fext
MatrixXS fext;
// Mass_tilde: MT * Mass * M
LbsMatrixType Mass_tilde;
// Force due to gravity (premultiplier)
Eigen::MatrixXd fgrav;
// Direction of gravity
Eigen::Vector3d grav_dir;
// Magnitude of gravity
double grav_mag;
// Π1 from the paper
MatrixXS Pi_1;
// Default values
ArapDOFData():
energy(igl::ARAP_ENERGY_TYPE_SPOKES),
with_dynamics(false),
h(1),
grav_dir(0,-1,0),
grav_mag(0)
{
}
};
}
#ifndef IGL_STATIC_LIBRARY
# include "arap_dof.cpp"
#endif
#endif

View file

@ -0,0 +1,253 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "arap_linear_block.h"
#include "verbose.h"
#include "cotmatrix_entries.h"
#include <Eigen/Dense>
template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void igl::arap_linear_block(
const MatV & V,
const MatF & F,
const int d,
const igl::ARAPEnergyType energy,
Eigen::SparseMatrix<Scalar> & Kd)
{
switch(energy)
{
case ARAP_ENERGY_TYPE_SPOKES:
return igl::arap_linear_block_spokes(V,F,d,Kd);
break;
case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS:
return igl::arap_linear_block_spokes_and_rims(V,F,d,Kd);
break;
case ARAP_ENERGY_TYPE_ELEMENTS:
return igl::arap_linear_block_elements(V,F,d,Kd);
break;
default:
verbose("Unsupported energy type: %d\n",energy);
assert(false);
}
}
template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void igl::arap_linear_block_spokes(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd)
{
using namespace std;
using namespace Eigen;
// simplex size (3: triangles, 4: tetrahedra)
int simplex_size = F.cols();
// Number of elements
int m = F.rows();
// Temporary output
Matrix<int,Dynamic,2> edges;
Kd.resize(V.rows(), V.rows());
vector<Triplet<Scalar> > Kd_IJV;
if(simplex_size == 3)
{
// triangles
Kd.reserve(7*V.rows());
Kd_IJV.reserve(7*V.rows());
edges.resize(3,2);
edges <<
1,2,
2,0,
0,1;
}else if(simplex_size == 4)
{
// tets
Kd.reserve(17*V.rows());
Kd_IJV.reserve(17*V.rows());
edges.resize(6,2);
edges <<
1,2,
2,0,
0,1,
3,0,
3,1,
3,2;
}
// gather cotangent weights
Matrix<Scalar,Dynamic,Dynamic> C;
cotmatrix_entries(V,F,C);
// should have weights for each edge
assert(C.cols() == edges.rows());
// loop over elements
for(int i = 0;i<m;i++)
{
// loop over edges of element
for(int e = 0;e<edges.rows();e++)
{
int source = F(i,edges(e,0));
int dest = F(i,edges(e,1));
double v = 0.5*C(i,e)*(V(source,d)-V(dest,d));
Kd_IJV.push_back(Triplet<Scalar>(source,dest,v));
Kd_IJV.push_back(Triplet<Scalar>(dest,source,-v));
Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
}
}
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
Kd.makeCompressed();
}
template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd)
{
using namespace std;
using namespace Eigen;
// simplex size (3: triangles, 4: tetrahedra)
int simplex_size = F.cols();
// Number of elements
int m = F.rows();
// Temporary output
Kd.resize(V.rows(), V.rows());
vector<Triplet<Scalar> > Kd_IJV;
Matrix<int,Dynamic,2> edges;
if(simplex_size == 3)
{
// triangles
Kd.reserve(7*V.rows());
Kd_IJV.reserve(7*V.rows());
edges.resize(3,2);
edges <<
1,2,
2,0,
0,1;
}else if(simplex_size == 4)
{
// tets
Kd.reserve(17*V.rows());
Kd_IJV.reserve(17*V.rows());
edges.resize(6,2);
edges <<
1,2,
2,0,
0,1,
3,0,
3,1,
3,2;
// Not implemented yet for tets
assert(false);
}
// gather cotangent weights
Matrix<Scalar,Dynamic,Dynamic> C;
cotmatrix_entries(V,F,C);
// should have weights for each edge
assert(C.cols() == edges.rows());
// loop over elements
for(int i = 0;i<m;i++)
{
// loop over edges of element
for(int e = 0;e<edges.rows();e++)
{
int source = F(i,edges(e,0));
int dest = F(i,edges(e,1));
double v = C(i,e)*(V(source,d)-V(dest,d))/3.0;
// loop over edges again
for(int f = 0;f<edges.rows();f++)
{
int Rs = F(i,edges(f,0));
int Rd = F(i,edges(f,1));
if(Rs == source && Rd == dest)
{
Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,v));
Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,-v));
}else if(Rd == source)
{
Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,v));
}else if(Rs == dest)
{
Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,-v));
}
}
Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
}
}
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
Kd.makeCompressed();
}
template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void igl::arap_linear_block_elements(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd)
{
using namespace std;
using namespace Eigen;
// simplex size (3: triangles, 4: tetrahedra)
int simplex_size = F.cols();
// Number of elements
int m = F.rows();
// Temporary output
Kd.resize(V.rows(), F.rows());
vector<Triplet<Scalar> > Kd_IJV;
Matrix<int,Dynamic,2> edges;
if(simplex_size == 3)
{
// triangles
Kd.reserve(7*V.rows());
Kd_IJV.reserve(7*V.rows());
edges.resize(3,2);
edges <<
1,2,
2,0,
0,1;
}else if(simplex_size == 4)
{
// tets
Kd.reserve(17*V.rows());
Kd_IJV.reserve(17*V.rows());
edges.resize(6,2);
edges <<
1,2,
2,0,
0,1,
3,0,
3,1,
3,2;
}
// gather cotangent weights
Matrix<Scalar,Dynamic,Dynamic> C;
cotmatrix_entries(V,F,C);
// should have weights for each edge
assert(C.cols() == edges.rows());
// loop over elements
for(int i = 0;i<m;i++)
{
// loop over edges of element
for(int e = 0;e<edges.rows();e++)
{
int source = F(i,edges(e,0));
int dest = F(i,edges(e,1));
double v = C(i,e)*(V(source,d)-V(dest,d));
Kd_IJV.push_back(Triplet<Scalar>(source,i,v));
Kd_IJV.push_back(Triplet<Scalar>(dest,i,-v));
}
}
Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
Kd.makeCompressed();
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template IGL_INLINE void igl::arap_linear_block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
#endif

View file

@ -0,0 +1,78 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ARAP_LINEAR_BLOCK_H
#define IGL_ARAP_LINEAR_BLOCK_H
#include "igl_inline.h"
#include <Eigen/Sparse>
#include <igl/ARAPEnergyType.h>
namespace igl
{
// ARAP_LINEAR_BLOCK constructs a block of the matrix which constructs the
// linear terms of a given arap energy. When treating rotations as knowns
// (arranged in a column) then this constructs Kd of K such that the linear
// portion of the energy is as a column:
// K * R = [Kx Z ... Ky Z ...
// Z Kx ... Z Ky ...
// ... ]
// These blocks are also used to build the "covariance scatter matrices".
// Here we want to build a scatter matrix that multiplies against positions
// (treated as known) producing covariance matrices to fit each rotation.
// Notice that in the case of the RHS of the poisson solve the rotations are
// known and the positions unknown, and vice versa for rotation fitting.
// These linear block just relate the rotations to the positions, linearly in
// each.
//
// Templates:
// MatV vertex position matrix, e.g. Eigen::MatrixXd
// MatF face index matrix, e.g. Eigen::MatrixXd
// Scalar e.g. double
// Inputs:
// V #V by dim list of initial domain positions
// F #F by #simplex size list of triangle indices into V
// d coordinate of linear constructor to build
// energy ARAPEnergyType enum value defining which energy is being used.
// See ARAPEnergyType.h for valid options and explanations.
// Outputs:
// Kd #V by #V/#F block of the linear constructor matrix corresponding to
// coordinate d
//
template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void arap_linear_block(
const MatV & V,
const MatF & F,
const int d,
const igl::ARAPEnergyType energy,
Eigen::SparseMatrix<Scalar> & Kd);
// Helper functions for each energy type
template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void arap_linear_block_spokes(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd);
template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void arap_linear_block_spokes_and_rims(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd);
template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void arap_linear_block_elements(
const MatV & V,
const MatF & F,
const int d,
Eigen::SparseMatrix<Scalar> & Kd);
}
#ifndef IGL_STATIC_LIBRARY
# include "arap_linear_block.cpp"
#endif
#endif

89
src/igl/arap_rhs.cpp Normal file
View file

@ -0,0 +1,89 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "arap_rhs.h"
#include "arap_linear_block.h"
#include "verbose.h"
#include "repdiag.h"
#include "cat.h"
#include <iostream>
IGL_INLINE void igl::arap_rhs(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const int dim,
const igl::ARAPEnergyType energy,
Eigen::SparseMatrix<double>& K)
{
using namespace std;
using namespace Eigen;
// Number of dimensions
int Vdim = V.cols();
//// Number of mesh vertices
//int n = V.rows();
//// Number of mesh elements
//int m = F.rows();
//// number of rotations
//int nr;
switch(energy)
{
case ARAP_ENERGY_TYPE_SPOKES:
//nr = n;
break;
case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS:
//nr = n;
break;
case ARAP_ENERGY_TYPE_ELEMENTS:
//nr = m;
break;
default:
fprintf(
stderr,
"arap_rhs.h: Error: Unsupported arap energy %d\n",
energy);
return;
}
SparseMatrix<double> KX,KY,KZ;
arap_linear_block(V,F,0,energy,KX);
arap_linear_block(V,F,1,energy,KY);
if(Vdim == 2)
{
K = cat(2,repdiag(KX,dim),repdiag(KY,dim));
}else if(Vdim == 3)
{
arap_linear_block(V,F,2,energy,KZ);
if(dim == 3)
{
K = cat(2,cat(2,repdiag(KX,dim),repdiag(KY,dim)),repdiag(KZ,dim));
}else if(dim ==2)
{
SparseMatrix<double> ZZ(KX.rows()*2,KX.cols());
K = cat(2,cat(2,
cat(2,repdiag(KX,dim),ZZ),
cat(2,repdiag(KY,dim),ZZ)),
cat(2,repdiag(KZ,dim),ZZ));
}else
{
assert(false);
fprintf(
stderr,
"arap_rhs.h: Error: Unsupported dimension %d\n",
dim);
}
}else
{
assert(false);
fprintf(
stderr,
"arap_rhs.h: Error: Unsupported dimension %d\n",
Vdim);
return;
}
}

42
src/igl/arap_rhs.h Normal file
View file

@ -0,0 +1,42 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_ARAP_RHS_H
#define IGL_ARAP_RHS_H
#include "igl_inline.h"
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <igl/ARAPEnergyType.h>
namespace igl
{
// ARAP_RHS build right-hand side constructor of global poisson solve for
// various Arap energies
// Inputs:
// V #V by Vdim list of initial domain positions
// F #F by 3 list of triangle indices into V
// dim dimension being used at solve time. For deformation usually dim =
// V.cols(), for surface parameterization V.cols() = 3 and dim = 2
// energy igl::ARAPEnergyType enum value defining which energy is being
// used. See igl::ARAPEnergyType.h for valid options and explanations.
// Outputs:
// K #V*dim by #(F|V)*dim*dim matrix such that:
// b = K * reshape(permute(R,[3 1 2]),size(V|F,1)*size(V,2)*size(V,2),1);
//
// See also: arap_linear_block
IGL_INLINE void arap_rhs(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & F,
const int dim,
const igl::ARAPEnergyType energy,
Eigen::SparseMatrix<double>& K);
}
#ifndef IGL_STATIC_LIBRARY
#include "arap_rhs.cpp"
#endif
#endif

View file

@ -0,0 +1,29 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "average_onto_faces.h"
template <typename T, typename I>
IGL_INLINE void igl::average_onto_faces(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
const Eigen::Matrix<I, Eigen::Dynamic, Eigen::Dynamic> &F,
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &S,
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &SF)
{
SF = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>::Zero(F.rows(),S.cols());
for (int i = 0; i <F.rows(); ++i)
for (int j = 0; j<F.cols(); ++j)
SF.row(i) += S.row(F(i,j));
SF.array() /= F.cols();
};
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
#endif

View file

@ -0,0 +1,36 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_AVERAGE_ONTO_FACES_H
#define IGL_AVERAGE_ONTO_FACES_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
{
// average_onto_vertices
// Move a scalar field defined on faces to vertices by averaging
//
// Input:
// V,F: mesh
// S: scalar field defined on vertices, Vx1
//
// Output:
// SV: scalar field defined on faces
template <typename T, typename I>
IGL_INLINE void average_onto_faces(
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
const Eigen::Matrix<I, Eigen::Dynamic, Eigen::Dynamic> &F,
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &S,
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &SF);
}
#ifndef IGL_STATIC_LIBRARY
# include "average_onto_faces.cpp"
#endif
#endif

View file

@ -0,0 +1,33 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "average_onto_vertices.h"
template<typename DerivedV,typename DerivedF,typename DerivedS>
IGL_INLINE void igl::average_onto_vertices(const Eigen::MatrixBase<DerivedV> &V,
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedS> &S,
Eigen::MatrixBase<DerivedS> &SV)
{
SV = DerivedS::Zero(V.rows(),S.cols());
Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,1> COUNT(V.rows());
COUNT.setZero();
for (int i = 0; i <F.rows(); ++i)
{
for (int j = 0; j<F.cols(); ++j)
{
SV.row(F(i,j)) += S.row(i);
COUNT[F(i,j)] ++;
}
}
for (int i = 0; i <V.rows(); ++i)
SV.row(i) /= COUNT[i];
};
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
#endif

View file

@ -0,0 +1,35 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_AVERAGE_ONTO_VERTICES_H
#define IGL_AVERAGE_ONTO_VERTICES_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
{
// average_onto_vertices
// Move a scalar field defined on faces to vertices by averaging
//
// Input:
// V,F: mesh
// S: scalar field defined on faces, Fx1
//
// Output:
// SV: scalar field defined on vertices
template<typename DerivedV,typename DerivedF,typename DerivedS>
IGL_INLINE void average_onto_vertices(const Eigen::MatrixBase<DerivedV> &V,
const Eigen::MatrixBase<DerivedF> &F,
const Eigen::MatrixBase<DerivedS> &S,
Eigen::MatrixBase<DerivedS> &SV);
}
#ifndef IGL_STATIC_LIBRARY
# include "average_onto_vertices.cpp"
#endif
#endif

View file

@ -0,0 +1,39 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "avg_edge_length.h"
#include <vector>
template <typename DerivedV, typename DerivedF>
IGL_INLINE double igl::avg_edge_length(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F)
{
double avg = 0;
long int count = 0;
// Augh. Technically this is double counting interior edges...
for (unsigned i=0;i<F.rows();++i)
{
for (unsigned j=0;j<F.cols();++j)
{
++count;
avg += (V.row(F(i,j)) - V.row(F(i,(j+1)%F.cols()))).norm();
}
}
return avg / (double) count;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template double igl::avg_edge_length<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
template double igl::avg_edge_length<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
// generated by autoexplicit.sh
#endif

41
src/igl/avg_edge_length.h Normal file
View file

@ -0,0 +1,41 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_AVERAGEEDGELENGTH_H
#define IGL_AVERAGEEDGELENGTH_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <string>
#include <vector>
namespace igl
{
// Compute the average edge length for the given triangle mesh
// Templates:
// DerivedV derived from vertex positions matrix type: i.e. MatrixXd
// DerivedF derived from face indices matrix type: i.e. MatrixXi
// DerivedL derived from edge lengths matrix type: i.e. MatrixXd
// Inputs:
// V eigen matrix #V by 3
// F #F by simplex-size list of mesh faces (must be simplex)
// Outputs:
// l average edge length
//
// See also: adjacency_matrix
template <typename DerivedV, typename DerivedF>
IGL_INLINE double avg_edge_length(
const Eigen::MatrixBase<DerivedV>& V,
const Eigen::MatrixBase<DerivedF>& F);
}
#ifndef IGL_STATIC_LIBRARY
# include "avg_edge_length.cpp"
#endif
#endif

View file

@ -0,0 +1,42 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "axis_angle_to_quat.h"
#include "EPS.h"
#include <cmath>
// http://www.antisphere.com/Wiki/tools:anttweakbar
template <typename Q_type>
IGL_INLINE void igl::axis_angle_to_quat(
const Q_type *axis,
const Q_type angle,
Q_type *out)
{
Q_type n = axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2];
if( fabs(n)>igl::EPS<Q_type>())
{
Q_type f = 0.5*angle;
out[3] = cos(f);
f = sin(f)/sqrt(n);
out[0] = axis[0]*f;
out[1] = axis[1]*f;
out[2] = axis[2]*f;
}
else
{
out[3] = 1.0;
out[0] = out[1] = out[2] = 0.0;
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::axis_angle_to_quat<double>(double const*, double, double*);
// generated by autoexplicit.sh
template void igl::axis_angle_to_quat<float>(float const*, float, float*);
#endif

View file

@ -0,0 +1,33 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_AXIS_ANGLE_TO_QUAT_H
#define IGL_AXIS_ANGLE_TO_QUAT_H
#include "igl_inline.h"
namespace igl
{
// Convert axis angle representation of a rotation to a quaternion
// A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
// such that q = x*i + y*j + z*k + w
// Inputs:
// axis 3d vector
// angle scalar
// Outputs:
// quaternion
template <typename Q_type>
IGL_INLINE void axis_angle_to_quat(
const Q_type *axis,
const Q_type angle,
Q_type *out);
}
#ifndef IGL_STATIC_LIBRARY
# include "axis_angle_to_quat.cpp"
#endif
#endif

57
src/igl/barycenter.cpp Normal file
View file

@ -0,0 +1,57 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "barycenter.h"
template <
typename DerivedV,
typename DerivedF,
typename DerivedBC>
IGL_INLINE void igl::barycenter(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedBC> & BC)
{
BC.setZero(F.rows(),V.cols());
// Loop over faces
for(int i = 0;i<F.rows();i++)
{
// loop around face
for(int j = 0;j<F.cols();j++)
{
// Accumulate
BC.row(i) += V.row(F(i,j));
}
// average
BC.row(i) /= double(F.cols());
}
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
#endif

36
src/igl/barycenter.h Normal file
View file

@ -0,0 +1,36 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BARYCENTER_H
#define IGL_BARYCENTER_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
{
// Computes the barycenter of every simplex
//
// Inputs:
// V #V x dim matrix of vertex coordinates
// F #F x simplex_size matrix of indices of simplex corners into V
// Output:
// BC #F x dim matrix of 3d vertices
//
template <
typename DerivedV,
typename DerivedF,
typename DerivedBC>
IGL_INLINE void barycenter(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedBC> & BC);
}
#ifndef IGL_STATIC_LIBRARY
# include "barycenter.cpp"
#endif
#endif

View file

@ -0,0 +1,113 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "barycentric_coordinates.h"
#include "volume.h"
template <
typename DerivedP,
typename DerivedA,
typename DerivedB,
typename DerivedC,
typename DerivedD,
typename DerivedL>
IGL_INLINE void igl::barycentric_coordinates(
const Eigen::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedA> & A,
const Eigen::MatrixBase<DerivedB> & B,
const Eigen::MatrixBase<DerivedC> & C,
const Eigen::MatrixBase<DerivedD> & D,
Eigen::PlainObjectBase<DerivedL> & L)
{
using namespace Eigen;
assert(P.cols() == 3 && "query must be in 3d");
assert(A.cols() == 3 && "corners must be in 3d");
assert(B.cols() == 3 && "corners must be in 3d");
assert(C.cols() == 3 && "corners must be in 3d");
assert(D.cols() == 3 && "corners must be in 3d");
assert(P.rows() == A.rows() && "Must have same number of queries as corners");
assert(A.rows() == B.rows() && "Corners must be same size");
assert(A.rows() == C.rows() && "Corners must be same size");
assert(A.rows() == D.rows() && "Corners must be same size");
typedef Matrix<typename DerivedL::Scalar,DerivedL::RowsAtCompileTime,1>
VectorXS;
// Total volume
VectorXS vol,LA,LB,LC,LD;
volume(B,D,C,P,LA);
volume(A,C,D,P,LB);
volume(A,D,B,P,LC);
volume(A,B,C,P,LD);
volume(A,B,C,D,vol);
L.resize(P.rows(),4);
L<<LA,LB,LC,LD;
L.array().colwise() /= vol.array();
}
template <
typename DerivedP,
typename DerivedA,
typename DerivedB,
typename DerivedC,
typename DerivedL>
IGL_INLINE void igl::barycentric_coordinates(
const Eigen::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedA> & A,
const Eigen::MatrixBase<DerivedB> & B,
const Eigen::MatrixBase<DerivedC> & C,
Eigen::PlainObjectBase<DerivedL> & L)
{
using namespace Eigen;
#ifndef NDEBUG
const int DIM = P.cols();
assert(A.cols() == DIM && "corners must be in same dimension as query");
assert(B.cols() == DIM && "corners must be in same dimension as query");
assert(C.cols() == DIM && "corners must be in same dimension as query");
assert(P.rows() == A.rows() && "Must have same number of queries as corners");
assert(A.rows() == B.rows() && "Corners must be same size");
assert(A.rows() == C.rows() && "Corners must be same size");
#endif
// http://gamedev.stackexchange.com/a/23745
typedef
Eigen::Array<
typename DerivedP::Scalar,
DerivedP::RowsAtCompileTime,
DerivedP::ColsAtCompileTime>
ArrayS;
typedef
Eigen::Array<
typename DerivedP::Scalar,
DerivedP::RowsAtCompileTime,
1>
VectorS;
const ArrayS v0 = B.array() - A.array();
const ArrayS v1 = C.array() - A.array();
const ArrayS v2 = P.array() - A.array();
VectorS d00 = (v0*v0).rowwise().sum();
VectorS d01 = (v0*v1).rowwise().sum();
VectorS d11 = (v1*v1).rowwise().sum();
VectorS d20 = (v2*v0).rowwise().sum();
VectorS d21 = (v2*v1).rowwise().sum();
VectorS denom = d00 * d11 - d01 * d01;
L.resize(P.rows(),3);
L.col(1) = (d11 * d20 - d01 * d21) / denom;
L.col(2) = (d00 * d21 - d01 * d20) / denom;
L.col(0) = 1.0f -(L.col(1) + L.col(2)).array();
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::barycentric_coordinates<Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
template void igl::barycentric_coordinates<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
template void igl::barycentric_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
template void igl::barycentric_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif

View file

@ -0,0 +1,68 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BARYCENTRIC_COORDINATES_H
#define IGL_BARYCENTRIC_COORDINATES_H
#include "igl_inline.h"
#include <Eigen/Core>
namespace igl
{
// Compute barycentric coordinates in a tet
//
// Inputs:
// P #P by 3 Query points in 3d
// A #P by 3 Tet corners in 3d
// B #P by 3 Tet corners in 3d
// C #P by 3 Tet corners in 3d
// D #P by 3 Tet corners in 3d
// Outputs:
// L #P by 4 list of barycentric coordinates
//
template <
typename DerivedP,
typename DerivedA,
typename DerivedB,
typename DerivedC,
typename DerivedD,
typename DerivedL>
IGL_INLINE void barycentric_coordinates(
const Eigen::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedA> & A,
const Eigen::MatrixBase<DerivedB> & B,
const Eigen::MatrixBase<DerivedC> & C,
const Eigen::MatrixBase<DerivedD> & D,
Eigen::PlainObjectBase<DerivedL> & L);
// Compute barycentric coordinates in a triangle
//
// Inputs:
// P #P by dim Query points
// A #P by dim Triangle corners
// B #P by dim Triangle corners
// C #P by dim Triangle corners
// Outputs:
// L #P by 3 list of barycentric coordinates
//
template <
typename DerivedP,
typename DerivedA,
typename DerivedB,
typename DerivedC,
typename DerivedL>
IGL_INLINE void barycentric_coordinates(
const Eigen::MatrixBase<DerivedP> & P,
const Eigen::MatrixBase<DerivedA> & A,
const Eigen::MatrixBase<DerivedB> & B,
const Eigen::MatrixBase<DerivedC> & C,
Eigen::PlainObjectBase<DerivedL> & L);
}
#ifndef IGL_STATIC_LIBRARY
# include "barycentric_coordinates.cpp"
#endif
#endif

View file

@ -0,0 +1,44 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "barycentric_to_global.h"
// For error printing
#include <cstdio>
#include <vector>
namespace igl
{
template <typename Scalar, typename Index>
IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> barycentric_to_global(
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc)
{
Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> R;
R.resize(bc.rows(),3);
for (unsigned i=0; i<R.rows(); ++i)
{
unsigned id = round(bc(i,0));
double u = bc(i,1);
double v = bc(i,2);
if (id != -1)
R.row(i) = V.row(F(id,0)) +
((V.row(F(id,1)) - V.row(F(id,0))) * u +
(V.row(F(id,2)) - V.row(F(id,0))) * v );
else
R.row(i) << 0,0,0;
}
return R;
}
}
#ifdef IGL_STATIC_LIBRARY
template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::barycentric_to_global<double, int>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&);
#endif

42
src/igl/barycentric_to_global.h Executable file
View file

@ -0,0 +1,42 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BARYCENTRIC2GLOBAL_H
#define IGL_BARYCENTRIC2GLOBAL_H
#include <igl/igl_inline.h>
#include <Eigen/Dense>
#include <Eigen/Sparse>
namespace igl
{
// Converts barycentric coordinates in the embree form to 3D coordinates
// Embree stores barycentric coordinates as triples: fid, bc1, bc2
// fid is the id of a face, bc1 is the displacement of the point wrt the
// first vertex v0 and the edge v1-v0. Similarly, bc2 is the displacement
// wrt v2-v0.
//
// Input:
// V: #Vx3 Vertices of the mesh
// F: #Fxe Faces of the mesh
// bc: #Xx3 Barycentric coordinates, one row per point
//
// Output:
// #X: #Xx3 3D coordinates of all points in bc
template <typename Scalar, typename Index>
IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
barycentric_to_global(
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc);
}
#ifndef IGL_STATIC_LIBRARY
# include "barycentric_to_global.cpp"
#endif
#endif

38
src/igl/basename.cpp Normal file
View file

@ -0,0 +1,38 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "basename.h"
#include <algorithm>
IGL_INLINE std::string igl::basename(const std::string & path)
{
if(path == "")
{
return std::string("");
}
// http://stackoverflow.com/questions/5077693/dirnamephp-similar-function-in-c
std::string::const_reverse_iterator last_slash =
std::find(
path.rbegin(),
path.rend(), '/');
if( last_slash == path.rend() )
{
// No slashes found
return path;
}else if(1 == (last_slash.base() - path.begin()))
{
// Slash is first char
return std::string(path.begin()+1,path.end());
}else if(path.end() == last_slash.base() )
{
// Slash is last char
std::string redo = std::string(path.begin(),path.end()-1);
return igl::basename(redo);
}
return std::string(last_slash.base(),path.end());
}

29
src/igl/basename.h Normal file
View file

@ -0,0 +1,29 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BASENAME_H
#define IGL_BASENAME_H
#include "igl_inline.h"
#include <string>
namespace igl
{
// Function like PHP's basename: /etc/sudoers.d --> sudoers.d
// Input:
// path string containing input path
// Returns string containing basename (see php's basename)
//
// See also: dirname, pathinfo
IGL_INLINE std::string basename(const std::string & path);
}
#ifndef IGL_STATIC_LIBRARY
# include "basename.cpp"
#endif
#endif

143
src/igl/bbw.cpp Normal file
View file

@ -0,0 +1,143 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "bbw.h"
#include "min_quad_with_fixed.h"
#include "harmonic.h"
#include "parallel_for.h"
#include <Eigen/Sparse>
#include <iostream>
#include <mutex>
#include <cstdio>
igl::BBWData::BBWData():
partition_unity(false),
W0(),
active_set_params(),
verbosity(0)
{
// We know that the Bilaplacian is positive semi-definite
active_set_params.Auu_pd = true;
}
void igl::BBWData::print()
{
using namespace std;
cout<<"partition_unity: "<<partition_unity<<endl;
cout<<"W0=["<<endl<<W0<<endl<<"];"<<endl;
}
template <
typename DerivedV,
typename DerivedEle,
typename Derivedb,
typename Derivedbc,
typename DerivedW>
IGL_INLINE bool igl::bbw(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedEle> & Ele,
const Eigen::PlainObjectBase<Derivedb> & b,
const Eigen::PlainObjectBase<Derivedbc> & bc,
igl::BBWData & data,
Eigen::PlainObjectBase<DerivedW> & W
)
{
using namespace std;
using namespace Eigen;
assert(!data.partition_unity && "partition_unity not implemented yet");
// number of domain vertices
int n = V.rows();
// number of handles
int m = bc.cols();
// Build biharmonic operator
Eigen::SparseMatrix<typename DerivedV::Scalar> Q;
harmonic(V,Ele,2,Q);
W.derived().resize(n,m);
// No linear terms
VectorXd c = VectorXd::Zero(n);
// No linear constraints
SparseMatrix<typename DerivedW::Scalar> A(0,n),Aeq(0,n),Aieq(0,n);
VectorXd Beq(0,1),Bieq(0,1);
// Upper and lower box constraints (Constant bounds)
VectorXd ux = VectorXd::Ones(n);
VectorXd lx = VectorXd::Zero(n);
active_set_params eff_params = data.active_set_params;
if(data.verbosity >= 1)
{
cout<<"BBW: max_iter: "<<data.active_set_params.max_iter<<endl;
cout<<"BBW: eff_max_iter: "<<eff_params.max_iter<<endl;
}
if(data.verbosity >= 1)
{
cout<<"BBW: Computing initial weights for "<<m<<" handle"<<
(m!=1?"s":"")<<"."<<endl;
}
min_quad_with_fixed_data<typename DerivedW::Scalar > mqwf;
min_quad_with_fixed_precompute(Q,b,Aeq,true,mqwf);
min_quad_with_fixed_solve(mqwf,c,bc,Beq,W);
// decrement
eff_params.max_iter--;
bool error = false;
// Loop over handles
std::mutex critical;
const auto & optimize_weight = [&](const int i)
{
// Quicker exit for paralle_for
if(error)
{
return;
}
if(data.verbosity >= 1)
{
std::lock_guard<std::mutex> lock(critical);
cout<<"BBW: Computing weight for handle "<<i+1<<" out of "<<m<<
"."<<endl;
}
VectorXd bci = bc.col(i);
VectorXd Wi;
// use initial guess
Wi = W.col(i);
SolverStatus ret = active_set(
Q,c,b,bci,Aeq,Beq,Aieq,Bieq,lx,ux,eff_params,Wi);
switch(ret)
{
case SOLVER_STATUS_CONVERGED:
break;
case SOLVER_STATUS_MAX_ITER:
cerr<<"active_set: max iter without convergence."<<endl;
break;
case SOLVER_STATUS_ERROR:
default:
cerr<<"active_set error."<<endl;
error = true;
}
W.col(i) = Wi;
};
parallel_for(m,optimize_weight,2);
if(error)
{
return false;
}
#ifndef NDEBUG
const double min_rowsum = W.rowwise().sum().array().abs().minCoeff();
if(min_rowsum < 0.1)
{
cerr<<"bbw.cpp: Warning, minimum row sum is very low. Consider more "
"active set iterations or enforcing partition of unity."<<endl;
}
#endif
return true;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::bbw<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::BBWData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif

77
src/igl/bbw.h Normal file
View file

@ -0,0 +1,77 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BBW_H
#define IGL_BBW_H
#include "igl_inline.h"
#include <Eigen/Dense>
#include <igl/active_set.h>
namespace igl
{
// Container for BBW computation related data and flags
class BBWData
{
public:
// Enforce partition of unity during optimization (optimize all weight
// simultaneously)
bool partition_unity;
// Initial guess
Eigen::MatrixXd W0;
igl::active_set_params active_set_params;
// Verbosity level
// 0: quiet
// 1: loud
// 2: louder
int verbosity;
public:
IGL_INLINE BBWData();
// Print current state of object
IGL_INLINE void print();
};
// Compute Bounded Biharmonic Weights on a given domain (V,Ele) with a given
// set of boundary conditions
//
// Templates
// DerivedV derived type of eigen matrix for V (e.g. MatrixXd)
// DerivedF derived type of eigen matrix for F (e.g. MatrixXi)
// Derivedb derived type of eigen matrix for b (e.g. VectorXi)
// Derivedbc derived type of eigen matrix for bc (e.g. MatrixXd)
// DerivedW derived type of eigen matrix for W (e.g. MatrixXd)
// Inputs:
// V #V by dim vertex positions
// Ele #Elements by simplex-size list of element indices
// b #b boundary indices into V
// bc #b by #W list of boundary values
// data object containing options, initial guess --> solution and results
// Outputs:
// W #V by #W list of *unnormalized* weights to normalize use
// igl::normalize_row_sums(W,W);
// Returns true on success, false on failure
template <
typename DerivedV,
typename DerivedEle,
typename Derivedb,
typename Derivedbc,
typename DerivedW>
IGL_INLINE bool bbw(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedEle> & Ele,
const Eigen::PlainObjectBase<Derivedb> & b,
const Eigen::PlainObjectBase<Derivedbc> & bc,
BBWData & data,
Eigen::PlainObjectBase<DerivedW> & W);
}
#ifndef IGL_STATIC_LIBRARY
# include "bbw.cpp"
#endif
#endif

93
src/igl/bfs.cpp Normal file
View file

@ -0,0 +1,93 @@
#include "bfs.h"
#include "list_to_matrix.h"
#include <vector>
#include <queue>
template <
typename AType,
typename DerivedD,
typename DerivedP>
IGL_INLINE void igl::bfs(
const AType & A,
const size_t s,
Eigen::PlainObjectBase<DerivedD> & D,
Eigen::PlainObjectBase<DerivedP> & P)
{
std::vector<typename DerivedD::Scalar> vD;
std::vector<typename DerivedP::Scalar> vP;
bfs(A,s,vD,vP);
list_to_matrix(vD,D);
list_to_matrix(vP,P);
}
template <
typename AType,
typename DType,
typename PType>
IGL_INLINE void igl::bfs(
const std::vector<std::vector<AType> > & A,
const size_t s,
std::vector<DType> & D,
std::vector<PType> & P)
{
// number of nodes
int N = s+1;
for(const auto & Ai : A) for(const auto & a : Ai) N = std::max(N,a+1);
std::vector<bool> seen(N,false);
P.resize(N,-1);
std::queue<std::pair<int,int> > Q;
Q.push({s,-1});
while(!Q.empty())
{
const int f = Q.front().first;
const int p = Q.front().second;
Q.pop();
if(seen[f])
{
continue;
}
D.push_back(f);
P[f] = p;
seen[f] = true;
for(const auto & n : A[f]) Q.push({n,f});
}
}
template <
typename AType,
typename DType,
typename PType>
IGL_INLINE void igl::bfs(
const Eigen::SparseMatrix<AType> & A,
const size_t s,
std::vector<DType> & D,
std::vector<PType> & P)
{
// number of nodes
int N = A.rows();
assert(A.rows() == A.cols());
std::vector<bool> seen(N,false);
P.resize(N,-1);
std::queue<std::pair<int,int> > Q;
Q.push({s,-1});
while(!Q.empty())
{
const int f = Q.front().first;
const int p = Q.front().second;
Q.pop();
if(seen[f])
{
continue;
}
D.push_back(f);
P[f] = p;
seen[f] = true;
for(typename Eigen::SparseMatrix<AType>::InnerIterator it (A,f); it; ++it)
{
if(it.value()) Q.push({it.index(),f});
}
}
}

54
src/igl/bfs.h Normal file
View file

@ -0,0 +1,54 @@
#ifndef IGL_BFS_H
#define IGL_BFS_H
#include "igl_inline.h"
#include <Eigen/Core>
#include <vector>
#include <Eigen/Sparse>
namespace igl
{
// Traverse a **directed** graph represented by an adjacency list using
// breadth first search
//
// Inputs:
// A #V list of adjacency lists or #V by #V adjacency matrix
// s starting node (index into A)
// Outputs:
// D #V list of indices into rows of A in the order in which graph nodes
// are discovered.
// P #V list of indices into rows of A of predecessor in resulting
// spanning tree {-1 indicates root/not discovered), order corresponds to
// V **not** D.
template <
typename AType,
typename DerivedD,
typename DerivedP>
IGL_INLINE void bfs(
const AType & A,
const size_t s,
Eigen::PlainObjectBase<DerivedD> & D,
Eigen::PlainObjectBase<DerivedP> & P);
template <
typename AType,
typename DType,
typename PType>
IGL_INLINE void bfs(
const std::vector<std::vector<AType> > & A,
const size_t s,
std::vector<DType> & D,
std::vector<PType> & P);
template <
typename AType,
typename DType,
typename PType>
IGL_INLINE void bfs(
const Eigen::SparseMatrix<AType> & A,
const size_t s,
std::vector<DType> & D,
std::vector<PType> & P);
}
#ifndef IGL_STATIC_LIBRARY
# include "bfs.cpp"
#endif
#endif

100
src/igl/bfs_orient.cpp Normal file
View file

@ -0,0 +1,100 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "bfs_orient.h"
#include "orientable_patches.h"
#include <Eigen/Sparse>
#include <queue>
template <typename DerivedF, typename DerivedFF, typename DerivedC>
IGL_INLINE void igl::bfs_orient(
const Eigen::PlainObjectBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedFF> & FF,
Eigen::PlainObjectBase<DerivedC> & C)
{
using namespace Eigen;
using namespace std;
SparseMatrix<int> A;
orientable_patches(F,C,A);
// number of faces
const int m = F.rows();
// number of patches
const int num_cc = C.maxCoeff()+1;
VectorXi seen = VectorXi::Zero(m);
// Edge sets
const int ES[3][2] = {{1,2},{2,0},{0,1}};
if(&FF != &F)
{
FF = F;
}
// loop over patches
#pragma omp parallel for
for(int c = 0;c<num_cc;c++)
{
queue<int> Q;
// find first member of patch c
for(int f = 0;f<FF.rows();f++)
{
if(C(f) == c)
{
Q.push(f);
break;
}
}
assert(!Q.empty());
while(!Q.empty())
{
const int f = Q.front();
Q.pop();
if(seen(f) > 0)
{
continue;
}
seen(f)++;
// loop over neighbors of f
for(typename SparseMatrix<int>::InnerIterator it (A,f); it; ++it)
{
// might be some lingering zeros, and skip self-adjacency
if(it.value() != 0 && it.row() != f)
{
const int n = it.row();
assert(n != f);
// loop over edges of f
for(int efi = 0;efi<3;efi++)
{
// efi'th edge of face f
Vector2i ef(FF(f,ES[efi][0]),FF(f,ES[efi][1]));
// loop over edges of n
for(int eni = 0;eni<3;eni++)
{
// eni'th edge of face n
Vector2i en(FF(n,ES[eni][0]),FF(n,ES[eni][1]));
// Match (half-edges go same direction)
if(ef(0) == en(0) && ef(1) == en(1))
{
// flip face n
FF.row(n) = FF.row(n).reverse().eval();
}
}
}
// add neighbor to queue
Q.push(n);
}
}
}
}
// make sure flip is OK if &FF = &F
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::bfs_orient<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
#endif

36
src/igl/bfs_orient.h Normal file
View file

@ -0,0 +1,36 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BFS_ORIENT_H
#define IGL_BFS_ORIENT_H
#include <Eigen/Core>
#include <igl/igl_inline.h>
namespace igl
{
// Consistently orient faces in orientable patches using BFS
//
// F = bfs_orient(F,V);
//
// Inputs:
// F #F by 3 list of faces
// Outputs:
// FF #F by 3 list of faces (OK if same as F)
// C #F list of component ids
//
//
template <typename DerivedF, typename DerivedFF, typename DerivedC>
IGL_INLINE void bfs_orient(
const Eigen::PlainObjectBase<DerivedF> & F,
Eigen::PlainObjectBase<DerivedFF> & FF,
Eigen::PlainObjectBase<DerivedC> & C);
};
#ifndef IGL_STATIC_LIBRARY
# include "bfs_orient.cpp"
#endif
#endif

View file

@ -0,0 +1,203 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "biharmonic_coordinates.h"
#include "cotmatrix.h"
#include "sum.h"
#include "massmatrix.h"
#include "min_quad_with_fixed.h"
#include "crouzeix_raviart_massmatrix.h"
#include "crouzeix_raviart_cotmatrix.h"
#include "normal_derivative.h"
#include "on_boundary.h"
#include <Eigen/Sparse>
template <
typename DerivedV,
typename DerivedT,
typename SType,
typename DerivedW>
IGL_INLINE bool igl::biharmonic_coordinates(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedT> & T,
const std::vector<std::vector<SType> > & S,
Eigen::PlainObjectBase<DerivedW> & W)
{
return biharmonic_coordinates(V,T,S,2,W);
}
template <
typename DerivedV,
typename DerivedT,
typename SType,
typename DerivedW>
IGL_INLINE bool igl::biharmonic_coordinates(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedT> & T,
const std::vector<std::vector<SType> > & S,
const int k,
Eigen::PlainObjectBase<DerivedW> & W)
{
using namespace Eigen;
using namespace std;
// This is not the most efficient way to build A, but follows "Linear
// Subspace Design for Real-Time Shape Deformation" [Wang et al. 2015].
SparseMatrix<double> A;
{
DiagonalMatrix<double,Dynamic> Minv;
SparseMatrix<double> L,K;
Array<bool,Dynamic,Dynamic> C;
{
Array<bool,Dynamic,1> I;
on_boundary(T,I,C);
}
#ifdef false
// Version described in paper is "wrong"
// http://www.cs.toronto.edu/~jacobson/images/error-in-linear-subspace-design-for-real-time-shape-deformation-2017-wang-et-al.pdf
SparseMatrix<double> N,Z,M;
normal_derivative(V,T,N);
{
std::vector<Triplet<double> >ZIJV;
for(int t =0;t<T.rows();t++)
{
for(int f =0;f<T.cols();f++)
{
if(C(t,f))
{
const int i = t+f*T.rows();
for(int c = 1;c<T.cols();c++)
{
ZIJV.emplace_back(T(t,(f+c)%T.cols()),i,1);
}
}
}
}
Z.resize(V.rows(),N.rows());
Z.setFromTriplets(ZIJV.begin(),ZIJV.end());
N = (Z*N).eval();
}
cotmatrix(V,T,L);
K = N+L;
massmatrix(V,T,MASSMATRIX_TYPE_DEFAULT,M);
// normalize
M /= ((VectorXd)M.diagonal()).array().abs().maxCoeff();
Minv =
((VectorXd)M.diagonal().array().inverse()).asDiagonal();
#else
Eigen::SparseMatrix<double> M;
Eigen::MatrixXi E;
Eigen::VectorXi EMAP;
crouzeix_raviart_massmatrix(V,T,M,E,EMAP);
crouzeix_raviart_cotmatrix(V,T,E,EMAP,L);
// Ad #E by #V facet-vertex incidence matrix
Eigen::SparseMatrix<double> Ad(E.rows(),V.rows());
{
std::vector<Eigen::Triplet<double> > AIJV(E.size());
for(int e = 0;e<E.rows();e++)
{
for(int c = 0;c<E.cols();c++)
{
AIJV[e+c*E.rows()] = Eigen::Triplet<double>(e,E(e,c),1);
}
}
Ad.setFromTriplets(AIJV.begin(),AIJV.end());
}
// Degrees
Eigen::VectorXd De;
sum(Ad,2,De);
Eigen::DiagonalMatrix<double,Eigen::Dynamic> De_diag =
De.array().inverse().matrix().asDiagonal();
K = L*(De_diag*Ad);
// normalize
M /= ((VectorXd)M.diagonal()).array().abs().maxCoeff();
Minv = ((VectorXd)M.diagonal().array().inverse()).asDiagonal();
// kill boundary edges
for(int f = 0;f<T.rows();f++)
{
for(int c = 0;c<T.cols();c++)
{
if(C(f,c))
{
const int e = EMAP(f+T.rows()*c);
Minv.diagonal()(e) = 0;
}
}
}
#endif
switch(k)
{
default:
assert(false && "unsupported");
case 2:
// For C1 smoothness in 2D, one should use bi-harmonic
A = K.transpose() * (Minv * K);
break;
case 3:
// For C1 smoothness in 3D, one should use tri-harmonic
A = K.transpose() * (Minv * (-L * (Minv * K)));
break;
}
}
// Vertices in point handles
const size_t mp =
count_if(S.begin(),S.end(),[](const vector<int> & h){return h.size()==1;});
// number of region handles
const size_t r = S.size()-mp;
// Vertices in region handles
size_t mr = 0;
for(const auto & h : S)
{
if(h.size() > 1)
{
mr += h.size();
}
}
const size_t dim = T.cols()-1;
// Might as well be dense... I think...
MatrixXd J = MatrixXd::Zero(mp+mr,mp+r*(dim+1));
VectorXi b(mp+mr);
MatrixXd H(mp+r*(dim+1),dim);
{
int v = 0;
int c = 0;
for(int h = 0;h<S.size();h++)
{
if(S[h].size()==1)
{
H.row(c) = V.block(S[h][0],0,1,dim);
J(v,c++) = 1;
b(v) = S[h][0];
v++;
}else
{
assert(S[h].size() >= dim+1);
for(int p = 0;p<S[h].size();p++)
{
for(int d = 0;d<dim;d++)
{
J(v,c+d) = V(S[h][p],d);
}
J(v,c+dim) = 1;
b(v) = S[h][p];
v++;
}
H.block(c,0,dim+1,dim).setIdentity();
c+=dim+1;
}
}
}
// minimize ½ W' A W'
// subject to W(b,:) = J
return min_quad_with_fixed(
A,VectorXd::Zero(A.rows()).eval(),b,J,SparseMatrix<double>(),VectorXd(),true,W);
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::biharmonic_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
#endif

View file

@ -0,0 +1,90 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BIHARMONIC_COORDINATES_H
#define IGL_BIHARMONIC_COORDINATES_H
#include "igl_inline.h"
#include <Eigen/Dense>
#include <vector>
namespace igl
{
// Compute "discrete biharmonic generalized barycentric coordinates" as
// described in "Linear Subspace Design for Real-Time Shape Deformation"
// [Wang et al. 2015]. Not to be confused with "Bounded Biharmonic Weights
// for Real-Time Deformation" [Jacobson et al. 2011] or "Biharmonic
// Coordinates" (2D complex barycentric coordinates) [Weber et al. 2012].
// These weights minimize a discrete version of the squared Laplacian energy
// subject to positional interpolation constraints at selected vertices
// (point handles) and transformation interpolation constraints at regions
// (region handles).
//
// Templates:
// HType should be a simple index type e.g. `int`,`size_t`
// Inputs:
// V #V by dim list of mesh vertex positions
// T #T by dim+1 list of / triangle indices into V if dim=2
// \ tetrahedron indices into V if dim=3
// S #point-handles+#region-handles list of lists of selected vertices for
// each handle. Point handles should have singleton lists and region
// handles should have lists of size at least dim+1 (and these points
// should be in general position).
// Outputs:
// W #V by #points-handles+(#region-handles * dim+1) matrix of weights so
// that columns correspond to each handles generalized barycentric
// coordinates (for point-handles) or animation space weights (for region
// handles).
// returns true only on success
//
// Example:
//
// MatrixXd W;
// igl::biharmonic_coordinates(V,F,S,W);
// const size_t dim = T.cols()-1;
// MatrixXd H(W.cols(),dim);
// {
// int c = 0;
// for(int h = 0;h<S.size();h++)
// {
// if(S[h].size()==1)
// {
// H.row(c++) = V.block(S[h][0],0,1,dim);
// }else
// {
// H.block(c,0,dim+1,dim).setIdentity();
// c+=dim+1;
// }
// }
// }
// assert( (V-(W*H)).array().maxCoeff() < 1e-7 );
template <
typename DerivedV,
typename DerivedT,
typename SType,
typename DerivedW>
IGL_INLINE bool biharmonic_coordinates(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedT> & T,
const std::vector<std::vector<SType> > & S,
Eigen::PlainObjectBase<DerivedW> & W);
// k 2-->biharmonic, 3-->triharmonic
template <
typename DerivedV,
typename DerivedT,
typename SType,
typename DerivedW>
IGL_INLINE bool biharmonic_coordinates(
const Eigen::PlainObjectBase<DerivedV> & V,
const Eigen::PlainObjectBase<DerivedT> & T,
const std::vector<std::vector<SType> > & S,
const int k,
Eigen::PlainObjectBase<DerivedW> & W);
};
# ifndef IGL_STATIC_LIBRARY
# include "biharmonic_coordinates.cpp"
# endif
#endif

View file

@ -0,0 +1,115 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "bijective_composite_harmonic_mapping.h"
#include "slice.h"
#include "doublearea.h"
#include "harmonic.h"
//#include "matlab/MatlabWorkspace.h"
#include <iostream>
template <
typename DerivedV,
typename DerivedF,
typename Derivedb,
typename Derivedbc,
typename DerivedU>
IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<Derivedb> & b,
const Eigen::MatrixBase<Derivedbc> & bc,
Eigen::PlainObjectBase<DerivedU> & U)
{
return bijective_composite_harmonic_mapping(V,F,b,bc,1,200,20,true,U);
}
template <
typename DerivedV,
typename DerivedF,
typename Derivedb,
typename Derivedbc,
typename DerivedU>
IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<Derivedb> & b,
const Eigen::MatrixBase<Derivedbc> & bc,
const int min_steps,
const int max_steps,
const int num_inner_iters,
const bool test_for_flips,
Eigen::PlainObjectBase<DerivedU> & U)
{
typedef typename Derivedbc::Scalar Scalar;
assert(V.cols() == 2 && bc.cols() == 2 && "Input should be 2D");
assert(F.cols() == 3 && "F should contain triangles");
int tries = 0;
int nsteps = min_steps;
Derivedbc bc0;
slice(V,b,1,bc0);
// It's difficult to check for flips "robustly" in the sense that the input
// mesh might not have positive/consistent sign to begin with.
while(nsteps<=max_steps)
{
U = V;
int flipped = 0;
int nans = 0;
int step = 0;
for(;step<=nsteps;step++)
{
const Scalar t = ((Scalar)step)/((Scalar)nsteps);
// linearly interpolate boundary conditions
// TODO: replace this with something that guarantees a homotopic "morph"
// of the boundary conditions. Something like "Homotopic Morphing of
// Planar Curves" [Dym et al. 2015] but also handling multiple connected
// components.
Derivedbc bct = bc0 + t*(bc - bc0);
// Compute dsicrete harmonic map using metric of previous step
for(int iter = 0;iter<num_inner_iters;iter++)
{
//std::cout<<nsteps<<" t: "<<t<<" iter: "<<iter;
//igl::matlab::MatlabWorkspace mw;
//mw.save(U,"U");
//mw.save_index(F,"F");
//mw.save_index(b,"b");
//mw.save(bct,"bct");
//mw.write("numerical.mat");
harmonic(DerivedU(U),F,b,bct,1,U);
igl::slice(U,b,1,bct);
nans = (U.array() != U.array()).count();
if(test_for_flips)
{
Eigen::Matrix<Scalar,Eigen::Dynamic,1> A;
doublearea(U,F,A);
flipped = (A.array() < 0 ).count();
//std::cout<<" "<<flipped<<" nan? "<<(U.array() != U.array()).any()<<std::endl;
if(flipped == 0 && nans == 0) break;
}
}
if(flipped > 0 || nans>0) break;
}
if(flipped == 0 && nans == 0)
{
return step == nsteps+1;
}
nsteps *= 2;
}
//std::cout<<"failed to finish in "<<nsteps<<"..."<<std::endl;
return false;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template bool igl::bijective_composite_harmonic_mapping<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
// generated by autoexplicit.sh
template bool igl::bijective_composite_harmonic_mapping<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, int, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
#endif

View file

@ -0,0 +1,79 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BIJECTIVE_COMPOSITE_HARMONIC_MAPPING_H
#define IGL_BIJECTIVE_COMPOSITE_HARMONIC_MAPPING_H
#include "igl_inline.h"
#include <Eigen/Core>
namespace igl
{
// Compute a planar mapping of a triangulated polygon (V,F) subjected to
// boundary conditions (b,bc). The mapping should be bijective in the sense
// that no triangles' areas become negative (this assumes they started
// positive). This mapping is computed by "composing" harmonic mappings
// between incremental morphs of the boundary conditions. This is a bit like
// a discrete version of "Bijective Composite Mean Value Mappings" [Schneider
// et al. 2013] but with a discrete harmonic map (cf. harmonic coordinates)
// instead of mean value coordinates. This is inspired by "Embedding a
// triangular graph within a given boundary" [Xu et al. 2011].
//
// Inputs:
// V #V by 2 list of triangle mesh vertex positions
// F #F by 3 list of triangle indices into V
// b #b list of boundary indices into V
// bc #b by 2 list of boundary conditions corresponding to b
// Outputs:
// U #V by 2 list of output mesh vertex locations
// Returns true if and only if U contains a successful bijectie mapping
//
//
template <
typename DerivedV,
typename DerivedF,
typename Derivedb,
typename Derivedbc,
typename DerivedU>
IGL_INLINE bool bijective_composite_harmonic_mapping(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<Derivedb> & b,
const Eigen::MatrixBase<Derivedbc> & bc,
Eigen::PlainObjectBase<DerivedU> & U);
//
// Inputs:
// min_steps minimum number of steps to take from V(b,:) to bc
// max_steps minimum number of steps to take from V(b,:) to bc (if
// max_steps == min_steps then no further number of steps will be tried)
// num_inner_iters number of iterations of harmonic solves to run after
// for each morph step (to try to push flips back in)
// test_for_flips whether to check if flips occurred (and trigger more
// steps). if test_for_flips = false then this function always returns
// true
//
template <
typename DerivedV,
typename DerivedF,
typename Derivedb,
typename Derivedbc,
typename DerivedU>
IGL_INLINE bool bijective_composite_harmonic_mapping(
const Eigen::MatrixBase<DerivedV> & V,
const Eigen::MatrixBase<DerivedF> & F,
const Eigen::MatrixBase<Derivedb> & b,
const Eigen::MatrixBase<Derivedbc> & bc,
const int min_steps,
const int max_steps,
const int num_inner_iters,
const bool test_for_flips,
Eigen::PlainObjectBase<DerivedU> & U);
}
#ifndef IGL_STATIC_LIBRARY
# include "bijective_composite_harmonic_mapping.cpp"
#endif
#endif

32
src/igl/bone_parents.cpp Normal file
View file

@ -0,0 +1,32 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "bone_parents.h"
template <typename DerivedBE, typename DerivedP>
IGL_INLINE void igl::bone_parents(
const Eigen::PlainObjectBase<DerivedBE>& BE,
Eigen::PlainObjectBase<DerivedP>& P)
{
P.resize(BE.rows(),1);
// Stupid O(n²) version
for(int e = 0;e<BE.rows();e++)
{
P(e) = -1;
for(int f = 0;f<BE.rows();f++)
{
if(BE(e,0) == BE(f,1))
{
P(e) = f;
}
}
}
}
#ifdef IGL_STATIC_LIBRARY
template void igl::bone_parents<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
#endif

32
src/igl/bone_parents.h Normal file
View file

@ -0,0 +1,32 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BONE_PARENTS_H
#define IGL_BONE_PARENTS_H
#include "igl_inline.h"
#include <Eigen/Core>
namespace igl
{
// BONE_PARENTS Recover "parent" bones from directed graph representation.
//
// Inputs:
// BE #BE by 2 list of directed bone edges
// Outputs:
// P #BE by 1 list of parent indices into BE, -1 means root.
//
template <typename DerivedBE, typename DerivedP>
IGL_INLINE void bone_parents(
const Eigen::PlainObjectBase<DerivedBE>& BE,
Eigen::PlainObjectBase<DerivedP>& P);
}
#ifndef IGL_STATIC_LIBRARY
# include "bone_parents.cpp"
#endif
#endif

View file

@ -0,0 +1,192 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "boundary_conditions.h"
#include "verbose.h"
#include "EPS.h"
#include "project_to_line.h"
#include <vector>
#include <map>
#include <iostream>
IGL_INLINE bool igl::boundary_conditions(
const Eigen::MatrixXd & V ,
const Eigen::MatrixXi & /*Ele*/,
const Eigen::MatrixXd & C ,
const Eigen::VectorXi & P ,
const Eigen::MatrixXi & BE ,
const Eigen::MatrixXi & CE ,
Eigen::VectorXi & b ,
Eigen::MatrixXd & bc )
{
using namespace Eigen;
using namespace std;
if(P.size()+BE.rows() == 0)
{
verbose("^%s: Error: no handles found\n",__FUNCTION__);
return false;
}
vector<int> bci;
vector<int> bcj;
vector<double> bcv;
// loop over points
for(int p = 0;p<P.size();p++)
{
VectorXd pos = C.row(P(p));
// loop over domain vertices
for(int i = 0;i<V.rows();i++)
{
// Find samples just on pos
//Vec3 vi(V(i,0),V(i,1),V(i,2));
// EIGEN GOTCHA:
// double sqrd = (V.row(i)-pos).array().pow(2).sum();
// Must first store in temporary
VectorXd vi = V.row(i);
double sqrd = (vi-pos).squaredNorm();
if(sqrd <= FLOAT_EPS)
{
//cout<<"sum((["<<
// V(i,0)<<" "<<
// V(i,1)<<" "<<
// V(i,2)<<"] - ["<<
// pos(0)<<" "<<
// pos(1)<<" "<<
// pos(2)<<"]).^2) = "<<sqrd<<endl;
bci.push_back(i);
bcj.push_back(p);
bcv.push_back(1.0);
}
}
}
// loop over bone edges
for(int e = 0;e<BE.rows();e++)
{
// loop over domain vertices
for(int i = 0;i<V.rows();i++)
{
// Find samples from tip up to tail
VectorXd tip = C.row(BE(e,0));
VectorXd tail = C.row(BE(e,1));
// Compute parameter along bone and squared distance
double t,sqrd;
project_to_line(
V(i,0),V(i,1),V(i,2),
tip(0),tip(1),tip(2),
tail(0),tail(1),tail(2),
t,sqrd);
if(t>=-FLOAT_EPS && t<=(1.0f+FLOAT_EPS) && sqrd<=FLOAT_EPS)
{
bci.push_back(i);
bcj.push_back(P.size()+e);
bcv.push_back(1.0);
}
}
}
// loop over cage edges
for(int e = 0;e<CE.rows();e++)
{
// loop over domain vertices
for(int i = 0;i<V.rows();i++)
{
// Find samples from tip up to tail
VectorXd tip = C.row(P(CE(e,0)));
VectorXd tail = C.row(P(CE(e,1)));
// Compute parameter along bone and squared distance
double t,sqrd;
project_to_line(
V(i,0),V(i,1),V(i,2),
tip(0),tip(1),tip(2),
tail(0),tail(1),tail(2),
t,sqrd);
if(t>=-FLOAT_EPS && t<=(1.0f+FLOAT_EPS) && sqrd<=FLOAT_EPS)
{
bci.push_back(i);
bcj.push_back(CE(e,0));
bcv.push_back(1.0-t);
bci.push_back(i);
bcj.push_back(CE(e,1));
bcv.push_back(t);
}
}
}
// find unique boundary indices
vector<int> vb = bci;
sort(vb.begin(),vb.end());
vb.erase(unique(vb.begin(), vb.end()), vb.end());
b.resize(vb.size());
bc = MatrixXd::Zero(vb.size(),P.size()+BE.rows());
// Map from boundary index to index in boundary
map<int,int> bim;
int i = 0;
// Also fill in b
for(vector<int>::iterator bit = vb.begin();bit != vb.end();bit++)
{
b(i) = *bit;
bim[*bit] = i;
i++;
}
// Build BC
for(i = 0;i < (int)bci.size();i++)
{
assert(bim.find(bci[i]) != bim.end());
bc(bim[bci[i]],bcj[i]) = bcv[i];
}
// Normalize across rows so that conditions sum to one
for(i = 0;i<bc.rows();i++)
{
double sum = bc.row(i).sum();
assert(sum != 0 && "Some boundary vertex getting all zero BCs");
bc.row(i).array() /= sum;
}
if(bc.size() == 0)
{
verbose("^%s: Error: boundary conditions are empty.\n",__FUNCTION__);
return false;
}
// If there's only a single boundary condition, the following tests
// are overzealous.
if(bc.cols() == 1)
{
// If there is only one weight function,
// then we expect that there is only one handle.
assert(P.rows() + BE.rows() == 1);
return true;
}
// Check that every Weight function has at least one boundary value of 1 and
// one value of 0
for(i = 0;i<bc.cols();i++)
{
double min_abs_c = bc.col(i).array().abs().minCoeff();
double max_c = bc.col(i).maxCoeff();
if(min_abs_c > FLOAT_EPS)
{
verbose("^%s: Error: handle %d does not receive 0 weight\n",__FUNCTION__,i);
return false;
}
if(max_c< (1-FLOAT_EPS))
{
verbose("^%s: Error: handle %d does not receive 1 weight\n",__FUNCTION__,i);
return false;
}
}
return true;
}

View file

@ -0,0 +1,55 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BOUNDARY_CONDITIONS_H
#define IGL_BOUNDARY_CONDITIONS_H
#include "igl_inline.h"
#include <Eigen/Dense>
namespace igl
{
// Compute boundary conditions for automatic weights computation. This
// function expects that the given mesh (V,Ele) has sufficient samples
// (vertices) exactly at point handle locations and exactly along bone and
// cage edges.
//
// Inputs:
// V #V by dim list of domain vertices
// Ele #Ele by simplex-size list of simplex indices
// C #C by dim list of handle positions
// P #P by 1 list of point handle indices into C
// BE #BE by 2 list of bone edge indices into C
// CE #CE by 2 list of cage edge indices into *P*
// Outputs:
// b #b list of boundary indices (indices into V of vertices which have
// known, fixed values)
// bc #b by #weights list of known/fixed values for boundary vertices
// (notice the #b != #weights in general because #b will include all the
// intermediary samples along each bone, etc.. The ordering of the
// weights corresponds to [P;BE]
// Returns false if boundary conditions are suspicious:
// P and BE are empty
// bc is empty
// some column of bc doesn't have a 0 (assuming bc has >1 columns)
// some column of bc doesn't have a 1 (assuming bc has >1 columns)
IGL_INLINE bool boundary_conditions(
const Eigen::MatrixXd & V,
const Eigen::MatrixXi & Ele,
const Eigen::MatrixXd & C,
const Eigen::VectorXi & P,
const Eigen::MatrixXi & BE,
const Eigen::MatrixXi & CE,
Eigen::VectorXi & b,
Eigen::MatrixXd & bc);
}
#ifndef IGL_STATIC_LIBRARY
# include "boundary_conditions.cpp"
#endif
#endif

141
src/igl/boundary_facets.cpp Normal file
View file

@ -0,0 +1,141 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "boundary_facets.h"
#include "face_occurrences.h"
// IGL includes
#include "sort.h"
// STL includes
#include <map>
#include <iostream>
template <typename IntegerT, typename IntegerF>
IGL_INLINE void igl::boundary_facets(
const std::vector<std::vector<IntegerT> > & T,
std::vector<std::vector<IntegerF> > & F)
{
using namespace std;
if(T.size() == 0)
{
F.clear();
return;
}
int simplex_size = T[0].size();
// Get a list of all faces
vector<vector<IntegerF> > allF(
T.size()*simplex_size,
vector<IntegerF>(simplex_size-1));
// Gather faces, loop over tets
for(int i = 0; i< (int)T.size();i++)
{
assert((int)T[i].size() == simplex_size);
switch(simplex_size)
{
case 4:
// get face in correct order
allF[i*simplex_size+0][0] = T[i][1];
allF[i*simplex_size+0][1] = T[i][3];
allF[i*simplex_size+0][2] = T[i][2];
// get face in correct order
allF[i*simplex_size+1][0] = T[i][0];
allF[i*simplex_size+1][1] = T[i][2];
allF[i*simplex_size+1][2] = T[i][3];
// get face in correct order
allF[i*simplex_size+2][0] = T[i][0];
allF[i*simplex_size+2][1] = T[i][3];
allF[i*simplex_size+2][2] = T[i][1];
// get face in correct order
allF[i*simplex_size+3][0] = T[i][0];
allF[i*simplex_size+3][1] = T[i][1];
allF[i*simplex_size+3][2] = T[i][2];
break;
case 3:
allF[i*simplex_size+0][0] = T[i][1];
allF[i*simplex_size+0][1] = T[i][2];
allF[i*simplex_size+1][0] = T[i][2];
allF[i*simplex_size+1][1] = T[i][0];
allF[i*simplex_size+2][0] = T[i][0];
allF[i*simplex_size+2][1] = T[i][1];
break;
}
}
// Counts
vector<int> C;
face_occurrences(allF,C);
// Q: Why not just count the number of ones?
// A: because we are including non-manifold edges as boundary edges
int twos = (int) count(C.begin(),C.end(),2);
//int ones = (int) count(C.begin(),C.end(),1);
// Resize output to fit number of ones
F.resize(allF.size() - twos);
//F.resize(ones);
int k = 0;
for(int i = 0;i< (int)allF.size();i++)
{
if(C[i] != 2)
{
assert(k<(int)F.size());
F[k] = allF[i];
k++;
}
}
assert(k==(int)F.size());
//if(k != F.size())
//{
// printf("%d =? %d\n",k,F.size());
//}
}
#include "list_to_matrix.h"
#include "matrix_to_list.h"
template <typename DerivedT, typename DerivedF>
IGL_INLINE void igl::boundary_facets(
const Eigen::PlainObjectBase<DerivedT>& T,
Eigen::PlainObjectBase<DerivedF>& F)
{
assert(T.cols() == 0 || T.cols() == 4 || T.cols() == 3);
using namespace std;
using namespace Eigen;
// Cop out: use vector of vectors version
vector<vector<typename DerivedT::Scalar> > vT;
matrix_to_list(T,vT);
vector<vector<typename DerivedF::Scalar> > vF;
boundary_facets(vT,vF);
list_to_matrix(vF,F);
}
template <typename DerivedT, typename Ret>
Ret igl::boundary_facets(
const Eigen::PlainObjectBase<DerivedT>& T)
{
Ret F;
igl::boundary_facets(T,F);
return F;
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
// generated by autoexplicit.sh
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
template void igl::boundary_facets<int, int>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
//template Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > igl::boundary_facets(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
#endif

52
src/igl/boundary_facets.h Normal file
View file

@ -0,0 +1,52 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#ifndef IGL_BOUNDARY_FACETS_H
#define IGL_BOUNDARY_FACETS_H
#include "igl_inline.h"
#include <Eigen/Dense>
#include <vector>
namespace igl
{
// BOUNDARY_FACETS Determine boundary faces (edges) of tetrahedra (triangles)
// stored in T (analogous to qptoolbox's `outline` and `boundary_faces`).
//
// Templates:
// IntegerT integer-value: e.g. int
// IntegerF integer-value: e.g. int
// Input:
// T tetrahedron (triangle) index list, m by 4 (3), where m is the number of tetrahedra
// Output:
// F list of boundary faces, n by 3 (2), where n is the number of boundary faces
//
//
template <typename IntegerT, typename IntegerF>
IGL_INLINE void boundary_facets(
const std::vector<std::vector<IntegerT> > & T,
std::vector<std::vector<IntegerF> > & F);
// Templates:
// DerivedT integer-value: i.e. from MatrixXi
// DerivedF integer-value: i.e. from MatrixXi
template <typename DerivedT, typename DerivedF>
IGL_INLINE void boundary_facets(
const Eigen::PlainObjectBase<DerivedT>& T,
Eigen::PlainObjectBase<DerivedF>& F);
// Same as above but returns F
template <typename DerivedT, typename Ret>
Ret boundary_facets(
const Eigen::PlainObjectBase<DerivedT>& T);
}
#ifndef IGL_STATIC_LIBRARY
# include "boundary_facets.cpp"
#endif
#endif

153
src/igl/boundary_loop.cpp Executable file
View file

@ -0,0 +1,153 @@
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "boundary_loop.h"
#include "slice.h"
#include "triangle_triangle_adjacency.h"
#include "vertex_triangle_adjacency.h"
#include "is_border_vertex.h"
#include <set>
template <typename DerivedF, typename Index>
IGL_INLINE void igl::boundary_loop(
const Eigen::PlainObjectBase<DerivedF> & F,
std::vector<std::vector<Index> >& L)
{
using namespace std;
using namespace Eigen;
if(F.rows() == 0)
return;
VectorXd Vdummy(F.maxCoeff()+1,1);
DerivedF TT,TTi;
vector<std::vector<int> > VF, VFi;
triangle_triangle_adjacency(F,TT,TTi);
vertex_triangle_adjacency(Vdummy,F,VF,VFi);
vector<bool> unvisited = is_border_vertex(Vdummy,F);
set<int> unseen;
for (size_t i = 0; i < unvisited.size(); ++i)
{
if (unvisited[i])
unseen.insert(unseen.end(),i);
}
while (!unseen.empty())
{
vector<Index> l;
// Get first vertex of loop
int start = *unseen.begin();
unseen.erase(unseen.begin());
unvisited[start] = false;
l.push_back(start);
bool done = false;
while (!done)
{
// Find next vertex
bool newBndEdge = false;
int v = l[l.size()-1];
int next;
for (int i = 0; i < (int)VF[v].size() && !newBndEdge; i++)
{
int fid = VF[v][i];
if (TT.row(fid).minCoeff() < 0.) // Face contains boundary edge
{
int vLoc = -1;
if (F(fid,0) == v) vLoc = 0;
if (F(fid,1) == v) vLoc = 1;
if (F(fid,2) == v) vLoc = 2;
int vNext = F(fid,(vLoc + 1) % F.cols());
newBndEdge = false;
if (unvisited[vNext] && TT(fid,vLoc) < 0)
{
next = vNext;
newBndEdge = true;
}
}
}
if (newBndEdge)
{
l.push_back(next);
unseen.erase(next);
unvisited[next] = false;
}
else
done = true;
}
L.push_back(l);
}
}
template <typename DerivedF, typename Index>
IGL_INLINE void igl::boundary_loop(
const Eigen::PlainObjectBase<DerivedF>& F,
std::vector<Index>& L)
{
using namespace Eigen;
using namespace std;
if(F.rows() == 0)
return;
vector<vector<int> > Lall;
boundary_loop(F,Lall);
int idxMax = -1;
size_t maxLen = 0;
for (size_t i = 0; i < Lall.size(); ++i)
{
if (Lall[i].size() > maxLen)
{
maxLen = Lall[i].size();
idxMax = i;
}
}
//Check for meshes without boundary
if (idxMax == -1)
{
L.clear();
return;
}
L.resize(Lall[idxMax].size());
for (size_t i = 0; i < Lall[idxMax].size(); ++i)
{
L[i] = Lall[idxMax][i];
}
}
template <typename DerivedF, typename DerivedL>
IGL_INLINE void igl::boundary_loop(
const Eigen::PlainObjectBase<DerivedF>& F,
Eigen::PlainObjectBase<DerivedL>& L)
{
using namespace Eigen;
using namespace std;
if(F.rows() == 0)
return;
vector<int> Lvec;
boundary_loop(F,Lvec);
L.resize(Lvec.size());
for (size_t i = 0; i < Lvec.size(); ++i)
L(i) = Lvec[i];
}
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template void igl::boundary_loop<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
#endif

Some files were not shown because too many files have changed in this diff Show more