// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2016 Alec Jacobson // // 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 "per_vertex_point_to_plane_quadrics.h" #include "quadric_binary_plus_operator.h" #include #include #include IGL_INLINE void igl::per_vertex_point_to_plane_quadrics( const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, const Eigen::MatrixXi & EMAP, const Eigen::MatrixXi & EF, const Eigen::MatrixXi & EI, std::vector< std::tuple > & quadrics) { using namespace std; typedef std::tuple Quadric; const int dim = V.cols(); //// Quadrics per face //std::vector face_quadrics(F.rows()); // Initialize each vertex quadric to zeros quadrics.resize( V.rows(), // gcc <=4.8 can't handle initializer lists correctly Quadric{Eigen::MatrixXd::Zero(dim,dim),Eigen::RowVectorXd::Zero(dim),0}); Eigen::MatrixXd I = Eigen::MatrixXd::Identity(dim,dim); // Rather initial with zeros, initial with a small amount of energy pull // toward original vertex position const double w = 1e-10; for(int v = 0;v(quadrics[v]) = w*I; Eigen::RowVectorXd Vv = V.row(v); std::get<1>(quadrics[v]) = w*-Vv; std::get<2>(quadrics[v]) = w*Vv.dot(Vv); } // Generic nD qslim from "Simplifying Surfaces with Color and Texture // using Quadric Error Metric" (follow up to original QSlim) for(int f = 0;fQuadric { // Dimension of subspace const int m = S.rows(); // Weight face's quadric (v'*A*v + 2*b'*v + c) by area // e1 and e2 should be perpendicular Eigen::MatrixXd A = I; Eigen::RowVectorXd b = -p; double c = p.dot(p); for(int i = 0;i edge opposite cth corner is boundary // Boundary edge vector const Eigen::RowVectorXd p = V.row(F(f,(infinite_corner+1)%3)); Eigen::RowVectorXd ev = V.row(F(f,(infinite_corner+2)%3)) - p; const double length = ev.norm(); ev /= length; // Face neighbor across boundary edge int e = EMAP(f+F.rows()*infinite_corner); int opp = EF(e,0) == f ? 1 : 0; int n = EF(e,opp); int nc = EI(e,opp); assert( ((F(f,(infinite_corner+1)%3) == F(n,(nc+1)%3) && F(f,(infinite_corner+2)%3) == F(n,(nc+2)%3)) || (F(f,(infinite_corner+1)%3) == F(n,(nc+2)%3) && F(f,(infinite_corner+2)%3) == F(n,(nc+1)%3))) && "Edge flaps not agreeing on shared edge"); // Edge vector on opposite face const Eigen::RowVectorXd eu = V.row(F(n,nc)) - p; assert(!std::isinf(eu(0))); // Matrix with vectors spanning plane as columns Eigen::MatrixXd A(ev.size(),2); A< qr(A); const Eigen::MatrixXd Q = qr.householderQ(); const Eigen::MatrixXd N = Q.topRightCorner(ev.size(),ev.size()-2).transpose(); assert(N.cols() == ev.size()); assert(N.rows() == ev.size()-2); Eigen::MatrixXd S(N.rows()+1,ev.size()); S<