Home | History | Annotate | Download | only in Imath
      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
     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
    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>
    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> >
    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
    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> >
    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
    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
    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
    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
   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