DistPointTriangle.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/DCPQuery.h>
  9. #include <Mathematics/Triangle.h>
  10. #include <Mathematics/Vector.h>
  11. namespace WwiseGTE
  12. {
  13. template <int N, typename Real>
  14. class DCPQuery<Real, Vector<N, Real>, Triangle<N, Real>>
  15. {
  16. public:
  17. struct Result
  18. {
  19. Real distance, sqrDistance;
  20. Real parameter[3]; // barycentric coordinates for triangle.v[3]
  21. Vector<N, Real> closest;
  22. };
  23. Result operator()(Vector<N, Real> const& point, Triangle<N, Real> const& triangle)
  24. {
  25. Vector<N, Real> diff = point - triangle.v[0];
  26. Vector<N, Real> edge0 = triangle.v[1] - triangle.v[0];
  27. Vector<N, Real> edge1 = triangle.v[2] - triangle.v[0];
  28. Real a00 = Dot(edge0, edge0);
  29. Real a01 = Dot(edge0, edge1);
  30. Real a11 = Dot(edge1, edge1);
  31. Real b0 = -Dot(diff, edge0);
  32. Real b1 = -Dot(diff, edge1);
  33. Real f00 = b0;
  34. Real f10 = b0 + a00;
  35. Real f01 = b0 + a01;
  36. Vector<2, Real> p0, p1, p;
  37. Real dt1, h0, h1;
  38. // Compute the endpoints p0 and p1 of the segment. The segment is
  39. // parameterized by L(z) = (1-z)*p0 + z*p1 for z in [0,1] and the
  40. // directional derivative of half the quadratic on the segment is
  41. // H(z) = Dot(p1-p0,gradient[Q](L(z))/2), where gradient[Q]/2 =
  42. // (F,G). By design, F(L(z)) = 0 for cases (2), (4), (5), and
  43. // (6). Cases (1) and (3) can correspond to no-intersection or
  44. // intersection of F = 0 with the triangle.
  45. if (f00 >= (Real)0)
  46. {
  47. if (f01 >= (Real)0)
  48. {
  49. // (1) p0 = (0,0), p1 = (0,1), H(z) = G(L(z))
  50. GetMinEdge02(a11, b1, p);
  51. }
  52. else
  53. {
  54. // (2) p0 = (0,t10), p1 = (t01,1-t01),
  55. // H(z) = (t11 - t10)*G(L(z))
  56. p0[0] = (Real)0;
  57. p0[1] = f00 / (f00 - f01);
  58. p1[0] = f01 / (f01 - f10);
  59. p1[1] = (Real)1 - p1[0];
  60. dt1 = p1[1] - p0[1];
  61. h0 = dt1 * (a11 * p0[1] + b1);
  62. if (h0 >= (Real)0)
  63. {
  64. GetMinEdge02(a11, b1, p);
  65. }
  66. else
  67. {
  68. h1 = dt1 * (a01 * p1[0] + a11 * p1[1] + b1);
  69. if (h1 <= (Real)0)
  70. {
  71. GetMinEdge12(a01, a11, b1, f10, f01, p);
  72. }
  73. else
  74. {
  75. GetMinInterior(p0, h0, p1, h1, p);
  76. }
  77. }
  78. }
  79. }
  80. else if (f01 <= (Real)0)
  81. {
  82. if (f10 <= (Real)0)
  83. {
  84. // (3) p0 = (1,0), p1 = (0,1), H(z) = G(L(z)) - F(L(z))
  85. GetMinEdge12(a01, a11, b1, f10, f01, p);
  86. }
  87. else
  88. {
  89. // (4) p0 = (t00,0), p1 = (t01,1-t01), H(z) = t11*G(L(z))
  90. p0[0] = f00 / (f00 - f10);
  91. p0[1] = (Real)0;
  92. p1[0] = f01 / (f01 - f10);
  93. p1[1] = (Real)1 - p1[0];
  94. h0 = p1[1] * (a01 * p0[0] + b1);
  95. if (h0 >= (Real)0)
  96. {
  97. p = p0; // GetMinEdge01
  98. }
  99. else
  100. {
  101. h1 = p1[1] * (a01 * p1[0] + a11 * p1[1] + b1);
  102. if (h1 <= (Real)0)
  103. {
  104. GetMinEdge12(a01, a11, b1, f10, f01, p);
  105. }
  106. else
  107. {
  108. GetMinInterior(p0, h0, p1, h1, p);
  109. }
  110. }
  111. }
  112. }
  113. else if (f10 <= (Real)0)
  114. {
  115. // (5) p0 = (0,t10), p1 = (t01,1-t01),
  116. // H(z) = (t11 - t10)*G(L(z))
  117. p0[0] = (Real)0;
  118. p0[1] = f00 / (f00 - f01);
  119. p1[0] = f01 / (f01 - f10);
  120. p1[1] = (Real)1 - p1[0];
  121. dt1 = p1[1] - p0[1];
  122. h0 = dt1 * (a11 * p0[1] + b1);
  123. if (h0 >= (Real)0)
  124. {
  125. GetMinEdge02(a11, b1, p);
  126. }
  127. else
  128. {
  129. h1 = dt1 * (a01 * p1[0] + a11 * p1[1] + b1);
  130. if (h1 <= (Real)0)
  131. {
  132. GetMinEdge12(a01, a11, b1, f10, f01, p);
  133. }
  134. else
  135. {
  136. GetMinInterior(p0, h0, p1, h1, p);
  137. }
  138. }
  139. }
  140. else
  141. {
  142. // (6) p0 = (t00,0), p1 = (0,t11), H(z) = t11*G(L(z))
  143. p0[0] = f00 / (f00 - f10);
  144. p0[1] = (Real)0;
  145. p1[0] = (Real)0;
  146. p1[1] = f00 / (f00 - f01);
  147. h0 = p1[1] * (a01 * p0[0] + b1);
  148. if (h0 >= (Real)0)
  149. {
  150. p = p0; // GetMinEdge01
  151. }
  152. else
  153. {
  154. h1 = p1[1] * (a11 * p1[1] + b1);
  155. if (h1 <= (Real)0)
  156. {
  157. GetMinEdge02(a11, b1, p);
  158. }
  159. else
  160. {
  161. GetMinInterior(p0, h0, p1, h1, p);
  162. }
  163. }
  164. }
  165. Result result;
  166. result.parameter[0] = (Real)1 - p[0] - p[1];
  167. result.parameter[1] = p[0];
  168. result.parameter[2] = p[1];
  169. result.closest = triangle.v[0] + p[0] * edge0 + p[1] * edge1;
  170. diff = point - result.closest;
  171. result.sqrDistance = Dot(diff, diff);
  172. result.distance = std::sqrt(result.sqrDistance);
  173. return result;
  174. }
  175. // TODO: This is the previous implementation based on quadratic
  176. // minimization with constraints. It was replaced by the current
  177. // operator() that uses the conjugate gradient algorithm. I will
  178. // keep both in the upcoming GTL code, so the old code is restored
  179. // here for now.
  180. Result DistanceByQM(Vector<N, Real> const& point, Triangle<N, Real> const& triangle)
  181. {
  182. // The member result.sqrDistance is set each block of the nested
  183. // if-then-else statements. The remaining members are all set at
  184. // the end of the function.
  185. Result result;
  186. Vector<N, Real> diff = triangle.v[0] - point;
  187. Vector<N, Real> edge0 = triangle.v[1] - triangle.v[0];
  188. Vector<N, Real> edge1 = triangle.v[2] - triangle.v[0];
  189. Real a00 = Dot(edge0, edge0);
  190. Real a01 = Dot(edge0, edge1);
  191. Real a11 = Dot(edge1, edge1);
  192. Real b0 = Dot(diff, edge0);
  193. Real b1 = Dot(diff, edge1);
  194. Real c = Dot(diff, diff);
  195. Real det = std::max(a00 * a11 - a01 * a01, (Real)0);
  196. Real s = a01 * b1 - a11 * b0;
  197. Real t = a01 * b0 - a00 * b1;
  198. if (s + t <= det)
  199. {
  200. if (s < (Real)0)
  201. {
  202. if (t < (Real)0) // region 4
  203. {
  204. if (b0 < (Real)0)
  205. {
  206. t = (Real)0;
  207. if (-b0 >= a00)
  208. {
  209. s = (Real)1;
  210. result.sqrDistance = a00 + (Real)2 * b0 + c;
  211. }
  212. else
  213. {
  214. s = -b0 / a00;
  215. result.sqrDistance = b0 * s + c;
  216. }
  217. }
  218. else
  219. {
  220. s = (Real)0;
  221. if (b1 >= (Real)0)
  222. {
  223. t = (Real)0;
  224. result.sqrDistance = c;
  225. }
  226. else if (-b1 >= a11)
  227. {
  228. t = (Real)1;
  229. result.sqrDistance = a11 + (Real)2 * b1 + c;
  230. }
  231. else
  232. {
  233. t = -b1 / a11;
  234. result.sqrDistance = b1 * t + c;
  235. }
  236. }
  237. }
  238. else // region 3
  239. {
  240. s = (Real)0;
  241. if (b1 >= (Real)0)
  242. {
  243. t = (Real)0;
  244. result.sqrDistance = c;
  245. }
  246. else if (-b1 >= a11)
  247. {
  248. t = (Real)1;
  249. result.sqrDistance = a11 + (Real)2 * b1 + c;
  250. }
  251. else
  252. {
  253. t = -b1 / a11;
  254. result.sqrDistance = b1 * t + c;
  255. }
  256. }
  257. }
  258. else if (t < (Real)0) // region 5
  259. {
  260. t = (Real)0;
  261. if (b0 >= (Real)0)
  262. {
  263. s = (Real)0;
  264. result.sqrDistance = c;
  265. }
  266. else if (-b0 >= a00)
  267. {
  268. s = (Real)1;
  269. result.sqrDistance = a00 + (Real)2 * b0 + c;
  270. }
  271. else
  272. {
  273. s = -b0 / a00;
  274. result.sqrDistance = b0 * s + c;
  275. }
  276. }
  277. else // region 0
  278. {
  279. // minimum at interior point
  280. Real invDet = ((Real)1) / det;
  281. s *= invDet;
  282. t *= invDet;
  283. result.sqrDistance = s * (a00 * s + a01 * t + (Real)2 * b0) +
  284. t * (a01 * s + a11 * t + (Real)2 * b1) + c;
  285. }
  286. }
  287. else
  288. {
  289. Real tmp0, tmp1, numer, denom;
  290. if (s < (Real)0) // region 2
  291. {
  292. tmp0 = a01 + b0;
  293. tmp1 = a11 + b1;
  294. if (tmp1 > tmp0)
  295. {
  296. numer = tmp1 - tmp0;
  297. denom = a00 - (Real)2 * a01 + a11;
  298. if (numer >= denom)
  299. {
  300. s = (Real)1;
  301. t = (Real)0;
  302. result.sqrDistance = a00 + (Real)2 * b0 + c;
  303. }
  304. else
  305. {
  306. s = numer / denom;
  307. t = (Real)1 - s;
  308. result.sqrDistance = s * (a00 * s + a01 * t + (Real)2 * b0) +
  309. t * (a01 * s + a11 * t + (Real)2 * b1) + c;
  310. }
  311. }
  312. else
  313. {
  314. s = (Real)0;
  315. if (tmp1 <= (Real)0)
  316. {
  317. t = (Real)1;
  318. result.sqrDistance = a11 + (Real)2 * b1 + c;
  319. }
  320. else if (b1 >= (Real)0)
  321. {
  322. t = (Real)0;
  323. result.sqrDistance = c;
  324. }
  325. else
  326. {
  327. t = -b1 / a11;
  328. result.sqrDistance = b1 * t + c;
  329. }
  330. }
  331. }
  332. else if (t < (Real)0) // region 6
  333. {
  334. tmp0 = a01 + b1;
  335. tmp1 = a00 + b0;
  336. if (tmp1 > tmp0)
  337. {
  338. numer = tmp1 - tmp0;
  339. denom = a00 - (Real)2 * a01 + a11;
  340. if (numer >= denom)
  341. {
  342. t = (Real)1;
  343. s = (Real)0;
  344. result.sqrDistance = a11 + (Real)2 * b1 + c;
  345. }
  346. else
  347. {
  348. t = numer / denom;
  349. s = (Real)1 - t;
  350. result.sqrDistance = s * (a00 * s + a01 * t + (Real)2 * b0) +
  351. t * (a01 * s + a11 * t + (Real)2 * b1) + c;
  352. }
  353. }
  354. else
  355. {
  356. t = (Real)0;
  357. if (tmp1 <= (Real)0)
  358. {
  359. s = (Real)1;
  360. result.sqrDistance = a00 + (Real)2 * b0 + c;
  361. }
  362. else if (b0 >= (Real)0)
  363. {
  364. s = (Real)0;
  365. result.sqrDistance = c;
  366. }
  367. else
  368. {
  369. s = -b0 / a00;
  370. result.sqrDistance = b0 * s + c;
  371. }
  372. }
  373. }
  374. else // region 1
  375. {
  376. numer = a11 + b1 - a01 - b0;
  377. if (numer <= (Real)0)
  378. {
  379. s = (Real)0;
  380. t = (Real)1;
  381. result.sqrDistance = a11 + (Real)2 * b1 + c;
  382. }
  383. else
  384. {
  385. denom = a00 - ((Real)2) * a01 + a11;
  386. if (numer >= denom)
  387. {
  388. s = (Real)1;
  389. t = (Real)0;
  390. result.sqrDistance = a00 + (Real)2 * b0 + c;
  391. }
  392. else
  393. {
  394. s = numer / denom;
  395. t = (Real)1 - s;
  396. result.sqrDistance = s * (a00 * s + a01 * t + (Real)2 * b0) +
  397. t * (a01 * s + a11 * t + (Real)2 * b1) + c;
  398. }
  399. }
  400. }
  401. }
  402. // Account for numerical round-off error.
  403. if (result.sqrDistance < (Real)0)
  404. {
  405. result.sqrDistance = (Real)0;
  406. }
  407. result.distance = sqrt(result.sqrDistance);
  408. result.closest = triangle.v[0] + s * edge0 + t * edge1;
  409. result.parameter[1] = s;
  410. result.parameter[2] = t;
  411. result.parameter[0] = (Real)1 - s - t;
  412. return result;
  413. }
  414. private:
  415. void GetMinEdge02(Real const& a11, Real const& b1, Vector<2, Real>& p)
  416. {
  417. p[0] = (Real)0;
  418. if (b1 >= (Real)0)
  419. {
  420. p[1] = (Real)0;
  421. }
  422. else if (a11 + b1 <= (Real)0)
  423. {
  424. p[1] = (Real)1;
  425. }
  426. else
  427. {
  428. p[1] = -b1 / a11;
  429. }
  430. }
  431. inline void GetMinEdge12(Real const& a01, Real const& a11, Real const& b1,
  432. Real const& f10, Real const& f01, Vector<2, Real>& p)
  433. {
  434. Real h0 = a01 + b1 - f10;
  435. if (h0 >= (Real)0)
  436. {
  437. p[1] = (Real)0;
  438. }
  439. else
  440. {
  441. Real h1 = a11 + b1 - f01;
  442. if (h1 <= (Real)0)
  443. {
  444. p[1] = (Real)1;
  445. }
  446. else
  447. {
  448. p[1] = h0 / (h0 - h1);
  449. }
  450. }
  451. p[0] = (Real)1 - p[1];
  452. }
  453. inline void GetMinInterior(Vector<2, Real> const& p0, Real const& h0,
  454. Vector<2, Real> const& p1, Real const& h1, Vector<2, Real>& p)
  455. {
  456. Real z = h0 / (h0 - h1);
  457. p = ((Real)1 - z) * p0 + z * p1;
  458. }
  459. };
  460. // Template aliases for convenience.
  461. template <int N, typename Real>
  462. using DCPPointTriangle = DCPQuery<Real, Vector<N, Real>, Triangle<N, Real>>;
  463. template <typename Real>
  464. using DCPPoint2Triangle2 = DCPPointTriangle<2, Real>;
  465. template <typename Real>
  466. using DCPPoint3Triangle3 = DCPPointTriangle<3, Real>;
  467. }