Merge branch 'dev_native' of https://github.com/prusa3d/Slic3r into dev_native
This commit is contained in:
commit
135ee60db4
2184 changed files with 237093 additions and 26 deletions
|
@ -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
1075
src/igl/AABB.cpp
Normal file
File diff suppressed because it is too large
Load diff
413
src/igl/AABB.h
Normal file
413
src/igl/AABB.h
Normal 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
36
src/igl/ARAPEnergyType.h
Normal 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
130
src/igl/AtA_cached.cpp
Normal 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
70
src/igl/AtA_cached.h
Normal 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
18
src/igl/C_STR.h
Normal 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
359
src/igl/Camera.h
Normal 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
30
src/igl/EPS.cpp
Normal 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
32
src/igl/EPS.h
Normal 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
|
158
src/igl/HalfEdgeIterator.cpp
Normal file
158
src/igl/HalfEdgeIterator.cpp
Normal 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
114
src/igl/HalfEdgeIterator.h
Normal 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
25
src/igl/Hit.h
Normal 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
28
src/igl/IO
Normal 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
117
src/igl/IndexComparison.h
Normal 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
61
src/igl/LinSpaced.h
Normal 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
23
src/igl/MeshBooleanType.h
Normal 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
27
src/igl/NormalType.h
Normal 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
22
src/igl/ONE.h
Normal 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
19
src/igl/PI.h
Normal 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
55
src/igl/REDRUM.h
Normal 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
18
src/igl/STR.h
Normal 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
|
|
@ -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
|
|
@ -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);)
|
137
src/igl/Singular_Value_Decomposition_Kernel_Declarations.hpp
Normal file
137
src/igl/Singular_Value_Decomposition_Kernel_Declarations.hpp
Normal 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;)
|
1277
src/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp
Normal file
1277
src/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp
Normal file
File diff suppressed because it is too large
Load diff
78
src/igl/Singular_Value_Decomposition_Preamble.hpp
Normal file
78
src/igl/Singular_Value_Decomposition_Preamble.hpp
Normal 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
23
src/igl/SolverStatus.h
Normal 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
70
src/igl/SortableRow.h
Normal 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
179
src/igl/Timer.h
Normal 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
69
src/igl/Viewport.h
Normal 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
377
src/igl/WindingNumberAABB.h
Normal 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
|
23
src/igl/WindingNumberMethod.h
Normal file
23
src/igl/WindingNumberMethod.h
Normal 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
503
src/igl/WindingNumberTree.h
Normal 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
21
src/igl/ZERO.h
Normal 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
370
src/igl/active_set.cpp
Executable 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
111
src/igl/active_set.h
Normal 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
168
src/igl/adjacency_list.cpp
Normal 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
51
src/igl/adjacency_list.h
Normal 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
|
74
src/igl/adjacency_matrix.cpp
Normal file
74
src/igl/adjacency_matrix.cpp
Normal 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
|
51
src/igl/adjacency_matrix.h
Normal file
51
src/igl/adjacency_matrix.h
Normal 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
26
src/igl/all.cpp
Normal 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
36
src/igl/all.h
Normal 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
26
src/igl/all_edges.cpp
Normal 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
38
src/igl/all_edges.h
Normal 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
|
39
src/igl/all_pairs_distances.cpp
Normal file
39
src/igl/all_pairs_distances.cpp
Normal 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
|
41
src/igl/all_pairs_distances.h
Normal file
41
src/igl/all_pairs_distances.h
Normal 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
|
137
src/igl/ambient_occlusion.cpp
Normal file
137
src/igl/ambient_occlusion.cpp
Normal 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
|
80
src/igl/ambient_occlusion.h
Normal file
80
src/igl/ambient_occlusion.h
Normal 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
|
20
src/igl/angular_distance.cpp
Normal file
20
src/igl/angular_distance.cpp
Normal 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);
|
||||
}
|
30
src/igl/angular_distance.h
Normal file
30
src/igl/angular_distance.h
Normal 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
|
934
src/igl/anttweakbar/ReAntTweakBar.cpp
Normal file
934
src/igl/anttweakbar/ReAntTweakBar.cpp
Normal 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;
|
||||
}
|
286
src/igl/anttweakbar/ReAntTweakBar.h
Normal file
286
src/igl/anttweakbar/ReAntTweakBar.h
Normal 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
|
81
src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.cpp
Normal file
81
src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.cpp
Normal 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;
|
||||
}
|
31
src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.h
Normal file
31
src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.h
Normal 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
26
src/igl/any.cpp
Normal 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
35
src/igl/any.h
Normal 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
20
src/igl/any_of.cpp
Normal 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
26
src/igl/any_of.h
Normal 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
312
src/igl/arap.cpp
Normal 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
104
src/igl/arap.h
Normal 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
884
src/igl/arap_dof.cpp
Normal 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
244
src/igl/arap_dof.h
Normal 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
|
253
src/igl/arap_linear_block.cpp
Normal file
253
src/igl/arap_linear_block.cpp
Normal 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
|
78
src/igl/arap_linear_block.h
Normal file
78
src/igl/arap_linear_block.h
Normal 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
89
src/igl/arap_rhs.cpp
Normal 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
42
src/igl/arap_rhs.h
Normal 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
|
29
src/igl/average_onto_faces.cpp
Normal file
29
src/igl/average_onto_faces.cpp
Normal 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
|
36
src/igl/average_onto_faces.h
Normal file
36
src/igl/average_onto_faces.h
Normal 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
|
33
src/igl/average_onto_vertices.cpp
Normal file
33
src/igl/average_onto_vertices.cpp
Normal 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
|
35
src/igl/average_onto_vertices.h
Normal file
35
src/igl/average_onto_vertices.h
Normal 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
|
39
src/igl/avg_edge_length.cpp
Normal file
39
src/igl/avg_edge_length.cpp
Normal 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
41
src/igl/avg_edge_length.h
Normal 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
|
42
src/igl/axis_angle_to_quat.cpp
Normal file
42
src/igl/axis_angle_to_quat.cpp
Normal 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
|
33
src/igl/axis_angle_to_quat.h
Normal file
33
src/igl/axis_angle_to_quat.h
Normal 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
57
src/igl/barycenter.cpp
Normal 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
36
src/igl/barycenter.h
Normal 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
|
113
src/igl/barycentric_coordinates.cpp
Normal file
113
src/igl/barycentric_coordinates.cpp
Normal 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
|
68
src/igl/barycentric_coordinates.h
Normal file
68
src/igl/barycentric_coordinates.h
Normal 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
|
44
src/igl/barycentric_to_global.cpp
Executable file
44
src/igl/barycentric_to_global.cpp
Executable 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
42
src/igl/barycentric_to_global.h
Executable 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
38
src/igl/basename.cpp
Normal 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
29
src/igl/basename.h
Normal 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
143
src/igl/bbw.cpp
Normal 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
77
src/igl/bbw.h
Normal 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
93
src/igl/bfs.cpp
Normal 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
54
src/igl/bfs.h
Normal 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
100
src/igl/bfs_orient.cpp
Normal 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
36
src/igl/bfs_orient.h
Normal 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
|
203
src/igl/biharmonic_coordinates.cpp
Normal file
203
src/igl/biharmonic_coordinates.cpp
Normal 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
|
90
src/igl/biharmonic_coordinates.h
Normal file
90
src/igl/biharmonic_coordinates.h
Normal 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
|
115
src/igl/bijective_composite_harmonic_mapping.cpp
Normal file
115
src/igl/bijective_composite_harmonic_mapping.cpp
Normal 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
|
79
src/igl/bijective_composite_harmonic_mapping.h
Normal file
79
src/igl/bijective_composite_harmonic_mapping.h
Normal 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
32
src/igl/bone_parents.cpp
Normal 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
32
src/igl/bone_parents.h
Normal 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
|
||||
|
192
src/igl/boundary_conditions.cpp
Normal file
192
src/igl/boundary_conditions.cpp
Normal 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;
|
||||
}
|
55
src/igl/boundary_conditions.h
Normal file
55
src/igl/boundary_conditions.h
Normal 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
141
src/igl/boundary_facets.cpp
Normal 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
52
src/igl/boundary_facets.h
Normal 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
153
src/igl/boundary_loop.cpp
Executable 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
Loading…
Reference in a new issue