find_intersections.cpp 12 KB

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