ImathBoxAlgo.h 22 KB

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