// 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 "outer_hull.h" #include "order_facets_around_edges.h" #include "../outer_element.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 "../writePLY.h" #include "../sort_angles.h" #include #include #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::cgal::outer_hull( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, const Eigen::PlainObjectBase & N, Eigen::PlainObjectBase & G, Eigen::PlainObjectBase & J, Eigen::PlainObjectBase & flip) { #ifdef IGL_OUTER_HULL_DEBUG std::cerr << "Extracting outer hull" << std::endl; #endif using namespace Eigen; using namespace std; 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(); // UNUSED: //const auto & duplicate_simplex = [&F](const int f, const int g)->bool //{ // return // (F(f,0) == F(g,0) && F(f,1) == F(g,1) && F(f,2) == F(g,2)) || // (F(f,1) == F(g,0) && F(f,2) == F(g,1) && F(f,0) == F(g,2)) || // (F(f,2) == F(g,0) && F(f,0) == F(g,1) && F(f,1) == F(g,2)) || // (F(f,0) == F(g,2) && F(f,1) == F(g,1) && F(f,2) == F(g,0)) || // (F(f,1) == F(g,2) && F(f,2) == F(g,1) && F(f,0) == F(g,0)) || // (F(f,2) == F(g,2) && F(f,0) == F(g,1) && F(f,1) == F(g,0)); //}; #ifdef IGL_OUTER_HULL_DEBUG cout<<"outer hull..."< MatrixX2I; typedef Matrix VectorXI; typedef Matrix Vector3F; MatrixX2I E,uE; VectorXI EMAP; vector > uE2E; unique_edge_map(F,E,uE,EMAP,uE2E); #ifdef IGL_OUTER_HULL_DEBUG for (size_t ui=0; ui > uE2oE; std::vector > uE2C; order_facets_around_edges(V, F, N, E, uE, EMAP, uE2E, uE2oE, uE2C); uE2E = uE2oE; VectorXI diIM(3*m); for (auto ue : uE2E) { for (size_t i=0; i > > 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); //size_t face_count = 0; 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; //std::cout << "face " << face_count++ << ": " << f << std::endl; //std::cout << "f " << F.row(f).array()+1 << std::endl; //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; // } // } //} if(nfei >= 0) { max_ne = uE2E[EMAP(e)][nfei]; } if(max_ne>=0) { // face of neighbor const int nf = max_ne%m; #ifdef IGL_OUTER_HULL_DEBUG if(!FH[nf]) { // first time seeing face cout<<(f+1)<<" --> "<<(nf+1)<bool { const auto & bounding_box = []( const Eigen::MatrixXd & V, const MatrixXG & F)-> Eigen::MatrixXd { Eigen::MatrixXd 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 //////////////////////////////////////////////////////////////////////// // // winding_number_3 expects colmajor // q could be so close (<~1e-15) 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? double q[3] = { CGAL::to_double(BC(AJ(0), 0)), CGAL::to_double(BC(AJ(0), 1)), CGAL::to_double(BC(AJ(0), 2)) }; // In a perfect world, it's enough to test a single point. double w; winding_number_3( V.data(),V.rows(), B.data(),B.rows(), q,1,&w); return w > 0.5 || w < -0.5; }; Eigen::MatrixXd Vcol(V.rows(), V.cols()); for (size_t i=0; i<(size_t)V.rows(); i++) { for (size_t j=0; j<(size_t)V.cols(); j++) { Vcol(i, j) = CGAL::to_double(V(i, j)); } } // 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::cgal::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_stable(V,F,N); return outer_hull(V,F,N,G,J,flip); } #ifdef IGL_STATIC_LIBRARY // Explicit template specialization #undef IGL_STATIC_LIBRARY #include #include #include #define IGL_STATIC_LIBRARY template void igl::cgal::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::cgal::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::cgal::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