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