123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- // 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 "planarize_quad_mesh.h"
- #include "quad_planarity.h"
- #include <Eigen/Sparse>
- #include <Eigen/Eigenvalues>
- #include <iostream>
- namespace igl
- {
- template <typename DerivedV, typename DerivedF>
- class PlanarizerShapeUp
- {
- protected:
- // number of faces, number of vertices
- long numV, numF;
- // references to the input faces and vertices
- const Eigen::PlainObjectBase<DerivedV> &Vin;
- const Eigen::PlainObjectBase<DerivedF> &Fin;
-
- // vector consisting of the vertex positions stacked: [x;y;z;x;y;z...]
- // vector consisting of a weight per face (currently all set to 1)
- // vector consisting of the projected face vertices (might be different for the same vertex belonging to different faces)
- Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> Vv, weightsSqrt, P;
-
- // Matrices as in the paper
- // Q: lhs matrix
- // Ni: matrix that subtracts the mean of a face from the 4 vertices of a face
- Eigen::SparseMatrix<typename DerivedV::Scalar > Q, Ni;
- Eigen::SimplicialLDLT<Eigen::SparseMatrix<typename DerivedV::Scalar > > solver;
-
- int maxIter;
- double threshold;
- const int ni = 4;
-
- // Matrix assemblers
- inline void assembleQ();
- inline void assembleP();
- inline void assembleNi();
- // Selects out of Vv the 4 vertices belonging to face fi
- inline void assembleSelector(int fi,
- Eigen::SparseMatrix<typename DerivedV::Scalar > &S);
-
-
- public:
- // Init - assemble stacked vector and lhs matrix, factorize
- inline PlanarizerShapeUp(const Eigen::PlainObjectBase<DerivedV> &V_,
- const Eigen::PlainObjectBase<DerivedF> &F_,
- const int maxIter_,
- const double &threshold_);
- // Planarization - output to Vout
- inline void planarize(Eigen::PlainObjectBase<DerivedV> &Vout);
- };
- }
- //Implementation
- template <typename DerivedV, typename DerivedF>
- inline igl::PlanarizerShapeUp<DerivedV, DerivedF>::PlanarizerShapeUp(const Eigen::PlainObjectBase<DerivedV> &V_,
- const Eigen::PlainObjectBase<DerivedF> &F_,
- const int maxIter_,
- const double &threshold_):
- numV(V_.rows()),
- numF(F_.rows()),
- Vin(V_),
- Fin(F_),
- weightsSqrt(Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1>::Ones(numF,1)),
- maxIter(maxIter_),
- threshold(threshold_)
- {
- // assemble stacked vertex position vector
- Vv.setZero(3*numV,1);
- for (int i =0;i<numV;++i)
- Vv.segment(3*i,3) = Vin.row(i);
- // assemble and factorize lhs matrix
- assembleQ();
- };
- template <typename DerivedV, typename DerivedF>
- inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::assembleQ()
- {
- std::vector<Eigen::Triplet<typename DerivedV::Scalar> > tripletList;
-
- // assemble the Ni matrix
- assembleNi();
-
- for (int fi = 0; fi< numF; fi++)
- {
- Eigen::SparseMatrix<typename DerivedV::Scalar > Sfi;
- assembleSelector(fi, Sfi);
-
- // the final matrix per face
- Eigen::SparseMatrix<typename DerivedV::Scalar > Qi = weightsSqrt(fi)*Ni*Sfi;
- // put it in the correct block of Q
- // todo: this can be made faster by omitting the selector matrix
- for (int k=0; k<Qi.outerSize(); ++k)
- for (typename Eigen::SparseMatrix<typename DerivedV::Scalar >::InnerIterator it(Qi,k); it; ++it)
- {
- typename DerivedV::Scalar val = it.value();
- int row = it.row();
- int col = it.col();
- tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(row+3*ni*fi,col,val));
- }
- }
-
- Q.resize(3*ni*numF,3*numV);
- Q.setFromTriplets(tripletList.begin(), tripletList.end());
- // the actual lhs matrix is Q'*Q
- // prefactor that matrix
- solver.compute(Q.transpose()*Q);
- if(solver.info()!=Eigen::Success)
- {
- std::cerr << "Cholesky failed - PlanarizerShapeUp.cpp" << std::endl;
- assert(0);
- }
- }
- template <typename DerivedV, typename DerivedF>
- inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::assembleNi()
- {
- std::vector<Eigen::Triplet<typename DerivedV::Scalar>> tripletList;
- for (int ii = 0; ii< ni; ii++)
- {
- for (int jj = 0; jj< ni; jj++)
- {
- tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+0,3*jj+0,-1./ni));
- tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+1,3*jj+1,-1./ni));
- tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+2,3*jj+2,-1./ni));
- }
- tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+0,3*ii+0,1.));
- tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+1,3*ii+1,1.));
- tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+2,3*ii+2,1.));
- }
- Ni.resize(3*ni,3*ni);
- Ni.setFromTriplets(tripletList.begin(), tripletList.end());
- }
- //assumes V stacked [x;y;z;x;y;z...];
- template <typename DerivedV, typename DerivedF>
- inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::assembleSelector(int fi,
- Eigen::SparseMatrix<typename DerivedV::Scalar > &S)
- {
-
- std::vector<Eigen::Triplet<typename DerivedV::Scalar>> tripletList;
- for (int fvi = 0; fvi< ni; fvi++)
- {
- int vi = Fin(fi,fvi);
- tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*fvi+0,3*vi+0,1.));
- tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*fvi+1,3*vi+1,1.));
- tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*fvi+2,3*vi+2,1.));
- }
-
- S.resize(3*ni,3*numV);
- S.setFromTriplets(tripletList.begin(), tripletList.end());
-
- }
- //project all faces to their closest planar face
- template <typename DerivedV, typename DerivedF>
- inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::assembleP()
- {
- P.setZero(3*ni*numF);
- for (int fi = 0; fi< numF; fi++)
- {
- // todo: this can be made faster by omitting the selector matrix
- Eigen::SparseMatrix<typename DerivedV::Scalar > Sfi;
- assembleSelector(fi, Sfi);
- Eigen::SparseMatrix<typename DerivedV::Scalar > NSi = Ni*Sfi;
-
- Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> Vi = NSi*Vv;
- Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> CC(3,ni);
- for (int i = 0; i <ni; ++i)
- CC.col(i) = Vi.segment(3*i, 3);
- Eigen::Matrix<typename DerivedV::Scalar, 3, 3> C = CC*CC.transpose();
-
- // Alec: Doesn't compile
- Eigen::EigenSolver<Eigen::Matrix<typename DerivedV::Scalar, 3, 3>> es(C);
- // the real() is for compilation purposes
- Eigen::Matrix<typename DerivedV::Scalar, 3, 1> lambda = es.eigenvalues().real();
- Eigen::Matrix<typename DerivedV::Scalar, 3, 3> U = es.eigenvectors().real();
- int min_i;
- lambda.cwiseAbs().minCoeff(&min_i);
- U.col(min_i).setZero();
- Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> PP = U*U.transpose()*CC;
- for (int i = 0; i <ni; ++i)
- P.segment(3*ni*fi+3*i, 3) = weightsSqrt[fi]*PP.col(i);
-
- }
- }
- template <typename DerivedV, typename DerivedF>
- inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::planarize(Eigen::PlainObjectBase<DerivedV> &Vout)
- {
- Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> planarity;
- Vout = Vin;
-
- for (int iter =0; iter<maxIter; ++iter)
- {
- igl::quad_planarity(Vout, Fin, planarity);
- typename DerivedV::Scalar nonPlanarity = planarity.cwiseAbs().maxCoeff();
- //std::cerr<<"iter #"<<iter<<": max non-planarity: "<<nonPlanarity<<std::endl;
- if (nonPlanarity<threshold)
- break;
- assembleP();
- Vv = solver.solve(Q.transpose()*P);
- if(solver.info()!=Eigen::Success)
- {
- std::cerr << "Linear solve failed - PlanarizerShapeUp.cpp" << std::endl;
- assert(0);
- }
- for (int i =0;i<numV;++i)
- Vout.row(i) << Vv.segment(3*i,3).transpose();
- }
- // set the mean of Vout to the mean of Vin
- Eigen::Matrix<typename DerivedV::Scalar, 1, 3> oldMean, newMean;
- oldMean = Vin.colwise().mean();
- newMean = Vout.colwise().mean();
- Vout.rowwise() += (oldMean - newMean);
-
- };
-
- template <typename DerivedV, typename DerivedF>
- IGL_INLINE void igl::planarize_quad_mesh(const Eigen::PlainObjectBase<DerivedV> &Vin,
- const Eigen::PlainObjectBase<DerivedF> &Fin,
- const int maxIter,
- const double &threshold,
- Eigen::PlainObjectBase<DerivedV> &Vout)
- {
- PlanarizerShapeUp<DerivedV, DerivedF> planarizer(Vin, Fin, maxIter, threshold);
- planarizer.planarize(Vout);
- }
- #ifdef IGL_STATIC_LIBRARY
- // Explicit template specialization
- template void igl::planarize_quad_mesh<Eigen::Matrix<double, -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, double const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
- #endif
|