find_intersections.cpp 12 KB

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