#include "outer_hull.h" #include "outer_facet.h" #include "sortrows.h" #include "facet_components.h" #include "winding_number.h" #include "triangle_triangle_adjacency.h" #include "unique_edge_map.h" #include "barycenter.h" #include "per_face_normals.h" #include #include #include #include #include //#define IGL_OUTER_HULL_DEBUG template < typename DerivedV, typename DerivedF, typename DerivedN, typename DerivedG, typename DerivedJ, typename Derivedflip> IGL_INLINE void igl::outer_hull( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, const Eigen::PlainObjectBase & N, Eigen::PlainObjectBase & G, Eigen::PlainObjectBase & J, Eigen::PlainObjectBase & flip) { using namespace Eigen; using namespace std; using namespace igl; typedef typename DerivedF::Index Index; Matrix C; typedef Matrix MatrixXV; typedef Matrix MatrixXF; typedef Matrix MatrixXG; typedef Matrix MatrixXJ; typedef Matrix RowVector3N; const Index m = F.rows(); #ifdef IGL_OUTER_HULL_DEBUG cout<<"outer hull..."< MatrixX2I; typedef Matrix VectorXI; MatrixX2I E,uE; VectorXI EMAP; vector > uE2E; unique_edge_map(F,E,uE,EMAP,uE2E); // TODO: // uE --> face-edge index, sorted CCW around edge according to normal // uE --> sorted order index // uE --> bool, whether needed to flip face to make "consistent" with unique // edge // Place order of each half-edge in its corresponding sorted list around edge VectorXI diIM(3*m); // Whether face's edge used for sorting is consistent with unique edge VectorXI dicons(3*m); // dihedral angles of faces around edge with face of edge in dicons vector > di(uE2E.size()); // For each list of face-edges incide on a unique edge for(size_t ui = 0;ui<(size_t)uE.rows();ui++) { // Base normal vector to orient against const auto fe0 = uE2E[ui][0]; const RowVector3N & eVp = N.row(fe0%m); MatrixXd di_I(uE2E[ui].size(),2); const typename DerivedF::Scalar d = F(fe0%m,((fe0/m)+2)%3); const typename DerivedF::Scalar s = F(fe0%m,((fe0/m)+1)%3); // Edge vector const auto & eV = (V.row(d)-V.row(s)).normalized(); vector cons(uE2E[ui].size()); // Loop over incident face edges for(size_t fei = 0;fei=2.*M_PI) { di_I(fei,0) = di_I(fei,0) - 2.*M_PI; } } di_I(fei,1) = f; } VectorXi IM; //igl::sort(di[ui],true,di[ui],IM); // Sort, but break ties using index to ensure that duplicates always show // up in same order. MatrixXd s_di_I; igl::sortrows(di_I,true,s_di_I,IM); di[ui].resize(uE2E[ui].size()); for(size_t i = 0;i temp = uE2E[ui]; for(size_t fei = 0;fei > > TT,_1; triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1); VectorXI counts; #ifdef IGL_OUTER_HULL_DEBUG cout<<"facet components..."< FH(m,false); vector EH(3*m,false); vector vG(ncc); vector vJ(ncc); vector vIM(ncc); for(size_t id = 0;id g(ncc,0); // place order of each face in its respective component for(Index f = 0;f Q; Q.push(f+0*m); Q.push(f+1*m); Q.push(f+2*m); flip(f) = f_flip; //cout<<"flip("< "<<(nf+1)<<", |"<< // di[EMAP(e)][diIM(e)]<<" - "< "<<(nf+1)<=max_di) // { // max_ne = ne; // max_di = ndi; // } //} ////cout<<(max_ne != max_ne_2)<<" =?= "< "<<(max_ne%m)+1<<" != "<<(max_ne_2%m)+1<<" ... "<=max_di) // { // max_ne = ne; // max_di = ndi; // } // } //} max_ne = max_ne_2; if(max_ne>=0) { // face of neighbor const int nf = max_ne%m; // corner of neighbor const int nc = max_ne/m; const int nd = F(nf,(nc+2)%3); const bool cons = (flip(f)?fd:fs) == nd; flip(nf) = (cons ? flip(f) : !flip(f)); //cout<<"flip("< & V, const MatrixXV & BC, const MatrixXG & A, const MatrixXJ & AJ, const MatrixXG & B)->bool { const auto & bounding_box = []( const Eigen::PlainObjectBase & V, const MatrixXG & F)-> MatrixXV { MatrixXV BB(2,3); BB<< 1e26,1e26,1e26, -1e26,-1e26,-1e26; const size_t m = F.rows(); for(size_t f = 0;f0 || (ABB.row(0)-BBB.row(1)).maxCoeff()>0 ) { // bounding boxes do not overlap return false; } //////////////////////////////////////////////////////////////////////// // POTENTIAL ROBUSTNESS WEAK AREA //////////////////////////////////////////////////////////////////////// // // q could be so close (<~1e-16) to B that the winding number is not a robust way to // determine inside/outsideness. We could try to find a _better_ q which is // farther away, but couldn't they all be bad? MatrixXV q = BC.row(AJ(0)); // In a perfect world, it's enough to test a single point. double w; // winding_number_3 expects colmajor const typename DerivedV::Scalar * Vdata; Vdata = V.data(); Matrix< typename DerivedV::Scalar, DerivedV::RowsAtCompileTime, DerivedV::ColsAtCompileTime, ColMajor> Vcol; if(DerivedV::IsRowMajor) { // copy to convert to colmajor Vcol = V; Vdata = Vcol.data(); } winding_number_3( Vdata,V.rows(), B.data(),B.rows(), q.data(),1,&w); return fabs(w)>0.5; }; // Reject components which are completely inside other components vector keep(ncc,true); size_t nG = 0; // This is O( ncc * ncc * m) for(size_t id = 0;id IGL_INLINE void igl::outer_hull( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, Eigen::PlainObjectBase & G, Eigen::PlainObjectBase & J, Eigen::PlainObjectBase & flip) { Eigen::Matrix N; per_face_normals(V,F,N); return outer_hull(V,F,N,G,J,flip); } #ifdef IGL_STATIC_LIBRARY // Explicit template specialization template void igl::outer_hull, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); template void igl::outer_hull, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); template void igl::outer_hull, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #endif