// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2015 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 "collapse_edge.h" #include "circulation.h" #include "edge_collapse_is_valid.h" #include IGL_INLINE bool igl::collapse_edge( const int e, const Eigen::RowVectorXd & p, Eigen::MatrixXd & V, Eigen::MatrixXi & F, Eigen::MatrixXi & E, Eigen::VectorXi & EMAP, Eigen::MatrixXi & EF, Eigen::MatrixXi & EI, int & a_e1, int & a_e2, int & a_f1, int & a_f2) { // Assign this to 0 rather than, say, -1 so that deleted elements will get // draw as degenerate elements at vertex 0 (which should always exist and // never get collapsed to anything else since it is the smallest index) using namespace Eigen; using namespace std; const int eflip = E(e,0)>E(e,1); // source and destination const int s = eflip?E(e,1):E(e,0); const int d = eflip?E(e,0):E(e,1); if(!edge_collapse_is_valid(e,F,E,EMAP,EF,EI)) { return false; } // Important to grab neighbors of d before monkeying with edges const std::vector nV2Fd = circulation(e,!eflip,F,E,EMAP,EF,EI); // The following implementation strongly relies on s & cost_and_placement, Eigen::MatrixXd & V, Eigen::MatrixXi & F, Eigen::MatrixXi & E, Eigen::VectorXi & EMAP, Eigen::MatrixXi & EF, Eigen::MatrixXi & EI, std::set > & Q, std::vector >::iterator > & Qit, Eigen::MatrixXd & C) { int e,e1,e2,f1,f2; return collapse_edge(cost_and_placement,V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2); } IGL_INLINE bool igl::collapse_edge( const std::function & cost_and_placement, Eigen::MatrixXd & V, Eigen::MatrixXi & F, Eigen::MatrixXi & E, Eigen::VectorXi & EMAP, Eigen::MatrixXi & EF, Eigen::MatrixXi & EI, std::set > & Q, std::vector >::iterator > & Qit, Eigen::MatrixXd & C, int & e, int & e1, int & e2, int & f1, int & f2) { using namespace Eigen; if(Q.empty()) { // no edges to collapse return false; } std::pair p = *(Q.begin()); if(p.first == std::numeric_limits::infinity()) { // min cost edge is infinite cost return false; } Q.erase(Q.begin()); e = p.second; Qit[e] = Q.end(); std::vector N = circulation(e, true,F,E,EMAP,EF,EI); std::vector Nd = circulation(e,false,F,E,EMAP,EF,EI); N.insert(N.begin(),Nd.begin(),Nd.end()); const bool collapsed = collapse_edge(e,C.row(e),V,F,E,EMAP,EF,EI,e1,e2,f1,f2); if(collapsed) { // Erase the two, other collapsed edges Q.erase(Qit[e1]); Qit[e1] = Q.end(); Q.erase(Qit[e2]); Qit[e2] = Q.end(); // update local neighbors // loop over original face neighbors for(auto n : N) { if(F(n,0) != IGL_COLLAPSE_EDGE_NULL || F(n,1) != IGL_COLLAPSE_EDGE_NULL || F(n,2) != IGL_COLLAPSE_EDGE_NULL) { for(int v = 0;v<3;v++) { // get edge id const int ei = EMAP(v*F.rows()+n); // erase old entry Q.erase(Qit[ei]); // compute cost and potential placement double cost; RowVectorXd place; cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place); // Replace in queue Qit[ei] = Q.insert(std::pair(cost,ei)).first; C.row(ei) = place; } } } }else { // reinsert with infinite weight (the provided cost function must **not** // have given this un-collapsable edge inf cost already) p.first = std::numeric_limits::infinity(); Qit[e] = Q.insert(p).first; } return collapsed; }