DistPoint3Frustum3.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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/Frustum3.h>
  10. namespace WwiseGTE
  11. {
  12. template <typename Real>
  13. class DCPQuery<Real, Vector3<Real>, Frustum3<Real>>
  14. {
  15. public:
  16. struct Result
  17. {
  18. Real distance, sqrDistance;
  19. Vector3<Real> frustumClosestPoint;
  20. };
  21. Result operator()(Vector3<Real> const& point, Frustum3<Real> const& frustum)
  22. {
  23. Result result;
  24. // Compute coordinates of point with respect to frustum coordinate
  25. // system.
  26. Vector3<Real> diff = point - frustum.origin;
  27. Vector3<Real> test = {
  28. Dot(diff, frustum.rVector),
  29. Dot(diff, frustum.uVector),
  30. Dot(diff, frustum.dVector) };
  31. // Perform calculations in octant with nonnegative R and U
  32. // coordinates.
  33. bool rSignChange;
  34. if (test[0] < (Real)0)
  35. {
  36. rSignChange = true;
  37. test[0] = -test[0];
  38. }
  39. else
  40. {
  41. rSignChange = false;
  42. }
  43. bool uSignChange;
  44. if (test[1] < (Real)0)
  45. {
  46. uSignChange = true;
  47. test[1] = -test[1];
  48. }
  49. else
  50. {
  51. uSignChange = false;
  52. }
  53. // Frustum derived parameters.
  54. Real rmin = frustum.rBound;
  55. Real rmax = frustum.GetDRatio() * rmin;
  56. Real umin = frustum.uBound;
  57. Real umax = frustum.GetDRatio() * umin;
  58. Real dmin = frustum.dMin;
  59. Real dmax = frustum.dMax;
  60. Real rminSqr = rmin * rmin;
  61. Real uminSqr = umin * umin;
  62. Real dminSqr = dmin * dmin;
  63. Real minRDDot = rminSqr + dminSqr;
  64. Real minUDDot = uminSqr + dminSqr;
  65. Real minRUDDot = rminSqr + minUDDot;
  66. Real maxRDDot = frustum.GetDRatio() * minRDDot;
  67. Real maxUDDot = frustum.GetDRatio() * minUDDot;
  68. Real maxRUDDot = frustum.GetDRatio() * minRUDDot;
  69. // Algorithm computes closest point in all cases by determining
  70. // in which Voronoi region of the vertices, edges, and faces of
  71. // the frustum that the test point lives.
  72. Vector3<Real> closest;
  73. Real rDot, uDot, rdDot, udDot, rudDot, rEdgeDot, uEdgeDot, t;
  74. if (test[2] >= dmax)
  75. {
  76. if (test[0] <= rmax)
  77. {
  78. if (test[1] <= umax)
  79. {
  80. // F-face
  81. closest[0] = test[0];
  82. closest[1] = test[1];
  83. closest[2] = dmax;
  84. }
  85. else
  86. {
  87. // UF-edge
  88. closest[0] = test[0];
  89. closest[1] = umax;
  90. closest[2] = dmax;
  91. }
  92. }
  93. else
  94. {
  95. if (test[1] <= umax)
  96. {
  97. // LF-edge
  98. closest[0] = rmax;
  99. closest[1] = test[1];
  100. closest[2] = dmax;
  101. }
  102. else
  103. {
  104. // LUF-vertex
  105. closest[0] = rmax;
  106. closest[1] = umax;
  107. closest[2] = dmax;
  108. }
  109. }
  110. }
  111. else if (test[2] <= dmin)
  112. {
  113. if (test[0] <= rmin)
  114. {
  115. if (test[1] <= umin)
  116. {
  117. // N-face
  118. closest[0] = test[0];
  119. closest[1] = test[1];
  120. closest[2] = dmin;
  121. }
  122. else
  123. {
  124. udDot = umin * test[1] + dmin * test[2];
  125. if (udDot >= maxUDDot)
  126. {
  127. // UF-edge
  128. closest[0] = test[0];
  129. closest[1] = umax;
  130. closest[2] = dmax;
  131. }
  132. else if (udDot >= minUDDot)
  133. {
  134. // U-face
  135. uDot = dmin * test[1] - umin * test[2];
  136. t = uDot / minUDDot;
  137. closest[0] = test[0];
  138. closest[1] = test[1] - t * dmin;
  139. closest[2] = test[2] + t * umin;
  140. }
  141. else
  142. {
  143. // UN-edge
  144. closest[0] = test[0];
  145. closest[1] = umin;
  146. closest[2] = dmin;
  147. }
  148. }
  149. }
  150. else
  151. {
  152. if (test[1] <= umin)
  153. {
  154. rdDot = rmin * test[0] + dmin * test[2];
  155. if (rdDot >= maxRDDot)
  156. {
  157. // LF-edge
  158. closest[0] = rmax;
  159. closest[1] = test[1];
  160. closest[2] = dmax;
  161. }
  162. else if (rdDot >= minRDDot)
  163. {
  164. // L-face
  165. rDot = dmin * test[0] - rmin * test[2];
  166. t = rDot / minRDDot;
  167. closest[0] = test[0] - t * dmin;
  168. closest[1] = test[1];
  169. closest[2] = test[2] + t * rmin;
  170. }
  171. else
  172. {
  173. // LN-edge
  174. closest[0] = rmin;
  175. closest[1] = test[1];
  176. closest[2] = dmin;
  177. }
  178. }
  179. else
  180. {
  181. rudDot = rmin * test[0] + umin * test[1] + dmin * test[2];
  182. rEdgeDot = umin * rudDot - minRUDDot * test[1];
  183. if (rEdgeDot >= (Real)0)
  184. {
  185. rdDot = rmin * test[0] + dmin * test[2];
  186. if (rdDot >= maxRDDot)
  187. {
  188. // LF-edge
  189. closest[0] = rmax;
  190. closest[1] = test[1];
  191. closest[2] = dmax;
  192. }
  193. else if (rdDot >= minRDDot)
  194. {
  195. // L-face
  196. rDot = dmin * test[0] - rmin * test[2];
  197. t = rDot / minRDDot;
  198. closest[0] = test[0] - t * dmin;
  199. closest[1] = test[1];
  200. closest[2] = test[2] + t * rmin;
  201. }
  202. else
  203. {
  204. // LN-edge
  205. closest[0] = rmin;
  206. closest[1] = test[1];
  207. closest[2] = dmin;
  208. }
  209. }
  210. else
  211. {
  212. uEdgeDot = rmin * rudDot - minRUDDot * test[0];
  213. if (uEdgeDot >= (Real)0)
  214. {
  215. udDot = umin * test[1] + dmin * test[2];
  216. if (udDot >= maxUDDot)
  217. {
  218. // UF-edge
  219. closest[0] = test[0];
  220. closest[1] = umax;
  221. closest[2] = dmax;
  222. }
  223. else if (udDot >= minUDDot)
  224. {
  225. // U-face
  226. uDot = dmin * test[1] - umin * test[2];
  227. t = uDot / minUDDot;
  228. closest[0] = test[0];
  229. closest[1] = test[1] - t * dmin;
  230. closest[2] = test[2] + t * umin;
  231. }
  232. else
  233. {
  234. // UN-edge
  235. closest[0] = test[0];
  236. closest[1] = umin;
  237. closest[2] = dmin;
  238. }
  239. }
  240. else
  241. {
  242. if (rudDot >= maxRUDDot)
  243. {
  244. // LUF-vertex
  245. closest[0] = rmax;
  246. closest[1] = umax;
  247. closest[2] = dmax;
  248. }
  249. else if (rudDot >= minRUDDot)
  250. {
  251. // LU-edge
  252. t = rudDot / minRUDDot;
  253. closest[0] = t * rmin;
  254. closest[1] = t * umin;
  255. closest[2] = t * dmin;
  256. }
  257. else
  258. {
  259. // LUN-vertex
  260. closest[0] = rmin;
  261. closest[1] = umin;
  262. closest[2] = dmin;
  263. }
  264. }
  265. }
  266. }
  267. }
  268. }
  269. else
  270. {
  271. rDot = dmin * test[0] - rmin * test[2];
  272. uDot = dmin * test[1] - umin * test[2];
  273. if (rDot <= (Real)0)
  274. {
  275. if (uDot <= (Real)0)
  276. {
  277. // point inside frustum
  278. closest = test;
  279. }
  280. else
  281. {
  282. udDot = umin * test[1] + dmin * test[2];
  283. if (udDot >= maxUDDot)
  284. {
  285. // UF-edge
  286. closest[0] = test[0];
  287. closest[1] = umax;
  288. closest[2] = dmax;
  289. }
  290. else
  291. {
  292. // U-face
  293. t = uDot / minUDDot;
  294. closest[0] = test[0];
  295. closest[1] = test[1] - t * dmin;
  296. closest[2] = test[2] + t * umin;
  297. }
  298. }
  299. }
  300. else
  301. {
  302. if (uDot <= (Real)0)
  303. {
  304. rdDot = rmin * test[0] + dmin * test[2];
  305. if (rdDot >= maxRDDot)
  306. {
  307. // LF-edge
  308. closest[0] = rmax;
  309. closest[1] = test[1];
  310. closest[2] = dmax;
  311. }
  312. else
  313. {
  314. // L-face
  315. t = rDot / minRDDot;
  316. closest[0] = test[0] - t * dmin;
  317. closest[1] = test[1];
  318. closest[2] = test[2] + t * rmin;
  319. }
  320. }
  321. else
  322. {
  323. rudDot = rmin * test[0] + umin * test[1] + dmin * test[2];
  324. rEdgeDot = umin * rudDot - minRUDDot * test[1];
  325. if (rEdgeDot >= (Real)0)
  326. {
  327. rdDot = rmin * test[0] + dmin * test[2];
  328. if (rdDot >= maxRDDot)
  329. {
  330. // LF-edge
  331. closest[0] = rmax;
  332. closest[1] = test[1];
  333. closest[2] = dmax;
  334. }
  335. else // assert( rdDot >= minRDDot )
  336. {
  337. // L-face
  338. t = rDot / minRDDot;
  339. closest[0] = test[0] - t * dmin;
  340. closest[1] = test[1];
  341. closest[2] = test[2] + t * rmin;
  342. }
  343. }
  344. else
  345. {
  346. uEdgeDot = rmin * rudDot - minRUDDot * test[0];
  347. if (uEdgeDot >= (Real)0)
  348. {
  349. udDot = umin * test[1] + dmin * test[2];
  350. if (udDot >= maxUDDot)
  351. {
  352. // UF-edge
  353. closest[0] = test[0];
  354. closest[1] = umax;
  355. closest[2] = dmax;
  356. }
  357. else // assert( udDot >= minUDDot )
  358. {
  359. // U-face
  360. t = uDot / minUDDot;
  361. closest[0] = test[0];
  362. closest[1] = test[1] - t * dmin;
  363. closest[2] = test[2] + t * umin;
  364. }
  365. }
  366. else
  367. {
  368. if (rudDot >= maxRUDDot)
  369. {
  370. // LUF-vertex
  371. closest[0] = rmax;
  372. closest[1] = umax;
  373. closest[2] = dmax;
  374. }
  375. else // assert( rudDot >= minRUDDot )
  376. {
  377. // LU-edge
  378. t = rudDot / minRUDDot;
  379. closest[0] = t * rmin;
  380. closest[1] = t * umin;
  381. closest[2] = t * dmin;
  382. }
  383. }
  384. }
  385. }
  386. }
  387. }
  388. diff = test - closest;
  389. // Convert back to original quadrant.
  390. if (rSignChange)
  391. {
  392. closest[0] = -closest[0];
  393. }
  394. if (uSignChange)
  395. {
  396. closest[1] = -closest[1];
  397. }
  398. // Convert back to original coordinates.
  399. result.frustumClosestPoint = frustum.origin +
  400. closest[0] * frustum.rVector +
  401. closest[1] * frustum.uVector +
  402. closest[2] * frustum.dVector;
  403. result.sqrDistance = Dot(diff, diff);
  404. result.distance = std::sqrt(result.sqrDistance);
  405. return result;
  406. }
  407. };
  408. }