IGL_INLINE void igl::exterior_edges( const Eigen::MatrixXi & F, Eigen::MatrixXi & E) { using namespace Eigen; using namespace std; assert(F.cols() == 3); const size_t m = F.rows(); MatrixXi all_E,sall_E,sort_order; // Sort each edge by index all_edges(F,all_E); sort(all_E,2,true,sall_E,sort_order); // Find unique edges MatrixXi uE; VectorXi IA,EMAP; unique_rows(sall_E,uE,IA,EMAP); VectorXi counts = VectorXi::Zero(uE.rows()); for(size_t a = 0;a<3*m;a++) { counts(EMAP(a)) += (sort_order(a)==0?1:-1); } E.resize(all_E.rows(),2); { int e = 0; const size_t nue = uE.rows(); // Append each unique edge with a non-zero amount of signed occurances for(size_t ue = 0; ue<nue; ue++) { const int count = counts(ue); size_t i,j; if(count == 0) { continue; }else if(count < 0) { i = uE(ue,1); j = uE(ue,0); }else if(count > 0) { i = uE(ue,0); j = uE(ue,1); } // Append edge for every repeated entry const int abs_count = abs(count); for(size_t k = 0;k<abs_count;k++) { E(e,0) = i; E(e,1) = j; e++; } } E.conservativeResize(e,2); } }
void igl::collapse_small_triangles( const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, const double eps, Eigen::MatrixXi & FF) { using namespace Eigen; using namespace std; // Compute bounding box diagonal length double bbd = bounding_box_diagonal(V); MatrixXd l; edge_lengths(V,F,l); VectorXd dblA; doublearea(l,dblA); // Minimum area tolerance const double min_dblarea = 2.0*eps*bbd*bbd; Eigen::VectorXi FIM = colon<int>(0,V.rows()-1); int num_edge_collapses = 0; // Loop over triangles for(int f = 0;f<F.rows();f++) { if(dblA(f) < min_dblarea) { double minl = 0; int minli = -1; // Find shortest edge for(int e = 0;e<3;e++) { if(minli==-1 || l(f,e)<minl) { minli = e; minl = l(f,e); } } double maxl = 0; int maxli = -1; // Find longest edge for(int e = 0;e<3;e++) { if(maxli==-1 || l(f,e)>maxl) { maxli = e; maxl = l(f,e); } } // Be sure that min and max aren't the same maxli = (minli==maxli?(minli+1)%3:maxli); // Collapse min edge maintaining max edge: i-->j // Q: Why this direction? int i = maxli; int j = ((minli+1)%3 == maxli ? (minli+2)%3: (minli+1)%3); assert(i != minli); assert(j != minli); assert(i != j); FIM(F(f,i)) = FIM(F(f,j)); num_edge_collapses++; } } // Reindex faces MatrixXi rF = F; // Loop over triangles for(int f = 0;f<rF.rows();f++) { for(int i = 0;i<rF.cols();i++) { rF(f,i) = FIM(rF(f,i)); } } FF.resize(rF.rows(),rF.cols()); int num_face_collapses=0; // Only keep uncollapsed faces { int ff = 0; // Loop over triangles for(int f = 0;f<rF.rows();f++) { bool collapsed = false; // Check if any indices are the same for(int i = 0;i<rF.cols();i++) { for(int j = i+1;j<rF.cols();j++) { if(rF(f,i)==rF(f,j)) { collapsed = true; num_face_collapses++; break; } } } if(!collapsed) { FF.row(ff++) = rF.row(f); } } // Use conservative resize FF.conservativeResize(ff,FF.cols()); } //cout<<"num_edge_collapses: "<<num_edge_collapses<<endl; //cout<<"num_face_collapses: "<<num_face_collapses<<endl; if(num_edge_collapses == 0) { // There must have been a "collapsed edge" in the input assert(num_face_collapses==0); // Base case return; } //// force base case //return; MatrixXi recFF = FF; return collapse_small_triangles(V,recFF,eps,FF); }