find_intersections.cpp 12 KB

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