fast_find_intersections.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2022 Vladimir S. FONOV <[email protected]>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/
  8. #include "fast_find_intersections.h"
  9. #include "AABB.h"
  10. #include "tri_tri_intersect.h"
  11. #include "triangle_triangle_intersect_shared_edge.h"
  12. #include "triangle_triangle_intersect_shared_vertex.h"
  13. #include <stdio.h>
  14. template <
  15. typename DerivedV1,
  16. typename DerivedF1,
  17. typename DerivedV2,
  18. typename DerivedF2,
  19. typename DerivedIF,
  20. typename DerivedEV,
  21. typename DerivedEE,
  22. typename DerivedEI>
  23. IGL_INLINE bool igl::fast_find_intersections(
  24. const igl::AABB<DerivedV1,3> & tree,
  25. const Eigen::MatrixBase<DerivedV1> & V1,
  26. const Eigen::MatrixBase<DerivedF1> & F1,
  27. const Eigen::MatrixBase<DerivedV2> & V2,
  28. const Eigen::MatrixBase<DerivedF2> & F2,
  29. const bool detect_only,
  30. const bool first_only,
  31. Eigen::PlainObjectBase<DerivedIF> & IF,
  32. Eigen::PlainObjectBase<DerivedEV> & EV,
  33. Eigen::PlainObjectBase<DerivedEE> & EE,
  34. Eigen::PlainObjectBase<DerivedEI> & EI)
  35. {
  36. constexpr bool stinker = false;
  37. using AABBTree=igl::AABB<DerivedV1,3>;
  38. using Scalar=typename DerivedV1::Scalar;
  39. static_assert(
  40. std::is_same<Scalar,typename DerivedV2::Scalar>::value,
  41. "V1 and V2 must have the same scalar type");
  42. static_assert(
  43. std::is_same<Scalar,typename DerivedEV::Scalar>::value,
  44. "V1 and EV must have the same scalar type");
  45. using RowVector3S=Eigen::Matrix<Scalar,1,3>;
  46. if(first_only){ assert(detect_only && "first_only must imply detect_only"); }
  47. // Determine if V1,F1 and V2,F2 point to the same data
  48. const bool self_test = (&V1 == &V2) && (&F1 == &F2);
  49. if(stinker){ printf("%s\n",self_test?"🍎&(V1,F1) == 🍎&(V2,F2)":"🍎≠🍊"); }
  50. int num_if = 0;
  51. int num_ee = 0;
  52. const auto append_intersection =
  53. [&IF,&EV,&EE,&EI,&detect_only,&num_if,&num_ee](
  54. const int f1,
  55. const int f2,
  56. const bool coplanar,
  57. const RowVector3S & v1,
  58. const RowVector3S & v2)
  59. {
  60. if(!coplanar && !detect_only)
  61. {
  62. if(num_ee >= EE.rows())
  63. {
  64. EE.conservativeResize(2*EE.rows()+1,2);
  65. EI.conservativeResize(EE.rows());
  66. EV.conservativeResize(2*EE.rows(),3);
  67. }
  68. EI(num_ee) = num_if;
  69. EV.row(2*num_ee+0) = v1;
  70. EV.row(2*num_ee+1) = v2;
  71. EE.row(num_ee) << 2*num_ee+0, 2*num_ee+1;
  72. num_ee++;
  73. }
  74. if(num_if >= IF.rows())
  75. {
  76. IF.conservativeResize(2*IF.rows()+1,2);
  77. }
  78. IF.row(num_if++) << f1,f2;
  79. };
  80. // Returns corner in ith face opposite of shared edge; -1 otherwise
  81. const auto shared_edge = [&F1](const int f, const int g)->int
  82. {
  83. for(int c = 0;c<3;c++)
  84. {
  85. int s = F1(f,(c+1)%3);
  86. int d = F1(f,(c+2)%3);
  87. for(int e = 0;e<3;e++)
  88. {
  89. // Find in opposite direction on jth face
  90. if(F1(g,e) == d && F1(g,(e+1)%3) == s)
  91. {
  92. return c;
  93. }
  94. }
  95. }
  96. return -1;
  97. };
  98. // Returns corner of shared vertex in ith face; -1 otherwise
  99. const auto shared_vertex = [&F1](const int f, const int g, int & sf, int & sg)->bool
  100. {
  101. for(sf = 0;sf<3;sf++)
  102. {
  103. for(sg = 0;sg<3;sg++)
  104. {
  105. if(F1(g,sg) == F1(f,sf))
  106. {
  107. return true;
  108. }
  109. }
  110. }
  111. return false;
  112. };
  113. RowVector3S dummy;
  114. for(int f2 = 0; f2<F2.rows(); ++f2)
  115. {
  116. if(stinker){ printf("f2: %d\n",f2); }
  117. Eigen::AlignedBox<Scalar,3> box;
  118. box.extend( V2.row( F2(f2,0) ).transpose() );
  119. box.extend( V2.row( F2(f2,1) ).transpose() );
  120. box.extend( V2.row( F2(f2,2) ).transpose() );
  121. std::vector<const AABBTree*> candidates;
  122. tree.append_intersecting_leaves(box, candidates);
  123. for(const auto * candidate : candidates)
  124. {
  125. const int f1 = candidate->m_primitive;
  126. if(stinker){ printf(" f1: %d\n",f1); }
  127. bool found_intersection = false;
  128. bool yes_shared_verted = false;
  129. bool yes_shared_edge = false;
  130. if(self_test)
  131. {
  132. // Skip self-test and direction f2>=f1 (assumes by symmetry we'll find
  133. // the other direction since we're testing all pairs)
  134. if(f1 >= f2)
  135. {
  136. if(stinker){ printf(" ⏭\n"); }
  137. continue;
  138. }
  139. const int c = shared_edge(f1,f2);
  140. yes_shared_edge = c != -1;
  141. if(yes_shared_edge)
  142. {
  143. if(stinker){ printf(" ⚠️ shared edge\n"); }
  144. if(stinker)
  145. {
  146. printf(" %d: %d %d %d\n",f1,F1(f1,0),F1(f1,1),F1(f1,2));
  147. printf(" %d: %d %d %d\n",f2,F1(f2,0),F1(f2,1),F1(f2,2));
  148. printf(" edge: %d %d\n",F1(f1,(c+1)%3),F1(f1,(c+2)%3));
  149. }
  150. found_intersection = igl::triangle_triangle_intersect_shared_edge(
  151. V1,F1,f1,c,V1.row(F1(f1,c)),f2,1e-8);
  152. if(found_intersection)
  153. {
  154. append_intersection(f1,f2,true,dummy,dummy);
  155. }
  156. }else
  157. {
  158. int sf,sg;
  159. yes_shared_verted = shared_vertex(f1,f2,sf,sg);
  160. if(yes_shared_verted)
  161. {
  162. if(stinker){ printf(" ⚠️ shared vertex\n"); }
  163. // Just to be sure. c≠sf
  164. const int c = (sf+1)%3;
  165. assert(F1(f1,sf) == F1(f2,sg));
  166. found_intersection = igl::triangle_triangle_intersect_shared_vertex(
  167. V1,F1,f1,sf,c,V1.row(F1(f1,c)),f2,sg,1e-14);
  168. if(found_intersection && detect_only)
  169. {
  170. append_intersection(f1,f2,true,dummy,dummy);
  171. }
  172. }
  173. }
  174. }
  175. if(
  176. !self_test ||
  177. (!yes_shared_verted && !yes_shared_edge) ||
  178. (yes_shared_verted && found_intersection && !detect_only))
  179. {
  180. bool coplanar = false;
  181. RowVector3S v1,v2;
  182. const bool tt_found_intersection =
  183. igl::tri_tri_intersection_test_3d(
  184. V2.row(F2(f2,0)),V2.row(F2(f2,1)),V2.row(F2(f2,2)),
  185. V1.row(F1(f1,0)),V1.row(F1(f1,1)),V1.row(F1(f1,2)),
  186. coplanar,
  187. v1,v2);
  188. if(found_intersection && !tt_found_intersection)
  189. {
  190. // We failed to find the edge. Mark it as an intersection but don't
  191. // include edge.
  192. append_intersection(f1,f2,true,dummy,dummy);
  193. }else if(tt_found_intersection)
  194. {
  195. found_intersection = true;
  196. append_intersection(f1,f2,false,v1,v2);
  197. }
  198. }
  199. if(stinker) { printf(" %s\n",found_intersection? "☠️":"❌"); }
  200. if(num_if && first_only) { break; }
  201. }
  202. if(num_if && first_only) { break; }
  203. }
  204. if(!detect_only)
  205. {
  206. EV.conservativeResize(2*num_ee,3);
  207. EE.conservativeResize(num_ee,2);
  208. EI.conservativeResize(num_ee,1);
  209. }
  210. IF.conservativeResize(num_if,2);
  211. return IF.rows();
  212. }
  213. template <
  214. typename DerivedV1,
  215. typename DerivedF1,
  216. typename DerivedV2,
  217. typename DerivedF2,
  218. typename DerivedIF,
  219. typename DerivedEV,
  220. typename DerivedEE,
  221. typename DerivedEI>
  222. IGL_INLINE bool igl::fast_find_intersections(
  223. const Eigen::MatrixBase<DerivedV1> & V1,
  224. const Eigen::MatrixBase<DerivedF1> & F1,
  225. const Eigen::MatrixBase<DerivedV2> & V2,
  226. const Eigen::MatrixBase<DerivedF2> & F2,
  227. const bool detect_only,
  228. const bool first_only,
  229. Eigen::PlainObjectBase<DerivedIF> & IF,
  230. Eigen::PlainObjectBase<DerivedEV> & EV,
  231. Eigen::PlainObjectBase<DerivedEE> & EE,
  232. Eigen::PlainObjectBase<DerivedEI> & EI)
  233. {
  234. igl::AABB<DerivedV1,3> tree1;
  235. tree1.init(V1,F1);
  236. return fast_find_intersections(
  237. tree1,V1,F1,V2,F2,detect_only,first_only,IF,EV,EE,EI);
  238. }
  239. #ifdef IGL_STATIC_LIBRARY
  240. // Explicit template instantiation
  241. // generated by autoexplicit.sh
  242. template bool igl::fast_find_intersections<Eigen::Matrix<double, -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::Matrix<int, -1, -1, 0, -1, -1>, 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::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&, bool, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  243. #endif