mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Added libigl library files (header-only library)
This commit is contained in:
		
							parent
							
								
									9b5c7aadad
								
							
						
					
					
						commit
						a4acca24ff
					
				
					 1087 changed files with 118219 additions and 0 deletions
				
			
		
							
								
								
									
										1075
									
								
								xs/src/igl/AABB.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1075
									
								
								xs/src/igl/AABB.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										413
									
								
								xs/src/igl/AABB.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										413
									
								
								xs/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
									
								
								xs/src/igl/ARAPEnergyType.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								xs/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
									
								
								xs/src/igl/AtA_cached.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								xs/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
									
								
								xs/src/igl/AtA_cached.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								xs/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
									
								
								xs/src/igl/C_STR.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								xs/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
									
								
								xs/src/igl/Camera.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								xs/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
									
								
								xs/src/igl/EPS.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								xs/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
									
								
								xs/src/igl/EPS.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								xs/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
									
								
								xs/src/igl/HalfEdgeIterator.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								xs/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
									
								
								xs/src/igl/HalfEdgeIterator.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								xs/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
									
								
								xs/src/igl/Hit.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								xs/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
									
								
								xs/src/igl/IO
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								xs/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
									
								
								xs/src/igl/IndexComparison.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								xs/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
									
								
								xs/src/igl/LinSpaced.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								xs/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
									
								
								xs/src/igl/MeshBooleanType.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								xs/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
									
								
								xs/src/igl/NormalType.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								xs/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
									
								
								xs/src/igl/ONE.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								xs/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
									
								
								xs/src/igl/PI.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								xs/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
									
								
								xs/src/igl/REDRUM.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								xs/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
									
								
								xs/src/igl/STR.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								xs/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
									
								
								xs/src/igl/Singular_Value_Decomposition_Kernel_Declarations.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								xs/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
									
								
								xs/src/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1277
									
								
								xs/src/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										78
									
								
								xs/src/igl/Singular_Value_Decomposition_Preamble.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								xs/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
									
								
								xs/src/igl/SolverStatus.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								xs/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
									
								
								xs/src/igl/SortableRow.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								xs/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
									
								
								xs/src/igl/Timer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								xs/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
									
								
								xs/src/igl/Viewport.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								xs/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
									
								
								xs/src/igl/WindingNumberAABB.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										377
									
								
								xs/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
									
								
								xs/src/igl/WindingNumberMethod.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								xs/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
									
								
								xs/src/igl/WindingNumberTree.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										503
									
								
								xs/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
									
								
								xs/src/igl/ZERO.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								xs/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
									
								
								xs/src/igl/active_set.cpp
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										370
									
								
								xs/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
									
								
								xs/src/igl/active_set.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								xs/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
									
								
								xs/src/igl/adjacency_list.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								xs/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
									
								
								xs/src/igl/adjacency_list.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								xs/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
									
								
								xs/src/igl/adjacency_matrix.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								xs/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
									
								
								xs/src/igl/adjacency_matrix.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								xs/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
									
								
								xs/src/igl/all.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								xs/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
									
								
								xs/src/igl/all.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								xs/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
									
								
								xs/src/igl/all_edges.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								xs/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
									
								
								xs/src/igl/all_edges.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								xs/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
									
								
								xs/src/igl/all_pairs_distances.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								xs/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
									
								
								xs/src/igl/all_pairs_distances.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								xs/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
									
								
								xs/src/igl/ambient_occlusion.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								xs/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
									
								
								xs/src/igl/ambient_occlusion.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								xs/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
									
								
								xs/src/igl/angular_distance.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								xs/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
									
								
								xs/src/igl/angular_distance.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								xs/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
									
								
								xs/src/igl/anttweakbar/ReAntTweakBar.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										934
									
								
								xs/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
									
								
								xs/src/igl/anttweakbar/ReAntTweakBar.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								xs/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
									
								
								xs/src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								xs/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
									
								
								xs/src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								xs/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
									
								
								xs/src/igl/any.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								xs/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
									
								
								xs/src/igl/any.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								xs/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
									
								
								xs/src/igl/any_of.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								xs/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
									
								
								xs/src/igl/any_of.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								xs/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
									
								
								xs/src/igl/arap.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										312
									
								
								xs/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
									
								
								xs/src/igl/arap.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								xs/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
									
								
								xs/src/igl/arap_dof.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										884
									
								
								xs/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
									
								
								xs/src/igl/arap_dof.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								xs/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
									
								
								xs/src/igl/arap_linear_block.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								xs/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
									
								
								xs/src/igl/arap_linear_block.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								xs/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
									
								
								xs/src/igl/arap_rhs.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								xs/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
									
								
								xs/src/igl/arap_rhs.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								xs/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
									
								
								xs/src/igl/average_onto_faces.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								xs/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
									
								
								xs/src/igl/average_onto_faces.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								xs/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
									
								
								xs/src/igl/average_onto_vertices.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								xs/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
									
								
								xs/src/igl/average_onto_vertices.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								xs/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
									
								
								xs/src/igl/avg_edge_length.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								xs/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
									
								
								xs/src/igl/avg_edge_length.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								xs/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
									
								
								xs/src/igl/axis_angle_to_quat.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								xs/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
									
								
								xs/src/igl/axis_angle_to_quat.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								xs/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
									
								
								xs/src/igl/barycenter.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								xs/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
									
								
								xs/src/igl/barycenter.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								xs/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
									
								
								xs/src/igl/barycentric_coordinates.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								xs/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
									
								
								xs/src/igl/barycentric_coordinates.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								xs/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
									
								
								xs/src/igl/barycentric_to_global.cpp
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										44
									
								
								xs/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
									
								
								xs/src/igl/barycentric_to_global.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										42
									
								
								xs/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
									
								
								xs/src/igl/basename.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								xs/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
									
								
								xs/src/igl/basename.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								xs/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
									
								
								xs/src/igl/bbw.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								xs/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
									
								
								xs/src/igl/bbw.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								xs/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
									
								
								xs/src/igl/bfs.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								xs/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
									
								
								xs/src/igl/bfs.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								xs/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
									
								
								xs/src/igl/bfs_orient.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								xs/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
									
								
								xs/src/igl/bfs_orient.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								xs/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
									
								
								xs/src/igl/biharmonic_coordinates.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								xs/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
									
								
								xs/src/igl/biharmonic_coordinates.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								xs/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
									
								
								xs/src/igl/bijective_composite_harmonic_mapping.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								xs/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
									
								
								xs/src/igl/bijective_composite_harmonic_mapping.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								xs/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
									
								
								xs/src/igl/bone_parents.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								xs/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
									
								
								xs/src/igl/bone_parents.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								xs/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
									
								
								xs/src/igl/boundary_conditions.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								xs/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
									
								
								xs/src/igl/boundary_conditions.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								xs/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
									
								
								xs/src/igl/boundary_facets.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								xs/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
									
								
								xs/src/igl/boundary_facets.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								xs/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
									
								
								xs/src/igl/boundary_loop.cpp
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										153
									
								
								xs/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 | ||||||
							
								
								
									
										66
									
								
								xs/src/igl/boundary_loop.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										66
									
								
								xs/src/igl/boundary_loop.h
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,66 @@ | ||||||
|  | // 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/.
 | ||||||
