triangle_triangle_intersect_shared_vertex.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #include "triangle_triangle_intersect_shared_vertex.h"
  2. #include "ray_triangle_intersect.h"
  3. #include "barycentric_coordinates.h"
  4. #include "matlab_format.h"
  5. #include <Eigen/Geometry>
  6. #include <iostream>
  7. #include <iomanip>
  8. #include <stdio.h>
  9. // std::signbit
  10. #include <cmath>
  11. //#define IGL_TRIANGLE_TRIANGLE_INTERSECT_SHARED_VERTEX_DEBUG
  12. #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_SHARED_VERTEX_DEBUG
  13. // CGAL::Epeck
  14. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  15. #warning "🐌🐌🐌🐌🐌🐌🐌🐌 Slow debug mode for igl::triangle_triangle_intersect"
  16. #endif
  17. template <
  18. typename DerivedV,
  19. typename DerivedF,
  20. typename Derivedp>
  21. IGL_INLINE bool igl::triangle_triangle_intersect_shared_vertex(
  22. const Eigen::MatrixBase<DerivedV> & V,
  23. const Eigen::MatrixBase<DerivedF> & F,
  24. const int f,
  25. const int sf,
  26. const int c,
  27. const Eigen::MatrixBase<Derivedp> & p,
  28. const int g,
  29. const int sg,
  30. const typename DerivedV::Scalar epsilon)
  31. {
  32. static_assert(
  33. std::is_same<typename DerivedV::Scalar,typename Derivedp::Scalar>::value,
  34. "V and p should have same Scalar type");
  35. assert(V.cols() == 3);
  36. assert(p.cols() == 3);
  37. #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_DEBUG
  38. using Kernel = CGAL::Epeck;
  39. typedef CGAL::Point_3<Kernel> Point_3;
  40. typedef CGAL::Segment_3<Kernel> Segment_3;
  41. typedef CGAL::Triangle_3<Kernel> Triangle_3;
  42. bool cgal_found_intersection = false;
  43. Point_3 Vg[3];
  44. Point_3 Vf[3];
  45. for(int i = 0;i<3;i++)
  46. {
  47. Vg[i] = Point_3(V(F(g,i),0),V(F(g,i),1),V(F(g,i),2));
  48. if(i == c)
  49. {
  50. Vf[i] = Point_3(p(0),p(1),p(2));
  51. }else
  52. {
  53. Vf[i] = Point_3(V(F(f,i),0),V(F(f,i),1),V(F(f,i),2));
  54. }
  55. }
  56. Triangle_3 Tg(Vg[0],Vg[1],Vg[2]);
  57. Triangle_3 Tf(Vf[0],Vf[1],Vf[2]);
  58. #endif
  59. constexpr bool stinker = false;
  60. bool found_intersection = false;
  61. // If they share a vertex and intersect, then an opposite edge must
  62. // stab through the other triangle.
  63. // Using ray_triangle_intersect now, not sure we need this copy or cast
  64. Eigen::RowVector3d g0 = V.row(F(g,0)).template cast<double>();
  65. Eigen::RowVector3d g1 = V.row(F(g,1)).template cast<double>();
  66. Eigen::RowVector3d g2 = V.row(F(g,2)).template cast<double>();
  67. Eigen::RowVector3d fs;
  68. if(((sf+1)%3)==c)
  69. {
  70. fs = p;
  71. }else
  72. {
  73. fs = V.row(F(f,(sf+1)%3));
  74. }
  75. Eigen::RowVector3d fd;
  76. if( ((sf+2)%3)==c )
  77. {
  78. fd = p.template cast<double>();
  79. }else
  80. {
  81. fd = V.row(F(f,(sf+2)%3)).template cast<double>();
  82. }
  83. Eigen::RowVector3d fdir = fd - fs;
  84. double t,u,v;
  85. if(stinker)
  86. {
  87. std::cout<<"T = ["<<g0<<";" <<g1<<";"<<g2<<"];"<<std::endl;
  88. std::cout<<"src = [" <<fs<<"];"<<std::endl;
  89. std::cout<<"dir = [" <<fdir<<"];"<<std::endl;
  90. }
  91. // p = (1-u-v)*a + u*b + v*c
  92. const auto bary = [](
  93. const Eigen::RowVector3d & p,
  94. const Eigen::RowVector3d & a,
  95. const Eigen::RowVector3d & b,
  96. const Eigen::RowVector3d & c,
  97. double & u,
  98. double & v)
  99. {
  100. const auto v0 = (b-a).eval();
  101. const auto v1 = (c-a).eval();
  102. const auto v2 = (p-a).eval();
  103. const double d00 = v0.dot(v0);
  104. const double d01 = v0.dot(v1);
  105. const double d11 = v1.dot(v1);
  106. const double d20 = v2.dot(v0);
  107. const double d21 = v2.dot(v1);
  108. const double denom = d00 * d11 - d01 * d01;
  109. u = (d11 * d20 - d01 * d21) / denom;
  110. v = (d00 * d21 - d01 * d20) / denom;
  111. // Equivalent:
  112. //Eigen::RowVector3d l;
  113. //igl::barycentric_coordinates(p,a,b,c,l);
  114. //u = l(1); v = l(2);
  115. };
  116. // Does the segment (A,B) intersect the triangle (0,0),(1,0),(0,1)?
  117. const auto intersect_unit_helper = [](
  118. const Eigen::RowVector2d & A,
  119. const Eigen::RowVector2d & B) -> bool
  120. {
  121. // Check if P is inside (0,0),(1,0),(0,1) triangle
  122. const auto inside_unit = []( const Eigen::RowVector2d & P) -> bool
  123. {
  124. return P(0) >= 0 && P(1) >= 0 && P(0) + P(1) <= 1;
  125. };
  126. if(inside_unit(A) || inside_unit(B))
  127. {
  128. return true;
  129. }
  130. const auto open_interval_contains_zero = [](
  131. const double a, const double b) -> bool
  132. {
  133. // handle case where either is 0.0 or -0.0
  134. if(a==0 || b==0) { return false; }
  135. return std::signbit(a) != std::signbit(b);
  136. };
  137. // Now check if the segment intersects any of the edges.
  138. // Does A-B intesect X-axis?
  139. if(open_interval_contains_zero(A(1),B(1)))
  140. {
  141. assert((A(1) - B(1)) != 0);
  142. // A and B are on opposite sides of the X-axis
  143. const double t = A(1) / (A(1) - B(1));
  144. const double x = A(0) + t * (B(0) - A(0));
  145. if(x >= 0 && x <= 1)
  146. {
  147. return true;
  148. }
  149. }
  150. // Does A-B intesect Y-axis?
  151. if(open_interval_contains_zero(A(0),B(0)))
  152. {
  153. assert((A(0) - B(0)) != 0);
  154. // A and B are on opposite sides of the Y-axis
  155. const double t = A(0) / (A(0) - B(0));
  156. const double y = A(1) + t * (B(1) - A(1));
  157. if(y >= 0 && y <= 1)
  158. {
  159. return true;
  160. }
  161. }
  162. // Does A-B intersect the line x+y=1?
  163. if(open_interval_contains_zero(A(0) + A(1) - 1.0,B(0) + B(1) - 1.0))
  164. {
  165. assert((A(0) + A(1) - 1.0) - (B(0) + B(1) - 1.0) != 0);
  166. // A and B are on opposite sides of the line x+y=1
  167. // x+y=1
  168. // A(0) + t * (B(0) - A(0)) + A(1) + t * (B(1) - A(1)) = 1
  169. // t * (B(0) - A(0) + B(1) - A(1)) = 1 - A(0) - A(1)
  170. const double t = (1 - A(0) - A(1)) / (B(0) - A(0) + B(1) - A(1));
  171. const double y = A(1) + t * (B(1) - A(1));
  172. if(y >= 0 && y <= 1)
  173. {
  174. return true;
  175. }
  176. }
  177. return false;
  178. };
  179. const auto intersect_unit = [&intersect_unit_helper](
  180. const Eigen::RowVector2d & A,
  181. const Eigen::RowVector2d & B) -> bool
  182. {
  183. #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_SHARED_VERTEX_DEBUG
  184. printf("A=[%g,%g];B=[%g,%g];\n",
  185. A(0),A(1),B(0),B(1));
  186. #endif
  187. const bool ret = intersect_unit_helper(A,B);
  188. return ret;
  189. };
  190. const auto point_on_plane = [&epsilon](
  191. const Eigen::RowVector3d & p,
  192. const Eigen::RowVector3d & a,
  193. const Eigen::RowVector3d & b,
  194. const Eigen::RowVector3d & c) -> bool
  195. {
  196. const auto n = (b-a).cross(c-a);
  197. const auto d = n.dot(p-a);
  198. return std::abs(d) < epsilon*n.stableNorm();
  199. };
  200. //if(intersect_triangle1(
  201. // fs.data(),fdir.data(),
  202. // g0.data(),g1.data(),g2.data(),
  203. // &t,&u,&v))
  204. bool parallel = false;
  205. if(ray_triangle_intersect(
  206. fs,fdir,
  207. g0,g1,g2,
  208. epsilon,
  209. t,u,v,parallel))
  210. {
  211. found_intersection = t > 0.0 && t<1.0+epsilon;
  212. }else if(parallel)
  213. {
  214. if(stinker){ printf(" parallel\n"); }
  215. if(point_on_plane(fs,g0,g1,g2))
  216. {
  217. if(stinker){ printf(" coplanar\n"); }
  218. // deal with parallel
  219. Eigen::RowVector2d s2,d2;
  220. bary(fs,g0,g1,g2,s2(0),s2(1));
  221. bary(fd,g0,g1,g2,d2(0),d2(1));
  222. found_intersection = intersect_unit(s2,d2);
  223. }
  224. }
  225. if(stinker){ printf(" found_intersection: %d\n",found_intersection); }
  226. if(!found_intersection)
  227. {
  228. Eigen::RowVector3d fv[3];
  229. fv[0] = V.row(F(f,0)).template cast<double>();
  230. fv[1] = V.row(F(f,1)).template cast<double>();
  231. fv[2] = V.row(F(f,2)).template cast<double>();
  232. fv[c] = p.template cast<double>();
  233. Eigen::RowVector3d gs = V.row(F(g,(sg+1)%3)).template cast<double>();
  234. Eigen::RowVector3d gd = V.row(F(g,(sg+2)%3)).template cast<double>();
  235. Eigen::RowVector3d gdir = gd - gs;
  236. if(stinker)
  237. {
  238. std::cout<<"T = ["<<fv[0]<<";"<<fv[1]<<";"<<fv[2]<<"];"<<std::endl;
  239. std::cout<<"src = [" <<gs<<"];"<<std::endl;
  240. std::cout<<"dir = [" <<gdir<<"];"<<std::endl;
  241. }
  242. if(ray_triangle_intersect(
  243. gs,gdir,
  244. fv[0],fv[1],fv[2],
  245. epsilon,
  246. t,u,v,parallel))
  247. {
  248. found_intersection = t > 0 && t<1+epsilon;
  249. }else if(parallel)
  250. {
  251. if(stinker){ printf(" parallel2\n"); }
  252. if(point_on_plane(gs,fv[0],fv[1],fv[2]))
  253. {
  254. if(stinker){ printf(" coplanar\n"); }
  255. // deal with parallel
  256. //assert(false);
  257. Eigen::RowVector2d s2,d2;
  258. bary(gs,fv[0],fv[1],fv[2],s2(0),s2(1));
  259. bary(gd,fv[0],fv[1],fv[2],d2(0),d2(1));
  260. found_intersection = intersect_unit(s2,d2);
  261. }
  262. }
  263. }
  264. if(stinker){ printf(" found_intersection2: %d\n",found_intersection); }
  265. #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_SHARED_VERTEX_DEBUG
  266. if(CGAL::do_intersect(Tg,Tf))
  267. {
  268. CGAL::Object obj = CGAL::intersection(Tg,Tf);
  269. if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
  270. {
  271. printf(" ✅ sure it's a segment\n");
  272. cgal_found_intersection = true;
  273. }else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
  274. {
  275. printf(" ❌ it's just the point.\n");
  276. } else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
  277. {
  278. cgal_found_intersection = true;
  279. printf(" ✅ sure it's a triangle\n");
  280. } else if(const std::vector<Point_3 > *polyp =
  281. CGAL::object_cast< std::vector<Point_3 > >(&obj))
  282. {
  283. cgal_found_intersection = true;
  284. printf(" ✅ polygon\n");
  285. }else {
  286. printf(" 🤔 da fuke?\n");
  287. }
  288. }
  289. printf("%d,%d %s vs %s\n",f,c,found_intersection?"☠️":"✅",cgal_found_intersection?"☠️":"✅");
  290. if(found_intersection != cgal_found_intersection)
  291. {
  292. printf("Tg = [[%g,%g,%g];[%g,%g,%g];[%g,%g,%g]];\n",
  293. CGAL::to_double(Tg.vertex(0).x()),
  294. CGAL::to_double(Tg.vertex(0).y()),
  295. CGAL::to_double(Tg.vertex(0).z()),
  296. CGAL::to_double(Tg.vertex(1).x()),
  297. CGAL::to_double(Tg.vertex(1).y()),
  298. CGAL::to_double(Tg.vertex(1).z()),
  299. CGAL::to_double(Tg.vertex(2).x()),
  300. CGAL::to_double(Tg.vertex(2).y()),
  301. CGAL::to_double(Tg.vertex(2).z()));
  302. printf("Tf = [[%g,%g,%g];[%g,%g,%g];[%g,%g,%g]];\n",
  303. CGAL::to_double(Tf.vertex(0).x()),
  304. CGAL::to_double(Tf.vertex(0).y()),
  305. CGAL::to_double(Tf.vertex(0).z()),
  306. CGAL::to_double(Tf.vertex(1).x()),
  307. CGAL::to_double(Tf.vertex(1).y()),
  308. CGAL::to_double(Tf.vertex(1).z()),
  309. CGAL::to_double(Tf.vertex(2).x()),
  310. CGAL::to_double(Tf.vertex(2).y()),
  311. CGAL::to_double(Tf.vertex(2).z()));
  312. }
  313. assert(found_intersection == cgal_found_intersection);
  314. #endif
  315. return found_intersection;
  316. }
  317. #ifdef IGL_STATIC_LIBRARY
  318. // Explicit template instantiation
  319. // generated by autoexplicit.sh
  320. template bool igl::triangle_triangle_intersect_shared_vertex<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 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&, int, int, int, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, int, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar);
  321. template bool igl::triangle_triangle_intersect_shared_vertex<Eigen::Matrix<double, -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&, int, int, int, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, int, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar);
  322. template bool igl::triangle_triangle_intersect_shared_vertex<Eigen::Matrix<double, -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&, int, int, int, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1, -1, false> > const&, int, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar);
  323. #endif