8#ifndef IGL_COPYLEFT_CGAL_SELFINTERSECTMESH_H
9#define IGL_COPYLEFT_CGAL_SELFINTERSECTMESH_H
11#include "CGAL_includes.hpp"
25#ifndef IGL_FIRST_HIT_EXCEPTION
26#define IGL_FIRST_HIT_EXCEPTION 10
76 typedef CGAL::Exact_intersections_tag
Itag;
82 CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator>
86 const Eigen::MatrixBase<DerivedV> &
V;
87 const Eigen::MatrixBase<DerivedF> &
F;
89 typedef typename DerivedF::Index
Index;
91 typedef std::vector<std::pair<Index, CGAL::Object>>
ObjectList;
100 typedef std::pair<Index,Index>
EMK;
103 typedef std::vector<Index>
EMV;
107 std::vector<std::pair<TrianglesIterator, TrianglesIterator> >
128 const Eigen::MatrixBase<DerivedV> &
V,
129 const Eigen::MatrixBase<DerivedF> &
F,
131 Eigen::PlainObjectBase<DerivedVV> & VV,
132 Eigen::PlainObjectBase<DerivedFF> & FF,
133 Eigen::PlainObjectBase<DerivedIF> & IF,
134 Eigen::PlainObjectBase<DerivedJ> & J,
135 Eigen::PlainObjectBase<DerivedIM> & IM);
140 inline void mark_offensive(
const Index f);
145 inline void count_intersection(
const Index fa,
const Index fb);
156 inline bool intersect(
174 inline bool single_shared_vertex(
189 inline bool single_shared_vertex(
206 inline bool double_shared_vertex(
211 const std::vector<std::pair<Index,Index> > shared);
236 std::mutex m_offending_lock;
318 const Eigen::MatrixBase<DerivedV> &
V,
319 const Eigen::MatrixBase<DerivedF> &
F,
321 Eigen::PlainObjectBase<DerivedVV> & VV,
322 Eigen::PlainObjectBase<DerivedFF> & FF,
323 Eigen::PlainObjectBase<DerivedIF> & IF,
324 Eigen::PlainObjectBase<DerivedJ> & J,
325 Eigen::PlainObjectBase<DerivedIM> & IM):
334#ifdef IGL_SELFINTERSECTMESH_TIMING
335 const auto & tictoc = []() ->
double
342 const auto log_time = [&](
const std::string& label) ->
void{
343 std::printf(
"%50s: %0.5lf\n",
344 C_STR(
"SelfIntersectMesh." << label),tictoc());
351#ifdef IGL_SELFINTERSECTMESH_TIMING
352 log_time(
"convert_to_triangle_list");
356 std::vector<Box> boxes;
357 boxes.reserve(
T.size());
363 if (!tit->is_degenerate())
365 boxes.push_back(
Box(tit->bbox(), tit));
369 std::function<void(
const Box &a,
const Box &b)> cb =
373 std::placeholders::_1,
374 std::placeholders::_2);
375#ifdef IGL_SELFINTERSECTMESH_TIMING
376 log_time(
"box_and_bind");
379 CGAL::box_self_intersection_d(boxes.begin(), boxes.end(),cb,std::ptrdiff_t(
params.cutoff));
380#ifdef IGL_SELFINTERSECTMESH_TIMING
381 log_time(
"box_intersection_d");
394#ifdef IGL_SELFINTERSECTMESH_TIMING
395 log_time(
"resolve_intersection");
399 assert(
lIF.size()%2 == 0);
400 IF.resize(
lIF.size()/2,2);
404 typename IndexList::const_iterator ifit =
lIF.begin();
415#ifdef IGL_SELFINTERSECTMESH_TIMING
416 log_time(
"store_intersecting_face_pairs");
426 params.stitch_all,
params.slow_and_more_precise_rounding,VV,FF,J,IM);
428#ifdef IGL_SELFINTERSECTMESH_TIMING
429 log_time(
"remesh_intersection");
451 DerivedIM>::mark_offensive(
const Index f)
454 if(offending.count(f) == 0)
478 DerivedIM>::count_intersection(
482 std::lock_guard<std::mutex> guard(m_offending_lock);
487 if(params.first_only && this->count >= 1)
503inline bool igl::copyleft::cgal::SelfIntersectMesh<
512 const Triangle_3 & A,
513 const Triangle_3 & B,
518 if(!CGAL::do_intersect(A,B))
522 count_intersection(fa,fb);
523 if(!params.detect_only)
526 CGAL::Object result = CGAL::intersection(A,B);
529 std::lock_guard<std::mutex> guard(m_offending_lock);
530 offending[fa].push_back({fb, result});
531 offending[fb].push_back({fa, result});
545inline bool igl::copyleft::cgal::SelfIntersectMesh<
553 DerivedIM>::single_shared_vertex(
554 const Triangle_3 & A,
555 const Triangle_3 & B,
561 if(single_shared_vertex(A,B,fa,fb,va))
565 return single_shared_vertex(B,A,fb,fa,vb);
577inline bool igl::copyleft::cgal::SelfIntersectMesh<
585 DerivedIM>::single_shared_vertex(
586 const Triangle_3 & A,
587 const Triangle_3 & B,
597 if(CGAL::do_intersect(sa,B))
601 if(params.detect_only)
603 count_intersection(fa,fb);
606 CGAL::Object result = CGAL::intersection(sa,B);
607 if(
const Point_3 * p = CGAL::object_cast<Point_3 >(&result))
610 CGAL::Object seg = CGAL::make_object(Segment_3(
613 count_intersection(fa,fb);
614 std::lock_guard<std::mutex> guard(m_offending_lock);
615 offending[fa].push_back({fb, seg});
616 offending[fb].push_back({fa, seg});
618 }
else if(CGAL::object_cast<Segment_3 >(&result))
623 assert(test &&
"intersect should agree with do_intersect");
628 assert(
false &&
"Segment ∩ triangle neither point nor segment?");
645inline bool igl::copyleft::cgal::SelfIntersectMesh<
653 DerivedIM>::double_shared_vertex(
654 const Triangle_3 & A,
655 const Triangle_3 & B,
658 const std::vector<std::pair<Index,Index> > shared)
660 auto opposite_vertex = [](
const Index a0,
const Index a1) {
673 Index a2 = opposite_vertex(shared[0].first, shared[1].first);
674 if (! B.supporting_plane().has_on(A.vertex(a2)))
677 Index b2 = opposite_vertex(shared[0].second, shared[1].second);
679 if (
int(CGAL::coplanar_orientation(A.vertex(shared[0].first), A.vertex(shared[1].first), A.vertex(a2))) *
680 int(CGAL::coplanar_orientation(B.vertex(shared[0].second), B.vertex(shared[1].second), B.vertex(b2))) < 0)
691 const auto & opposite_point_inside = [](
692 const Triangle_3 & A,
const Index a2,
const Triangle_3 & B)
695 return CGAL::do_intersect(A.vertex(a2),B);
700 const auto & opposite_edges_intersect = [](
701 const Triangle_3 & A,
const Index va,
702 const Triangle_3 & B,
const Index vb) ->
bool
704 Segment_3 sa( A.vertex((va+1)%3), A.vertex((va+2)%3));
705 Segment_3 sb( B.vertex((vb+1)%3), B.vertex((vb+2)%3));
706 bool ret = CGAL::do_intersect(sa,sb);
711 !opposite_point_inside(A,a2,B) &&
712 !opposite_point_inside(B,b2,A) &&
713 !opposite_edges_intersect(A,shared[0].first,B,shared[1].second) &&
714 !opposite_edges_intersect(A,shared[1].first,B,shared[0].second))
720 count_intersection(fa,fb);
721 if(params.detect_only)
729 CGAL::Object result = CGAL::intersection(A,B);
732 if(CGAL::object_cast<Segment_3 >(&result))
736 "Co-planar non-degenerate triangles should intersect over triangle");
738 }
else if(CGAL::object_cast<Point_3 >(&result))
742 "Co-planar non-degenerate triangles should intersect over triangle");
747 std::lock_guard<std::mutex> guard(m_offending_lock);
748 offending[fa].push_back({fb, result});
749 offending[fb].push_back({fa, result});
755 assert(
false &&
"CGAL::intersection should agree with predicate tests");
783inline void igl::copyleft::cgal::SelfIntersectMesh<
817 std::mutex exception_mutex;
818 bool exception_fired =
false;
825 auto process_chunk = [&](
const size_t first,
const size_t last) ->
void
829 assert(last >= first);
831 for (
size_t i=first; i<last; i++)
833 if(exception_fired)
return;
834 Index fa=
T.size(), fb=
T.size();
837 fa = tri_pair.first -
T.begin();
838 fb = tri_pair.second -
T.begin();
840 assert(fa <
T.size());
841 assert(fb <
T.size());
843 if(exception_fired)
return;
849 Index comb_shared_vertices = 0;
852 Index geo_shared_vertices = 0;
854 std::vector<std::pair<Index,Index> > shared;
860 if(
F(fa,ea) ==
F(fb,eb))
862 comb_shared_vertices++;
863 shared.emplace_back(ea,eb);
864 }
else if(A.vertex(ea) == B.vertex(eb))
866 geo_shared_vertices++;
867 shared.emplace_back(ea,eb);
871 const Index total_shared_vertices =
872 comb_shared_vertices + geo_shared_vertices;
873 if(exception_fired)
return;
875 if(comb_shared_vertices== 3)
877 assert(shared.size() == 3);
882 if(total_shared_vertices== 3)
884 assert(shared.size() == 3);
889 if(total_shared_vertices == 2)
891 assert(shared.size() == 2);
900 double_shared_vertex(A,B,fa,fb,shared);
903 assert(total_shared_vertices<=1);
904 if(total_shared_vertices==1)
906 single_shared_vertex(A,B,fa,fb,shared[0].first,shared[0].second);
914 std::lock_guard<std::mutex> exception_lock(exception_mutex);
915 exception_fired =
true;
920 assert(num_threads > 0);
922 const size_t chunk_size = num_pairs / num_threads;
923 std::vector<std::thread> threads;
924 for (
size_t i=0; i<num_threads-1; i++)
926 threads.emplace_back(process_chunk, i*chunk_size, (i+1)*chunk_size);
929 process_chunk((num_threads-1)*chunk_size, num_pairs);
930 for (
auto& t : threads)
932 if (t.joinable()) t.join();
934 if(exception_fired)
throw exception;
#define C_STR(X)
Convert a stream of things to a const char *.
Definition C_STR.h:28
#define IGL_FIRST_HIT_EXCEPTION
Definition SelfIntersectMesh.h:26
Class for computing the self-intersections of a mesh.
Definition SelfIntersectMesh.h:53
CGAL::Triangle_3< Kernel > Triangle_3
Definition SelfIntersectMesh.h:68
CGAL::Segment_3< Kernel > Segment_3
Definition SelfIntersectMesh.h:67
CGAL::Tetrahedron_3< Kernel > Tetrahedron_3
Definition SelfIntersectMesh.h:70
IndexList lIF
Definition SelfIntersectMesh.h:95
CGAL::Point_2< Kernel > Point_2
Definition SelfIntersectMesh.h:72
Index count
Definition SelfIntersectMesh.h:90
void process_intersecting_boxes()
Process all of the intersecting boxes.
Definition SelfIntersectMesh.h:815
std::pair< Index, Index > EMK
Definition SelfIntersectMesh.h:100
std::vector< std::pair< TrianglesIterator, TrianglesIterator > > candidate_triangle_pairs
Definition SelfIntersectMesh.h:108
DerivedF::Index Index
Definition SelfIntersectMesh.h:89
CGAL::Box_intersection_d::Box_with_handle_d< double, 3, TrianglesIterator > Box
Definition SelfIntersectMesh.h:83
const Eigen::MatrixBase< DerivedF > & F
Definition SelfIntersectMesh.h:87
RemeshSelfIntersectionsParam params
Definition SelfIntersectMesh.h:111
Triangles T
Definition SelfIntersectMesh.h:93
CGAL::Plane_3< Kernel > Plane_3
Definition SelfIntersectMesh.h:69
const Eigen::MatrixBase< DerivedV > & V
Definition SelfIntersectMesh.h:86
std::map< EMK, EMV > EdgeMap
Definition SelfIntersectMesh.h:105
CGAL::Segment_2< Kernel > Segment_2
Definition SelfIntersectMesh.h:73
SelfIntersectMesh(const Eigen::MatrixBase< DerivedV > &V, const Eigen::MatrixBase< DerivedF > &F, const RemeshSelfIntersectionsParam ¶ms, Eigen::PlainObjectBase< DerivedVV > &VV, Eigen::PlainObjectBase< DerivedFF > &FF, Eigen::PlainObjectBase< DerivedIF > &IF, Eigen::PlainObjectBase< DerivedJ > &J, Eigen::PlainObjectBase< DerivedIM > &IM)
Constructs (VV,FF) a new mesh with self-intersections of (V,F) subdivided.
Definition SelfIntersectMesh.h:317
std::vector< std::pair< Index, CGAL::Object > > ObjectList
Definition SelfIntersectMesh.h:91
CGAL::Point_3< Kernel > Point_3
Definition SelfIntersectMesh.h:66
static void box_intersect_static(SelfIntersectMesh *SIM, const Box &a, const Box &b)
Static function that captures a SelfIntersectMesh instance to pass to cgal.
Definition SelfIntersectMesh.h:292
void box_intersect(const Box &a, const Box &b)
Callback function called during box self intersections test.
Definition SelfIntersectMesh.h:791
std::vector< Index > IndexList
Definition SelfIntersectMesh.h:94
std::vector< Triangle_3 > Triangles
Definition SelfIntersectMesh.h:78
Triangles::iterator TrianglesIterator
Definition SelfIntersectMesh.h:79
std::vector< Index > EMV
Definition SelfIntersectMesh.h:103
std::map< Index, ObjectList > offending
Definition SelfIntersectMesh.h:98
CGAL::Exact_intersections_tag Itag
Definition SelfIntersectMesh.h:76
CGAL::Triangle_2< Kernel > Triangle_2
Definition SelfIntersectMesh.h:74
Triangles::const_iterator TrianglesConstIterator
Definition SelfIntersectMesh.h:80
void remesh_intersections(const Eigen::MatrixBase< DerivedV > &V, const Eigen::MatrixBase< DerivedF > &F, const std::vector< CGAL::Triangle_3< Kernel > > &T, const std::map< typename DerivedF::Index, std::vector< std::pair< typename DerivedF::Index, CGAL::Object > > > &offending, bool stitch_all, bool slow_and_more_precise_rounding, Eigen::PlainObjectBase< DerivedVV > &VV, Eigen::PlainObjectBase< DerivedFF > &FF, Eigen::PlainObjectBase< DerivedJ > &J, Eigen::PlainObjectBase< DerivedIM > &IM)
Remesh faces according to results of intersection detection and construction (e.g.
void mesh_to_cgal_triangle_list(const Eigen::MatrixBase< DerivedV > &V, const Eigen::MatrixBase< DerivedF > &F, std::vector< CGAL::Triangle_3< Kernel > > &T)
Convert a mesh (V,F) to a list of CGAL triangles.
double get_seconds()
Current time in seconds.
void intersect(const M &A, const M &B, M &C)
Determine the intersect between two sets of coefficients using ==.
void count(const Eigen::SparseMatrix< XType > &X, const int dim, Eigen::SparseVector< SType > &S)
Count the number of non-zeros in the columns or rows of a sparse matrix.
unsigned int default_num_threads(unsigned int force_num_threads=0)
Returns the default number of threads used in libigl.
Parameters for SelfIntersectMesh, remesh_self_intersections and remesh_intersections,...
Definition RemeshSelfIntersectionsParam.h:21