|  | #ifndef IGL_BOUNDARY_LOOP_H | ||||||
|  | #define IGL_BOUNDARY_LOOP_H | ||||||
|  | #include "igl_inline.h" | ||||||
|  | 
 | ||||||
|  | #include <Eigen/Dense> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | namespace igl | ||||||
|  | { | ||||||
|  |   // Compute list of ordered boundary loops for a manifold mesh.
 | ||||||
|  |   //
 | ||||||
|  |   // Templates:
 | ||||||
|  |   //  Index  index type
 | ||||||
|  |   // Inputs:
 | ||||||
|  |   //   F  #V by dim list of mesh faces
 | ||||||
|  |   // Outputs:
 | ||||||
|  |   //   L  list of loops where L[i] = ordered list of boundary vertices in loop i
 | ||||||
|  |   //
 | ||||||
|  |   template <typename DerivedF, typename Index> | ||||||
|  |   IGL_INLINE void boundary_loop( | ||||||
|  |     const Eigen::PlainObjectBase<DerivedF>& F,  | ||||||
|  |     std::vector<std::vector<Index> >& L); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   // Compute ordered boundary loops for a manifold mesh and return the 
 | ||||||
|  |   // longest loop in terms of vertices.
 | ||||||
|  |   //
 | ||||||
|  |   // Templates:
 | ||||||
|  |   //  Index  index type
 | ||||||
|  |   // Inputs:
 | ||||||
|  |   //   F  #V by dim list of mesh faces
 | ||||||
|  |   // Outputs:
 | ||||||
|  |   //   L  ordered list of boundary vertices of longest boundary loop
 | ||||||
|  |   //
 | ||||||
|  |   template <typename DerivedF, typename Index> | ||||||
|  |   IGL_INLINE void boundary_loop( | ||||||
|  |     const Eigen::PlainObjectBase<DerivedF>& F,  | ||||||
|  |     std::vector<Index>& L); | ||||||
|  | 
 | ||||||
|  |   // Compute ordered boundary loops for a manifold mesh and return the 
 | ||||||
|  |   // longest loop in terms of vertices.
 | ||||||
|  |   //
 | ||||||
|  |   // Templates:
 | ||||||
|  |   //  Index  index type
 | ||||||
|  |   // Inputs:
 | ||||||
|  |   //   F  #V by dim list of mesh faces
 | ||||||
|  |   // Outputs:
 | ||||||
|  |   //   L  ordered list of boundary vertices of longest boundary loop
 | ||||||
|  |   //
 | ||||||
|  |   template <typename DerivedF, typename DerivedL> | ||||||
|  |   IGL_INLINE void boundary_loop( | ||||||
|  |     const Eigen::PlainObjectBase<DerivedF>& F,  | ||||||
|  |     Eigen::PlainObjectBase<DerivedL>& L); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifndef IGL_STATIC_LIBRARY | ||||||
|  | #  include "boundary_loop.cpp" | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Matena
						Lukas Matena