| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- #include "triangle_triangle_intersect.h"
- #include "triangle_triangle_intersect_shared_edge.h"
- #include "triangle_triangle_intersect_shared_vertex.h"
- #include "tri_tri_intersect.h"
- #include <Eigen/Geometry>
- #include <stdio.h>
- #include <igl/unique_edge_map.h>
- #include <igl/barycentric_coordinates.h>
- #include <unordered_map>
- //#define IGL_TRIANGLE_TRIANGLE_INTERSECT_DEBUG
- #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_DEBUG
- // CGAL::Epeck
- #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
- #warning "🐌🐌🐌🐌🐌🐌🐌🐌 Slow debug mode for igl::triangle_triangle_intersect"
- #endif
- template <
- typename DerivedV,
- typename DerivedF,
- typename DerivedE,
- typename DerivedEMAP,
- typename DerivedEF,
- typename Derivedp>
- IGL_INLINE bool igl::triangle_triangle_intersect(
- const Eigen::MatrixBase<DerivedV> & V,
- const Eigen::MatrixBase<DerivedF> & F,
- const Eigen::MatrixBase<DerivedE> & E,
- const Eigen::MatrixBase<DerivedEMAP> & EMAP,
- const Eigen::MatrixBase<DerivedEF> & EF,
- const int f,
- const int c,
- const Eigen::MatrixBase<Derivedp> & p,
- const int g)
- {
- static_assert(
- std::is_same<typename DerivedV::Scalar,typename Derivedp::Scalar>::value,
- "V and p should have same Scalar type");
- assert(V.cols() == 3);
- assert(p.cols() == 3);
- #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_DEBUG
- using Kernel = CGAL::Epeck;
- typedef CGAL::Point_3<Kernel> Point_3;
- typedef CGAL::Segment_3<Kernel> Segment_3;
- typedef CGAL::Triangle_3<Kernel> Triangle_3;
- bool cgal_found_intersection = false;
- Point_3 Vg[3];
- Point_3 Vf[3];
- for(int i = 0;i<3;i++)
- {
- Vg[i] = Point_3(V(F(g,i),0),V(F(g,i),1),V(F(g,i),2));
- if(i == c)
- {
- Vf[i] = Point_3(p(0),p(1),p(2));
- }else
- {
- Vf[i] = Point_3(V(F(f,i),0),V(F(f,i),1),V(F(f,i),2));
- }
- }
- Triangle_3 Tg(Vg[0],Vg[1],Vg[2]);
- Triangle_3 Tf(Vf[0],Vf[1],Vf[2]);
- #endif
- // I'm leaving this debug printing stuff in for a bit until I trust this
- // better.
- constexpr bool stinker = false;
- //const bool stinker = (f==1492 && g==1554);
- if(stinker) { printf("👀\n"); }
- bool found_intersection = false;
- // So edge opposite F(f,c) is the outer edge.
- const bool share_edge_opposite_c = [&]()
- {
- const int o = EMAP(f + c*F.rows());
- return (EF(o,0) == f && EF(o,1) == g) || (EF(o,1) == f && EF(o,0) == g);
- }();
- const int o = EMAP(f + c*F.rows());
- // Do they share the edge opposite c?
- if(share_edge_opposite_c)
- {
- if(stinker) { printf("⚠️ shares an edge\n"); }
- found_intersection = triangle_triangle_intersect_shared_edge(V,F,f,c,p,g,1e-8);
- }else
- {
- if(stinker) { printf("does not share an edge\n"); }
- // Do they share a vertex?
- int sf,sg;
- bool found_shared_vertex = false;
- for(sf = 0;sf<3;sf++)
- {
- if(sf == c){ continue;}
- for(sg = 0;sg<3;sg++)
- {
- if(F(f,sf) == F(g,sg))
- {
- found_shared_vertex = true;
- break;
- }
- }
- if(found_shared_vertex) { break;}
- }
- if(found_shared_vertex)
- {
- if(stinker) { printf("⚠️ shares a vertex\n"); }
- found_intersection =
- triangle_triangle_intersect_shared_vertex(V,F,f,sf,c,p,g,sg,1e-14);
- }else
- {
- bool coplanar;
- Eigen::RowVector3d i1,i2;
- found_intersection =
- igl::tri_tri_overlap_test_3d(
- V.row(F(g,0)).template cast<double>(),
- V.row(F(g,1)).template cast<double>(),
- V.row(F(g,2)).template cast<double>(),
- p.template cast<double>(),
- V.row(F(f,(c+1)%3)).template cast<double>(),
- V.row(F(f,(c+2)%3)).template cast<double>()) &&
- igl::tri_tri_intersection_test_3d(
- V.row(F(g,0)).template cast<double>(),
- V.row(F(g,1)).template cast<double>(),
- V.row(F(g,2)).template cast<double>(),
- p.template cast<double>(),
- V.row(F(f,(c+1)%3)).template cast<double>(),
- V.row(F(f,(c+2)%3)).template cast<double>(),
- coplanar,
- i1,i2);
- if(stinker) { printf("tri_tri_intersection_test_3d says %s\n",found_intersection?"☠️":"✅"); }
- #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_DEBUG
- if(CGAL::do_intersect(Tg,Tf))
- {
- cgal_found_intersection = true;
- printf(" ✅ sure it's anything\n");
- }
- assert(found_intersection == cgal_found_intersection);
- #endif
- }
- }
- if(stinker) { printf("%s\n",found_intersection?"☠️":"✅"); }
- return found_intersection;
- }
- template <
- typename DerivedV,
- typename DerivedF,
- typename DerivedIF,
- typename DerivedEV,
- typename DerivedEE>
- void igl::triangle_triangle_intersect(
- const Eigen::MatrixBase<DerivedV> & V1,
- const Eigen::MatrixBase<DerivedF> & F1,
- const Eigen::MatrixBase<DerivedV> & V2,
- const Eigen::MatrixBase<DerivedF> & F2,
- const Eigen::MatrixBase<DerivedIF> & IF,
- Eigen::PlainObjectBase<DerivedEV> & EV,
- Eigen::PlainObjectBase<DerivedEE> & EE)
- {
- using Scalar = typename DerivedEV::Scalar;
- using RowVector3S = Eigen::Matrix<Scalar,1,3>;
- // We were promised that IF is a list of non-coplanar non-degenerately
- // intersecting triangle pairs. This implies that the set of intersection is a
- // line-segment whose endpoints are defined by edge-triangle intersections.
- //
- // Each edge-triangle intersection will be stored in a map (e,f)
- //
- std::unordered_map<std::int64_t,int> uf_to_ev;
- Eigen::VectorXi EMAP1;
- Eigen::MatrixXi uE1;
- {
- Eigen::VectorXi uEE,uEC;
- Eigen::MatrixXi E;
- igl::unique_edge_map(F1,E,uE1,EMAP1,uEE,uEC);
- }
- Eigen::VectorXi EMAP2_cpy;
- Eigen::MatrixXi uE2_cpy;
- const bool self = &F1 == &F2;
- if(!self)
- {
- Eigen::VectorXi uEE,uEC;
- Eigen::MatrixXi E;
- igl::unique_edge_map(F2,E,uE2_cpy,EMAP2_cpy,uEE,uEC);
- }
- const Eigen::VectorXi & EMAP2 = self?EMAP1:EMAP2_cpy;
- const Eigen::MatrixXi & uE2 = self?uE1:uE2_cpy;
- int num_ev = 0;
- EE.resize(IF.rows(),2);
- for(int i = 0; i<IF.rows(); i++)
- {
- // Just try all 6 edges
- Eigen::Matrix<double,6,6> B;
- Eigen::Matrix<double,6,3> X;
- Eigen::Matrix<int,6,2> uf;
- for(int p = 0;p<2;p++)
- {
- const auto consider_edges = [&B,&X,&uf]
- (const int p,
- const int f1,
- const int f2,
- const Eigen::MatrixBase<DerivedV> & V1,
- const Eigen::MatrixBase<DerivedF> & F1,
- const Eigen::VectorXi & EMAP1,
- const Eigen::MatrixXi & uE1,
- const Eigen::MatrixBase<DerivedV> & V2,
- const Eigen::MatrixBase<DerivedF> & F2)
- {
- for(int e1 = 0;e1<3;e1++)
- {
- // intersect edge (ij) opposite vertex F(f1,e1) with triangle ABC of F(f2,:)
- const int u1 = EMAP1(f1 +(EMAP1.size()/3)*e1);
- uf.row(p*3+e1) << u1,f2;
- const int i = uE1(u1,0);
- const int j = uE1(u1,1);
- // Just copy.
- const RowVector3S Vi = V1.row(i);
- const RowVector3S Vj = V1.row(j);
- const RowVector3S VA = V2.row(F2(f2,0));
- const RowVector3S VB = V2.row(F2(f2,1));
- const RowVector3S VC = V2.row(F2(f2,2));
- // Find intersection of line (Vi,Vj) with plane of triangle (A,B,C)
- const RowVector3S n = (VB-VA).template head<3>().cross((VC-VA).template head<3>());
- const Scalar d = n.dot(VA);
- const Scalar t = (d - n.dot(Vi))/(n.dot(Vj-Vi));
- const RowVector3S x = Vi + t*(Vj-Vi);
-
- // Get barycenteric coordinates (possibly negative of X)
- RowVector3S b1;
- igl::barycentric_coordinates(x,VA,VB,VC,b1);
- B.row(p*3+e1).head<3>() = b1;
- RowVector3S b2;
- igl::barycentric_coordinates(x,
- V1.row(F1(f1,0)).template head<3>().eval(),
- V1.row(F1(f1,1)).template head<3>().eval(),
- V1.row(F1(f1,2)).template head<3>().eval(),
- b2);
- B.row(p*3+e1).tail<3>() = b2;
- X.row(p*3+e1) = x;
- }
- };
- const int f1 = IF(i,p);
- const int f2 = IF(i,(p+1)%2);
- consider_edges(p,f1,f2,
- p==0? V1:V2,
- p==0? F1:F2,
- p==0?EMAP1:EMAP2,
- p==0? uE1:uE2,
- p==0? V2:V1,
- p==0? F2:F1);
- }
- // Find the two rows in B with the largest-smallest element
- int j1,j2;
- {
- double b_min1 = -std::numeric_limits<double>::infinity();
- double b_min2 = -std::numeric_limits<double>::infinity();
- for(int j = 0;j<6;j++)
- {
- // It's not clear that using barycentric coordinates is better than
- // point_simplex distance (though that requires inequalities).
- const double bminj = B.row(j).minCoeff();
- if(bminj > b_min1)
- {
- b_min2 = b_min1;
- j2 = j1;
- b_min1 = bminj;
- j1 = j;
- }else if(bminj > b_min2)
- {
- b_min2 = bminj;
- j2 = j;
- }
- }
- }
- const auto append_or_find = [&](
- int p, int u, int f, const RowVector3S & x,
- std::unordered_map<std::int64_t,int> & uf_to_ev)->int
- {
- const std::int64_t key = (std::int64_t)u + ((std::int64_t)f << 32) + ((std::int64_t)p << 63);
- if(uf_to_ev.find(key) == uf_to_ev.end())
- {
- if(num_ev == EV.rows())
- {
- EV.conservativeResize(2*EV.rows()+1,3);
- }
- EV.row(num_ev) = x;
- uf_to_ev[key] = num_ev;
- num_ev++;
- }
- return uf_to_ev[key];
- };
- EE.row(i) <<
- append_or_find(j1>=3,uf(j1,0),uf(j1,1),X.row(j1),uf_to_ev),
- append_or_find(j2>=3,uf(j2,0),uf(j2,1),X.row(j2),uf_to_ev);
- }
- EV.conservativeResize(num_ev,3);
- }
- template <
- typename DerivedV,
- typename DerivedF,
- typename DerivedIF,
- typename DerivedEV,
- typename DerivedEE>
- void igl::triangle_triangle_intersect(
- const Eigen::MatrixBase<DerivedV> & V,
- const Eigen::MatrixBase<DerivedF> & F,
- const Eigen::MatrixBase<DerivedIF> & IF,
- Eigen::PlainObjectBase<DerivedEV> & EV,
- Eigen::PlainObjectBase<DerivedEE> & EE)
- {
- // overload will take care of detecting reference equality
- return triangle_triangle_intersect(V,F,V,F,IF,EV,EE);
- }
- #ifdef IGL_STATIC_LIBRARY
- // Explicit template instantiation
- // generated by autoexplicit.sh
- template void igl::triangle_triangle_intersect<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
- // generated by autoexplicit.sh
- template void igl::triangle_triangle_intersect<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
- template bool igl::triangle_triangle_intersect<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1, -1, false> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1, -1, false> > const&, int);
- template bool igl::triangle_triangle_intersect<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, int);
- #endif
|