opencv/3rdparty/openexr/Imath/ImathBoxAlgo.h

1016 lines
24 KiB
C
Raw Normal View History

2012-08-24 22:31:49 +02:00
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002-2010, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
2012-10-17 09:12:04 +02:00
//
2012-08-24 22:31:49 +02:00
// All rights reserved.
2012-10-17 09:12:04 +02:00
//
2012-08-24 22:31:49 +02:00
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
2012-10-17 09:12:04 +02:00
// from this software without specific prior written permission.
//
2012-08-24 22:31:49 +02:00
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_IMATHBOXALGO_H
#define INCLUDED_IMATHBOXALGO_H
//---------------------------------------------------------------------------
//
// This file contains algorithms applied to or in conjunction
// with bounding boxes (Imath::Box). These algorithms require
// more headers to compile. The assumption made is that these
// functions are called much less often than the basic box
// functions or these functions require more support classes.
//
// Contains:
//
// T clip<T>(const T& in, const Box<T>& box)
//
// Vec3<T> closestPointOnBox(const Vec3<T>&, const Box<Vec3<T>>& )
//
// Vec3<T> closestPointInBox(const Vec3<T>&, const Box<Vec3<T>>& )
//
// Box< Vec3<S> > transform(const Box<Vec3<S>>&, const Matrix44<T>&)
// Box< Vec3<S> > affineTransform(const Box<Vec3<S>>&, const Matrix44<T>&)
//
// void transform(const Box<Vec3<S>>&, const Matrix44<T>&, Box<V3ec3<S>>&)
// void affineTransform(const Box<Vec3<S>>&,
// const Matrix44<T>&,
// Box<V3ec3<S>>&)
//
// bool findEntryAndExitPoints(const Line<T> &line,
// const Box< Vec3<T> > &box,
// Vec3<T> &enterPoint,
// Vec3<T> &exitPoint)
//
2012-10-17 09:12:04 +02:00
// bool intersects(const Box<Vec3<T>> &box,
// const Line3<T> &ray,
2012-08-24 22:31:49 +02:00
// Vec3<T> intersectionPoint)
//
// bool intersects(const Box<Vec3<T>> &box, const Line3<T> &ray)
//
//---------------------------------------------------------------------------
#include "ImathBox.h"
#include "ImathMatrix.h"
#include "ImathLineAlgo.h"
#include "ImathPlane.h"
namespace Imath {
template <class T>
inline T
clip (const T &p, const Box<T> &box)
{
//
// Clip the coordinates of a point, p, against a box.
// The result, q, is the closest point to p that is inside the box.
//
T q;
for (int i = 0; i < int (box.min.dimensions()); i++)
{
2012-10-17 09:12:04 +02:00
if (p[i] < box.min[i])
q[i] = box.min[i];
else if (p[i] > box.max[i])
q[i] = box.max[i];
else
q[i] = p[i];
2012-08-24 22:31:49 +02:00
}
return q;
}
template <class T>
inline T
closestPointInBox (const T &p, const Box<T> &box)
{
return clip (p, box);
}
template <class T>
Vec3<T>
closestPointOnBox (const Vec3<T> &p, const Box< Vec3<T> > &box)
{
//
// Find the point, q, on the surface of
// the box, that is closest to point p.
//
// If the box is empty, return p.
//
if (box.isEmpty())
2012-10-17 09:12:04 +02:00
return p;
2012-08-24 22:31:49 +02:00
Vec3<T> q = closestPointInBox (p, box);
if (q == p)
{
2012-10-17 09:12:04 +02:00
Vec3<T> d1 = p - box.min;
Vec3<T> d2 = box.max - p;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
Vec3<T> d ((d1.x < d2.x)? d1.x: d2.x,
(d1.y < d2.y)? d1.y: d2.y,
(d1.z < d2.z)? d1.z: d2.z);
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (d.x < d.y && d.x < d.z)
{
q.x = (d1.x < d2.x)? box.min.x: box.max.x;
}
else if (d.y < d.z)
{
q.y = (d1.y < d2.y)? box.min.y: box.max.y;
}
else
{
q.z = (d1.z < d2.z)? box.min.z: box.max.z;
}
2012-08-24 22:31:49 +02:00
}
return q;
}
template <class S, class T>
Box< Vec3<S> >
transform (const Box< Vec3<S> > &box, const Matrix44<T> &m)
{
//
// Transform a 3D box by a matrix, and compute a new box that
// tightly encloses the transformed box.
//
// If m is an affine transform, then we use James Arvo's fast
// method as described in "Graphics Gems", Academic Press, 1990,
// pp. 548-550.
//
//
// A transformed empty box is still empty, and a transformed infinite box
// is still infinite
//
if (box.isEmpty() || box.isInfinite())
2012-10-17 09:12:04 +02:00
return box;
2012-08-24 22:31:49 +02:00
//
// If the last column of m is (0 0 0 1) then m is an affine
// transform, and we use the fast Graphics Gems trick.
//
if (m[0][3] == 0 && m[1][3] == 0 && m[2][3] == 0 && m[3][3] == 1)
{
2012-10-17 09:12:04 +02:00
Box< Vec3<S> > newBox;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
for (int i = 0; i < 3; i++)
2012-08-24 22:31:49 +02:00
{
2012-10-17 09:12:04 +02:00
newBox.min[i] = newBox.max[i] = (S) m[3][i];
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
for (int j = 0; j < 3; j++)
2012-08-24 22:31:49 +02:00
{
2012-10-17 09:12:04 +02:00
S a, b;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
a = (S) m[j][i] * box.min[j];
b = (S) m[j][i] * box.max[j];
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (a < b)
2012-08-24 22:31:49 +02:00
{
2012-10-17 09:12:04 +02:00
newBox.min[i] += a;
newBox.max[i] += b;
}
else
2012-08-24 22:31:49 +02:00
{
2012-10-17 09:12:04 +02:00
newBox.min[i] += b;
newBox.max[i] += a;
}
}
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
return newBox;
2012-08-24 22:31:49 +02:00
}
//
// M is a projection matrix. Do things the naive way:
// Transform the eight corners of the box, and find an
// axis-parallel box that encloses the transformed corners.
//
Vec3<S> points[8];
points[0][0] = points[1][0] = points[2][0] = points[3][0] = box.min[0];
points[4][0] = points[5][0] = points[6][0] = points[7][0] = box.max[0];
points[0][1] = points[1][1] = points[4][1] = points[5][1] = box.min[1];
points[2][1] = points[3][1] = points[6][1] = points[7][1] = box.max[1];
points[0][2] = points[2][2] = points[4][2] = points[6][2] = box.min[2];
points[1][2] = points[3][2] = points[5][2] = points[7][2] = box.max[2];
Box< Vec3<S> > newBox;
2012-10-17 09:12:04 +02:00
for (int i = 0; i < 8; i++)
newBox.extendBy (points[i] * m);
2012-08-24 22:31:49 +02:00
return newBox;
}
template <class S, class T>
void
transform (const Box< Vec3<S> > &box,
const Matrix44<T> &m,
Box< Vec3<S> > &result)
{
//
// Transform a 3D box by a matrix, and compute a new box that
// tightly encloses the transformed box.
//
// If m is an affine transform, then we use James Arvo's fast
// method as described in "Graphics Gems", Academic Press, 1990,
// pp. 548-550.
//
//
// A transformed empty box is still empty, and a transformed infinite
// box is still infinite
//
if (box.isEmpty() || box.isInfinite())
{
2012-10-17 09:12:04 +02:00
return;
2012-08-24 22:31:49 +02:00
}
//
// If the last column of m is (0 0 0 1) then m is an affine
// transform, and we use the fast Graphics Gems trick.
//
if (m[0][3] == 0 && m[1][3] == 0 && m[2][3] == 0 && m[3][3] == 1)
{
2012-10-17 09:12:04 +02:00
for (int i = 0; i < 3; i++)
2012-08-24 22:31:49 +02:00
{
2012-10-17 09:12:04 +02:00
result.min[i] = result.max[i] = (S) m[3][i];
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
for (int j = 0; j < 3; j++)
2012-08-24 22:31:49 +02:00
{
2012-10-17 09:12:04 +02:00
S a, b;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
a = (S) m[j][i] * box.min[j];
b = (S) m[j][i] * box.max[j];
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (a < b)
2012-08-24 22:31:49 +02:00
{
2012-10-17 09:12:04 +02:00
result.min[i] += a;
result.max[i] += b;
}
else
2012-08-24 22:31:49 +02:00
{
2012-10-17 09:12:04 +02:00
result.min[i] += b;
result.max[i] += a;
}
}
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
return;
2012-08-24 22:31:49 +02:00
}
//
// M is a projection matrix. Do things the naive way:
// Transform the eight corners of the box, and find an
// axis-parallel box that encloses the transformed corners.
//
Vec3<S> points[8];
points[0][0] = points[1][0] = points[2][0] = points[3][0] = box.min[0];
points[4][0] = points[5][0] = points[6][0] = points[7][0] = box.max[0];
points[0][1] = points[1][1] = points[4][1] = points[5][1] = box.min[1];
points[2][1] = points[3][1] = points[6][1] = points[7][1] = box.max[1];
points[0][2] = points[2][2] = points[4][2] = points[6][2] = box.min[2];
points[1][2] = points[3][2] = points[5][2] = points[7][2] = box.max[2];
2012-10-17 09:12:04 +02:00
for (int i = 0; i < 8; i++)
result.extendBy (points[i] * m);
2012-08-24 22:31:49 +02:00
}
template <class S, class T>
Box< Vec3<S> >
affineTransform (const Box< Vec3<S> > &box, const Matrix44<T> &m)
{
//
// Transform a 3D box by a matrix whose rightmost column
// is (0 0 0 1), and compute a new box that tightly encloses
// the transformed box.
//
// As in the transform() function, above, we use James Arvo's
// fast method.
//
if (box.isEmpty() || box.isInfinite())
{
2012-10-17 09:12:04 +02:00
//
// A transformed empty or infinite box is still empty or infinite
//
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
return box;
2012-08-24 22:31:49 +02:00
}
Box< Vec3<S> > newBox;
2012-10-17 09:12:04 +02:00
for (int i = 0; i < 3; i++)
2012-08-24 22:31:49 +02:00
{
2012-10-17 09:12:04 +02:00
newBox.min[i] = newBox.max[i] = (S) m[3][i];
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
for (int j = 0; j < 3; j++)
{
S a, b;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
a = (S) m[j][i] * box.min[j];
b = (S) m[j][i] * box.max[j];
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (a < b)
{
newBox.min[i] += a;
newBox.max[i] += b;
}
else
{
newBox.min[i] += b;
newBox.max[i] += a;
}
}
2012-08-24 22:31:49 +02:00
}
return newBox;
}
template <class S, class T>
void
affineTransform (const Box< Vec3<S> > &box,
const Matrix44<T> &m,
Box<Vec3<S> > &result)
{
//
// Transform a 3D box by a matrix whose rightmost column
// is (0 0 0 1), and compute a new box that tightly encloses
// the transformed box.
//
// As in the transform() function, above, we use James Arvo's
// fast method.
//
if (box.isEmpty())
{
2012-10-17 09:12:04 +02:00
//
// A transformed empty box is still empty
//
2012-08-24 22:31:49 +02:00
result.makeEmpty();
2012-10-17 09:12:04 +02:00
return;
2012-08-24 22:31:49 +02:00
}
if (box.isInfinite())
{
2012-10-17 09:12:04 +02:00
//
// A transformed infinite box is still infinite
//
2012-08-24 22:31:49 +02:00
result.makeInfinite();
2012-10-17 09:12:04 +02:00
return;
2012-08-24 22:31:49 +02:00
}
2012-10-17 09:12:04 +02:00
for (int i = 0; i < 3; i++)
2012-08-24 22:31:49 +02:00
{
2012-10-17 09:12:04 +02:00
result.min[i] = result.max[i] = (S) m[3][i];
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
for (int j = 0; j < 3; j++)
{
S a, b;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
a = (S) m[j][i] * box.min[j];
b = (S) m[j][i] * box.max[j];
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (a < b)
{
result.min[i] += a;
result.max[i] += b;
}
else
{
result.min[i] += b;
result.max[i] += a;
}
}
2012-08-24 22:31:49 +02:00
}
}
template <class T>
bool
findEntryAndExitPoints (const Line3<T> &r,
2012-10-17 09:12:04 +02:00
const Box<Vec3<T> > &b,
Vec3<T> &entry,
Vec3<T> &exit)
2012-08-24 22:31:49 +02:00
{
//
// Compute the points where a ray, r, enters and exits a box, b:
//
// findEntryAndExitPoints() returns
//
// - true if the ray starts inside the box or if the
// ray starts outside and intersects the box
//
// - false otherwise (that is, if the ray does not
// intersect the box)
//
// The entry and exit points are
//
// - points on two of the faces of the box when
// findEntryAndExitPoints() returns true
// (The entry end exit points may be on either
// side of the ray's origin)
//
// - undefined when findEntryAndExitPoints()
// returns false
//
if (b.isEmpty())
{
2012-10-17 09:12:04 +02:00
//
// No ray intersects an empty box
//
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
return false;
2012-08-24 22:31:49 +02:00
}
//
// The following description assumes that the ray's origin is outside
// the box, but the code below works even if the origin is inside the
// box:
//
// Between one and three "frontfacing" sides of the box are oriented
// towards the ray's origin, and between one and three "backfacing"
// sides are oriented away from the ray's origin.
// We intersect the ray with the planes that contain the sides of the
// box, and compare the distances between the ray's origin and the
// ray-plane intersections. The ray intersects the box if the most
// distant frontfacing intersection is nearer than the nearest
// backfacing intersection. If the ray does intersect the box, then
// the most distant frontfacing ray-plane intersection is the entry
// point and the nearest backfacing ray-plane intersection is the
// exit point.
//
const T TMAX = limits<T>::max();
T tFrontMax = -TMAX;
T tBackMin = TMAX;
//
// Minimum and maximum X sides.
//
if (r.dir.x >= 0)
{
2012-10-17 09:12:04 +02:00
T d1 = b.max.x - r.pos.x;
T d2 = b.min.x - r.pos.x;
if (r.dir.x > 1 ||
(abs (d1) < TMAX * r.dir.x &&
abs (d2) < TMAX * r.dir.x))
{
T t1 = d1 / r.dir.x;
T t2 = d2 / r.dir.x;
if (tBackMin > t1)
{
tBackMin = t1;
exit.x = b.max.x;
exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
}
if (tFrontMax < t2)
{
tFrontMax = t2;
entry.x = b.min.x;
entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
}
}
else if (r.pos.x < b.min.x || r.pos.x > b.max.x)
{
return false;
}
2012-08-24 22:31:49 +02:00
}
else // r.dir.x < 0
{
2012-10-17 09:12:04 +02:00
T d1 = b.min.x - r.pos.x;
T d2 = b.max.x - r.pos.x;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.dir.x < -1 ||
(abs (d1) < -TMAX * r.dir.x &&
abs (d2) < -TMAX * r.dir.x))
{
T t1 = d1 / r.dir.x;
T t2 = d2 / r.dir.x;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tBackMin > t1)
{
tBackMin = t1;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
exit.x = b.min.x;
exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tFrontMax < t2)
{
tFrontMax = t2;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
entry.x = b.max.x;
entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
}
}
else if (r.pos.x < b.min.x || r.pos.x > b.max.x)
{
return false;
}
2012-08-24 22:31:49 +02:00
}
//
// Minimum and maximum Y sides.
//
if (r.dir.y >= 0)
{
2012-10-17 09:12:04 +02:00
T d1 = b.max.y - r.pos.y;
T d2 = b.min.y - r.pos.y;
if (r.dir.y > 1 ||
(abs (d1) < TMAX * r.dir.y &&
abs (d2) < TMAX * r.dir.y))
{
T t1 = d1 / r.dir.y;
T t2 = d2 / r.dir.y;
if (tBackMin > t1)
{
tBackMin = t1;
exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
exit.y = b.max.y;
exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
}
if (tFrontMax < t2)
{
tFrontMax = t2;
entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
entry.y = b.min.y;
entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
}
}
else if (r.pos.y < b.min.y || r.pos.y > b.max.y)
{
return false;
}
2012-08-24 22:31:49 +02:00
}
else // r.dir.y < 0
{
2012-10-17 09:12:04 +02:00
T d1 = b.min.y - r.pos.y;
T d2 = b.max.y - r.pos.y;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.dir.y < -1 ||
(abs (d1) < -TMAX * r.dir.y &&
abs (d2) < -TMAX * r.dir.y))
{
T t1 = d1 / r.dir.y;
T t2 = d2 / r.dir.y;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tBackMin > t1)
{
tBackMin = t1;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
exit.y = b.min.y;
exit.z = clamp (r.pos.z + t1 * r.dir.z, b.min.z, b.max.z);
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tFrontMax < t2)
{
tFrontMax = t2;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
entry.y = b.max.y;
entry.z = clamp (r.pos.z + t2 * r.dir.z, b.min.z, b.max.z);
}
}
else if (r.pos.y < b.min.y || r.pos.y > b.max.y)
{
return false;
}
2012-08-24 22:31:49 +02:00
}
//
// Minimum and maximum Z sides.
//
if (r.dir.z >= 0)
{
2012-10-17 09:12:04 +02:00
T d1 = b.max.z - r.pos.z;
T d2 = b.min.z - r.pos.z;
if (r.dir.z > 1 ||
(abs (d1) < TMAX * r.dir.z &&
abs (d2) < TMAX * r.dir.z))
{
T t1 = d1 / r.dir.z;
T t2 = d2 / r.dir.z;
if (tBackMin > t1)
{
tBackMin = t1;
exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
exit.z = b.max.z;
}
if (tFrontMax < t2)
{
tFrontMax = t2;
entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
entry.z = b.min.z;
}
}
else if (r.pos.z < b.min.z || r.pos.z > b.max.z)
{
return false;
}
2012-08-24 22:31:49 +02:00
}
else // r.dir.z < 0
{
2012-10-17 09:12:04 +02:00
T d1 = b.min.z - r.pos.z;
T d2 = b.max.z - r.pos.z;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.dir.z < -1 ||
(abs (d1) < -TMAX * r.dir.z &&
abs (d2) < -TMAX * r.dir.z))
{
T t1 = d1 / r.dir.z;
T t2 = d2 / r.dir.z;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tBackMin > t1)
{
tBackMin = t1;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
exit.x = clamp (r.pos.x + t1 * r.dir.x, b.min.x, b.max.x);
exit.y = clamp (r.pos.y + t1 * r.dir.y, b.min.y, b.max.y);
exit.z = b.min.z;
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tFrontMax < t2)
{
tFrontMax = t2;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
entry.x = clamp (r.pos.x + t2 * r.dir.x, b.min.x, b.max.x);
entry.y = clamp (r.pos.y + t2 * r.dir.y, b.min.y, b.max.y);
entry.z = b.max.z;
}
}
else if (r.pos.z < b.min.z || r.pos.z > b.max.z)
{
return false;
}
2012-08-24 22:31:49 +02:00
}
return tFrontMax <= tBackMin;
}
template<class T>
bool
intersects (const Box< Vec3<T> > &b, const Line3<T> &r, Vec3<T> &ip)
{
//
// Intersect a ray, r, with a box, b, and compute the intersection
// point, ip:
//
// intersect() returns
//
// - true if the ray starts inside the box or if the
// ray starts outside and intersects the box
//
// - false if the ray starts outside the box and intersects it,
// but the intersection is behind the ray's origin.
//
// - false if the ray starts outside and does not intersect it
//
// The intersection point is
//
// - the ray's origin if the ray starts inside the box
//
// - a point on one of the faces of the box if the ray
// starts outside the box
//
// - undefined when intersect() returns false
//
if (b.isEmpty())
{
2012-10-17 09:12:04 +02:00
//
// No ray intersects an empty box
//
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
return false;
2012-08-24 22:31:49 +02:00
}
if (b.intersects (r.pos))
{
2012-10-17 09:12:04 +02:00
//
// The ray starts inside the box
//
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
ip = r.pos;
return true;
2012-08-24 22:31:49 +02:00
}
//
// The ray starts outside the box. Between one and three "frontfacing"
// sides of the box are oriented towards the ray, and between one and
// three "backfacing" sides are oriented away from the ray.
// We intersect the ray with the planes that contain the sides of the
// box, and compare the distances between ray's origin and the ray-plane
// intersections.
// The ray intersects the box if the most distant frontfacing intersection
// is nearer than the nearest backfacing intersection. If the ray does
// intersect the box, then the most distant frontfacing ray-plane
// intersection is the ray-box intersection.
//
const T TMAX = limits<T>::max();
T tFrontMax = -1;
T tBackMin = TMAX;
//
// Minimum and maximum X sides.
//
if (r.dir.x > 0)
{
2012-10-17 09:12:04 +02:00
if (r.pos.x > b.max.x)
return false;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
T d = b.max.x - r.pos.x;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.dir.x > 1 || d < TMAX * r.dir.x)
{
T t = d / r.dir.x;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tBackMin > t)
tBackMin = t;
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.pos.x <= b.min.x)
{
T d = b.min.x - r.pos.x;
T t = (r.dir.x > 1 || d < TMAX * r.dir.x)? d / r.dir.x: TMAX;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tFrontMax < t)
{
tFrontMax = t;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
ip.x = b.min.x;
ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
}
}
2012-08-24 22:31:49 +02:00
}
else if (r.dir.x < 0)
{
2012-10-17 09:12:04 +02:00
if (r.pos.x < b.min.x)
return false;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
T d = b.min.x - r.pos.x;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.dir.x < -1 || d > TMAX * r.dir.x)
{
T t = d / r.dir.x;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tBackMin > t)
tBackMin = t;
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.pos.x >= b.max.x)
{
T d = b.max.x - r.pos.x;
T t = (r.dir.x < -1 || d > TMAX * r.dir.x)? d / r.dir.x: TMAX;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tFrontMax < t)
{
tFrontMax = t;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
ip.x = b.max.x;
ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
}
}
2012-08-24 22:31:49 +02:00
}
else // r.dir.x == 0
{
2012-10-17 09:12:04 +02:00
if (r.pos.x < b.min.x || r.pos.x > b.max.x)
return false;
2012-08-24 22:31:49 +02:00
}
//
// Minimum and maximum Y sides.
//
if (r.dir.y > 0)
{
2012-10-17 09:12:04 +02:00
if (r.pos.y > b.max.y)
return false;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
T d = b.max.y - r.pos.y;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.dir.y > 1 || d < TMAX * r.dir.y)
{
T t = d / r.dir.y;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tBackMin > t)
tBackMin = t;
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.pos.y <= b.min.y)
{
T d = b.min.y - r.pos.y;
T t = (r.dir.y > 1 || d < TMAX * r.dir.y)? d / r.dir.y: TMAX;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tFrontMax < t)
{
tFrontMax = t;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
ip.y = b.min.y;
ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
}
}
2012-08-24 22:31:49 +02:00
}
else if (r.dir.y < 0)
{
2012-10-17 09:12:04 +02:00
if (r.pos.y < b.min.y)
return false;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
T d = b.min.y - r.pos.y;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.dir.y < -1 || d > TMAX * r.dir.y)
{
T t = d / r.dir.y;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tBackMin > t)
tBackMin = t;
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.pos.y >= b.max.y)
{
T d = b.max.y - r.pos.y;
T t = (r.dir.y < -1 || d > TMAX * r.dir.y)? d / r.dir.y: TMAX;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tFrontMax < t)
{
tFrontMax = t;
ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
ip.y = b.max.y;
ip.z = clamp (r.pos.z + t * r.dir.z, b.min.z, b.max.z);
}
}
2012-08-24 22:31:49 +02:00
}
else // r.dir.y == 0
{
2012-10-17 09:12:04 +02:00
if (r.pos.y < b.min.y || r.pos.y > b.max.y)
return false;
2012-08-24 22:31:49 +02:00
}
//
// Minimum and maximum Z sides.
//
if (r.dir.z > 0)
{
2012-10-17 09:12:04 +02:00
if (r.pos.z > b.max.z)
return false;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
T d = b.max.z - r.pos.z;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.dir.z > 1 || d < TMAX * r.dir.z)
{
T t = d / r.dir.z;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tBackMin > t)
tBackMin = t;
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.pos.z <= b.min.z)
{
T d = b.min.z - r.pos.z;
T t = (r.dir.z > 1 || d < TMAX * r.dir.z)? d / r.dir.z: TMAX;
if (tFrontMax < t)
{
tFrontMax = t;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
ip.z = b.min.z;
}
}
2012-08-24 22:31:49 +02:00
}
else if (r.dir.z < 0)
{
2012-10-17 09:12:04 +02:00
if (r.pos.z < b.min.z)
return false;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
T d = b.min.z - r.pos.z;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.dir.z < -1 || d > TMAX * r.dir.z)
{
T t = d / r.dir.z;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tBackMin > t)
tBackMin = t;
}
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (r.pos.z >= b.max.z)
{
T d = b.max.z - r.pos.z;
T t = (r.dir.z < -1 || d > TMAX * r.dir.z)? d / r.dir.z: TMAX;
2012-08-24 22:31:49 +02:00
2012-10-17 09:12:04 +02:00
if (tFrontMax < t)
{
tFrontMax = t;
ip.x = clamp (r.pos.x + t * r.dir.x, b.min.x, b.max.x);
ip.y = clamp (r.pos.y + t * r.dir.y, b.min.y, b.max.y);
ip.z = b.max.z;
}
}
2012-08-24 22:31:49 +02:00
}
else // r.dir.z == 0
{
2012-10-17 09:12:04 +02:00
if (r.pos.z < b.min.z || r.pos.z > b.max.z)
return false;
2012-08-24 22:31:49 +02:00
}
return tFrontMax <= tBackMin;
}
template<class T>
bool
intersects (const Box< Vec3<T> > &box, const Line3<T> &ray)
{
Vec3<T> ignored;
return intersects (box, ray, ignored);
}
} // namespace Imath
#endif