1 ///////////////////////////////////////////////////////////////////////////
3 // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
6 // All rights reserved.
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are
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
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.
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.
33 ///////////////////////////////////////////////////////////////////////////
37 #ifndef INCLUDED_IMATHBOXALGO_H
38 #define INCLUDED_IMATHBOXALGO_H
41 //---------------------------------------------------------------------------
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.
51 // T clip<T>(const T& in, const Box<T>& box)
53 // Vec3<T> closestPointOnBox(const Vec3<T>&, const Box<Vec3<T>>& )
55 // Vec3<T> closestPointInBox(const Vec3<T>&, const Box<Vec3<T>>& )
57 // void transform(Box<Vec3<T>>&, const Matrix44<T>&)
59 // bool findEntryAndExitPoints(const Line<T> &line,
60 // const Box< Vec3<T> > &box,
61 // Vec3<T> &enterPoint,
62 // Vec3<T> &exitPoint)
64 // bool intersects(const Box<Vec3<T>> &box,
65 // const Line3<T> &line,
68 // bool intersects(const Box<Vec3<T>> &box, const Line3<T> &line)
70 //---------------------------------------------------------------------------
73 #include "ImathMatrix.h"
74 #include "ImathLineAlgo.h"
75 #include "ImathPlane.h"
81 inline T clip(const T& in, const Box<T>& box)
84 // Clip a point so that it lies inside the given bbox
89 for (int i=0; i<(int)box.min.dimensions(); i++)
91 if (in[i] < box.min[i]) out[i] = box.min[i];
92 else if (in[i] > box.max[i]) out[i] = box.max[i];
101 // Return p if p is inside the box.
106 closestPointInBox(const Vec3<T>& p, const Box< Vec3<T> >& box )
112 else if (p.x > box.max.x)
119 else if (p.y > box.max.y)
126 else if (p.z > box.max.z)
135 Vec3<T> closestPointOnBox(const Vec3<T>& pt, const Box< Vec3<T> >& box )
138 // This sucker is specialized to work with a Vec3f and a box
144 // trivial cases first
147 else if (pt == box.center())
150 result[0] = (box.max[0] + box.min[0])/2.0;
151 result[1] = (box.max[1] + box.min[1])/2.0;
152 result[2] = box.max[2];
156 // Find the closest point on a unit box (from -1 to 1),
159 // Find the vector from center to the point, then scale
161 Vec3<T> vec = pt - box.center();
162 T sizeX = box.max[0]-box.min[0];
163 T sizeY = box.max[1]-box.min[1];
164 T sizeZ = box.max[2]-box.min[2];
176 // Side to snap side that has greatest magnitude in the vector.
178 mag[0] = fabs(vec[0]);
179 mag[1] = fabs(vec[1]);
180 mag[2] = fabs(vec[2]);
184 // Check if beyond corners
192 // snap to appropriate side
193 if ((mag[0] > mag[1]) && (mag[0] > mag[2]))
197 else if ((mag[1] > mag[0]) && (mag[1] > mag[2]))
201 else if ((mag[2] > mag[0]) && (mag[2] > mag[1]))
205 else if ((mag[0] == mag[1]) && (mag[0] == mag[2]))
208 result = Vec3<T>(1,1,1);
210 else if (mag[0] == mag[1])
212 // edge parallel with z
216 else if (mag[0] == mag[2])
218 // edge parallel with y
222 else if (mag[1] == mag[2])
224 // edge parallel with x
229 // Now make everything point the right way
230 for (int i=0; i < 3; i++)
233 result[i] = -result[i];
236 // scale back up and move to center
241 result += box.center();
246 template <class S, class T>
248 transform(const Box< Vec3<S> >& box, const Matrix44<T>& m)
250 // Transforms Box3f by matrix, enlarging Box3f to contain result.
251 // Clever method courtesy of Graphics Gems, pp. 548-550
253 // This works for projection matrices as well as simple affine
254 // transformations. Coordinates of the box are rehomogenized if there
255 // is a projection matrix
257 // a transformed empty box is still empty
261 // If the last column is close enuf to ( 0 0 0 1 ) then we use the
262 // fast, affine version. The tricky affine method could maybe be
263 // extended to deal with the projection case as well, but its not
264 // worth it right now.
266 if (m[0][3] * m[0][3] + m[1][3] * m[1][3] + m[2][3] * m[2][3]
267 + (1.0 - m[3][3]) * (1.0 - m[3][3]) < 0.00001)
269 // Affine version, use the Graphics Gems hack
271 Box< Vec3<S> > newBox;
273 for (i = 0; i < 3; i++)
275 newBox.min[i] = newBox.max[i] = (S) m[3][i];
277 for (j = 0; j < 3; j++)
281 a = (S) m[j][i] * box.min[j];
282 b = (S) m[j][i] * box.max[j];
300 // This is a projection matrix. Do things the naive way.
303 /* Set up the eight points at the corners of the extent */
304 points[0][0] = points[1][0] = points[2][0] = points[3][0] = box.min[0];
305 points[4][0] = points[5][0] = points[6][0] = points[7][0] = box.max[0];
307 points[0][1] = points[1][1] = points[4][1] = points[5][1] = box.min[1];
308 points[2][1] = points[3][1] = points[6][1] = points[7][1] = box.max[1];
310 points[0][2] = points[2][2] = points[4][2] = points[6][2] = box.min[2];
311 points[1][2] = points[3][2] = points[5][2] = points[7][2] = box.max[2];
313 Box< Vec3<S> > newBox;
314 for (int i = 0; i < 8; i++)
315 newBox.extendBy(points[i] * m);
322 affineTransform(const Box< Vec3<T> > &bbox, const Matrix44<T> &M)
324 float min0, max0, min1, max1, min2, max2, a, b;
325 float min0new, max0new, min1new, max1new, min2new, max2new;
334 min0new = max0new = M[3][0];
363 min1new = max1new = M[3][1];
392 min2new = max2new = M[3][2];
421 Box< Vec3<T> > xbbox;
423 xbbox.min[0] = min0new;
424 xbbox.max[0] = max0new;
425 xbbox.min[1] = min1new;
426 xbbox.max[1] = max1new;
427 xbbox.min[2] = min2new;
428 xbbox.max[2] = max2new;
435 bool findEntryAndExitPoints(const Line3<T>& line,
436 const Box<Vec3<T> >& box,
440 if ( box.isEmpty() ) return false;
441 if ( line.distanceTo(box.center()) > box.size().length()/2. ) return false;
443 Vec3<T> points[8], inter, bary;
446 bool front = false, valid, validIntersection = false;
448 // set up the eight coords of the corners of the box
449 for(i = 0; i < 8; i++)
451 points[i].setValue( i & 01 ? box.min[0] : box.max[0],
452 i & 02 ? box.min[1] : box.max[1],
453 i & 04 ? box.min[2] : box.max[2]);
456 // intersect the 12 triangles.
457 for(i = 0; i < 12; i++)
461 case 0: v0 = 2; v1 = 1; v2 = 0; break; // +z
462 case 1: v0 = 2; v1 = 3; v2 = 1; break;
464 case 2: v0 = 4; v1 = 5; v2 = 6; break; // -z
465 case 3: v0 = 6; v1 = 5; v2 = 7; break;
467 case 4: v0 = 0; v1 = 6; v2 = 2; break; // -x
468 case 5: v0 = 0; v1 = 4; v2 = 6; break;
470 case 6: v0 = 1; v1 = 3; v2 = 7; break; // +x
471 case 7: v0 = 1; v1 = 7; v2 = 5; break;
473 case 8: v0 = 1; v1 = 4; v2 = 0; break; // -y
474 case 9: v0 = 1; v1 = 5; v2 = 4; break;
476 case 10: v0 = 2; v1 = 7; v2 = 3; break; // +y
477 case 11: v0 = 2; v1 = 6; v2 = 7; break;
479 if((valid=intersect (line, points[v0], points[v1], points[v2],
480 inter, bary, front)) == true)
485 validIntersection = valid;
490 validIntersection = valid;
494 return validIntersection;
498 bool intersects(const Box< Vec3<T> > &box,
499 const Line3<T> &line,
503 Fast Ray-Box Intersection
505 from "Graphics Gems", Academic Press, 1990
510 const int middle = 2;
512 const Vec3<T> &minB = box.min;
513 const Vec3<T> &maxB = box.max;
514 const Vec3<T> &origin = line.pos;
515 const Vec3<T> &dir = line.dir;
521 float candidatePlane[3];
523 /* Find candidate planes; this loop can be avoided if
524 rays cast all from the eye(assume perpsective view) */
525 for (int i=0; i<3; i++)
527 if(origin[i] < minB[i])
530 candidatePlane[i] = minB[i];
533 else if (origin[i] > maxB[i])
536 candidatePlane[i] = maxB[i];
541 quadrant[i] = middle;
545 /* Ray origin inside bounding box */
553 /* Calculate T distances to candidate planes */
554 for (int i = 0; i < 3; i++)
556 if (quadrant[i] != middle && dir[i] !=0.)
558 maxT[i] = (candidatePlane[i]-origin[i]) / dir[i];
566 /* Get largest of the maxT's for final choice of intersection */
569 for (int i = 1; i < 3; i++)
571 if (maxT[whichPlane] < maxT[i])
577 /* Check final candidate actually inside box */
578 if (maxT[whichPlane] < 0.) return false;
580 for (int i = 0; i < 3; i++)
584 result[i] = origin[i] + maxT[whichPlane] *dir[i];
586 if ((quadrant[i] == right && result[i] < minB[i]) ||
587 (quadrant[i] == left && result[i] > maxB[i]))
589 return false; /* outside box */
594 result[i] = candidatePlane[i];
602 bool intersects(const Box< Vec3<T> > &box, const Line3<T> &line)
605 return intersects(box,line,ignored);