diff --git a/include/igl/comiso/frame_field.cpp b/include/igl/comiso/frame_field.cpp index 0bed30b3c..90eaf5769 100644 --- a/include/igl/comiso/frame_field.cpp +++ b/include/igl/comiso/frame_field.cpp @@ -12,55 +12,33 @@ namespace igl class FrameInterpolator { public: - // Constraint type - enum ConstraintType { FREE, SOFT, HARD }; - // Init IGL_INLINE FrameInterpolator(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F); IGL_INLINE ~FrameInterpolator(); - // Generate the frame field - IGL_INLINE void solve(bool hard_const); - - IGL_INLINE void setConstraint(const int fid, const Eigen::VectorXd& v, ConstraintType type = HARD); - - IGL_INLINE void setConstraintProportionalScale(const int fid, const double scale, ConstraintType type = HARD); - - // Set the ratio between smoothness and soft constraints (0 -> smoothness only, 1 -> soft constr only) - IGL_INLINE void setSoftAlpha(double alpha); - // Reset constraints (at least one constraint must be present or solve will fail) IGL_INLINE void resetConstraints(); - // Return the current field - IGL_INLINE Eigen::MatrixXd getFieldPerFace(); + IGL_INLINE void setConstraint(const int fid, const Eigen::VectorXd& v); - // Return the singularities - IGL_INLINE Eigen::VectorXd getSingularityIndexPerVertex(); - - - // -------------- This is untested and unstable code - - IGL_INLINE void setConstraint_polar(const int fid, const Eigen::VectorXd& v, ConstraintType type); - - IGL_INLINE void interpolateSymmetric_polar(const bool bilaplacian); + IGL_INLINE void interpolateSymmetric(); // Generate the frame field - IGL_INLINE void solve_polar(const bool bilaplacian,bool hard_const); + IGL_INLINE void solve(); // Convert the frame field in the canonical representation - IGL_INLINE void frame2canonical_polar(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, Eigen::VectorXd& S); + IGL_INLINE void frame2canonical(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, Eigen::VectorXd& S); // Convert the canonical representation in a frame field - IGL_INLINE void canonical2frame_polar(const Eigen::MatrixXd& TP, const double theta, const Eigen::VectorXd& S, Eigen::RowVectorXd& v); + IGL_INLINE void canonical2frame(const Eigen::MatrixXd& TP, const double theta, const Eigen::VectorXd& S, Eigen::RowVectorXd& v); - IGL_INLINE Eigen::MatrixXd getFieldPerFace_polar(); + IGL_INLINE Eigen::MatrixXd getFieldPerFace(); IGL_INLINE void PolarDecomposition(Eigen::MatrixXd V, Eigen::MatrixXd& U, Eigen::MatrixXd& P); // Symmetric - Eigen::MatrixXd S_polar; - std::vector S_polar_c; + Eigen::MatrixXd S; + std::vector S_c; // ------------------------------------------------- @@ -82,20 +60,8 @@ private: // Convert an angle in a vector in the tangent space IGL_INLINE Eigen::RowVectorXd theta2vector(const Eigen::MatrixXd& TP, const double theta); - // Convert the frame field in the canonical representation - IGL_INLINE void frame2canonical(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, double& beta, Eigen::RowVectorXd& d); - - // Convert the canonical representation in a frame field - IGL_INLINE void canonical2frame(const Eigen::MatrixXd& TP, const double theta, const double beta, const Eigen::RowVectorXd& d, Eigen::RowVectorXd& v); - // Interpolate the cross field (theta) - IGL_INLINE void interpolateCross(bool hard_const); - - // Interpolate the skewness (beta) - IGL_INLINE void interpolateSkewness(); - - // Interpolate the scale (d) - IGL_INLINE void interpolateScale(); + IGL_INLINE void interpolateCross(); // Compute difference between reference frames IGL_INLINE void computek(); @@ -105,18 +71,7 @@ private: // Cross field direction Eigen::VectorXd thetas; - std::vector thetas_c; - - // Skewness - Eigen::VectorXd betas; - std::vector betas_c; - - // Scale - Eigen::MatrixXd ds; - std::vector ds_c; - - // Soft constraints strenght - double softAlpha; + std::vector thetas_c; // Edge Topology Eigen::MatrixXi EV, FE, EF; @@ -133,9 +88,6 @@ private: // Normals per face Eigen::MatrixXd N; - // Singularity index - Eigen::VectorXd singularityIndex; - // Reference frame per triangle std::vector TPs; @@ -189,25 +141,11 @@ FrameInterpolator::FrameInterpolator(const Eigen::MatrixXd& _V, const Eigen::Mat // Compute k, differences between reference frames computek(); - softAlpha = 0.5; - // Alloc internal variables thetas = VectorXd::Zero(F.rows()); -// thetas_c.resize(F.rows()); - - betas = VectorXd::Zero(F.rows()); -// betas_c.resize(F.rows()); - - ds = MatrixXd::Constant(F.rows(),2,1); -// ds_c.resize(F.rows()); - - S_polar = MatrixXd::Zero(F.rows(),3); -// S_polar_c.resize(F.rows()); - - singularityIndex = VectorXd::Zero(V.rows()); + S = MatrixXd::Zero(F.rows(),3); compute_edge_consistency(); - } FrameInterpolator::~FrameInterpolator() @@ -215,80 +153,6 @@ FrameInterpolator::~FrameInterpolator() } -void FrameInterpolator::solve(bool hard_const) -{ - interpolateCross(hard_const); - interpolateSkewness(); - interpolateScale(); -} - -void FrameInterpolator::setConstraint(const int fid, const Eigen::VectorXd& v, ConstraintType type) -{ - using namespace std; - using namespace Eigen; - - double t_; - double b_; - RowVectorXd d_; - frame2canonical(TPs[fid],v,t_,b_,d_); - -// cerr << "TP: " << endl << TPs[fid] << endl; -// cerr << "v: " << endl << TPs[fid] << endl; -// cerr << "t_: " << endl << TPs[fid] << endl; -// cerr << "b_: " << endl << TPs[fid] << endl; -// cerr << "d_: " << endl << TPs[fid] << endl; - - Eigen::RowVectorXd v2; - canonical2frame(TPs[fid], t_, b_, d_, v2); -// cerr << "Cosntraint: " << t_ << " " << b_ << " " << d_ << endl; -// cerr << "Compare: " << endl << v.transpose() << endl << v2 << endl; - - thetas(fid) = t_; - thetas_c[fid] = type; - - betas(fid) = b_; - betas_c[fid] = type; - - ds.row(fid) = d_; - ds_c[fid] = type; -} - -void FrameInterpolator::setConstraintProportionalScale(const int fid, const double scale, ConstraintType type) -{ - using namespace std; - using namespace Eigen; - - - assert(scale>0); - ds.row(fid) = ds.row(fid) * scale; - ds_c[fid] = type; -} - -void FrameInterpolator::setSoftAlpha(double alpha) -{ - assert(alpha >= 0 && alpha <= 1); - softAlpha = alpha; -} - - -Eigen::MatrixXd FrameInterpolator::getFieldPerFace() -{ - Eigen::MatrixXd R(F.rows(),6); - for (unsigned i=0; i(0); - RowVectorXd v1 = v.segment<3>(3); - - if (debug) - { - cerr << "v0:" << endl << v0 << endl; - cerr << "v1:" << endl << v1 << endl; - } - - // Find canonical cross field - double theta0 = mod2pi(vector2theta(TP,v0)); - double theta1 = mod2pi(vector2theta(TP,v1)); - //cerr << mod2pi(theta0) << " " << mod2pi(theta1) << endl; - - // Find the closest pair -// if (mod2pi(abs(theta0 + M_PI - theta1)) < mod2pi(abs(theta0 - theta1))) -// theta0 = theta0 + M_PI; - - // Express theta1 as a displacement wrt theta0 - theta1 = mod2pi(theta1 - theta0); - - // Find the closest representative - if (theta1 > M_PI) - theta1 -= M_PI; - assert(theta1 < M_PI); - - // Extract theta and beta - theta = mod2pi(theta1/2.0 + theta0); - beta = theta1/2.0; - - //cerr << mod2pi(beta + theta) << " " << mod2pi(-beta + theta) << endl; - - d.resize(2); - // Find the scaling factors - d(0) = v0.norm(); - d(1) = v1.norm(); - - if (debug) - { - cerr << "d:" << endl << d << endl; - cerr << "thetavector:" << endl << theta2vector(TP, theta) << endl; - } - -} - -void FrameInterpolator::canonical2frame(const Eigen::MatrixXd& TP, const double theta, const double beta, const Eigen::RowVectorXd& d, Eigen::RowVectorXd& v) -{ - using namespace std; - using namespace Eigen; - - - assert(d.cols() == 2 && d.rows() == 1); - - double theta0 = theta + M_PI - beta; - double theta1 = theta + M_PI + beta; - - RowVectorXd v0 = theta2vector(TP,modpi(theta0)) * d(0); - RowVectorXd v1 = theta2vector(TP,modpi(theta1)) * d(1); - -// cerr << "v0 : " << v0 << endl; -// cerr << "v1 : " << v1 << endl; - - v.resize(6); - v << v0, v1; -} - -void FrameInterpolator::interpolateCross(bool hard_const) +void FrameInterpolator::interpolateCross() { using namespace std; using namespace Eigen; NRosyField nrosy(V,F); - nrosy.setSoftAlpha(softAlpha); for (unsigned i=0; i triplet; - std::vector triplets; - triplets.reserve(4*F.rows()); - - VectorXd b = VectorXd::Zero(F.rows()); - - // Build L and b - for (unsigned eid=0; eid L(F.rows(),F.rows()); - L.setFromTriplets(triplets.begin(), triplets.end()); - - // Solve Lx = b; - - SimplicialLDLT > solver; - solver.compute(L); - - if(solver.info()!=Success) - { - std::cerr << "Cholesky failed - frame_interpolator.cpp" << std::endl; - assert(0); - } - - VectorXd x; - x = solver.solve(b); - -// cerr << "Skewness: " << x << endl; - - if(solver.info()!=Success) - { - std::cerr << "Linear solve failed - frame_interpolator.cpp" << std::endl; - assert(0); - } - - // Copy back the result - betas = x; -} - -void FrameInterpolator::interpolateScale() -{ - using namespace std; - using namespace Eigen; - - compute_edge_consistency(); - - // Generate enriched Laplacian matrix (see notes) - // the variables here are d1, d2 - typedef Eigen::Triplet triplet; - std::vector triplets; - triplets.reserve(4*F.rows()*2); - - VectorXd b = VectorXd::Zero(F.rows()*2); - - // Build L and b - for (unsigned eid=0; eid L(F.rows()*2,F.rows()*2); - L.setFromTriplets(triplets.begin(), triplets.end()); - - // Solve Lx = b; - - SimplicialLDLT > solver; - solver.compute(L); - - if(solver.info()!=Success) - { - std::cerr << "Cholesky failed - frame_interpolator.cpp" << std::endl; - assert(0); - } - - VectorXd x; - x = solver.solve(b); - -// cerr << "Scale: " << endl << x << endl; - if(solver.info()!=Success) - { - std::cerr << "Linear solve failed - frame_interpolator.cpp" << std::endl; - assert(0); - } - - // Copy back the result - ds << x.block(0, 0, ds.rows(), 1), x.block(ds.rows(), 0, ds.rows(), 1); + for (unsigned i=0; i triplet; std::vector triplets; @@ -939,79 +497,26 @@ void FrameInterpolator::interpolateSymmetric_polar(const bool bilaplacian) double r_c = sin(z==1?k(eid):-k(eid)); double r_d = cos(z==1?k(eid):-k(eid)); - if (true) - { - if (true) - { - // First term - // w_a_0 = r_a^2 w_a_1 + 2 r_a r_b w_b_1 + r_b^2 w_c_1 = 0 - triplets.push_back(triplet(w_a_0,w_a_0, -1 )); - triplets.push_back(triplet(w_a_0,w_a_1, r_a*r_a )); - triplets.push_back(triplet(w_a_0,w_b_1, 2 * r_a*r_b )); - triplets.push_back(triplet(w_a_0,w_c_1, r_b*r_b )); + // First term + // w_a_0 = r_a^2 w_a_1 + 2 r_a r_b w_b_1 + r_b^2 w_c_1 = 0 + triplets.push_back(triplet(w_a_0,w_a_0, -1 )); + triplets.push_back(triplet(w_a_0,w_a_1, r_a*r_a )); + triplets.push_back(triplet(w_a_0,w_b_1, 2 * r_a*r_b )); + triplets.push_back(triplet(w_a_0,w_c_1, r_b*r_b )); - // Second term - // w_b_0 = r_a r_c w_a + (r_b r_c + r_a r_d) w_b + r_b r_d w_c - triplets.push_back(triplet(w_b_0,w_b_0, -1 )); - triplets.push_back(triplet(w_b_0,w_a_1, r_a*r_c )); - triplets.push_back(triplet(w_b_0,w_b_1, r_b*r_c + r_a*r_d )); - triplets.push_back(triplet(w_b_0,w_c_1, r_b*r_d )); + // Second term + // w_b_0 = r_a r_c w_a + (r_b r_c + r_a r_d) w_b + r_b r_d w_c + triplets.push_back(triplet(w_b_0,w_b_0, -1 )); + triplets.push_back(triplet(w_b_0,w_a_1, r_a*r_c )); + triplets.push_back(triplet(w_b_0,w_b_1, r_b*r_c + r_a*r_d )); + triplets.push_back(triplet(w_b_0,w_c_1, r_b*r_d )); - // Third term - // w_c_0 = r_c^2 w_a + 2 r_c r_d w_b + r_d^2 w_c - triplets.push_back(triplet(w_c_0,w_c_0, -1 )); - triplets.push_back(triplet(w_c_0,w_a_1, r_c*r_c )); - triplets.push_back(triplet(w_c_0,w_b_1, 2 * r_c*r_d )); - triplets.push_back(triplet(w_c_0,w_c_1, r_d*r_d )); - } - else - { - // First term - // w_a_0 = r_a^2 w_a_1 + 2 r_a r_b w_b_1 + r_b^2 w_c_1 = 0 - triplets.push_back(triplet(w_a_0,w_a_1, r_a*r_a )); - triplets.push_back(triplet(w_a_0,w_b_1, 2 * r_a*r_b )); - triplets.push_back(triplet(w_a_0,w_c_1, r_b*r_b )); - triplets.push_back(triplet(w_a_0,w_a_0, - r_a*r_a )); - triplets.push_back(triplet(w_a_0,w_a_0, - 2 * r_a*r_b )); - triplets.push_back(triplet(w_a_0,w_a_0, - r_b*r_b )); - - // Second term - // w_b_0 = r_a r_c w_a + (r_b r_c + r_a r_d) w_b + r_b r_d w_c - triplets.push_back(triplet(w_b_0,w_a_1, r_a*r_c )); - triplets.push_back(triplet(w_b_0,w_b_1, r_b*r_c + r_a*r_d )); - triplets.push_back(triplet(w_b_0,w_c_1, r_b*r_d )); - triplets.push_back(triplet(w_b_0,w_b_0, - r_a*r_c )); - triplets.push_back(triplet(w_b_0,w_b_0, -r_b*r_c + r_a*r_d )); - triplets.push_back(triplet(w_b_0,w_b_0, - r_b*r_d )); - - // Third term - // w_c_0 = r_c^2 w_a + 2 r_c r_d w_b + r_d^2 w_c - triplets.push_back(triplet(w_c_0,w_a_1, r_c*r_c )); - triplets.push_back(triplet(w_c_0,w_b_1, 2 * r_c*r_d )); - triplets.push_back(triplet(w_c_0,w_c_1, r_d*r_d )); - triplets.push_back(triplet(w_c_0,w_c_0, - r_c*r_c )); - triplets.push_back(triplet(w_c_0,w_c_0, - 2 * r_c*r_d )); - triplets.push_back(triplet(w_c_0,w_c_0, - r_d*r_d )); - - } - } - else - { - // Simple Laplacian - // w_a_0 = r_a^2 w_a_1 + 2 r_a r_b w_b_1 + r_b^2 w_c_1 = 0 - triplets.push_back(triplet(w_a_0,w_a_0, -1 )); - triplets.push_back(triplet(w_a_0,w_a_1, 1 )); - - // Second term - // w_b_0 = r_a r_c w_a + (r_b r_c + r_a r_d) w_b + r_b r_d w_c - triplets.push_back(triplet(w_b_0,w_b_0, -1 )); - triplets.push_back(triplet(w_b_0,w_b_1, 1 )); - - // Third term - // w_c_0 = r_c^2 w_a + 2 r_c r_d w_b + r_d^2 w_c - triplets.push_back(triplet(w_c_0,w_c_0, -1 )); - triplets.push_back(triplet(w_c_0,w_c_1, 1 )); - } + // Third term + // w_c_0 = r_c^2 w_a + 2 r_c r_d w_b + r_d^2 w_c + triplets.push_back(triplet(w_c_0,w_c_0, -1 )); + triplets.push_back(triplet(w_c_0,w_a_1, r_c*r_c )); + triplets.push_back(triplet(w_c_0,w_b_1, 2 * r_c*r_d )); + triplets.push_back(triplet(w_c_0,w_c_1, r_d*r_d )); } } } @@ -1025,12 +530,12 @@ void FrameInterpolator::interpolateSymmetric_polar(const bool bilaplacian) double w = 100000; for (unsigned fid=0; fid < F.rows(); ++fid) { - if (S_polar_c[fid] != FREE) + if (S_c[fid]) { for (unsigned i=0;i<3;++i) { triplets.push_back(triplet(3*fid + i,3*fid + i,w)); - b(3*fid + i) += w*S_polar(fid,i); + b(3*fid + i) += w*S(fid,i); } } } @@ -1040,68 +545,38 @@ void FrameInterpolator::interpolateSymmetric_polar(const bool bilaplacian) SparseMatrix M; - if (!bilaplacian) - M = L + soft; - else - M = L * L + soft; + M = L + soft; // Solve Lx = b; -// MatrixXd Dense(L); -// -// cerr << "Is sym:" << (Dense - Dense.transpose()).maxCoeff() << endl; - -// SimplicialLDLT > solver; SparseLU > solver; solver.compute(M); if(solver.info()!=Success) { - std::cerr << "Cholesky failed - frame_interpolator.cpp" << std::endl; + std::cerr << "LU failed - frame_interpolator.cpp" << std::endl; assert(0); } MatrixXd x; x = solver.solve(b); -// cerr << "Skewness: " << x << endl; - if(solver.info()!=Success) { std::cerr << "Linear solve failed - frame_interpolator.cpp" << std::endl; assert(0); } - S_polar = MatrixXd::Zero(F.rows(),3); + S = MatrixXd::Zero(F.rows(),3); // Copy back the result for (unsigned i=0;i S_es(T_POLAR); - VectorXd eivals = S_es.eigenvalues(); - -// cerr << "eivals:" << eivals << endl; - double t = eivals.minCoeff(); - if (t < 0) - { - cerr << "NOOOOOOOO!" << endl; - exit(1); - } -// cerr << S_polar << endl; - } - } } -void FrameInterpolator::setConstraint_polar(const int fid, const Eigen::VectorXd& v, ConstraintType type) +void FrameInterpolator::setConstraint(const int fid, const Eigen::VectorXd& v) { using namespace std; using namespace Eigen; @@ -1109,26 +584,20 @@ void FrameInterpolator::setConstraint_polar(const int fid, const Eigen::VectorXd double t_; VectorXd S_; - frame2canonical_polar(TPs[fid],v,t_,S_); + frame2canonical(TPs[fid],v,t_,S_); Eigen::RowVectorXd v2; - canonical2frame_polar(TPs[fid], t_, S_, v2); - - -// cerr << "Constraint: " << t_ << " " << S_ << endl; -// cerr << "Compare: " << endl << v.transpose() << endl << v2 << endl; -// cerr << "Diff: " << endl << v.transpose() - v2 << endl; -// cerr << "Diff: " << endl << v.transpose() + v2 << endl; + canonical2frame(TPs[fid], t_, S_, v2); thetas(fid) = t_; - thetas_c[fid] = type; + thetas_c[fid] = true; - S_polar.row(fid) = S_; - S_polar_c[fid] = type; + S.row(fid) = S_; + S_c[fid] = true; } -Eigen::MatrixXd FrameInterpolator::getFieldPerFace_polar() +Eigen::MatrixXd FrameInterpolator::getFieldPerFace() { using namespace std; using namespace Eigen; @@ -1137,7 +606,7 @@ Eigen::MatrixXd FrameInterpolator::getFieldPerFace_polar() for (unsigned i=0; i S_es(P); - // if (S_es.eigenvalues().minCoeff() < 0) - // { - // U = -U; - // P = -P; - // } } } @@ -1173,8 +634,7 @@ IGL_INLINE void igl::frame_field( const Eigen::MatrixXd& bc1, const Eigen::MatrixXd& bc2, Eigen::MatrixXd& F1, - Eigen::MatrixXd& F2, - Eigen::VectorXd& S + Eigen::MatrixXd& F2 ) { @@ -1182,22 +642,21 @@ IGL_INLINE void igl::frame_field( using namespace Eigen; assert(b.size() > 0); - + // Init Solver FrameInterpolator field(V,F); - + for (unsigned i=0; i