find_intersections.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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 gth face
  76. //if(F1(g,e) == d && F1(g,(e+1)%3) == s)
  77. // Find in either direction on gth face
  78. if(
  79. (F1(g,e) == d && F1(g,(e+1)%3) == s) ||
  80. (F1(g,e) == s && F1(g,(e+1)%3) == d))
  81. {
  82. return c;
  83. }
  84. }
  85. }
  86. return -1;
  87. };
  88. // Returns corner of shared vertex in ith face; -1 otherwise
  89. const auto shared_vertex = [&F1](const int f, const int g, int & sf, int & sg)->bool
  90. {
  91. for(sf = 0;sf<3;sf++)
  92. {
  93. for(sg = 0;sg<3;sg++)
  94. {
  95. if(F1(g,sg) == F1(f,sf))
  96. {
  97. return true;
  98. }
  99. }
  100. }
  101. return false;
  102. };
  103. RowVector3S dummy;
  104. igl::parallel_for(F2.rows(),[&](const int f2)
  105. {
  106. if(stinker){ printf("f2: %d\n",f2); }
  107. Eigen::AlignedBox<Scalar,3> box;
  108. box.extend( V2.row( F2(f2,0) ).transpose() );
  109. box.extend( V2.row( F2(f2,1) ).transpose() );
  110. box.extend( V2.row( F2(f2,2) ).transpose() );
  111. std::vector<const AABBTree*> candidates;
  112. tree1.append_intersecting_leaves(box, candidates);
  113. for(const auto * candidate : candidates)
  114. {
  115. const int f1 = candidate->m_primitive;
  116. if(stinker){ printf(" f1: %d\n",f1); }
  117. bool found_intersection = false;
  118. bool yes_shared_verted = false;
  119. bool yes_shared_edge = false;
  120. if(self_test)
  121. {
  122. // Skip self-test and direction f2>=f1 (assumes by symmetry we'll find
  123. // the other direction since we're testing all pairs)
  124. if(f1 >= f2)
  125. {
  126. if(stinker){ printf(" ⏭\n"); }
  127. continue;
  128. }
  129. const int c = shared_edge(f1,f2);
  130. yes_shared_edge = c != -1;
  131. if(yes_shared_edge)
  132. {
  133. if(stinker){ printf(" ⚠️ shared edge\n"); }
  134. if(stinker)
  135. {
  136. printf(" %d: %d %d %d\n",f1,F1(f1,0),F1(f1,1),F1(f1,2));
  137. printf(" %d: %d %d %d\n",f2,F1(f2,0),F1(f2,1),F1(f2,2));
  138. printf(" edge: %d %d\n",F1(f1,(c+1)%3),F1(f1,(c+2)%3));
  139. }
  140. found_intersection = igl::triangle_triangle_intersect_shared_edge(
  141. V1,F1,f1,c,V1.row(F1(f1,c)),f2,1e-8);
  142. if(found_intersection)
  143. {
  144. append_intersection(f1,f2,true);
  145. }
  146. }else
  147. {
  148. int sf,sg;
  149. yes_shared_verted = shared_vertex(f1,f2,sf,sg);
  150. if(yes_shared_verted)
  151. {
  152. if(stinker){ printf(" ⚠️ shared vertex\n"); }
  153. // Just to be sure. c≠sf
  154. const int c = (sf+1)%3;
  155. assert(F1(f1,sf) == F1(f2,sg));
  156. found_intersection = igl::triangle_triangle_intersect_shared_vertex(
  157. V1,F1,f1,sf,c,V1.row(F1(f1,c)),f2,sg,1e-14);
  158. if(found_intersection && detect_only)
  159. {
  160. // But wait? Couldn't these be coplanar?
  161. append_intersection(f1,f2,false);
  162. }
  163. }
  164. }
  165. }
  166. // This logic is confusing.
  167. if(
  168. !self_test ||
  169. (!yes_shared_verted && !yes_shared_edge) ||
  170. (yes_shared_verted && found_intersection && !detect_only))
  171. {
  172. bool coplanar = false;
  173. RowVector3S v1,v2;
  174. const bool tt_found_intersection =
  175. triangle_triangle_intersect(
  176. V2.row(F2(f2,0)).template head<3>().eval(),
  177. V2.row(F2(f2,1)).template head<3>().eval(),
  178. V2.row(F2(f2,2)).template head<3>().eval(),
  179. V1.row(F1(f1,0)).template head<3>().eval(),
  180. V1.row(F1(f1,1)).template head<3>().eval(),
  181. V1.row(F1(f1,2)).template head<3>().eval(),
  182. coplanar);
  183. if(found_intersection && !tt_found_intersection)
  184. {
  185. // We failed to find the edge. Mark it as an intersection but don't
  186. // include edge.
  187. append_intersection(f1,f2,coplanar);
  188. }else if(tt_found_intersection)
  189. {
  190. found_intersection = true;
  191. append_intersection(f1,f2,coplanar);
  192. }
  193. }
  194. if(stinker) { printf(" %s\n",found_intersection? "☠️":"❌"); }
  195. if(num_if && first_only) { return; }
  196. }
  197. if(num_if && first_only) { return; }
  198. },1000);
  199. IF.conservativeResize(num_if,2);
  200. CP.conservativeResize(IF.rows());
  201. return IF.rows();
  202. }
  203. template <
  204. typename DerivedV1,
  205. typename DerivedF1,
  206. typename DerivedV2,
  207. typename DerivedF2,
  208. typename DerivedIF,
  209. typename DerivedCP>
  210. IGL_INLINE bool igl::predicates::find_intersections(
  211. const Eigen::MatrixBase<DerivedV1> & V1,
  212. const Eigen::MatrixBase<DerivedF1> & F1,
  213. const Eigen::MatrixBase<DerivedV2> & V2,
  214. const Eigen::MatrixBase<DerivedF2> & F2,
  215. const bool first_only,
  216. Eigen::PlainObjectBase<DerivedIF> & IF,
  217. Eigen::PlainObjectBase<DerivedCP> & CP)
  218. {
  219. igl::AABB<DerivedV1,3> tree1;
  220. tree1.init(V1,F1);
  221. return find_intersections(tree1,V1,F1,V2,F2,first_only,IF,CP);
  222. }
  223. template <
  224. typename DerivedV1,
  225. typename DerivedF1,
  226. typename DerivedV2,
  227. typename DerivedF2,
  228. typename DerivedIF,
  229. typename DerivedCP,
  230. typename DerivedEV,
  231. typename DerivedEE,
  232. typename DerivedEI>
  233. IGL_INLINE bool igl::predicates::find_intersections(
  234. const Eigen::MatrixBase<DerivedV1> & V1,
  235. const Eigen::MatrixBase<DerivedF1> & F1,
  236. const Eigen::MatrixBase<DerivedV2> & V2,
  237. const Eigen::MatrixBase<DerivedF2> & F2,
  238. Eigen::PlainObjectBase<DerivedIF> & IF,
  239. Eigen::PlainObjectBase<DerivedCP> & CP,
  240. Eigen::PlainObjectBase<DerivedEV> & EV,
  241. Eigen::PlainObjectBase<DerivedEE> & EE,
  242. Eigen::PlainObjectBase<DerivedEI> & EI)
  243. {
  244. igl::AABB<DerivedV1,3> tree1;
  245. tree1.init(V1,F1);
  246. return find_intersections(tree1,V1,F1,V2,F2,IF,CP,EV,EE,EI);
  247. }
  248. template <
  249. typename DerivedV1,
  250. typename DerivedF1,
  251. typename DerivedV2,
  252. typename DerivedF2,
  253. typename DerivedIF,
  254. typename DerivedCP,
  255. typename DerivedEV,
  256. typename DerivedEE,
  257. typename DerivedEI>
  258. IGL_INLINE bool igl::predicates::find_intersections(
  259. const igl::AABB<DerivedV1,3> & tree1,
  260. const Eigen::MatrixBase<DerivedV1> & V1,
  261. const Eigen::MatrixBase<DerivedF1> & F1,
  262. const Eigen::MatrixBase<DerivedV2> & V2,
  263. const Eigen::MatrixBase<DerivedF2> & F2,
  264. Eigen::PlainObjectBase<DerivedIF> & IF,
  265. Eigen::PlainObjectBase<DerivedCP> & CP,
  266. Eigen::PlainObjectBase<DerivedEV> & EV,
  267. Eigen::PlainObjectBase<DerivedEE> & EE,
  268. Eigen::PlainObjectBase<DerivedEI> & EI)
  269. {
  270. if(!find_intersections(tree1,V1,F1,V2,F2,false,IF,CP)) { return false; }
  271. std::vector<int> EI_vec = igl::find((CP.array()==false).eval());
  272. igl::list_to_matrix(EI_vec,EI);
  273. const auto IF_EI = IF(EI_vec,Eigen::placeholders::all).eval();
  274. igl::triangle_triangle_intersect(V1,F1,V2,F2,IF_EI,EV,EE);
  275. return true;
  276. }
  277. #ifdef IGL_STATIC_LIBRARY
  278. // Explicit template instantiation
  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::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> >&);
  281. // generated by autoexplicit.sh
  282. 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> >&);
  283. // generated by autoexplicit.sh
  284. 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> >&);
  285. #endif