triangle_triangle_intersect.cpp 11 KB

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