triangle_triangle_intersect.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #include "triangle_triangle_intersect.h"
  2. #include "triangle_triangle_intersect_shared_edge.h"
  3. #include "triangle_triangle_intersect_shared_vertex.h"
  4. #include "tri_tri_intersect.h"
  5. #include <Eigen/Geometry>
  6. #include <stdio.h>
  7. #include <igl/unique_edge_map.h>
  8. #include <igl/barycentric_coordinates.h>
  9. #include <unordered_map>
  10. //#define IGL_TRIANGLE_TRIANGLE_INTERSECT_DEBUG
  11. #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_DEBUG
  12. // CGAL::Epeck
  13. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  14. #warning "🐌🐌🐌🐌🐌🐌🐌🐌 Slow debug mode for igl::triangle_triangle_intersect"
  15. #endif
  16. template <
  17. typename DerivedV,
  18. typename DerivedF,
  19. typename DerivedE,
  20. typename DerivedEMAP,
  21. typename DerivedEF,
  22. typename Derivedp>
  23. IGL_INLINE bool igl::triangle_triangle_intersect(
  24. const Eigen::MatrixBase<DerivedV> & V,
  25. const Eigen::MatrixBase<DerivedF> & F,
  26. const Eigen::MatrixBase<DerivedE> & E,
  27. const Eigen::MatrixBase<DerivedEMAP> & EMAP,
  28. const Eigen::MatrixBase<DerivedEF> & EF,
  29. const int f,
  30. const int c,
  31. const Eigen::MatrixBase<Derivedp> & p,
  32. const int g)
  33. {
  34. static_assert(
  35. std::is_same<typename DerivedV::Scalar,typename Derivedp::Scalar>::value,
  36. "V and p should have same Scalar type");
  37. assert(V.cols() == 3);
  38. assert(p.cols() == 3);
  39. #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_DEBUG
  40. using Kernel = CGAL::Epeck;
  41. typedef CGAL::Point_3<Kernel> Point_3;
  42. typedef CGAL::Segment_3<Kernel> Segment_3;
  43. typedef CGAL::Triangle_3<Kernel> Triangle_3;
  44. bool cgal_found_intersection = false;
  45. Point_3 Vg[3];
  46. Point_3 Vf[3];
  47. for(int i = 0;i<3;i++)
  48. {
  49. Vg[i] = Point_3(V(F(g,i),0),V(F(g,i),1),V(F(g,i),2));
  50. if(i == c)
  51. {
  52. Vf[i] = Point_3(p(0),p(1),p(2));
  53. }else
  54. {
  55. Vf[i] = Point_3(V(F(f,i),0),V(F(f,i),1),V(F(f,i),2));
  56. }
  57. }
  58. Triangle_3 Tg(Vg[0],Vg[1],Vg[2]);
  59. Triangle_3 Tf(Vf[0],Vf[1],Vf[2]);
  60. #endif
  61. // I'm leaving this debug printing stuff in for a bit until I trust this
  62. // better.
  63. constexpr bool stinker = false;
  64. //const bool stinker = (f==1492 && g==1554);
  65. if(stinker) { printf("👀\n"); }
  66. bool found_intersection = false;
  67. // So edge opposite F(f,c) is the outer edge.
  68. const bool share_edge_opposite_c = [&]()
  69. {
  70. const int o = EMAP(f + c*F.rows());
  71. return (EF(o,0) == f && EF(o,1) == g) || (EF(o,1) == f && EF(o,0) == g);
  72. }();
  73. const int o = EMAP(f + c*F.rows());
  74. // Do they share the edge opposite c?
  75. if(share_edge_opposite_c)
  76. {
  77. if(stinker) { printf("⚠️ shares an edge\n"); }
  78. found_intersection = triangle_triangle_intersect_shared_edge(V,F,f,c,p,g,1e-8);
  79. }else
  80. {
  81. if(stinker) { printf("does not share an edge\n"); }
  82. // Do they share a vertex?
  83. int sf,sg;
  84. bool found_shared_vertex = false;
  85. for(sf = 0;sf<3;sf++)
  86. {
  87. if(sf == c){ continue;}
  88. for(sg = 0;sg<3;sg++)
  89. {
  90. if(F(f,sf) == F(g,sg))
  91. {
  92. found_shared_vertex = true;
  93. break;
  94. }
  95. }
  96. if(found_shared_vertex) { break;}
  97. }
  98. if(found_shared_vertex)
  99. {
  100. if(stinker) { printf("⚠️ shares a vertex\n"); }
  101. found_intersection =
  102. triangle_triangle_intersect_shared_vertex(V,F,f,sf,c,p,g,sg,1e-14);
  103. }else
  104. {
  105. bool coplanar;
  106. Eigen::RowVector3d i1,i2;
  107. found_intersection =
  108. igl::tri_tri_overlap_test_3d(
  109. V.row(F(g,0)).template cast<double>(),
  110. V.row(F(g,1)).template cast<double>(),
  111. V.row(F(g,2)).template cast<double>(),
  112. p.template cast<double>(),
  113. V.row(F(f,(c+1)%3)).template cast<double>(),
  114. V.row(F(f,(c+2)%3)).template cast<double>()) &&
  115. igl::tri_tri_intersection_test_3d(
  116. V.row(F(g,0)).template cast<double>(),
  117. V.row(F(g,1)).template cast<double>(),
  118. V.row(F(g,2)).template cast<double>(),
  119. p.template cast<double>(),
  120. V.row(F(f,(c+1)%3)).template cast<double>(),
  121. V.row(F(f,(c+2)%3)).template cast<double>(),
  122. coplanar,
  123. i1,i2);
  124. if(stinker) { printf("tri_tri_intersection_test_3d says %s\n",found_intersection?"☠️":"✅"); }
  125. #ifdef IGL_TRIANGLE_TRIANGLE_INTERSECT_DEBUG
  126. if(CGAL::do_intersect(Tg,Tf))
  127. {
  128. cgal_found_intersection = true;
  129. printf(" ✅ sure it's anything\n");
  130. }
  131. assert(found_intersection == cgal_found_intersection);
  132. #endif
  133. }
  134. }
  135. if(stinker) { printf("%s\n",found_intersection?"☠️":"✅"); }
  136. return found_intersection;
  137. }
  138. template <
  139. typename DerivedV,
  140. typename DerivedF,
  141. typename DerivedIF,
  142. typename DerivedEV,
  143. typename DerivedEE>
  144. void igl::triangle_triangle_intersect(
  145. const Eigen::MatrixBase<DerivedV> & V1,
  146. const Eigen::MatrixBase<DerivedF> & F1,
  147. const Eigen::MatrixBase<DerivedV> & V2,
  148. const Eigen::MatrixBase<DerivedF> & F2,
  149. const Eigen::MatrixBase<DerivedIF> & IF,
  150. Eigen::PlainObjectBase<DerivedEV> & EV,
  151. Eigen::PlainObjectBase<DerivedEE> & EE)
  152. {
  153. using Scalar = typename DerivedEV::Scalar;
  154. using RowVector3S = Eigen::Matrix<Scalar,1,3>;
  155. // We were promised that IF is a list of non-coplanar non-degenerately
  156. // intersecting triangle pairs. This implies that the set of intersection is a
  157. // line-segment whose endpoints are defined by edge-triangle intersections.
  158. //
  159. // Each edge-triangle intersection will be stored in a map (e,f)
  160. //
  161. std::unordered_map<std::int64_t,int> uf_to_ev;
  162. Eigen::VectorXi EMAP1;
  163. Eigen::MatrixXi uE1;
  164. {
  165. Eigen::VectorXi uEE,uEC;
  166. Eigen::MatrixXi E;
  167. igl::unique_edge_map(F1,E,uE1,EMAP1,uEE,uEC);
  168. }
  169. Eigen::VectorXi EMAP2_cpy;
  170. Eigen::MatrixXi uE2_cpy;
  171. const bool self = &F1 == &F2;
  172. if(!self)
  173. {
  174. Eigen::VectorXi uEE,uEC;
  175. Eigen::MatrixXi E;
  176. igl::unique_edge_map(F2,E,uE2_cpy,EMAP2_cpy,uEE,uEC);
  177. }
  178. const Eigen::VectorXi & EMAP2 = self?EMAP1:EMAP2_cpy;
  179. const Eigen::MatrixXi & uE2 = self?uE1:uE2_cpy;
  180. int num_ev = 0;
  181. EE.resize(IF.rows(),2);
  182. for(int i = 0; i<IF.rows(); i++)
  183. {
  184. // Just try all 6 edges
  185. Eigen::Matrix<double,6,6> B;
  186. Eigen::Matrix<double,6,3> X;
  187. Eigen::Matrix<int,6,2> uf;
  188. for(int p = 0;p<2;p++)
  189. {
  190. const auto consider_edges = [&B,&X,&uf]
  191. (const int p,
  192. const int f1,
  193. const int f2,
  194. const Eigen::MatrixBase<DerivedV> & V1,
  195. const Eigen::MatrixBase<DerivedF> & F1,
  196. const Eigen::VectorXi & EMAP1,
  197. const Eigen::MatrixXi & uE1,
  198. const Eigen::MatrixBase<DerivedV> & V2,
  199. const Eigen::MatrixBase<DerivedF> & F2)
  200. {
  201. for(int e1 = 0;e1<3;e1++)
  202. {
  203. // intersect edge (ij) opposite vertex F(f1,e1) with triangle ABC of F(f2,:)
  204. const int u1 = EMAP1(f1 +(EMAP1.size()/3)*e1);
  205. uf.row(p*3+e1) << u1,f2;
  206. const int i = uE1(u1,0);
  207. const int j = uE1(u1,1);
  208. // Just copy.
  209. const RowVector3S Vi = V1.row(i);
  210. const RowVector3S Vj = V1.row(j);
  211. const RowVector3S VA = V2.row(F2(f2,0));
  212. const RowVector3S VB = V2.row(F2(f2,1));
  213. const RowVector3S VC = V2.row(F2(f2,2));
  214. // Find intersection of line (Vi,Vj) with plane of triangle (A,B,C)
  215. const RowVector3S n = (VB-VA).template head<3>().cross((VC-VA).template head<3>());
  216. const Scalar d = n.dot(VA);
  217. const Scalar t = (d - n.dot(Vi))/(n.dot(Vj-Vi));
  218. const RowVector3S x = Vi + t*(Vj-Vi);
  219. // Get barycenteric coordinates (possibly negative of X)
  220. RowVector3S b1;
  221. igl::barycentric_coordinates(x,VA,VB,VC,b1);
  222. B.row(p*3+e1).head<3>() = b1;
  223. RowVector3S b2;
  224. igl::barycentric_coordinates(x,
  225. V1.row(F1(f1,0)).template head<3>().eval(),
  226. V1.row(F1(f1,1)).template head<3>().eval(),
  227. V1.row(F1(f1,2)).template head<3>().eval(),
  228. b2);
  229. B.row(p*3+e1).tail<3>() = b2;
  230. X.row(p*3+e1) = x;
  231. }
  232. };
  233. const int f1 = IF(i,p);
  234. const int f2 = IF(i,(p+1)%2);
  235. consider_edges(p,f1,f2,
  236. p==0? V1:V2,
  237. p==0? F1:F2,
  238. p==0?EMAP1:EMAP2,
  239. p==0? uE1:uE2,
  240. p==0? V2:V1,
  241. p==0? F2:F1);
  242. }
  243. // Find the two rows in B with the largest-smallest element
  244. int j1,j2;
  245. {
  246. double b_min1 = -std::numeric_limits<double>::infinity();
  247. double b_min2 = -std::numeric_limits<double>::infinity();
  248. for(int j = 0;j<6;j++)
  249. {
  250. // It's not clear that using barycentric coordinates is better than
  251. // point_simplex distance (though that requires inequalities).
  252. const double bminj = B.row(j).minCoeff();
  253. if(bminj > b_min1)
  254. {
  255. b_min2 = b_min1;
  256. j2 = j1;
  257. b_min1 = bminj;
  258. j1 = j;
  259. }else if(bminj > b_min2)
  260. {
  261. b_min2 = bminj;
  262. j2 = j;
  263. }
  264. }
  265. }
  266. const auto append_or_find = [&](
  267. int p, int u, int f, const RowVector3S & x,
  268. std::unordered_map<std::int64_t,int> & uf_to_ev)->int
  269. {
  270. const std::int64_t key = (std::int64_t)u + ((std::int64_t)f << 32) + ((std::int64_t)p << 63);
  271. if(uf_to_ev.find(key) == uf_to_ev.end())
  272. {
  273. if(num_ev == EV.rows())
  274. {
  275. EV.conservativeResize(2*EV.rows()+1,3);
  276. }
  277. EV.row(num_ev) = x;
  278. uf_to_ev[key] = num_ev;
  279. num_ev++;
  280. }
  281. return uf_to_ev[key];
  282. };
  283. EE.row(i) <<
  284. append_or_find(j1>=3,uf(j1,0),uf(j1,1),X.row(j1),uf_to_ev),
  285. append_or_find(j2>=3,uf(j2,0),uf(j2,1),X.row(j2),uf_to_ev);
  286. }
  287. EV.conservativeResize(num_ev,3);
  288. }
  289. template <
  290. typename DerivedV,
  291. typename DerivedF,
  292. typename DerivedIF,
  293. typename DerivedEV,
  294. typename DerivedEE>
  295. void igl::triangle_triangle_intersect(
  296. const Eigen::MatrixBase<DerivedV> & V,
  297. const Eigen::MatrixBase<DerivedF> & F,
  298. const Eigen::MatrixBase<DerivedIF> & IF,
  299. Eigen::PlainObjectBase<DerivedEV> & EV,
  300. Eigen::PlainObjectBase<DerivedEE> & EE)
  301. {
  302. // overload will take care of detecting reference equality
  303. return triangle_triangle_intersect(V,F,V,F,IF,EV,EE);
  304. }
  305. #ifdef IGL_STATIC_LIBRARY
  306. // Explicit template instantiation
  307. // generated by autoexplicit.sh
  308. 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> >&);
  309. // generated by autoexplicit.sh
  310. 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> >&);
  311. 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);
  312. 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);
  313. #endif