#include "triangle_triangle_intersect_shared_vertex.h" #include "ray_triangle_intersect.h" #include "barycentric_coordinates.h" #include "matlab_format.h" #include #include #include #include // std::signbit #include //#define IGL_TRIANGLE_TRIANGLE_INTERSECT_SHARED_VERTEX_DEBUG #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_SHARED_VERTEX_DEBUG // CGAL::Epeck #include #warning "🐌🐌🐌🐌🐌🐌🐌🐌 Slow debug mode for igl::triangle_triangle_intersect" #endif template < typename DerivedV, typename DerivedF, typename Derivedp> IGL_INLINE bool igl::triangle_triangle_intersect_shared_vertex( const Eigen::MatrixBase & V, const Eigen::MatrixBase & F, const int f, const int sf, const int c, const Eigen::MatrixBase & p, const int g, const int sg, const typename DerivedV::Scalar epsilon) { static_assert( std::is_same::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 Point_3; typedef CGAL::Segment_3 Segment_3; typedef CGAL::Triangle_3 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 constexpr bool stinker = false; bool found_intersection = false; // If they share a vertex and intersect, then an opposite edge must // stab through the other triangle. // Using ray_triangle_intersect now, not sure we need this copy or cast Eigen::RowVector3d g0 = V.row(F(g,0)).template cast(); Eigen::RowVector3d g1 = V.row(F(g,1)).template cast(); Eigen::RowVector3d g2 = V.row(F(g,2)).template cast(); Eigen::RowVector3d fs; if(((sf+1)%3)==c) { fs = p; }else { fs = V.row(F(f,(sf+1)%3)); } Eigen::RowVector3d fd; if( ((sf+2)%3)==c ) { fd = p.template cast(); }else { fd = V.row(F(f,(sf+2)%3)).template cast(); } Eigen::RowVector3d fdir = fd - fs; double t,u,v; if(stinker) { std::cout<<"T = ["< bool { // Check if P is inside (0,0),(1,0),(0,1) triangle const auto inside_unit = []( const Eigen::RowVector2d & P) -> bool { return P(0) >= 0 && P(1) >= 0 && P(0) + P(1) <= 1; }; if(inside_unit(A) || inside_unit(B)) { return true; } const auto open_interval_contains_zero = []( const double a, const double b) -> bool { // handle case where either is 0.0 or -0.0 if(a==0 || b==0) { return false; } return std::signbit(a) != std::signbit(b); }; // Now check if the segment intersects any of the edges. // Does A-B intesect X-axis? if(open_interval_contains_zero(A(1),B(1))) { assert((A(1) - B(1)) != 0); // A and B are on opposite sides of the X-axis const double t = A(1) / (A(1) - B(1)); const double x = A(0) + t * (B(0) - A(0)); if(x >= 0 && x <= 1) { return true; } } // Does A-B intesect Y-axis? if(open_interval_contains_zero(A(0),B(0))) { assert((A(0) - B(0)) != 0); // A and B are on opposite sides of the Y-axis const double t = A(0) / (A(0) - B(0)); const double y = A(1) + t * (B(1) - A(1)); if(y >= 0 && y <= 1) { return true; } } // Does A-B intersect the line x+y=1? if(open_interval_contains_zero(A(0) + A(1) - 1.0,B(0) + B(1) - 1.0)) { assert((A(0) + A(1) - 1.0) - (B(0) + B(1) - 1.0) != 0); // A and B are on opposite sides of the line x+y=1 // x+y=1 // A(0) + t * (B(0) - A(0)) + A(1) + t * (B(1) - A(1)) = 1 // t * (B(0) - A(0) + B(1) - A(1)) = 1 - A(0) - A(1) const double t = (1 - A(0) - A(1)) / (B(0) - A(0) + B(1) - A(1)); const double y = A(1) + t * (B(1) - A(1)); if(y >= 0 && y <= 1) { return true; } } return false; }; const auto intersect_unit = [&intersect_unit_helper]( const Eigen::RowVector2d & A, const Eigen::RowVector2d & B) -> bool { #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_SHARED_VERTEX_DEBUG printf("A=[%g,%g];B=[%g,%g];\n", A(0),A(1),B(0),B(1)); #endif const bool ret = intersect_unit_helper(A,B); return ret; }; const auto point_on_plane = [&epsilon]( const Eigen::RowVector3d & p, const Eigen::RowVector3d & a, const Eigen::RowVector3d & b, const Eigen::RowVector3d & c) -> bool { const auto n = (b-a).cross(c-a); const auto d = n.dot(p-a); return std::abs(d) < epsilon*n.stableNorm(); }; //if(intersect_triangle1( // fs.data(),fdir.data(), // g0.data(),g1.data(),g2.data(), // &t,&u,&v)) bool parallel = false; if(ray_triangle_intersect( fs,fdir, g0,g1,g2, epsilon, t,u,v,parallel)) { found_intersection = t > 0.0 && t<1.0+epsilon; }else if(parallel) { if(stinker){ printf(" parallel\n"); } if(point_on_plane(fs,g0,g1,g2)) { if(stinker){ printf(" coplanar\n"); } // deal with parallel Eigen::RowVector2d s2,d2; bary(fs,g0,g1,g2,s2(0),s2(1)); bary(fd,g0,g1,g2,d2(0),d2(1)); found_intersection = intersect_unit(s2,d2); } } if(stinker){ printf(" found_intersection: %d\n",found_intersection); } if(!found_intersection) { Eigen::RowVector3d fv[3]; fv[0] = V.row(F(f,0)).template cast(); fv[1] = V.row(F(f,1)).template cast(); fv[2] = V.row(F(f,2)).template cast(); fv[c] = p.template cast(); Eigen::RowVector3d gs = V.row(F(g,(sg+1)%3)).template cast(); Eigen::RowVector3d gd = V.row(F(g,(sg+2)%3)).template cast(); Eigen::RowVector3d gdir = gd - gs; if(stinker) { std::cout<<"T = ["< 0 && t<1+epsilon; }else if(parallel) { if(stinker){ printf(" parallel2\n"); } if(point_on_plane(gs,fv[0],fv[1],fv[2])) { if(stinker){ printf(" coplanar\n"); } // deal with parallel //assert(false); Eigen::RowVector2d s2,d2; bary(gs,fv[0],fv[1],fv[2],s2(0),s2(1)); bary(gd,fv[0],fv[1],fv[2],d2(0),d2(1)); found_intersection = intersect_unit(s2,d2); } } } if(stinker){ printf(" found_intersection2: %d\n",found_intersection); } #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_SHARED_VERTEX_DEBUG if(CGAL::do_intersect(Tg,Tf)) { CGAL::Object obj = CGAL::intersection(Tg,Tf); if(const Segment_3 *iseg = CGAL::object_cast(&obj)) { printf(" ✅ sure it's a segment\n"); cgal_found_intersection = true; }else if(const Point_3 *ipoint = CGAL::object_cast(&obj)) { printf(" ❌ it's just the point.\n"); } else if(const Triangle_3 *itri = CGAL::object_cast(&obj)) { cgal_found_intersection = true; printf(" ✅ sure it's a triangle\n"); } else if(const std::vector *polyp = CGAL::object_cast< std::vector >(&obj)) { cgal_found_intersection = true; printf(" ✅ polygon\n"); }else { printf(" 🤔 da fuke?\n"); } } printf("%d,%d %s vs %s\n",f,c,found_intersection?"☠️":"✅",cgal_found_intersection?"☠️":"✅"); if(found_intersection != cgal_found_intersection) { printf("Tg = [[%g,%g,%g];[%g,%g,%g];[%g,%g,%g]];\n", CGAL::to_double(Tg.vertex(0).x()), CGAL::to_double(Tg.vertex(0).y()), CGAL::to_double(Tg.vertex(0).z()), CGAL::to_double(Tg.vertex(1).x()), CGAL::to_double(Tg.vertex(1).y()), CGAL::to_double(Tg.vertex(1).z()), CGAL::to_double(Tg.vertex(2).x()), CGAL::to_double(Tg.vertex(2).y()), CGAL::to_double(Tg.vertex(2).z())); printf("Tf = [[%g,%g,%g];[%g,%g,%g];[%g,%g,%g]];\n", CGAL::to_double(Tf.vertex(0).x()), CGAL::to_double(Tf.vertex(0).y()), CGAL::to_double(Tf.vertex(0).z()), CGAL::to_double(Tf.vertex(1).x()), CGAL::to_double(Tf.vertex(1).y()), CGAL::to_double(Tf.vertex(1).z()), CGAL::to_double(Tf.vertex(2).x()), CGAL::to_double(Tf.vertex(2).y()), CGAL::to_double(Tf.vertex(2).z())); } assert(found_intersection == cgal_found_intersection); #endif return found_intersection; } #ifdef IGL_STATIC_LIBRARY // Explicit template instantiation // generated by autoexplicit.sh template bool igl::triangle_triangle_intersect_shared_vertex, Eigen::Matrix, Eigen::Block const, 1, -1, false> >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, int, Eigen::MatrixBase const, 1, -1, false> > const&, int, int, Eigen::Matrix::Scalar); template bool igl::triangle_triangle_intersect_shared_vertex, Eigen::Matrix, Eigen::Matrix >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, int, Eigen::MatrixBase > const&, int, int, Eigen::Matrix::Scalar); template bool igl::triangle_triangle_intersect_shared_vertex, Eigen::Matrix, Eigen::Block, 1, -1, false> >(Eigen::MatrixBase > const&, Eigen::MatrixBase > const&, int, int, int, Eigen::MatrixBase, 1, -1, false> > const&, int, int, Eigen::Matrix::Scalar); #endif