/src/FreeImage/Source/OpenEXR/Imath/ImathBoxAlgo.h

https://bitbucket.org/cabalistic/ogredeps/ · C++ Header · 870 lines · 514 code · 152 blank · 204 comment · 135 complexity · 9c1b1681221ae66da311afd180790b33 MD5 · raw file

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