123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- // This file is part of libigl, a simple c++ geometry processing library.
- //
- // Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
- //
- // This Source Code Form is subject to the terms of the Mozilla Public License
- // v. 2.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_INTEGRABLE_POLYVECTOR_FIELDS
- #define IGL_INTEGRABLE_POLYVECTOR_FIELDS
- #include "igl_inline.h"
- #include <Eigen/Core>
- #include <Eigen/Sparse>
- namespace igl {
- // Compute a curl-free frame field from user constraints, optionally starting
- // from a gived frame field (assumed to be interpolating the constraints).
- // Implementation of the paper "Integrable PolyVector Fields", SIGGRAPH 2015.
- // Set of parameters used during solve
- struct integrable_polyvector_fields_parameters;
- // All data necessary for solving. Gets initialized from the original field
- // and gets updated during each solve.
- template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC> class IntegrableFieldSolverData;
- // Precomputes matrices and necessary initial variables from the mesh and the
- // original field. This function is meant to be called before solve().
- // Inputs:
- // V #V by 3 list of mesh vertex coordinates
- // F #F by 3 list of mesh faces (must be triangles)
- // b #B by 1 list of constrained face indices
- // bc #B by 6 list of the representative vectors at the constrained faces
- // constraint_level #B by 1 list of "constraint level" flag (level=2 indicates that both directions are constrained,
- // level = 1 indicates a partially constrained face, i.e. only the first vector will be constrained)
- // original_field #F by 6 list of the representative vectors of the frame field to be used as a starting point
- // (up to permutation and sign, stacked horizontally for each face)
- // Returns:
- // data an IntegrableFieldSolverData object that holds all intermediate
- // data needed by the solve routine, with correctly initialized values.
- //
- template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
- IGL_INLINE void integrable_polyvector_fields_precompute(const Eigen::PlainObjectBase<DerivedV>& V,
- const Eigen::PlainObjectBase<DerivedF>& F,
- const Eigen::VectorXi& b,
- const Eigen::PlainObjectBase<DerivedC>& bc,
- const Eigen::VectorXi& constraint_level,
- const Eigen::PlainObjectBase<DerivedFF>& original_field,
- igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &data);
- // Given the current estimate of the field, performes one round of optimization
- // iterations and updates the current estimate. The intermediate data is saved
- // and returned for the next iteration.
- // Inputs:
- // data an IntegrableFieldSolverData object that holds all intermediate
- // data needed by the solve routine, with their values at the current time instance.
- // params solver parameters (see below)
- // current_field #F by 6 list of the representative vectors of the current frame field to be used as a starting point
- // current_field_is_not_ccw boolean, determines whether the representative vectors in the current field are in
- // non- ccw order - if true, they will be corrected before being passed to the solver.
- // The field returned by this routine is always in ccw order, so this flag typically only
- // needs to be set to true during the first call to solve(). If unsure, set to true.
- // Returns:
- // current_field updated estimate for the integrable field
- //
- template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
- IGL_INLINE void integrable_polyvector_fields_solve(IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &cffsoldata,
- integrable_polyvector_fields_parameters ¶ms,
- Eigen::PlainObjectBase<DerivedFF>& current_field,
- bool current_field_is_not_ccw);
- };
- //parameters
- struct igl::integrable_polyvector_fields_parameters
- {
- // number of optimization iterations
- int numIter;
- //weight for barrier term (ensuring ccw ordering of the vectors per face)
- double wBarrier;
- //the s-parameter of the barrier term (see Schüller et al. 2013, Locally Injective Mappings)
- double sBarrier;
- //weight for the PolyCurl term of the energy
- double wCurl;
- //weight for the PolyQuotient term of the energy
- double wQuotCurl;
- //weight for the smoothness term of the energy
- double wSmooth;
- //weight for the closeness to the original field, for the unconstrained faces (regularization term)
- double wCloseUnconstrained;
- //weight for the closeness to the original field, for the constrained faces
- double wCloseConstrained;
- //the per-iteration reduction factor the smoothness weight
- double redFactor_wsmooth;
- //the step size for the Gauss-Newton optimization
- double gamma;
- //tikhonov regularization term (typically not needed, default value should suffice)
- double tikh_gamma;
- IGL_INLINE integrable_polyvector_fields_parameters();
- };
- //solver data
- template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
- class igl::IntegrableFieldSolverData
- {
- public:
- //Original field
- Eigen::VectorXd xOriginal;
- //Constraints
- Eigen::VectorXi constrained;
- Eigen::VectorXi is_constrained_face;//0 for unconstrained, 1 for constrained once (partial) and 2 for fully constrained
- Eigen::VectorXi indInConstrained;
- Eigen::MatrixXd constrained_vec3;
- //Mesh data
- //edges and normalized edge vectors
- Eigen::MatrixXd EVecNorm;
- Eigen::MatrixXi E, E2F, F2E;
- int numV, numF, numE;
- //interior edge data
- int numInteriorEdges;
- Eigen::Matrix<int,Eigen::Dynamic,2> E2F_int;
- Eigen::VectorXi indInteriorToFull;
- Eigen::VectorXi indFullToInterior;
- //per-edge angles (for parallel transport)
- Eigen::VectorXd K;
- //local bases
- Eigen::PlainObjectBase<DerivedV> B1, B2, FN;
- //Solver Data
- Eigen::VectorXd residuals;
- Eigen::SparseMatrix<double> Jac;
- Eigen::VectorXi II_Jac, JJ_Jac;
- Eigen::VectorXd SS_Jac;
- int numVariables;
- int num_residuals;
- int num_residuals_smooth;
- int num_residuals_close;
- int num_residuals_polycurl;
- int num_residuals_quotcurl;
- int num_residuals_barrier;
- const int numInnerJacCols_edge = 8;
- const int numInnerJacCols_face = 4;
- const int numInnerJacRows_smooth = 4;
- const int numInnerJacRows_polycurl = 2;
- const int numInnerJacRows_quotcurl = 1;
- const int numInnerJacRows_barrier = 1;
- const int numInnerJacRows_close = 4;
- int numJacElements_smooth;
- int numJacElements_polycurl;
- int numJacElements_quotcurl;
- int numJacElements_barrier;
- int numJacElements_close;
- int numJacElements;
- IGL_INLINE void add_jac_indices_face(const int numInnerRows,
- const int numInnerCols,
- const int startRowInJacobian,
- const int startIndexInVectors,
- Eigen::VectorXi &Rows,
- Eigen::VectorXi &Columns);
- IGL_INLINE void face_Jacobian_indices(const int &startRow,
- const int &toplace,
- const int& fi,
- const int& half_degree,
- const int &numInnerRows,
- const int &numInnerCols,
- Eigen::VectorXi &rows,
- Eigen::VectorXi &columns);
- IGL_INLINE void add_Jacobian_to_svector(const int &toplace,
- const Eigen::MatrixXd &tJac,
- Eigen::VectorXd &SS_Jac);
- IGL_INLINE void add_jac_indices_edge(const int numInnerRows,
- const int numInnerCols,
- const int startRowInJacobian,
- const int startIndexInVectors,
- Eigen::VectorXi &Rows,
- Eigen::VectorXi &Columns);
- IGL_INLINE void edge_Jacobian_indices(const int &startRow,
- const int &toplace,
- const int& a,
- const int& b,
- const int& half_degree,
- const int &numInnerRows,
- const int &numInnerCols,
- Eigen::VectorXi &rows,
- Eigen::VectorXi &columns);
- std::vector<int> indInSS_Hess_1_vec;
- std::vector<int> indInSS_Hess_2_vec;
- Eigen::SparseMatrix<double> Hess;
- std::vector<Eigen::Triplet<double> > Hess_triplets;
- Eigen::SimplicialLDLT<Eigen::SparseMatrix<double> > solver;
- IGL_INLINE void precomputeMesh(const Eigen::PlainObjectBase<DerivedV> &_V,
- const Eigen::PlainObjectBase<DerivedF> &_F);
- IGL_INLINE void computeInteriorEdges();
- IGL_INLINE void computeJacobianPattern();
- IGL_INLINE void computeHessianPattern();
- IGL_INLINE void computeNewHessValues();
- IGL_INLINE void initializeOriginalVariable(const Eigen::PlainObjectBase<DerivedFF>& original_field);
- IGL_INLINE void initializeConstraints(const Eigen::VectorXi& b,
- const Eigen::PlainObjectBase<DerivedC>& bc,
- const Eigen::VectorXi& constraint_level);
- IGL_INLINE void makeFieldCCW(Eigen::MatrixXd &sol3D);
- public:
- IGL_INLINE IntegrableFieldSolverData();
- IGL_INLINE IntegrableFieldSolverData(
- const Eigen::PlainObjectBase<DerivedV> &_V,
- const Eigen::PlainObjectBase<DerivedF> &_F,
- const Eigen::VectorXi& b,
- const Eigen::VectorXi& constraint_level,
- const Eigen::PlainObjectBase<DerivedFF>& original_field);
- };
- #ifndef IGL_STATIC_LIBRARY
- #include "integrable_polyvector_fields.cpp"
- #endif
- #endif /* defined(IGL_INTEGRABLE_POLYVECTOR_FIELDS) */
|