// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2014 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 "intersect_other.h" #include "CGAL_includes.hpp" #include "mesh_to_cgal_triangle_list.h" #include "remesh_intersections.h" #include "../../slice_mask.h" #include "../../remove_unreferenced.h" #ifndef IGL_FIRST_HIT_EXCEPTION #define IGL_FIRST_HIT_EXCEPTION 10 #endif // Un-exposed helper functions namespace igl { namespace copyleft { namespace cgal { template static IGL_INLINE void push_result( const Eigen::PlainObjectBase & F, const int f, const int f_other, const CGAL::Object & result, std::map< typename DerivedF::Index, std::vector > > & offending) //std::map< // std::pair, // std::vector > & edge2faces) { typedef typename DerivedF::Index Index; typedef std::pair EMK; if(offending.count(f) == 0) { // first time marking, initialize with new id and empty list offending[f] = {}; for(Index e = 0; e<3;e++) { // append face to edge's list Index i = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+1)%3) : F(f,(e+2)%3); Index j = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+2)%3) : F(f,(e+1)%3); //edge2faces[EMK(i,j)].push_back(f); } } offending[f].push_back({f_other,result}); } template < typename Kernel, typename DerivedVA, typename DerivedFA, typename DerivedVB, typename DerivedFB, typename DerivedIF, typename DerivedVVAB, typename DerivedFFAB, typename DerivedJAB, typename DerivedIMAB> static IGL_INLINE bool intersect_other_helper( const Eigen::PlainObjectBase & VA, const Eigen::PlainObjectBase & FA, const Eigen::PlainObjectBase & VB, const Eigen::PlainObjectBase & FB, const RemeshSelfIntersectionsParam & params, Eigen::PlainObjectBase & IF, Eigen::PlainObjectBase & VVAB, Eigen::PlainObjectBase & FFAB, Eigen::PlainObjectBase & JAB, Eigen::PlainObjectBase & IMAB) { using namespace std; using namespace Eigen; typedef typename DerivedFA::Index Index; // 3D Primitives typedef CGAL::Point_3 Point_3; typedef CGAL::Segment_3 Segment_3; typedef CGAL::Triangle_3 Triangle_3; typedef CGAL::Plane_3 Plane_3; typedef CGAL::Tetrahedron_3 Tetrahedron_3; // 2D Primitives typedef CGAL::Point_2 Point_2; typedef CGAL::Segment_2 Segment_2; typedef CGAL::Triangle_2 Triangle_2; // 2D Constrained Delaunay Triangulation types typedef CGAL::Triangulation_vertex_base_2 TVB_2; typedef CGAL::Constrained_triangulation_face_base_2 CTAB_2; typedef CGAL::Triangulation_data_structure_2 TDS_2; typedef CGAL::Exact_intersections_tag Itag; // Axis-align boxes for all-pairs self-intersection detection typedef std::vector Triangles; typedef typename Triangles::iterator TrianglesIterator; typedef typename Triangles::const_iterator TrianglesConstIterator; typedef CGAL::Box_intersection_d::Box_with_handle_d Box; typedef std::map > > OffendingMap; typedef std::map,std::vector > EdgeMap; typedef std::pair EMK; Triangles TA,TB; // Compute and process self intersections mesh_to_cgal_triangle_list(VA,FA,TA); mesh_to_cgal_triangle_list(VB,FB,TB); // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5 // Create the corresponding vector of bounding boxes std::vector A_boxes,B_boxes; const auto box_up = [](Triangles & T, std::vector & boxes) -> void { boxes.reserve(T.size()); for ( TrianglesIterator tit = T.begin(); tit != T.end(); ++tit) { boxes.push_back(Box(tit->bbox(), tit)); } }; box_up(TA,A_boxes); box_up(TB,B_boxes); OffendingMap offendingA,offendingB; //EdgeMap edge2facesA,edge2facesB; std::list lIF; const auto cb = [&](const Box &a, const Box &b) -> void { using namespace std; // index in F and T int fa = a.handle()-TA.begin(); int fb = b.handle()-TB.begin(); const Triangle_3 & A = *a.handle(); const Triangle_3 & B = *b.handle(); if(CGAL::do_intersect(A,B)) { // There was an intersection lIF.push_back(fa); lIF.push_back(fb); if(params.first_only) { throw IGL_FIRST_HIT_EXCEPTION; } if(!params.detect_only) { CGAL::Object result = CGAL::intersection(A,B); push_result(FA,fa,fb,result,offendingA); push_result(FB,fb,fa,result,offendingB); } } }; try{ CGAL::box_intersection_d( A_boxes.begin(), A_boxes.end(), B_boxes.begin(), B_boxes.end(), cb); }catch(int e) { // Rethrow if not FIRST_HIT_EXCEPTION if(e != IGL_FIRST_HIT_EXCEPTION) { throw e; } // Otherwise just fall through } // Convert lIF to Eigen matrix assert(lIF.size()%2 == 0); IF.resize(lIF.size()/2,2); { int i=0; for( list::const_iterator ifit = lIF.begin(); ifit!=lIF.end(); ) { IF(i,0) = (*ifit); ifit++; IF(i,1) = (*ifit); ifit++; i++; } } if(!params.detect_only) { // Obsolete, now remesh_intersections expects a single mesh // remesh_intersections(VA,FA,TA,offendingA,VVA,FFA,JA,IMA); // remesh_intersections(VB,FB,TB,offendingB,VVB,FFB,JB,IMB); // Combine mesh and offending maps DerivedVA VAB(VA.rows()+VB.rows(),3); VAB< 0; } } } } template < typename DerivedVA, typename DerivedFA, typename DerivedVB, typename DerivedFB, typename DerivedIF, typename DerivedVVAB, typename DerivedFFAB, typename DerivedJAB, typename DerivedIMAB> IGL_INLINE bool igl::copyleft::cgal::intersect_other( const Eigen::PlainObjectBase & VA, const Eigen::PlainObjectBase & FA, const Eigen::PlainObjectBase & VB, const Eigen::PlainObjectBase & FB, const RemeshSelfIntersectionsParam & params, Eigen::PlainObjectBase & IF, Eigen::PlainObjectBase & VVAB, Eigen::PlainObjectBase & FFAB, Eigen::PlainObjectBase & JAB, Eigen::PlainObjectBase & IMAB) { if(params.detect_only) { return intersect_other_helper (VA,FA,VB,FB,params,IF,VVAB,FFAB,JAB,IMAB); }else { return intersect_other_helper (VA,FA,VB,FB,params,IF,VVAB,FFAB,JAB,IMAB); } } IGL_INLINE bool igl::copyleft::cgal::intersect_other( const Eigen::MatrixXd & VA, const Eigen::MatrixXi & FA, const Eigen::MatrixXd & VB, const Eigen::MatrixXi & FB, const bool first_only, Eigen::MatrixXi & IF) { Eigen::MatrixXd VVAB; Eigen::MatrixXi FFAB; Eigen::VectorXi JAB,IMAB; return intersect_other( VA,FA,VB,FB,{true,first_only},IF,VVAB,FFAB,JAB,IMAB); } #ifdef IGL_STATIC_LIBRARY // Explicit template instantiation // generated by autoexplicit.sh template bool igl::copyleft::cgal::intersect_other, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); template bool igl::copyleft::cgal::intersect_other, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #endif