From 1673d7f58817ce81e2b5b923e58b742f774b36f0 Mon Sep 17 00:00:00 2001 From: Daniele Panozzo Date: Thu, 19 Jun 2014 23:21:14 +0200 Subject: [PATCH 1/3] merge Former-commit-id: 12b9f9c99f47d4c440fe059b2dc21d45cad59ba0 --- include/igl/arap_rhs.cpp | 34 +++++--------------- include/igl/covariance_scatter_matrix.cpp | 5 +-- include/igl/covariance_scatter_matrix.h | 7 ++-- include/igl/matlab_format.cpp | 1 - include/igl/svd3x3/Makefile | 9 ------ include/igl/svd3x3/arap.cpp | 39 ++++++++--------------- include/igl/svd3x3/arap.h | 5 +-- include/igl/svd3x3/arap_dof.cpp | 2 +- include/igl/svd3x3/fit_rotations.cpp | 29 +++-------------- include/igl/svd3x3/fit_rotations.h | 2 -- include/igl/viewer/TODOs.txt | 2 -- include/igl/viewer/Viewer.cpp | 7 ++-- include/igl/writeOBJ.cpp | 1 - 13 files changed, 40 insertions(+), 103 deletions(-) diff --git a/include/igl/arap_rhs.cpp b/include/igl/arap_rhs.cpp index a9e16197c..800b3d868 100644 --- a/include/igl/arap_rhs.cpp +++ b/include/igl/arap_rhs.cpp @@ -20,8 +20,8 @@ IGL_INLINE void igl::arap_rhs( { using namespace igl; using namespace Eigen; - // Number of dimensions - int Vdim = V.cols(); + //// Number of dimensions + //int dim = V.cols(); //// Number of mesh vertices //int n = V.rows(); //// Number of mesh elements @@ -42,7 +42,7 @@ IGL_INLINE void igl::arap_rhs( default: fprintf( stderr, - "arap_rhs.h: Error: Unsupported arap energy %d\n", + "covariance_scatter_matrix.h: Error: Unsupported arap energy %d\n", energy); return; } @@ -50,37 +50,19 @@ IGL_INLINE void igl::arap_rhs( SparseMatrix KX,KY,KZ; arap_linear_block(V,F,0,energy,KX); arap_linear_block(V,F,1,energy,KY); - if(Vdim == 2) + if(dim == 2) { K = cat(2,repdiag(KX,dim),repdiag(KY,dim)); - }else if(Vdim == 3) + }else if(dim == 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 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); - } + K = cat(2,cat(2,repdiag(KX,dim),repdiag(KY,dim)),repdiag(KZ,dim)); }else { - assert(false); fprintf( stderr, - "arap_rhs.h: Error: Unsupported dimension %d\n", - Vdim); + "covariance_scatter_matrix.h: Error: Unsupported dimension %d\n", + dim); return; } diff --git a/include/igl/covariance_scatter_matrix.cpp b/include/igl/covariance_scatter_matrix.cpp index 90c9b4fdb..5403ae6a2 100644 --- a/include/igl/covariance_scatter_matrix.cpp +++ b/include/igl/covariance_scatter_matrix.cpp @@ -17,6 +17,7 @@ IGL_INLINE void igl::covariance_scatter_matrix( const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, + const int dim, const ARAPEnergyType energy, Eigen::SparseMatrix& CSM) { @@ -25,8 +26,8 @@ IGL_INLINE void igl::covariance_scatter_matrix( // number of mesh vertices int n = V.rows(); assert(n > F.maxCoeff()); - // dimension of mesh - int dim = V.cols(); + //// dimension of mesh + //int dim = V.cols(); // Number of mesh elements int m = F.rows(); diff --git a/include/igl/covariance_scatter_matrix.h b/include/igl/covariance_scatter_matrix.h index 8378196df..33193b9bc 100644 --- a/include/igl/covariance_scatter_matrix.h +++ b/include/igl/covariance_scatter_matrix.h @@ -17,17 +17,20 @@ namespace igl { // Construct the covariance scatter matrix for a given arap energy // Inputs: - // V #V by Vdim list of initial domain positions + // V #V by dim 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 ARAPEnergyType enum value defining which energy is being used. // See ARAPEnergyType.h for valid options and explanations. // Outputs: - // CSM dim*#V/#F by dim*#V sparse matrix containing special laplacians along + // CSM dim*#V by dim*#V sparse matrix containing special laplacians along // the diagonal so that when multiplied by V gives covariance matrix // elements, can be used to speed up covariance matrix computation IGL_INLINE void covariance_scatter_matrix( const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, + const int dim, const ARAPEnergyType energy, Eigen::SparseMatrix& CSM); } diff --git a/include/igl/matlab_format.cpp b/include/igl/matlab_format.cpp index 598b8e23f..8a9a04f50 100644 --- a/include/igl/matlab_format.cpp +++ b/include/igl/matlab_format.cpp @@ -118,5 +118,4 @@ template Eigen::WithFormat > const igl::mat template Eigen::WithFormat > const igl::matlab_format >(Eigen::PlainObjectBase > const&, std::basic_string, std::allocator >); template Eigen::WithFormat > const igl::matlab_format >(Eigen::PlainObjectBase > const&, std::basic_string, std::allocator >); template Eigen::WithFormat > const igl::matlab_format >(Eigen::PlainObjectBase > const&, std::basic_string, std::allocator >); -template Eigen::WithFormat > const igl::matlab_format >(Eigen::PlainObjectBase > const&, std::basic_string, std::allocator >); #endif diff --git a/include/igl/svd3x3/Makefile b/include/igl/svd3x3/Makefile index aa1871c00..e8b761e88 100644 --- a/include/igl/svd3x3/Makefile +++ b/include/igl/svd3x3/Makefile @@ -27,15 +27,6 @@ SINGULAR_VALUE_DECOMPOSITION_INC=\ EIGEN3_INC=-I$(DEFAULT_PREFIX)/include/eigen3 -I$(DEFAULT_PREFIX)/include/eigen3/unsupported INC+=$(EIGEN3_INC) $(SINGULAR_VALUE_DECOMPOSITION_INC) -# Matlab dependency -ifndef MATLAB - MATLAB=/Applications/MATLAB_R2013b.app/ - $(warning MATLAB undefined. Setting MATLAB=${MATLAB}) -endif -MATLAB_INC=-I$(MATLAB)/extern/include/ -MATLAB_LIB=-L$(MATLAB)/bin/maci64 -lmx -leng -INC+=$(MATLAB_INC) - obj: mkdir -p obj diff --git a/include/igl/svd3x3/arap.cpp b/include/igl/svd3x3/arap.cpp index db089a5ef..e3f954e67 100644 --- a/include/igl/svd3x3/arap.cpp +++ b/include/igl/svd3x3/arap.cpp @@ -21,6 +21,7 @@ #include #include + template < typename DerivedV, typename DerivedF, @@ -48,7 +49,6 @@ IGL_INLINE bool igl::arap_precomputation( //const int dim = V.cols(); assert((dim == 3 || dim ==2) && "dim should be 2 or 3"); data.dim = dim; - data.Vdim = V.cols(); //assert(dim == 3 && "Only 3d supported"); // Defaults data.f_ext = Eigen::MatrixXd::Zero(n,data.dim); @@ -81,7 +81,7 @@ IGL_INLINE bool igl::arap_precomputation( // Get covariance scatter matrix, when applied collects the covariance // matrices used to fit rotations to during optimization - covariance_scatter_matrix(V,F,eff_energy,data.CSM); + covariance_scatter_matrix(V,F,data.dim,eff_energy,data.CSM); // Get group sum scatter matrix, when applied sums all entries of the same // group according to G @@ -115,13 +115,12 @@ IGL_INLINE bool igl::arap_precomputation( group_sum_matrix(data.G,G_sum); } SparseMatrix G_sum_dim; - repdiag(G_sum,data.Vdim,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(V,F,data.dim,eff_energy,data.K); - assert(data.K.rows() == data.n*data.dim); SparseMatrix Q = (-0.5*L).eval(); @@ -188,25 +187,19 @@ IGL_INLINE bool igl::arap_solve( U.row(data.b(bi)) = bc.row(bi); } - const auto & Udim = U.replicate(data.Vdim,1); - assert(U.cols() == data.dim); - assert(data.Vdim >= data.dim); - // As if U.col(2) was 0 - MatrixXd S = MatrixXd::Zero(data.CSM.rows(),data.Vdim); - S.leftCols(data.dim) = data.CSM * Udim; + const auto & Udim = U.replicate(data.dim,1); + MatrixXd S = data.CSM * Udim; - const int Rdim = data.Vdim; - MatrixXd R(Rdim,data.CSM.rows()); - if(R.rows() == 2) + MatrixXd R(data.dim,data.CSM.rows()); + if(data.dim == 2) { fit_rotations_planar(S,R); - cerr<<"PLANAR"<0) - { - bcc = bc.col(c); - } + bcc = bc.col(c); min_quad_with_fixed_solve( data.solver_data, Bc,bcc,Beq, diff --git a/include/igl/svd3x3/arap.h b/include/igl/svd3x3/arap.h index 85f90178e..6b016af7b 100644 --- a/include/igl/svd3x3/arap.h +++ b/include/igl/svd3x3/arap.h @@ -32,7 +32,6 @@ namespace igl // solver_data quadratic solver data // b list of boundary indices into V // dim dimension being used for solving - // Vdim dimension of original V (determines dimension of rotation fitting) int n; Eigen::VectorXi G; ARAPEnergyType energy; @@ -45,7 +44,6 @@ namespace igl min_quad_with_fixed_data solver_data; Eigen::VectorXi b; int dim; - int Vdim; ARAPData(): n(0), G(), @@ -58,8 +56,7 @@ namespace igl CSM(), solver_data(), b(), - dim(-1), // force this to be set by _precomputation - Vdim(-1) // force this to be set by _precomputation + dim(-1) // force this to be set by _precomputation { }; }; diff --git a/include/igl/svd3x3/arap_dof.cpp b/include/igl/svd3x3/arap_dof.cpp index 55ec39baa..9e68374e5 100644 --- a/include/igl/svd3x3/arap_dof.cpp +++ b/include/igl/svd3x3/arap_dof.cpp @@ -123,7 +123,7 @@ IGL_INLINE bool igl::arap_dof_precomputation( // used to fit rotations to during optimization SparseMatrix CSM; //printf("covariance_scatter_matrix()\n"); - covariance_scatter_matrix(V,F,data.energy,CSM); + covariance_scatter_matrix(V,F,V.cols(),data.energy,CSM); #ifdef EXTREME_VERBOSE cout<<"CSMIJV=["< #include #include -#include #include template IGL_INLINE void igl::fit_rotations( const Eigen::PlainObjectBase & S, - const bool single_precision, Eigen::PlainObjectBase & R) { using namespace std; const int dim = S.cols(); const int nr = S.rows()/dim; assert(nr * dim == S.rows()); - assert(dim == 3); // resize output R.resize(dim,dim*nr); // hopefully no op (should be already allocated) @@ -44,29 +41,12 @@ IGL_INLINE void igl::fit_rotations( si(i,j) = S(i*nr+r,j); } } - typedef Eigen::Matrix Mat3; - typedef Eigen::Matrix Vec3; - Mat3 ri; - if(single_precision) - { - polar_svd3x3(si, ri); - }else - { - Mat3 ti,ui,vi; - Vec3 _; - igl::polar_svd(si,ri,ti,ui,_,vi); - // Check for reflection - if(ri.determinant() < 0) - { - vi.col(1) *= -1.; - ri = ui * vi.transpose(); - } - } + Eigen::Matrix ri; + Eigen::Matrix ti; + polar_svd3x3(si, ri); assert(ri.determinant() >= 0); // Not sure why polar_dec computes transpose... R.block(0,r*dim,dim,dim) = ri.block(0,0,dim,dim).transpose(); - //cout<, Eigen::Matrix >(Eigen::PlainObjectBase > const&, bool, Eigen::PlainObjectBase >&); +template void igl::fit_rotations, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::fit_rotations_planar, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::fit_rotations_planar, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); #endif diff --git a/include/igl/svd3x3/fit_rotations.h b/include/igl/svd3x3/fit_rotations.h index 5968a1338..4a4c06617 100644 --- a/include/igl/svd3x3/fit_rotations.h +++ b/include/igl/svd3x3/fit_rotations.h @@ -17,14 +17,12 @@ namespace igl // // Inputs: // S nr*dim by dim stack of covariance matrices - // single_precision whether to use single precision (faster) // Outputs: // R dim by dim * nr list of rotations // template IGL_INLINE void fit_rotations( const Eigen::PlainObjectBase & S, - const bool single_precision, Eigen::PlainObjectBase & R); // FIT_ROTATIONS Given an input mesh and new positions find 2D rotations for diff --git a/include/igl/viewer/TODOs.txt b/include/igl/viewer/TODOs.txt index c1faf2f77..10a44d34b 100644 --- a/include/igl/viewer/TODOs.txt +++ b/include/igl/viewer/TODOs.txt @@ -1,5 +1,3 @@ -- snap to canonical recenters origin but trackball does not -+ snap to canonical view key shortcut is not working - rewrite in libigl style - separate various class into their own .h/.cpp pairs - remove use of double underscores (http://stackoverflow.com/a/224420/148668) diff --git a/include/igl/viewer/Viewer.cpp b/include/igl/viewer/Viewer.cpp index 4be4e89f5..8faa197fd 100644 --- a/include/igl/viewer/Viewer.cpp +++ b/include/igl/viewer/Viewer.cpp @@ -935,14 +935,13 @@ namespace igl if (key == 'A') mouse_scroll(-1); - // Why aren't these handled view AntTweakBar? - if (key == 'z') // Don't use 'Z' because that clobbers snap_to_canonical_view_quat + if (key == 'Z') options.trackball_angle << 0.0f, 0.0f, 0.0f, 1.0f; - if (key == 'y') + if (key == 'Y') options.trackball_angle << -sqrt(2.0f)/2.0f, 0.0f, 0.0f, sqrt(2.0f)/2.0f; - if (key == 'x') + if (key == 'X') options.trackball_angle << -0.5f, -0.5f, -0.5f, 0.5f; diff --git a/include/igl/writeOBJ.cpp b/include/igl/writeOBJ.cpp index 17b19ecbc..ff45c3692 100644 --- a/include/igl/writeOBJ.cpp +++ b/include/igl/writeOBJ.cpp @@ -120,5 +120,4 @@ IGL_INLINE bool igl::writeOBJ( template bool igl::writeOBJ, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); template bool igl::writeOBJ, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); template bool igl::writeOBJ, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); -template bool igl::writeOBJ, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); #endif From 15ba98008b3427484c41c8be5d6ae2cf4e1da2e8 Mon Sep 17 00:00:00 2001 From: Daniele Panozzo Date: Thu, 19 Jun 2014 23:24:12 +0200 Subject: [PATCH 2/3] merge Former-commit-id: d3139c316fbf705a6e749fc5bce4bce226b7e922 --- include/igl/arap_rhs.cpp | 34 +++++++++++++++----- include/igl/covariance_scatter_matrix.cpp | 5 ++- include/igl/covariance_scatter_matrix.h | 7 ++-- include/igl/matlab_format.cpp | 1 + include/igl/svd3x3/Makefile | 9 ++++++ include/igl/svd3x3/arap.cpp | 39 +++++++++++++++-------- include/igl/svd3x3/arap.h | 5 ++- include/igl/svd3x3/arap_dof.cpp | 2 +- include/igl/svd3x3/fit_rotations.cpp | 29 ++++++++++++++--- include/igl/svd3x3/fit_rotations.h | 2 ++ include/igl/viewer/TODOs.txt | 2 ++ include/igl/viewer/Viewer.cpp | 7 ++-- include/igl/writeOBJ.cpp | 1 + 13 files changed, 103 insertions(+), 40 deletions(-) diff --git a/include/igl/arap_rhs.cpp b/include/igl/arap_rhs.cpp index 800b3d868..a9e16197c 100644 --- a/include/igl/arap_rhs.cpp +++ b/include/igl/arap_rhs.cpp @@ -20,8 +20,8 @@ IGL_INLINE void igl::arap_rhs( { using namespace igl; using namespace Eigen; - //// Number of dimensions - //int dim = V.cols(); + // Number of dimensions + int Vdim = V.cols(); //// Number of mesh vertices //int n = V.rows(); //// Number of mesh elements @@ -42,7 +42,7 @@ IGL_INLINE void igl::arap_rhs( default: fprintf( stderr, - "covariance_scatter_matrix.h: Error: Unsupported arap energy %d\n", + "arap_rhs.h: Error: Unsupported arap energy %d\n", energy); return; } @@ -50,19 +50,37 @@ IGL_INLINE void igl::arap_rhs( SparseMatrix KX,KY,KZ; arap_linear_block(V,F,0,energy,KX); arap_linear_block(V,F,1,energy,KY); - if(dim == 2) + if(Vdim == 2) { K = cat(2,repdiag(KX,dim),repdiag(KY,dim)); - }else if(dim == 3) + }else if(Vdim == 3) { arap_linear_block(V,F,2,energy,KZ); - K = cat(2,cat(2,repdiag(KX,dim),repdiag(KY,dim)),repdiag(KZ,dim)); + if(dim == 3) + { + K = cat(2,cat(2,repdiag(KX,dim),repdiag(KY,dim)),repdiag(KZ,dim)); + }else if(dim ==2) + { + SparseMatrix 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, - "covariance_scatter_matrix.h: Error: Unsupported dimension %d\n", - dim); + "arap_rhs.h: Error: Unsupported dimension %d\n", + Vdim); return; } diff --git a/include/igl/covariance_scatter_matrix.cpp b/include/igl/covariance_scatter_matrix.cpp index 5403ae6a2..90c9b4fdb 100644 --- a/include/igl/covariance_scatter_matrix.cpp +++ b/include/igl/covariance_scatter_matrix.cpp @@ -17,7 +17,6 @@ IGL_INLINE void igl::covariance_scatter_matrix( const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, - const int dim, const ARAPEnergyType energy, Eigen::SparseMatrix& CSM) { @@ -26,8 +25,8 @@ IGL_INLINE void igl::covariance_scatter_matrix( // number of mesh vertices int n = V.rows(); assert(n > F.maxCoeff()); - //// dimension of mesh - //int dim = V.cols(); + // dimension of mesh + int dim = V.cols(); // Number of mesh elements int m = F.rows(); diff --git a/include/igl/covariance_scatter_matrix.h b/include/igl/covariance_scatter_matrix.h index 33193b9bc..8378196df 100644 --- a/include/igl/covariance_scatter_matrix.h +++ b/include/igl/covariance_scatter_matrix.h @@ -17,20 +17,17 @@ namespace igl { // Construct the covariance scatter matrix for a given arap energy // Inputs: - // V #V by dim list of initial domain positions + // 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 ARAPEnergyType enum value defining which energy is being used. // See ARAPEnergyType.h for valid options and explanations. // Outputs: - // CSM dim*#V by dim*#V sparse matrix containing special laplacians along + // CSM dim*#V/#F by dim*#V sparse matrix containing special laplacians along // the diagonal so that when multiplied by V gives covariance matrix // elements, can be used to speed up covariance matrix computation IGL_INLINE void covariance_scatter_matrix( const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, - const int dim, const ARAPEnergyType energy, Eigen::SparseMatrix& CSM); } diff --git a/include/igl/matlab_format.cpp b/include/igl/matlab_format.cpp index 8a9a04f50..598b8e23f 100644 --- a/include/igl/matlab_format.cpp +++ b/include/igl/matlab_format.cpp @@ -118,4 +118,5 @@ template Eigen::WithFormat > const igl::mat template Eigen::WithFormat > const igl::matlab_format >(Eigen::PlainObjectBase > const&, std::basic_string, std::allocator >); template Eigen::WithFormat > const igl::matlab_format >(Eigen::PlainObjectBase > const&, std::basic_string, std::allocator >); template Eigen::WithFormat > const igl::matlab_format >(Eigen::PlainObjectBase > const&, std::basic_string, std::allocator >); +template Eigen::WithFormat > const igl::matlab_format >(Eigen::PlainObjectBase > const&, std::basic_string, std::allocator >); #endif diff --git a/include/igl/svd3x3/Makefile b/include/igl/svd3x3/Makefile index e8b761e88..aa1871c00 100644 --- a/include/igl/svd3x3/Makefile +++ b/include/igl/svd3x3/Makefile @@ -27,6 +27,15 @@ SINGULAR_VALUE_DECOMPOSITION_INC=\ EIGEN3_INC=-I$(DEFAULT_PREFIX)/include/eigen3 -I$(DEFAULT_PREFIX)/include/eigen3/unsupported INC+=$(EIGEN3_INC) $(SINGULAR_VALUE_DECOMPOSITION_INC) +# Matlab dependency +ifndef MATLAB + MATLAB=/Applications/MATLAB_R2013b.app/ + $(warning MATLAB undefined. Setting MATLAB=${MATLAB}) +endif +MATLAB_INC=-I$(MATLAB)/extern/include/ +MATLAB_LIB=-L$(MATLAB)/bin/maci64 -lmx -leng +INC+=$(MATLAB_INC) + obj: mkdir -p obj diff --git a/include/igl/svd3x3/arap.cpp b/include/igl/svd3x3/arap.cpp index e3f954e67..db089a5ef 100644 --- a/include/igl/svd3x3/arap.cpp +++ b/include/igl/svd3x3/arap.cpp @@ -21,7 +21,6 @@ #include #include - template < typename DerivedV, typename DerivedF, @@ -49,6 +48,7 @@ IGL_INLINE bool igl::arap_precomputation( //const int dim = V.cols(); assert((dim == 3 || dim ==2) && "dim should be 2 or 3"); data.dim = dim; + data.Vdim = V.cols(); //assert(dim == 3 && "Only 3d supported"); // Defaults data.f_ext = Eigen::MatrixXd::Zero(n,data.dim); @@ -81,7 +81,7 @@ IGL_INLINE bool igl::arap_precomputation( // Get covariance scatter matrix, when applied collects the covariance // matrices used to fit rotations to during optimization - covariance_scatter_matrix(V,F,data.dim,eff_energy,data.CSM); + covariance_scatter_matrix(V,F,eff_energy,data.CSM); // Get group sum scatter matrix, when applied sums all entries of the same // group according to G @@ -115,12 +115,13 @@ IGL_INLINE bool igl::arap_precomputation( group_sum_matrix(data.G,G_sum); } SparseMatrix G_sum_dim; - repdiag(G_sum,data.dim,G_sum_dim); + repdiag(G_sum,data.Vdim,G_sum_dim); assert(G_sum_dim.cols() == data.CSM.rows()); data.CSM = (G_sum_dim * data.CSM).eval(); arap_rhs(V,F,data.dim,eff_energy,data.K); + assert(data.K.rows() == data.n*data.dim); SparseMatrix Q = (-0.5*L).eval(); @@ -187,19 +188,25 @@ IGL_INLINE bool igl::arap_solve( U.row(data.b(bi)) = bc.row(bi); } - const auto & Udim = U.replicate(data.dim,1); - MatrixXd S = data.CSM * Udim; + const auto & Udim = U.replicate(data.Vdim,1); + assert(U.cols() == data.dim); + assert(data.Vdim >= data.dim); + // As if U.col(2) was 0 + MatrixXd S = MatrixXd::Zero(data.CSM.rows(),data.Vdim); + S.leftCols(data.dim) = data.CSM * Udim; - MatrixXd R(data.dim,data.CSM.rows()); - if(data.dim == 2) + const int Rdim = data.Vdim; + MatrixXd R(Rdim,data.CSM.rows()); + if(R.rows() == 2) { fit_rotations_planar(S,R); + cerr<<"PLANAR"<0) + { + bcc = bc.col(c); + } min_quad_with_fixed_solve( data.solver_data, Bc,bcc,Beq, diff --git a/include/igl/svd3x3/arap.h b/include/igl/svd3x3/arap.h index 6b016af7b..85f90178e 100644 --- a/include/igl/svd3x3/arap.h +++ b/include/igl/svd3x3/arap.h @@ -32,6 +32,7 @@ namespace igl // solver_data quadratic solver data // b list of boundary indices into V // dim dimension being used for solving + // Vdim dimension of original V (determines dimension of rotation fitting) int n; Eigen::VectorXi G; ARAPEnergyType energy; @@ -44,6 +45,7 @@ namespace igl min_quad_with_fixed_data solver_data; Eigen::VectorXi b; int dim; + int Vdim; ARAPData(): n(0), G(), @@ -56,7 +58,8 @@ namespace igl CSM(), solver_data(), b(), - dim(-1) // force this to be set by _precomputation + dim(-1), // force this to be set by _precomputation + Vdim(-1) // force this to be set by _precomputation { }; }; diff --git a/include/igl/svd3x3/arap_dof.cpp b/include/igl/svd3x3/arap_dof.cpp index 9e68374e5..55ec39baa 100644 --- a/include/igl/svd3x3/arap_dof.cpp +++ b/include/igl/svd3x3/arap_dof.cpp @@ -123,7 +123,7 @@ IGL_INLINE bool igl::arap_dof_precomputation( // used to fit rotations to during optimization SparseMatrix CSM; //printf("covariance_scatter_matrix()\n"); - covariance_scatter_matrix(V,F,V.cols(),data.energy,CSM); + covariance_scatter_matrix(V,F,data.energy,CSM); #ifdef EXTREME_VERBOSE cout<<"CSMIJV=["< #include #include +#include #include template IGL_INLINE void igl::fit_rotations( const Eigen::PlainObjectBase & S, + const bool single_precision, Eigen::PlainObjectBase & R) { using namespace std; const int dim = S.cols(); const int nr = S.rows()/dim; assert(nr * dim == S.rows()); + assert(dim == 3); // resize output R.resize(dim,dim*nr); // hopefully no op (should be already allocated) @@ -41,12 +44,29 @@ IGL_INLINE void igl::fit_rotations( si(i,j) = S(i*nr+r,j); } } - Eigen::Matrix ri; - Eigen::Matrix ti; - polar_svd3x3(si, ri); + typedef Eigen::Matrix Mat3; + typedef Eigen::Matrix Vec3; + Mat3 ri; + if(single_precision) + { + polar_svd3x3(si, ri); + }else + { + Mat3 ti,ui,vi; + Vec3 _; + igl::polar_svd(si,ri,ti,ui,_,vi); + // Check for reflection + if(ri.determinant() < 0) + { + vi.col(1) *= -1.; + ri = ui * vi.transpose(); + } + } assert(ri.determinant() >= 0); // Not sure why polar_dec computes transpose... R.block(0,r*dim,dim,dim) = ri.block(0,0,dim,dim).transpose(); + //cout<, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); +template void igl::fit_rotations, Eigen::Matrix >(Eigen::PlainObjectBase > const&, bool, Eigen::PlainObjectBase >&); template void igl::fit_rotations_planar, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::fit_rotations_planar, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); #endif diff --git a/include/igl/svd3x3/fit_rotations.h b/include/igl/svd3x3/fit_rotations.h index 4a4c06617..5968a1338 100644 --- a/include/igl/svd3x3/fit_rotations.h +++ b/include/igl/svd3x3/fit_rotations.h @@ -17,12 +17,14 @@ namespace igl // // Inputs: // S nr*dim by dim stack of covariance matrices + // single_precision whether to use single precision (faster) // Outputs: // R dim by dim * nr list of rotations // template IGL_INLINE void fit_rotations( const Eigen::PlainObjectBase & S, + const bool single_precision, Eigen::PlainObjectBase & R); // FIT_ROTATIONS Given an input mesh and new positions find 2D rotations for diff --git a/include/igl/viewer/TODOs.txt b/include/igl/viewer/TODOs.txt index 10a44d34b..c1faf2f77 100644 --- a/include/igl/viewer/TODOs.txt +++ b/include/igl/viewer/TODOs.txt @@ -1,3 +1,5 @@ +- snap to canonical recenters origin but trackball does not ++ snap to canonical view key shortcut is not working - rewrite in libigl style - separate various class into their own .h/.cpp pairs - remove use of double underscores (http://stackoverflow.com/a/224420/148668) diff --git a/include/igl/viewer/Viewer.cpp b/include/igl/viewer/Viewer.cpp index 8faa197fd..4be4e89f5 100644 --- a/include/igl/viewer/Viewer.cpp +++ b/include/igl/viewer/Viewer.cpp @@ -935,13 +935,14 @@ namespace igl if (key == 'A') mouse_scroll(-1); - if (key == 'Z') + // Why aren't these handled view AntTweakBar? + if (key == 'z') // Don't use 'Z' because that clobbers snap_to_canonical_view_quat options.trackball_angle << 0.0f, 0.0f, 0.0f, 1.0f; - if (key == 'Y') + if (key == 'y') options.trackball_angle << -sqrt(2.0f)/2.0f, 0.0f, 0.0f, sqrt(2.0f)/2.0f; - if (key == 'X') + if (key == 'x') options.trackball_angle << -0.5f, -0.5f, -0.5f, 0.5f; diff --git a/include/igl/writeOBJ.cpp b/include/igl/writeOBJ.cpp index ff45c3692..17b19ecbc 100644 --- a/include/igl/writeOBJ.cpp +++ b/include/igl/writeOBJ.cpp @@ -120,4 +120,5 @@ IGL_INLINE bool igl::writeOBJ( template bool igl::writeOBJ, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); template bool igl::writeOBJ, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); template bool igl::writeOBJ, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); +template bool igl::writeOBJ, Eigen::Matrix, Eigen::Matrix >(std::basic_string, std::allocator >, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&); #endif From 9a0c025dfb6cececb2482498959c2f111dbc4c57 Mon Sep 17 00:00:00 2001 From: Daniele Panozzo Date: Thu, 19 Jun 2014 23:25:18 +0200 Subject: [PATCH 3/3] - added tutorial example LSCM + helper functions Former-commit-id: d8dd6bcf8b25c2b5628433c5e78f8e9ea50c4278 --- include/igl/areamatrix.cpp | 53 +++++++++++++++++ include/igl/areamatrix.h | 44 ++++++++++++++ include/igl/kronecker_product.cpp | 64 +++++++++++++++++++++ include/igl/kronecker_product.h | 35 +++++++++++ include/igl/lscm.cpp | 83 +++++++++++++++++++++++++++ include/igl/lscm.h | 44 ++++++++++++++ tutorial/502_LSCMParam/CMakeLists.txt | 11 ++++ tutorial/502_LSCMParam/main.cpp | 53 +++++++++++++++++ 8 files changed, 387 insertions(+) create mode 100644 include/igl/areamatrix.cpp create mode 100644 include/igl/areamatrix.h create mode 100644 include/igl/kronecker_product.cpp create mode 100644 include/igl/kronecker_product.h create mode 100644 include/igl/lscm.cpp create mode 100644 include/igl/lscm.h create mode 100644 tutorial/502_LSCMParam/CMakeLists.txt create mode 100755 tutorial/502_LSCMParam/main.cpp diff --git a/include/igl/areamatrix.cpp b/include/igl/areamatrix.cpp new file mode 100644 index 000000000..ff33a5ce6 --- /dev/null +++ b/include/igl/areamatrix.cpp @@ -0,0 +1,53 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.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 "areamatrix.h" +#include + +// Bug in unsupported/Eigen/SparseExtra needs iostream first +#include +#include + +#include + +template +IGL_INLINE void igl::areamatrix( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::SparseMatrix& A) +{ + using namespace Eigen; + using namespace std; + + SparseMatrix aux (V.rows() * 2, V.rows() * 2); + SparseMatrix auxT(V.rows() * 2, V.rows() * 2); + + vector > auxTripletList; + vector > auxTTripletList; + + Eigen::VectorXi bnd; + igl::boundary_vertices_sorted(V,F,bnd); + + for(int k = 0; k < bnd.size(); k++) + { + int i = bnd[k]; + int j = k + 1 == bnd.size() ? bnd[0] : bnd[k+1]; + auxTripletList.push_back(Triplet(i+V.rows(), j, -0.5)); + auxTripletList.push_back(Triplet(i, j+V.rows(), 0.5)); + auxTTripletList.push_back(Triplet(j, i+V.rows(), -0.5)); + auxTTripletList.push_back(Triplet(j+V.rows(), i, 0.5)); + } + + aux.setFromTriplets(auxTripletList.begin(), auxTripletList.end()); + auxT.setFromTriplets(auxTTripletList.begin(), auxTTripletList.end()); + A = (aux + auxT)/2; +} + +#ifndef IGL_HEADER_ONLY +// Explicit template specialization +// generated by autoexplicit.sh +#endif diff --git a/include/igl/areamatrix.h b/include/igl/areamatrix.h new file mode 100644 index 000000000..26b5c72fa --- /dev/null +++ b/include/igl/areamatrix.h @@ -0,0 +1,44 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.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_AREAMATRIX_H +#define IGL_AREAMATRIX_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Constructs the symmetric area matrix A, s.t. + // [V.col(0)' V.col(1)'] * A * [V.col(0); V.col(1)] is the area of the planar mesh (V,F). + // Note: (V,F) must be a genus-0 mesh, with a single boundary + // + // Templates: + // DerivedV derived type of eigen matrix for V (e.g. derived from + // MatrixXd) + // DerivedF derived type of eigen matrix for F (e.g. derived from + // MatrixXi) + // Scalar scalar type for eigen sparse matrix (e.g. double) + // Inputs: + // V #V by 2 list of mesh vertex positions + // F #F by 3 list of mesh faces (must be triangles) + // Outputs: + // A #Vx2 by #Vx2 area matrix + // + template + IGL_INLINE void areamatrix( + const Eigen::PlainObjectBase & V, + const Eigen::PlainObjectBase & F, + Eigen::SparseMatrix& A); +} + +#ifdef IGL_HEADER_ONLY +# include "areamatrix.cpp" +#endif + +#endif diff --git a/include/igl/kronecker_product.cpp b/include/igl/kronecker_product.cpp new file mode 100644 index 000000000..260594cd5 --- /dev/null +++ b/include/igl/kronecker_product.cpp @@ -0,0 +1,64 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.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 "kronecker_product.h" + +// Bug in unsupported/Eigen/SparseExtra needs iostream first +#include +#include + +template +IGL_INLINE Eigen::SparseMatrix igl::kronecker_product( + const Eigen::SparseMatrix & A, + const Eigen::SparseMatrix & B) +{ + using namespace Eigen; + using namespace std; + + // Convert B in triplets format + MatrixXd B_triplets(B.nonZeros(),3); + int count = 0; + for (int k=0; k::InnerIterator it(B,k); it; ++it) + B_triplets.row(count++) << it.row(), it.col(), it.value(); + + MatrixXd C_triplets(B_triplets.rows()*A.nonZeros(),3); + count = 0; + for (int k=0; k::InnerIterator it(A,k); it; ++it) + { + int i = it.row(); + int j = it.col(); + double v = it.value(); + + MatrixXd B_triplets_copy = B_triplets; + B_triplets_copy.col(0) = B_triplets_copy.col(0).array() + double(B.rows()*i); + B_triplets_copy.col(1) = B_triplets_copy.col(1).array() + double(B.cols()*j); + B_triplets_copy.col(2) = B_triplets_copy.col(2).array() * v; + + C_triplets.block(count*B_triplets.rows(),0, + B_triplets.rows(), B_triplets.cols()) = B_triplets_copy; + + count++; + } + + typedef Eigen::Triplet T; + std::vector triplets; + triplets.reserve(C_triplets.rows()); + + for(unsigned i=0; i C(A.rows()*B.rows(),A.cols()*B.cols()); + C.setFromTriplets(triplets.begin(),triplets.end()); + + return C; +} + +#ifndef IGL_HEADER_ONLY +// Explicit template specialization +// generated by autoexplicit.sh +#endif diff --git a/include/igl/kronecker_product.h b/include/igl/kronecker_product.h new file mode 100644 index 000000000..1f5747b9b --- /dev/null +++ b/include/igl/kronecker_product.h @@ -0,0 +1,35 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.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_KRONECKERPRODUCT_H +#define IGL_KRONECKERPRODUCT_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Computes the Kronecker product between sparse matrices A and B. + // + // Inputs: + // A #M by #N sparse matrix + // B #P by #Q sparse matrix + // Outputs: + // #M*#P by #N*#Q sparse matrix + // + template + IGL_INLINE Eigen::SparseMatrix kronecker_product( + const Eigen::SparseMatrix & A, + const Eigen::SparseMatrix & B); +} + +#ifdef IGL_HEADER_ONLY +# include "kronecker_product.cpp" +#endif + +#endif diff --git a/include/igl/lscm.cpp b/include/igl/lscm.cpp new file mode 100644 index 000000000..cdf6beb58 --- /dev/null +++ b/include/igl/lscm.cpp @@ -0,0 +1,83 @@ +// This file is part of libigl, a simple c++ geometry processing library. +// +// Copyright (C) 2014 Daniele Panozzo +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.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 "lscm.h" + +// Bug in unsupported/Eigen/SparseExtra needs iostream first +#include +#include + +#include +#include +#include +#include +#include + +IGL_INLINE Eigen::MatrixXd igl::lscm( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc) +{ + using namespace Eigen; + + // Assemble the area matrix (note that A is #Vx2 by #Vx2) + SparseMatrix A; + igl::areamatrix(V,F,A); + + // Assemble the cotan laplacian matrix + SparseMatrix L; + igl::cotmatrix(V,F,L); + + SparseMatrix I2(2,2); + I2.insert(0,0) = 1; + I2.insert(1,1) = 1; + + SparseMatrix L_flat = igl::kronecker_product(I2,L); + + VectorXi b_flat = b; + MatrixXd bc_flat = bc; + + if (b.size() < 2) + { + // if no boundary conditions are provided, fix two boundary points + Eigen::VectorXi bnd; + igl::boundary_vertices_sorted(V,F,bnd); + + int v1 = bnd(0); + int v2 = bnd(round(bnd.size()/2)); + + b_flat.resize(4); + b_flat << v1, v1+1, v2, v2+1; + bc_flat.resize(4,1); + bc_flat << 0, 1, 0, 0; + } + + // Minimize the LSCM energy + SparseMatrix Q = -0.5*L_flat + A; + const VectorXd B_flat = VectorXd::Zero(V.rows()*2); + igl::min_quad_with_fixed_data data; + igl::min_quad_with_fixed_precompute(Q,b_flat,SparseMatrix(),true,data); + + MatrixXd W_flat; + if(!min_quad_with_fixed_solve(data,B_flat,bc_flat,VectorXd(),W_flat)) + assert(false); + + MatrixXd V_uv(V.rows(),2); + for (unsigned i=0;i +// +// This Source Code Form is subject to the terms of the Mozilla Public License +// v. 2.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_LSCM_H +#define IGL_LSCM_H +#include "igl_inline.h" + +#include +#include + +namespace igl +{ + // Compute a Least-squares conformal map parametrization following the algorithm + // presented in: Spectral Conformal Parameterization, + // Patrick Mullen, Yiying Tong, Pierre Alliez and Mathieu Desbrun + // Note: (V,F) must be a genus-0 mesh, with a single boundary + // + // Inputs: + // V #V by 3 list of mesh vertex positions + // F #F by 3 list of mesh faces (must be triangles) + // b #b boundary indices into V + // bc #b by #W list of boundary values +// Outputs: + // UV #V by 2 list of 2D mesh vertex positions in UV space + // + // Note: if b and bc are empty, lscm automatically removes the null space + // by fixing two farthest points on the boundary + + IGL_INLINE Eigen::MatrixXd lscm( + const Eigen::MatrixXd& V, + const Eigen::MatrixXi& F, + const Eigen::VectorXi& b, + const Eigen::MatrixXd& bc); +} + +#ifdef IGL_HEADER_ONLY +# include "lscm.cpp" +#endif + +#endif diff --git a/tutorial/502_LSCMParam/CMakeLists.txt b/tutorial/502_LSCMParam/CMakeLists.txt new file mode 100644 index 000000000..45b5531e1 --- /dev/null +++ b/tutorial/502_LSCMParam/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.6) +project(502_LSCMParam) + +include("../CMakeLists.shared") + +set(SOURCES +${PROJECT_SOURCE_DIR}/main.cpp +) + +add_executable(${CMAKE_PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES}) +target_link_libraries(${CMAKE_PROJECT_NAME} ${SHARED_LIBRARIES}) diff --git a/tutorial/502_LSCMParam/main.cpp b/tutorial/502_LSCMParam/main.cpp new file mode 100755 index 000000000..1d0f5916d --- /dev/null +++ b/tutorial/502_LSCMParam/main.cpp @@ -0,0 +1,53 @@ +#include +#include + +#include + +Eigen::MatrixXd V; +Eigen::MatrixXi F; +Eigen::MatrixXd V_uv; + +bool key_down(igl::Viewer& viewer, unsigned char key, int modifier) +{ + + if (key == '1') + // Plot the 3D mesh + viewer.set_mesh(V,F); + else if (key == '2') + // Plot the mesh in 2D using the UV coordinates as vertex coordinates + viewer.set_mesh(V_uv,F); + + viewer.compute_normals(); + + return false; +} + +int main(int argc, char *argv[]) +{ + using namespace Eigen; + using namespace std; + + // Load a mesh in OFF format + igl::readOFF("../shared/camelhead.off", V, F); + + // LSCM parametrization + V_uv = igl::lscm(V,F,Eigen::VectorXi(),Eigen::MatrixXd()); + + // Scale the uv + V_uv *= 5; + + // Plot the mesh + igl::Viewer viewer; + viewer.set_mesh(V, F); + viewer.set_uv(V_uv); + viewer.callback_key_down = &key_down; + + // Disable wireframe + viewer.options.show_lines = false; + + // Draw checkerboard texture + viewer.options.show_texture = true; + + // Launch the viewer + viewer.launch(); +}