triangle_triangle_intersect.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #include "triangle_triangle_intersect.h"
  2. #include "predicates.h"
  3. #include "exactinit.h"
  4. #include "orient2d.h"
  5. #include "orient3d.h"
  6. #include <Eigen/Core>
  7. #include <Eigen/Geometry>
  8. template <typename Vector3D>
  9. IGL_INLINE bool igl::predicates::triangle_triangle_intersect(
  10. const Vector3D & p1,
  11. const Vector3D & q1,
  12. const Vector3D & r1,
  13. const Vector3D & p2,
  14. const Vector3D & q2,
  15. const Vector3D & r2,
  16. bool & coplanar)
  17. {
  18. coplanar = false;
  19. // yet another translation of tri_tri_intersect.c [Guigue & Devillers]
  20. exactinit();
  21. using Vector2D = Eigen::Matrix<typename Vector3D::Scalar,2,1>;
  22. constexpr Orientation COPLANAR = igl::predicates::Orientation::COPLANAR;
  23. constexpr Orientation NEGATIVE = igl::predicates::Orientation::NEGATIVE;
  24. constexpr Orientation POSITIVE = igl::predicates::Orientation::POSITIVE;
  25. // Determine for each vertex of one triangle if it's above, below or on the
  26. // plane of the other triangle.
  27. // SUB(v1,p2,r2)
  28. // SUB(v2,q2,r2)
  29. // CROSS(N2,v1,v2)
  30. // SUB(v1,p1,r2)
  31. // dp1 = DOT(v1,N2);
  32. // dp1 = (p1-r2).dot( (p2-r2).cross(q2-r2) );
  33. const Orientation dp1 = orient3d(p2,q2,r2,p1);
  34. const Orientation dq1 = orient3d(p2,q2,r2,q1);
  35. const Orientation dr1 = orient3d(p2,q2,r2,r1);
  36. const auto same_non_coplanar = [&NEGATIVE,&COPLANAR,&POSITIVE](
  37. const Orientation a,
  38. const Orientation b,
  39. const Orientation c)
  40. {
  41. return (a == POSITIVE && b == POSITIVE && c == POSITIVE) ||
  42. (a == NEGATIVE && b == NEGATIVE && c == NEGATIVE);
  43. };
  44. if(same_non_coplanar(dp1,dq1,dr1)) { return false; }
  45. const Orientation dp2 = orient3d(p1,q1,r1,p2);
  46. const Orientation dq2 = orient3d(p1,q1,r1,q2);
  47. const Orientation dr2 = orient3d(p1,q1,r1,r2);
  48. // Theoreticaly, this should have already been fired above
  49. if(same_non_coplanar(dp2,dq2,dr2)) { return false; }
  50. const auto tri_tri_overlap_test_2d = [&NEGATIVE,&COPLANAR,&POSITIVE](
  51. const Vector2D & p1,
  52. const Vector2D & q1,
  53. const Vector2D & r1,
  54. const Vector2D & p2,
  55. const Vector2D & q2,
  56. const Vector2D & r2)->bool
  57. {
  58. const auto ccw_tri_tri_intersection_2d = [&NEGATIVE,&COPLANAR,&POSITIVE](
  59. const Vector2D & p1,
  60. const Vector2D & q1,
  61. const Vector2D & r1,
  62. const Vector2D & p2,
  63. const Vector2D & q2,
  64. const Vector2D & r2)->bool
  65. {
  66. const auto INTERSECTION_TEST_VERTEX = [&NEGATIVE,&COPLANAR,&POSITIVE](
  67. const Vector2D & P1,
  68. const Vector2D & Q1,
  69. const Vector2D & R1,
  70. const Vector2D & P2,
  71. const Vector2D & Q2,
  72. const Vector2D & R2)->bool
  73. {
  74. if (orient2d(R2,P2,Q1) != NEGATIVE)
  75. if (orient2d(R2,Q2,Q1) != POSITIVE)
  76. if (orient2d(P1,P2,Q1) == POSITIVE) {
  77. if (orient2d(P1,Q2,Q1) != POSITIVE) return 1;
  78. else return 0;} else {
  79. if (orient2d(P1,P2,R1) != NEGATIVE)
  80. if (orient2d(Q1,R1,P2) != NEGATIVE) return 1;
  81. else return 0;
  82. else return 0;}
  83. else
  84. if (orient2d(P1,Q2,Q1) != POSITIVE)
  85. if (orient2d(R2,Q2,R1) != POSITIVE)
  86. if (orient2d(Q1,R1,Q2) != NEGATIVE) return 1;
  87. else return 0;
  88. else return 0;
  89. else return 0;
  90. else
  91. if (orient2d(R2,P2,R1) != NEGATIVE)
  92. if (orient2d(Q1,R1,R2) != NEGATIVE)
  93. if (orient2d(P1,P2,R1) != NEGATIVE) return 1;
  94. else return 0;
  95. else
  96. if (orient2d(Q1,R1,Q2) != NEGATIVE) {
  97. if (orient2d(R2,R1,Q2) != NEGATIVE) return 1;
  98. else return 0; }
  99. else return 0;
  100. else return 0;
  101. };
  102. const auto INTERSECTION_TEST_EDGE = [&NEGATIVE,&COPLANAR,&POSITIVE](
  103. const Vector2D & P1,
  104. const Vector2D & Q1,
  105. const Vector2D & R1,
  106. const Vector2D & P2,
  107. const Vector2D & Q2,
  108. const Vector2D & R2)->bool
  109. {
  110. if (orient2d(R2,P2,Q1) != NEGATIVE) {
  111. if (orient2d(P1,P2,Q1) != NEGATIVE) {
  112. if (orient2d(P1,Q1,R2) != NEGATIVE) return 1;
  113. else return 0;} else {
  114. if (orient2d(Q1,R1,P2) != NEGATIVE){
  115. if (orient2d(R1,P1,P2) != NEGATIVE) return 1; else return 0;}
  116. else return 0; }
  117. } else {
  118. if (orient2d(R2,P2,R1) != NEGATIVE) {
  119. if (orient2d(P1,P2,R1) != NEGATIVE) {
  120. if (orient2d(P1,R1,R2) != NEGATIVE) return 1;
  121. else {
  122. if (orient2d(Q1,R1,R2) != NEGATIVE) return 1; else return 0;}}
  123. else return 0; }
  124. else return 0; }
  125. };
  126. if ( orient2d(p2,q2,p1) != NEGATIVE ) {
  127. if ( orient2d(q2,r2,p1) != NEGATIVE ) {
  128. if ( orient2d(r2,p2,p1) != NEGATIVE ) return 1;
  129. else return INTERSECTION_TEST_EDGE(p1,q1,r1,p2,q2,r2);
  130. } else {
  131. if ( orient2d(r2,p2,p1) != NEGATIVE )
  132. return INTERSECTION_TEST_EDGE(p1,q1,r1,r2,p2,q2);
  133. else return INTERSECTION_TEST_VERTEX(p1,q1,r1,p2,q2,r2);}}
  134. else {
  135. if ( orient2d(q2,r2,p1) != NEGATIVE ) {
  136. if ( orient2d(r2,p2,p1) != NEGATIVE )
  137. return INTERSECTION_TEST_EDGE(p1,q1,r1,q2,r2,p2);
  138. else return INTERSECTION_TEST_VERTEX(p1,q1,r1,q2,r2,p2);}
  139. else return INTERSECTION_TEST_VERTEX(p1,q1,r1,r2,p2,q2);}
  140. return false;
  141. };
  142. if ( orient2d(p1,q1,r1) == NEGATIVE )
  143. if ( orient2d(p2,q2,r2) == NEGATIVE )
  144. return ccw_tri_tri_intersection_2d(p1,r1,q1,p2,r2,q2);
  145. else
  146. return ccw_tri_tri_intersection_2d(p1,r1,q1,p2,q2,r2);
  147. else
  148. if ( orient2d(p2,q2,r2) == NEGATIVE )
  149. return ccw_tri_tri_intersection_2d(p1,q1,r1,p2,r2,q2);
  150. else
  151. return ccw_tri_tri_intersection_2d(p1,q1,r1,p2,q2,r2);
  152. };
  153. const auto coplanar_tri_tri3d = [&tri_tri_overlap_test_2d,&NEGATIVE,&COPLANAR,&POSITIVE](
  154. const Vector3D & p1,
  155. const Vector3D & q1,
  156. const Vector3D & r1,
  157. const Vector3D & p2,
  158. const Vector3D & q2,
  159. const Vector3D & r2)->bool
  160. {
  161. Vector3D normal_1 = (q1-p1).cross(r1-p1);
  162. const auto n_x = ((normal_1[0]<0)?-normal_1[0]:normal_1[0]);
  163. const auto n_y = ((normal_1[1]<0)?-normal_1[1]:normal_1[1]);
  164. const auto n_z = ((normal_1[2]<0)?-normal_1[2]:normal_1[2]);
  165. Vector2D P1,Q1,R1,P2,Q2,R2;
  166. if (( n_x > n_z ) && ( n_x >= n_y )) {
  167. // Project onto plane YZ
  168. P1[0] = q1[2]; P1[1] = q1[1];
  169. Q1[0] = p1[2]; Q1[1] = p1[1];
  170. R1[0] = r1[2]; R1[1] = r1[1];
  171. P2[0] = q2[2]; P2[1] = q2[1];
  172. Q2[0] = p2[2]; Q2[1] = p2[1];
  173. R2[0] = r2[2]; R2[1] = r2[1];
  174. } else if (( n_y > n_z ) && ( n_y >= n_x )) {
  175. // Project onto plane XZ
  176. P1[0] = q1[0]; P1[1] = q1[2];
  177. Q1[0] = p1[0]; Q1[1] = p1[2];
  178. R1[0] = r1[0]; R1[1] = r1[2];
  179. P2[0] = q2[0]; P2[1] = q2[2];
  180. Q2[0] = p2[0]; Q2[1] = p2[2];
  181. R2[0] = r2[0]; R2[1] = r2[2];
  182. } else {
  183. // Project onto plane XY
  184. P1[0] = p1[0]; P1[1] = p1[1];
  185. Q1[0] = q1[0]; Q1[1] = q1[1];
  186. R1[0] = r1[0]; R1[1] = r1[1];
  187. P2[0] = p2[0]; P2[1] = p2[1];
  188. Q2[0] = q2[0]; Q2[1] = q2[1];
  189. R2[0] = r2[0]; R2[1] = r2[1];
  190. }
  191. return tri_tri_overlap_test_2d(P1,Q1,R1,P2,Q2,R2);
  192. exit(1);
  193. return false;
  194. };
  195. const auto TRI_TRI_3D = [&coplanar_tri_tri3d,&coplanar,&NEGATIVE,&COPLANAR,&POSITIVE](
  196. const Vector3D & p1,
  197. const Vector3D & q1,
  198. const Vector3D & r1,
  199. const Vector3D & p2,
  200. const Vector3D & q2,
  201. const Vector3D & r2,
  202. const Orientation dp2,
  203. const Orientation dq2,
  204. const Orientation dr2)->bool
  205. {
  206. const auto CHECK_MIN_MAX = [&NEGATIVE,&COPLANAR,&POSITIVE](
  207. const Vector3D & p1,
  208. const Vector3D & q1,
  209. const Vector3D & r1,
  210. const Vector3D & p2,
  211. const Vector3D & q2,
  212. const Vector3D & r2)->bool
  213. {
  214. if (orient3d(p2,p1,q1,q2) == POSITIVE) { return false; }
  215. if (orient3d(p2,r1,p1,r2) == POSITIVE) { return false; }
  216. return true;
  217. };
  218. if (dp2 == POSITIVE) {
  219. if (dq2 == POSITIVE) return CHECK_MIN_MAX(p1,r1,q1,r2,p2,q2) ;
  220. else if (dr2 == POSITIVE) return CHECK_MIN_MAX(p1,r1,q1,q2,r2,p2);
  221. else return CHECK_MIN_MAX(p1,q1,r1,p2,q2,r2);
  222. } else if (dp2 == NEGATIVE) {
  223. if (dq2 == NEGATIVE) return CHECK_MIN_MAX(p1,q1,r1,r2,p2,q2);
  224. else if (dr2 == NEGATIVE) return CHECK_MIN_MAX(p1,q1,r1,q2,r2,p2);
  225. else return CHECK_MIN_MAX(p1,r1,q1,p2,q2,r2);
  226. } else {
  227. if (dq2 == NEGATIVE) {
  228. if (dr2 == POSITIVE || dr2 == COPLANAR) return CHECK_MIN_MAX(p1,r1,q1,q2,r2,p2);
  229. else return CHECK_MIN_MAX(p1,q1,r1,p2,q2,r2);
  230. }
  231. else if (dq2 == POSITIVE) {
  232. if (dr2 == POSITIVE) return CHECK_MIN_MAX(p1,r1,q1,p2,q2,r2);
  233. else return CHECK_MIN_MAX(p1,q1,r1,q2,r2,p2);
  234. }
  235. else {
  236. if (dr2 == POSITIVE) return CHECK_MIN_MAX(p1,q1,r1,r2,p2,q2);
  237. else if (dr2 == NEGATIVE) return CHECK_MIN_MAX(p1,r1,q1,r2,p2,q2);
  238. else
  239. {
  240. coplanar = coplanar_tri_tri3d(p1,q1,r1,p2,q2,r2);
  241. return coplanar;
  242. }
  243. }
  244. }
  245. };
  246. if (dp1 == POSITIVE) {
  247. if (dq1 == POSITIVE) return TRI_TRI_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2);
  248. else if (dr1 == POSITIVE) return TRI_TRI_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2) ;
  249. else return TRI_TRI_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2);
  250. } else if (dp1 == NEGATIVE) {
  251. if (dq1 == NEGATIVE) return TRI_TRI_3D(r1,p1,q1,p2,q2,r2,dp2,dq2,dr2);
  252. else if (dr1 == NEGATIVE) return TRI_TRI_3D(q1,r1,p1,p2,q2,r2,dp2,dq2,dr2);
  253. else return TRI_TRI_3D(p1,q1,r1,p2,r2,q2,dp2,dr2,dq2);
  254. } else {
  255. if (dq1 == NEGATIVE) {
  256. // why COPLANAR here? It seems so haphazard.
  257. if (dr1 == POSITIVE || dr1 == COPLANAR) return TRI_TRI_3D(q1,r1,p1,p2,r2,q2,dp2,dr2,dq2);
  258. else return TRI_TRI_3D(p1,q1,r1,p2,q2,r2,dp2,dq2,dr2);
  259. }
  260. else if (dq1 == POSITIVE) {
  261. if (dr1 == POSITIVE) return TRI_TRI_3D(p1,q1,r1,p2,r2,q2,dp2,dr2,dq2);
  262. else return TRI_TRI_3D(q1,r1,p1,p2,q2,r2,dp2,dq2,dr2);
  263. }
  264. else {
  265. if (dr1 == POSITIVE) return TRI_TRI_3D(r1,p1,q1,p2,q2,r2,dp2,dq2,dr2);
  266. else if (dr1 == NEGATIVE) return TRI_TRI_3D(r1,p1,q1,p2,r2,q2,dp2,dr2,dq2);
  267. else
  268. {
  269. coplanar = coplanar_tri_tri3d(p1,q1,r1,p2,q2,r2);
  270. return coplanar;
  271. }
  272. }
  273. }
  274. }
  275. #ifdef IGL_STATIC_LIBRARY
  276. // Explicit template specialization
  277. // template using Eigen::Vector3d.
  278. template bool igl::predicates::triangle_triangle_intersect<Eigen::Vector3d>(
  279. const Eigen::Vector3d & p1,
  280. const Eigen::Vector3d & q1,
  281. const Eigen::Vector3d & r1,
  282. const Eigen::Vector3d & p2,
  283. const Eigen::Vector3d & q2,
  284. const Eigen::Vector3d & r2,
  285. bool & coplanar);
  286. template bool igl::predicates::triangle_triangle_intersect<Eigen::RowVector3d>(
  287. const Eigen::RowVector3d & p1,
  288. const Eigen::RowVector3d & q1,
  289. const Eigen::RowVector3d & r1,
  290. const Eigen::RowVector3d & p2,
  291. const Eigen::RowVector3d & q2,
  292. const Eigen::RowVector3d & r2,
  293. bool & coplanar);
  294. #endif