ImathBoxAlgo.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. //
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Copyright Contributors to the OpenEXR Project.
  4. //
  5. //
  6. // Axis-aligned bounding box utility functions
  7. //
  8. #ifndef INCLUDED_IMATHBOXALGO_H
  9. #define INCLUDED_IMATHBOXALGO_H
  10. #include "ImathNamespace.h"
  11. #include "ImathBox.h"
  12. #include "ImathLineAlgo.h"
  13. #include "ImathMatrix.h"
  14. #include "ImathPlane.h"
  15. IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
  16. ///
  17. /// Clip the coordinates of a point, `p`, against a `Box<T>`, `box`.
  18. /// Return the closest point to `p` that is inside the box.
  19. ///
  20. template <class T>
  21. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
  22. clip (const T& p, const Box<T>& box) IMATH_NOEXCEPT
  23. {
  24. T q;
  25. for (int i = 0; i < int (box.min.dimensions()); i++)
  26. {
  27. if (p[i] < box.min[i])
  28. q[i] = box.min[i];
  29. else if (p[i] > box.max[i])
  30. q[i] = box.max[i];
  31. else
  32. q[i] = p[i];
  33. }
  34. return q;
  35. }
  36. ///
  37. /// Return the point in or on the `Box<T>`, `box`, that is closesest to
  38. /// the point, `p`.
  39. ///
  40. template <class T>
  41. IMATH_HOSTDEVICE constexpr inline T
  42. closestPointInBox (const T& p, const Box<T>& box) IMATH_NOEXCEPT
  43. {
  44. return clip (p, box);
  45. }
  46. ///
  47. /// Return the point on the surface of the `Box<T>`, `box`, that is
  48. /// closest to point `p`.
  49. ///
  50. /// If the box is empty, return `p`.
  51. ///
  52. template <class T>
  53. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3<T>
  54. closestPointOnBox (const Vec3<T>& p, const Box<Vec3<T>>& box) IMATH_NOEXCEPT
  55. {
  56. if (box.isEmpty())
  57. return p;
  58. Vec3<T> q = closestPointInBox (p, box);
  59. if (q == p)
  60. {
  61. Vec3<T> d1 = p - box.min;
  62. Vec3<T> d2 = box.max - p;
  63. Vec3<T> d ((d1.x < d2.x) ? d1.x : d2.x,
  64. (d1.y < d2.y) ? d1.y : d2.y,
  65. (d1.z < d2.z) ? d1.z : d2.z);
  66. if (d.x < d.y && d.x < d.z)
  67. {
  68. q.x = (d1.x < d2.x) ? box.min.x : box.max.x;
  69. }
  70. else if (d.y < d.z)
  71. {
  72. q.y = (d1.y < d2.y) ? box.min.y : box.max.y;
  73. }
  74. else
  75. {
  76. q.z = (d1.z < d2.z) ? box.min.z : box.max.z;
  77. }
  78. }
  79. return q;
  80. }
  81. ///
  82. /// Transform a 3D box by a matrix, and compute a new box that
  83. /// tightly encloses the transformed box. Return the transformed box.
  84. ///
  85. /// If `m` is an affine transform, then we use James Arvo's fast
  86. /// method as described in "Graphics Gems", Academic Press, 1990,
  87. /// pp. 548-550.
  88. ///
  89. /// A transformed empty box is still empty, and a transformed infinite box
  90. /// is still infinite.
  91. ///
  92. template <class S, class T>
  93. IMATH_HOSTDEVICE Box<Vec3<S>>
  94. transform (const Box<Vec3<S>>& box, const Matrix44<T>& m) IMATH_NOEXCEPT
  95. {
  96. if (box.isEmpty() || box.isInfinite())
  97. return box;
  98. //
  99. // If the last column of m is (0 0 0 1) then m is an affine
  100. // transform, and we use the fast Graphics Gems trick.
  101. //
  102. if (m[0][3] == 0 && m[1][3] == 0 && m[2][3] == 0 && m[3][3] == 1)
  103. {
  104. Box<Vec3<S>> newBox;
  105. for (int i = 0; i < 3; i++)
  106. {
  107. newBox.min[i] = newBox.max[i] = (S) m[3][i];
  108. for (int j = 0; j < 3; j++)
  109. {
  110. S a, b;
  111. a = (S) m[j][i] * box.min[j];
  112. b = (S) m[j][i] * box.max[j];
  113. if (a < b)
  114. {
  115. newBox.min[i] += a;
  116. newBox.max[i] += b;
  117. }
  118. else
  119. {
  120. newBox.min[i] += b;
  121. newBox.max[i] += a;
  122. }
  123. }
  124. }
  125. return newBox;
  126. }
  127. //
  128. // M is a projection matrix. Do things the naive way:
  129. // Transform the eight corners of the box, and find an
  130. // axis-parallel box that encloses the transformed corners.
  131. //
  132. Vec3<S> points[8];
  133. points[0][0] = points[1][0] = points[2][0] = points[3][0] = box.min[0];
  134. points[4][0] = points[5][0] = points[6][0] = points[7][0] = box.max[0];
  135. points[0][1] = points[1][1] = points[4][1] = points[5][1] = box.min[1];
  136. points[2][1] = points[3][1] = points[6][1] = points[7][1] = box.max[1];
  137. points[0][2] = points[2][2] = points[4][2] = points[6][2] = box.min[2];
  138. points[1][2] = points[3][2] = points[5][2] = points[7][2] = box.max[2];
  139. Box<Vec3<S>> newBox;
  140. for (int i = 0; i < 8; i++)
  141. newBox.extendBy (points[i] * m);
  142. return newBox;
  143. }
  144. ///
  145. /// Transform a 3D box by a matrix, and compute a new box that
  146. /// tightly encloses the transformed box. The transformed box is
  147. /// returned in the `result` argument.
  148. ///
  149. /// If m is an affine transform, then we use James Arvo's fast
  150. /// method as described in "Graphics Gems", Academic Press, 1990,
  151. /// pp. 548-550.
  152. ///
  153. /// A transformed empty box is still empty, and a transformed infinite
  154. /// box is still infinite
  155. ///
  156. template <class S, class T>
  157. IMATH_HOSTDEVICE void
  158. transform (const Box<Vec3<S>>& box, const Matrix44<T>& m, Box<Vec3<S>>& result) IMATH_NOEXCEPT
  159. {
  160. if (box.isEmpty() || box.isInfinite())
  161. {
  162. return;
  163. }
  164. //
  165. // If the last column of m is (0 0 0 1) then m is an affine
  166. // transform, and we use the fast Graphics Gems trick.
  167. //
  168. if (m[0][3] == 0 && m[1][3] == 0 && m[2][3] == 0 && m[3][3] == 1)
  169. {
  170. for (int i = 0; i < 3; i++)
  171. {
  172. result.min[i] = result.max[i] = (S) m[3][i];
  173. for (int j = 0; j < 3; j++)
  174. {
  175. S a, b;
  176. a = (S) m[j][i] * box.min[j];
  177. b = (S) m[j][i] * box.max[j];
  178. if (a < b)
  179. {
  180. result.min[i] += a;
  181. result.max[i] += b;
  182. }
  183. else
  184. {
  185. result.min[i] += b;
  186. result.max[i] += a;
  187. }
  188. }
  189. }
  190. return;
  191. }
  192. //
  193. // M is a projection matrix. Do things the naive way:
  194. // Transform the eight corners of the box, and find an
  195. // axis-parallel box that encloses the transformed corners.
  196. //
  197. Vec3<S> points[8];
  198. points[0][0] = points[1][0] = points[2][0] = points[3][0] = box.min[0];
  199. points[4][0] = points[5][0] = points[6][0] = points[7][0] = box.max[0];
  200. points[0][1] = points[1][1] = points[4][1] = points[5][1] = box.min[1];
  201. points[2][1] = points[3][1] = points[6][1] = points[7][1] = box.max[1];
  202. points[0][2] = points[2][2] = points[4][2] = points[6][2] = box.min[2];
  203. points[1][2] = points[3][2] = points[5][2] = points[7][2] = box.max[2];
  204. for (int i = 0; i < 8; i++)
  205. result.extendBy (points[i] * m);
  206. }
  207. ///
  208. /// Transform a 3D box by a matrix whose rightmost column `(0 0 0 1)`,
  209. /// and compute a new box that tightly encloses the transformed
  210. /// box. Return the transformed box.
  211. ///
  212. /// As in the transform() function, use James Arvo's fast method if
  213. /// possible.
  214. ///
  215. /// A transformed empty or infinite box is still empty or infinite.
  216. ///
  217. template <class S, class T>
  218. IMATH_HOSTDEVICE Box<Vec3<S>>
  219. affineTransform (const Box<Vec3<S>>& box, const Matrix44<T>& m) IMATH_NOEXCEPT
  220. {
  221. if (box.isEmpty() || box.isInfinite())
  222. return box;
  223. Box<Vec3<S>> newBox;
  224. for (int i = 0; i < 3; i++)
  225. {
  226. newBox.min[i] = newBox.max[i] = (S) m[3][i];
  227. for (int j = 0; j < 3; j++)
  228. {
  229. S a, b;
  230. a = (S) m[j][i] * box.min[j];
  231. b = (S) m[j][i] * box.max[j];
  232. if (a < b)
  233. {
  234. newBox.min[i] += a;
  235. newBox.max[i] += b;
  236. }
  237. else
  238. {
  239. newBox.min[i] += b;
  240. newBox.max[i] += a;
  241. }
  242. }
  243. }
  244. return newBox;
  245. }
  246. ///
  247. /// Transform a 3D box by a matrix whose rightmost column is
  248. /// `(0 0 0 1)`, and compute a new box that tightly encloses
  249. /// the transformed box. Return the transformed box in the `result`
  250. /// argument.
  251. ///
  252. /// As in the transform() function, use James Arvo's fast method if
  253. /// possible.
  254. ///
  255. /// A transformed empty or infinite box is still empty or infinite.
  256. ///
  257. template <class S, class T>
  258. IMATH_HOSTDEVICE void
  259. affineTransform (const Box<Vec3<S>>& box, const Matrix44<T>& m, Box<Vec3<S>>& result) IMATH_NOEXCEPT
  260. {
  261. if (box.isEmpty())
  262. {
  263. result.makeEmpty();
  264. return;
  265. }
  266. if (box.isInfinite())
  267. {
  268. result.makeInfinite();
  269. return;
  270. }
  271. for (int i = 0; i < 3; i++)
  272. {
  273. result.min[i] = result.max[i] = (S) m[3][i];
  274. for (int j = 0; j < 3; j++)
  275. {
  276. S a, b;
  277. a = (S) m[j][i] * box.min[j];
  278. b = (S) m[j][i] * box.max[j];
  279. if (a < b)
  280. {
  281. result.min[i] += a;
  282. result.max[i] += b;
  283. }
  284. else
  285. {
  286. result.min[i] += b;
  287. result.max[i] += a;
  288. }
  289. }
  290. }
  291. }
  292. ///
  293. /// Compute the points where a ray, `r`, enters and exits a 3D box, `b`:
  294. ///
  295. /// Return true if the ray starts inside the box or if the ray starts
  296. /// outside and intersects the box, or return false otherwise (that
  297. /// is, if the ray does not intersect the box).
  298. ///
  299. /// The entry and exit points are the points on two of the faces of
  300. /// the box when the function returns true (the entry end exit points
  301. /// may be on either side of the ray's origin), or undefined if the
  302. /// the function returns false.
  303. ///
  304. template <class T>
  305. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool
  306. findEntryAndExitPoints (const Line3<T>& r, const Box<Vec3<T>>& b, Vec3<T>& entry, Vec3<T>& exit) IMATH_NOEXCEPT
  307. {
  308. if (b.isEmpty())
  309. {
  310. //
  311. // No ray intersects an empty box
  312. //
  313. return false;
  314. }
  315. //
  316. // The following description assumes that the ray's origin is outside
  317. // the box, but the code below works even if the origin is inside the
  318. // box:
  319. //
  320. // Between one and three "frontfacing" sides of the box are oriented
  321. // towards the ray's origin, and between one and three "backfacing"
  322. // sides are oriented away from the ray's origin.
  323. // We intersect the ray with the planes that contain the sides of the
  324. // box, and compare the distances between the ray's origin and the
  325. // ray-plane intersections. The ray intersects the box if the most
  326. // distant frontfacing intersection is nearer than the nearest
  327. // backfacing intersection. If the ray does intersect the box, then
  328. // the most distant frontfacing ray-plane intersection is the entry
  329. // point and the nearest backfacing ray-plane intersection is the
  330. // exit point.
  331. //
  332. const T TMAX = std::numeric_limits<T>::max();
  333. T tFrontMax = -TMAX;
  334. T tBackMin = TMAX;
  335. //
  336. // Minimum and maximum X sides.
  337. //
  338. if (r.dir.x >= 0)
  339. {
  340. T d1 = b.max.x - r.pos.x;
  341. T d2 = b.min.x - r.pos.x;
  342. if (r.dir.x > 1 || (abs (d1) < TMAX * r.dir.x && abs (d2) < TMAX * r.dir.x))
  343. {
  344. T t1 = d1 / r.dir.x;
  345. T t2 = d2 / r.dir.x;
  346. if (tBackMin > t1)
  347. {
  348. tBackMin = t1;
  349. exit.x = b.max.x;
  350. exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
  351. exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
  352. }
  353. if (tFrontMax < t2)
  354. {
  355. tFrontMax = t2;
  356. entry.x = b.min.x;
  357. entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
  358. entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
  359. }
  360. }
  361. else if (r.pos.x < b.min.x || r.pos.x > b.max.x)
  362. {
  363. return false;
  364. }
  365. }
  366. else // r.dir.x < 0
  367. {
  368. T d1 = b.min.x - r.pos.x;
  369. T d2 = b.max.x - r.pos.x;
  370. if (r.dir.x < -1 || (abs (d1) < -TMAX * r.dir.x && abs (d2) < -TMAX * r.dir.x))
  371. {
  372. T t1 = d1 / r.dir.x;
  373. T t2 = d2 / r.dir.x;
  374. if (tBackMin > t1)
  375. {
  376. tBackMin = t1;
  377. exit.x = b.min.x;
  378. exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
  379. exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
  380. }
  381. if (tFrontMax < t2)
  382. {
  383. tFrontMax = t2;
  384. entry.x = b.max.x;
  385. entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
  386. entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
  387. }
  388. }
  389. else if (r.pos.x < b.min.x || r.pos.x > b.max.x)
  390. {
  391. return false;
  392. }
  393. }
  394. //
  395. // Minimum and maximum Y sides.
  396. //
  397. if (r.dir.y >= 0)
  398. {
  399. T d1 = b.max.y - r.pos.y;
  400. T d2 = b.min.y - r.pos.y;
  401. if (r.dir.y > 1 || (abs (d1) < TMAX * r.dir.y && abs (d2) < TMAX * r.dir.y))
  402. {
  403. T t1 = d1 / r.dir.y;
  404. T t2 = d2 / r.dir.y;
  405. if (tBackMin > t1)
  406. {
  407. tBackMin = t1;
  408. exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
  409. exit.y = b.max.y;
  410. exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
  411. }
  412. if (tFrontMax < t2)
  413. {
  414. tFrontMax = t2;
  415. entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
  416. entry.y = b.min.y;
  417. entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
  418. }
  419. }
  420. else if (r.pos.y < b.min.y || r.pos.y > b.max.y)
  421. {
  422. return false;
  423. }
  424. }
  425. else // r.dir.y < 0
  426. {
  427. T d1 = b.min.y - r.pos.y;
  428. T d2 = b.max.y - r.pos.y;
  429. if (r.dir.y < -1 || (abs (d1) < -TMAX * r.dir.y && abs (d2) < -TMAX * r.dir.y))
  430. {
  431. T t1 = d1 / r.dir.y;
  432. T t2 = d2 / r.dir.y;
  433. if (tBackMin > t1)
  434. {
  435. tBackMin = t1;
  436. exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
  437. exit.y = b.min.y;
  438. exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
  439. }
  440. if (tFrontMax < t2)
  441. {
  442. tFrontMax = t2;
  443. entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
  444. entry.y = b.max.y;
  445. entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
  446. }
  447. }
  448. else if (r.pos.y < b.min.y || r.pos.y > b.max.y)
  449. {
  450. return false;
  451. }
  452. }
  453. //
  454. // Minimum and maximum Z sides.
  455. //
  456. if (r.dir.z >= 0)
  457. {
  458. T d1 = b.max.z - r.pos.z;
  459. T d2 = b.min.z - r.pos.z;
  460. if (r.dir.z > 1 || (abs (d1) < TMAX * r.dir.z && abs (d2) < TMAX * r.dir.z))
  461. {
  462. T t1 = d1 / r.dir.z;
  463. T t2 = d2 / r.dir.z;
  464. if (tBackMin > t1)
  465. {
  466. tBackMin = t1;
  467. exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
  468. exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
  469. exit.z = b.max.z;
  470. }
  471. if (tFrontMax < t2)
  472. {
  473. tFrontMax = t2;
  474. entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
  475. entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
  476. entry.z = b.min.z;
  477. }
  478. }
  479. else if (r.pos.z < b.min.z || r.pos.z > b.max.z)
  480. {
  481. return false;
  482. }
  483. }
  484. else // r.dir.z < 0
  485. {
  486. T d1 = b.min.z - r.pos.z;
  487. T d2 = b.max.z - r.pos.z;
  488. if (r.dir.z < -1 || (abs (d1) < -TMAX * r.dir.z && abs (d2) < -TMAX * r.dir.z))
  489. {
  490. T t1 = d1 / r.dir.z;
  491. T t2 = d2 / r.dir.z;
  492. if (tBackMin > t1)
  493. {
  494. tBackMin = t1;
  495. exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
  496. exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
  497. exit.z = b.min.z;
  498. }
  499. if (tFrontMax < t2)
  500. {
  501. tFrontMax = t2;
  502. entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
  503. entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
  504. entry.z = b.max.z;
  505. }
  506. }
  507. else if (r.pos.z < b.min.z || r.pos.z > b.max.z)
  508. {
  509. return false;
  510. }
  511. }
  512. return tFrontMax <= tBackMin;
  513. }
  514. ///
  515. /// Intersect a ray, `r`, with a 3D box, `b, and compute the intersection
  516. /// point, returned in `ip`.
  517. ///
  518. /// The intersection point is
  519. /// - the ray's origin if the ray starts inside the box
  520. /// - a point on one of the faces of the box if the ray
  521. /// starts outside the box
  522. /// - undefined when intersect() returns false
  523. ///
  524. /// @return
  525. /// - true if the ray starts inside the box or if the
  526. /// ray starts outside and intersects the box
  527. /// - false if the ray starts outside the box and intersects it,
  528. /// but the intersection is behind the ray's origin.
  529. /// - false if the ray starts outside and does not intersect it
  530. ///
  531. template <class T>
  532. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool
  533. intersects (const Box<Vec3<T>>& b, const Line3<T>& r, Vec3<T>& ip) IMATH_NOEXCEPT
  534. {
  535. if (b.isEmpty())
  536. {
  537. //
  538. // No ray intersects an empty box
  539. //
  540. return false;
  541. }
  542. if (b.intersects (r.pos))
  543. {
  544. //
  545. // The ray starts inside the box
  546. //
  547. ip = r.pos;
  548. return true;
  549. }
  550. //
  551. // The ray starts outside the box. Between one and three "frontfacing"
  552. // sides of the box are oriented towards the ray, and between one and
  553. // three "backfacing" sides are oriented away from the ray.
  554. // We intersect the ray with the planes that contain the sides of the
  555. // box, and compare the distances between ray's origin and the ray-plane
  556. // intersections.
  557. // The ray intersects the box if the most distant frontfacing intersection
  558. // is nearer than the nearest backfacing intersection. If the ray does
  559. // intersect the box, then the most distant frontfacing ray-plane
  560. // intersection is the ray-box intersection.
  561. //
  562. const T TMAX = std::numeric_limits<T>::max();
  563. T tFrontMax = -1;
  564. T tBackMin = TMAX;
  565. //
  566. // Minimum and maximum X sides.
  567. //
  568. if (r.dir.x > 0)
  569. {
  570. if (r.pos.x > b.max.x)
  571. return false;
  572. T d = b.max.x - r.pos.x;
  573. if (r.dir.x > 1 || d < TMAX * r.dir.x)
  574. {
  575. T t = d / r.dir.x;
  576. if (tBackMin > t)
  577. tBackMin = t;
  578. }
  579. if (r.pos.x <= b.min.x)
  580. {
  581. T d = b.min.x - r.pos.x;
  582. T t = (r.dir.x > 1 || d < TMAX * r.dir.x) ? d / r.dir.x : TMAX;
  583. if (tFrontMax < t)
  584. {
  585. tFrontMax = t;
  586. ip.x = b.min.x;
  587. ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
  588. ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
  589. }
  590. }
  591. }
  592. else if (r.dir.x < 0)
  593. {
  594. if (r.pos.x < b.min.x)
  595. return false;
  596. T d = b.min.x - r.pos.x;
  597. if (r.dir.x < -1 || d > TMAX * r.dir.x)
  598. {
  599. T t = d / r.dir.x;
  600. if (tBackMin > t)
  601. tBackMin = t;
  602. }
  603. if (r.pos.x >= b.max.x)
  604. {
  605. T d = b.max.x - r.pos.x;
  606. T t = (r.dir.x < -1 || d > TMAX * r.dir.x) ? d / r.dir.x : TMAX;
  607. if (tFrontMax < t)
  608. {
  609. tFrontMax = t;
  610. ip.x = b.max.x;
  611. ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
  612. ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
  613. }
  614. }
  615. }
  616. else // r.dir.x == 0
  617. {
  618. if (r.pos.x < b.min.x || r.pos.x > b.max.x)
  619. return false;
  620. }
  621. //
  622. // Minimum and maximum Y sides.
  623. //
  624. if (r.dir.y > 0)
  625. {
  626. if (r.pos.y > b.max.y)
  627. return false;
  628. T d = b.max.y - r.pos.y;
  629. if (r.dir.y > 1 || d < TMAX * r.dir.y)
  630. {
  631. T t = d / r.dir.y;
  632. if (tBackMin > t)
  633. tBackMin = t;
  634. }
  635. if (r.pos.y <= b.min.y)
  636. {
  637. T d = b.min.y - r.pos.y;
  638. T t = (r.dir.y > 1 || d < TMAX * r.dir.y) ? d / r.dir.y : TMAX;
  639. if (tFrontMax < t)
  640. {
  641. tFrontMax = t;
  642. ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
  643. ip.y = b.min.y;
  644. ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
  645. }
  646. }
  647. }
  648. else if (r.dir.y < 0)
  649. {
  650. if (r.pos.y < b.min.y)
  651. return false;
  652. T d = b.min.y - r.pos.y;
  653. if (r.dir.y < -1 || d > TMAX * r.dir.y)
  654. {
  655. T t = d / r.dir.y;
  656. if (tBackMin > t)
  657. tBackMin = t;
  658. }
  659. if (r.pos.y >= b.max.y)
  660. {
  661. T d = b.max.y - r.pos.y;
  662. T t = (r.dir.y < -1 || d > TMAX * r.dir.y) ? d / r.dir.y : TMAX;
  663. if (tFrontMax < t)
  664. {
  665. tFrontMax = t;
  666. ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
  667. ip.y = b.max.y;
  668. ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
  669. }
  670. }
  671. }
  672. else // r.dir.y == 0
  673. {
  674. if (r.pos.y < b.min.y || r.pos.y > b.max.y)
  675. return false;
  676. }
  677. //
  678. // Minimum and maximum Z sides.
  679. //
  680. if (r.dir.z > 0)
  681. {
  682. if (r.pos.z > b.max.z)
  683. return false;
  684. T d = b.max.z - r.pos.z;
  685. if (r.dir.z > 1 || d < TMAX * r.dir.z)
  686. {
  687. T t = d / r.dir.z;
  688. if (tBackMin > t)
  689. tBackMin = t;
  690. }
  691. if (r.pos.z <= b.min.z)
  692. {
  693. T d = b.min.z - r.pos.z;
  694. T t = (r.dir.z > 1 || d < TMAX * r.dir.z) ? d / r.dir.z : TMAX;
  695. if (tFrontMax < t)
  696. {
  697. tFrontMax = t;
  698. ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
  699. ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
  700. ip.z = b.min.z;
  701. }
  702. }
  703. }
  704. else if (r.dir.z < 0)
  705. {
  706. if (r.pos.z < b.min.z)
  707. return false;
  708. T d = b.min.z - r.pos.z;
  709. if (r.dir.z < -1 || d > TMAX * r.dir.z)
  710. {
  711. T t = d / r.dir.z;
  712. if (tBackMin > t)
  713. tBackMin = t;
  714. }
  715. if (r.pos.z >= b.max.z)
  716. {
  717. T d = b.max.z - r.pos.z;
  718. T t = (r.dir.z < -1 || d > TMAX * r.dir.z) ? d / r.dir.z : TMAX;
  719. if (tFrontMax < t)
  720. {
  721. tFrontMax = t;
  722. ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
  723. ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
  724. ip.z = b.max.z;
  725. }
  726. }
  727. }
  728. else // r.dir.z == 0
  729. {
  730. if (r.pos.z < b.min.z || r.pos.z > b.max.z)
  731. return false;
  732. }
  733. return tFrontMax <= tBackMin;
  734. }
  735. ///
  736. /// Return whether the the ray `ray` interects the 3D box `box`.
  737. ///
  738. template <class T>
  739. IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool
  740. intersects (const Box<Vec3<T>>& box, const Line3<T>& ray) IMATH_NOEXCEPT
  741. {
  742. Vec3<T> ignored;
  743. return intersects (box, ray, ignored);
  744. }
  745. IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
  746. #endif // INCLUDED_IMATHBOXALGO_H