Blame ImathTest/testBoxAlgo.cpp

Packit 8dc392
///////////////////////////////////////////////////////////////////////////
Packit 8dc392
//
Packit 8dc392
// Copyright (c) 2007, Industrial Light & Magic, a division of Lucas
Packit 8dc392
// Digital Ltd. LLC
Packit 8dc392
// 
Packit 8dc392
// All rights reserved.
Packit 8dc392
// 
Packit 8dc392
// Redistribution and use in source and binary forms, with or without
Packit 8dc392
// modification, are permitted provided that the following conditions are
Packit 8dc392
// met:
Packit 8dc392
// *       Redistributions of source code must retain the above copyright
Packit 8dc392
// notice, this list of conditions and the following disclaimer.
Packit 8dc392
// *       Redistributions in binary form must reproduce the above
Packit 8dc392
// copyright notice, this list of conditions and the following disclaimer
Packit 8dc392
// in the documentation and/or other materials provided with the
Packit 8dc392
// distribution.
Packit 8dc392
// *       Neither the name of Industrial Light & Magic nor the names of
Packit 8dc392
// its contributors may be used to endorse or promote products derived
Packit 8dc392
// from this software without specific prior written permission. 
Packit 8dc392
// 
Packit 8dc392
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 8dc392
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 8dc392
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 8dc392
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 8dc392
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 8dc392
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 8dc392
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 8dc392
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 8dc392
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 8dc392
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 8dc392
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 8dc392
//
Packit 8dc392
///////////////////////////////////////////////////////////////////////////
Packit 8dc392
Packit 8dc392
Packit 8dc392
#include <testBoxAlgo.h>
Packit 8dc392
#include "ImathBoxAlgo.h"
Packit 8dc392
#include "ImathRandom.h"
Packit 8dc392
#include <iostream>
Packit 8dc392
#include <algorithm>
Packit 8dc392
#include <assert.h>
Packit 8dc392
Packit 8dc392
Packit 8dc392
using namespace std;
Packit 8dc392
using namespace IMATH_INTERNAL_NAMESPACE;
Packit 8dc392
Packit 8dc392
namespace {
Packit 8dc392
Packit 8dc392
Packit 8dc392
bool
Packit 8dc392
approximatelyEqual (const V3f &p1, const V3f &p2, float e)
Packit 8dc392
{
Packit 8dc392
    float m = 0;
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 3; ++i)
Packit 8dc392
    {
Packit 8dc392
	m = max (m, abs (p1[i]));
Packit 8dc392
	m = max (m, abs (p2[i]));
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 3; ++i)
Packit 8dc392
	if (!equalWithAbsError (p1[i], p2[i], m * e))
Packit 8dc392
	    return false;
Packit 8dc392
    
Packit 8dc392
    return true;
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testEntryAndExitPoints (const Box3f &box)
Packit 8dc392
{
Packit 8dc392
    Rand48 random (2007);
Packit 8dc392
Packit 8dc392
    float e = 50 * limits<float>::epsilon();
Packit 8dc392
Packit 8dc392
    if (box.isEmpty())
Packit 8dc392
    {
Packit 8dc392
	cout << "    empty box, no rays intersect" << endl;
Packit 8dc392
Packit 8dc392
	for (int i = 0; i < 100000; ++i)
Packit 8dc392
	{
Packit 8dc392
	    V3f p1 (random.nextf (box.max.x, box.min.x),
Packit 8dc392
		    random.nextf (box.max.y, box.min.y),
Packit 8dc392
		    random.nextf (box.max.z, box.min.z));
Packit 8dc392
Packit 8dc392
	    V3f p2 (p1 + hollowSphereRand<V3f> (random));
Packit 8dc392
Packit 8dc392
	    V3f r, s;
Packit 8dc392
	    assert (!findEntryAndExitPoints (Line3f (p1, p2), box, r, s));
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	return;
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    cout << "    box = (" << box.min << " " << box.max << ")" << endl;
Packit 8dc392
Packit 8dc392
    if (box.max == box.min)
Packit 8dc392
    {
Packit 8dc392
	cout << "    single-point box, ray intersects" << endl;
Packit 8dc392
Packit 8dc392
	static const float off[6][3] =
Packit 8dc392
	{
Packit 8dc392
	    {-1, 0, 0}, {1, 0, 0},
Packit 8dc392
	    {0, -1, 0}, {0, 1, 0},
Packit 8dc392
	    {0, 0, -1}, {0, 0, 1}
Packit 8dc392
	};
Packit 8dc392
Packit 8dc392
	for (int i = 0; i < 6; ++i)
Packit 8dc392
	{
Packit 8dc392
	    V3f p1 (box.min.x + off[i][0],
Packit 8dc392
		    box.min.y + off[i][1],
Packit 8dc392
		    box.min.z + off[i][2]);
Packit 8dc392
Packit 8dc392
	    V3f r, s;
Packit 8dc392
	    assert (findEntryAndExitPoints (Line3f (p1, box.min), box, r, s));
Packit 8dc392
	    assert (r == box.min && s == box.min);
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	cout << "    single-point box, ray does not intersect" << endl;
Packit 8dc392
Packit 8dc392
	for (int i = 0; i < 100000; ++i)
Packit 8dc392
	{
Packit 8dc392
	    //
Packit 8dc392
	    // The ray starts at a distance of r2 from the of the
Packit 8dc392
	    // box, and it passes the box at a minimum distance of r1.
Packit 8dc392
	    //
Packit 8dc392
Packit 8dc392
	    const float r1 = 0.00001;
Packit 8dc392
	    const float r2 = 1.0;
Packit 8dc392
Packit 8dc392
	    V3f p1 = box.min + r2 * hollowSphereRand<V3f> (random);
Packit 8dc392
	    V3f p2;
Packit 8dc392
	    float r3;
Packit 8dc392
Packit 8dc392
	    do
Packit 8dc392
	    {
Packit 8dc392
		do 
Packit 8dc392
		{
Packit 8dc392
		    p2 = box.min + r2 * hollowSphereRand<V3f> (random);
Packit 8dc392
		}
Packit 8dc392
		while (approximatelyEqual (p1, p2, e));
Packit 8dc392
Packit 8dc392
		V3f d1 = (p2 - p1).normalized();
Packit 8dc392
		V3f d2 = (box.min - p1);
Packit 8dc392
		r3 = (d2 - d1 * (d1 ^ d2)).length();
Packit 8dc392
	    }
Packit 8dc392
	    while (r3 < r1);
Packit 8dc392
Packit 8dc392
	    Line3f ray (p1, p2);
Packit 8dc392
	    V3f r, s;
Packit 8dc392
Packit 8dc392
	    assert (!findEntryAndExitPoints (ray, box, r, s));
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	return;
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    cout << "    ray starts outside box, intersects" << endl;
Packit 8dc392
Packit 8dc392
    Box3f bigBox (box.min - (box.max - box.min),
Packit 8dc392
                  box.max + (box.max - box.min));
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 100000; ++i)
Packit 8dc392
    {
Packit 8dc392
	//
Packit 8dc392
	// Find starting point outside the box, end point inside the box
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	V3f p1;
Packit 8dc392
Packit 8dc392
	do
Packit 8dc392
	{
Packit 8dc392
	    p1 = V3f (random.nextf (bigBox.min.x, bigBox.max.x),
Packit 8dc392
		      random.nextf (bigBox.min.y, bigBox.max.y),
Packit 8dc392
		      random.nextf (bigBox.min.z, bigBox.max.z));
Packit 8dc392
	}
Packit 8dc392
	while (box.intersects (p1));
Packit 8dc392
Packit 8dc392
	V3f p2;
Packit 8dc392
	
Packit 8dc392
	do
Packit 8dc392
	{
Packit 8dc392
	    p2 = V3f (random.nextf (box.min.x, box.max.x),
Packit 8dc392
		      random.nextf (box.min.y, box.max.y),
Packit 8dc392
		      random.nextf (box.min.z, box.max.z));
Packit 8dc392
	}
Packit 8dc392
	while (approximatelyEqual (p1, p2, e));
Packit 8dc392
Packit 8dc392
	Line3f ray (p1, p2);
Packit 8dc392
Packit 8dc392
	V3f r, s;
Packit 8dc392
	bool b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Ray and box must intersect, entry and exit points
Packit 8dc392
	// must be on the surface of the box.
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	assert (b);
Packit 8dc392
Packit 8dc392
	assert (r.x == box.min.x || r.x == box.max.x ||
Packit 8dc392
		r.y == box.min.y || r.y == box.max.y ||
Packit 8dc392
		r.z == box.min.z || r.z == box.max.z);
Packit 8dc392
Packit 8dc392
	assert (s.x == box.min.x || s.x == box.max.x ||
Packit 8dc392
		s.y == box.min.y || s.y == box.max.y ||
Packit 8dc392
		s.z == box.min.z || s.z == box.max.z);
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Entry and exit points must be consistent
Packit 8dc392
	// with the direction of the ray
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	if (r.x == box.min.x)
Packit 8dc392
	    assert (ray.dir.x >= 0);
Packit 8dc392
Packit 8dc392
	if (r.x == box.max.x)
Packit 8dc392
	    assert (ray.dir.x <= 0);
Packit 8dc392
Packit 8dc392
	if (r.y == box.min.y)
Packit 8dc392
	    assert (ray.dir.y >= 0);
Packit 8dc392
Packit 8dc392
	if (r.y == box.max.y)
Packit 8dc392
	    assert (ray.dir.y <= 0);
Packit 8dc392
Packit 8dc392
	if (r.z == box.min.z)
Packit 8dc392
	    assert (ray.dir.z >= 0);
Packit 8dc392
Packit 8dc392
	if (r.z == box.max.z)
Packit 8dc392
	    assert (ray.dir.z <= 0);
Packit 8dc392
Packit 8dc392
	if (s.x == box.max.x)
Packit 8dc392
	    assert (ray.dir.x >= 0);
Packit 8dc392
Packit 8dc392
	if (s.x == box.min.x)
Packit 8dc392
	    assert (ray.dir.x <= 0);
Packit 8dc392
Packit 8dc392
	if (s.y == box.max.y)
Packit 8dc392
	    assert (ray.dir.y >= 0);
Packit 8dc392
Packit 8dc392
	if (s.y == box.min.y)
Packit 8dc392
	    assert (ray.dir.y <= 0);
Packit 8dc392
Packit 8dc392
	if (s.z == box.max.z)
Packit 8dc392
	    assert (ray.dir.z >= 0);
Packit 8dc392
Packit 8dc392
	if (s.z == box.min.z)
Packit 8dc392
	    assert (ray.dir.z <= 0);
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Entry and exit points must be approximately on the ray
Packit 8dc392
	// How far they can be off depends on how far p1 and the
Packit 8dc392
	// entry and exit points are are from the origin.
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	{
Packit 8dc392
	    V3f p3 = p1 + ray.dir * (ray.dir ^ (r - p1));
Packit 8dc392
	    float m = 0;
Packit 8dc392
Packit 8dc392
	    for (int j = 0; j < 3; ++j)
Packit 8dc392
	    {
Packit 8dc392
		m = max (abs (p1[j]), m);
Packit 8dc392
		m = max (abs (r[j]), m);
Packit 8dc392
	    }
Packit 8dc392
Packit 8dc392
	    float err = 30 * m * limits<float>::epsilon();
Packit 8dc392
	    assert (p3.equalWithAbsError (r, err));
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	{
Packit 8dc392
	    V3f p3 = p1 + ray.dir * (ray.dir ^ (s - p1));
Packit 8dc392
	    float m = 0;
Packit 8dc392
Packit 8dc392
	    for (int j = 0; j < 3; ++j)
Packit 8dc392
	    {
Packit 8dc392
		m = max (abs (p1[j]), m);
Packit 8dc392
		m = max (abs (s[j]), m);
Packit 8dc392
	    }
Packit 8dc392
Packit 8dc392
	    float err = 30 * m * limits<float>::epsilon();
Packit 8dc392
	    assert (p3.equalWithAbsError (s, err));
Packit 8dc392
	}
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    cout << "    ray starts outside box, does not intersect" << endl;
Packit 8dc392
Packit 8dc392
    V3f center = (box.min + box.max) * 0.5f;
Packit 8dc392
    float r1 = (box.max - box.min).length() * 0.51f;
Packit 8dc392
    float r2 = 2 * r1;
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 100000; ++i)
Packit 8dc392
    {
Packit 8dc392
	//
Packit 8dc392
	// The ray starts at a distance of r2 from the center
Packit 8dc392
	// of the box, and it passes the center at a minimum
Packit 8dc392
	// distance of r1.  (r1 and r2 are both greater than
Packit 8dc392
	// the distance between the center and the corners
Packit 8dc392
	// of the box.)
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	V3f p1 = center + r2 * hollowSphereRand<V3f> (random);
Packit 8dc392
	V3f p2;
Packit 8dc392
	float r3;
Packit 8dc392
Packit 8dc392
	do
Packit 8dc392
	{
Packit 8dc392
	    do 
Packit 8dc392
	    {
Packit 8dc392
		p2 = center + r2 * hollowSphereRand<V3f> (random);
Packit 8dc392
	    }
Packit 8dc392
	    while (approximatelyEqual (p1, p2, e));
Packit 8dc392
Packit 8dc392
	    V3f d1 = (p2 - p1).normalized();
Packit 8dc392
	    V3f d2 = (center - p1);
Packit 8dc392
	    r3 = (d2 - d1 * (d1 ^ d2)).length();
Packit 8dc392
	}
Packit 8dc392
	while (r3 < r1);
Packit 8dc392
Packit 8dc392
	Line3f ray (p1, p2);
Packit 8dc392
	V3f r, s;
Packit 8dc392
Packit 8dc392
	assert (!findEntryAndExitPoints (ray, box, r, s));
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
entryAndExitPoints1 ()
Packit 8dc392
{
Packit 8dc392
    cout << "  ray-box entry and exit, random rays" << endl;
Packit 8dc392
Packit 8dc392
    Box3f boxes[] =
Packit 8dc392
    {
Packit 8dc392
	// Boxes with a positive volume
Packit 8dc392
Packit 8dc392
	Box3f (V3f (-1, -1, -1), V3f (1, 1, 1)),
Packit 8dc392
	Box3f (V3f (10, 20, 30), V3f (1010, 21, 31)),
Packit 8dc392
	Box3f (V3f (10, 20, 30), V3f (11, 1020, 31)),
Packit 8dc392
	Box3f (V3f (10, 20, 30), V3f (11, 21, 1030)),
Packit 8dc392
	Box3f (V3f (-1e10f, -2e10f, -3e10f), V3f (5e15f, 6e15f, 7e15f)),
Packit 8dc392
Packit 8dc392
	// Non-empty, zero-volume boxes
Packit 8dc392
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (2, 1, 1)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (1, 2, 1)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (1, 1, 2)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (1, 2, 3)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (2, 3, 1)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (2, 1, 3)),
Packit 8dc392
	Box3f (V3f (-1, -2, 1), V3f (-1, -2, 1)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (1, 1, 1)),
Packit 8dc392
	Box3f (V3f (0, 0, 0), V3f (0, 0, 0)),
Packit 8dc392
Packit 8dc392
	// empty box
Packit 8dc392
Packit 8dc392
	Box3f ()
Packit 8dc392
    };
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < sizeof (boxes) / sizeof (boxes[0]); ++i)
Packit 8dc392
	testEntryAndExitPoints (boxes[i]);
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testPerturbedRayBoxEntryExit
Packit 8dc392
    (const Box3f &box,
Packit 8dc392
     const Line3f &ray,
Packit 8dc392
     bool result)
Packit 8dc392
{
Packit 8dc392
    cout << "    dir ~ " << ray.dir << ", result = " << result << endl;
Packit 8dc392
Packit 8dc392
    {
Packit 8dc392
	V3f r, s;
Packit 8dc392
	assert (result == findEntryAndExitPoints (ray, box, r, s));
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    Rand48 random (19);
Packit 8dc392
    const float e = 1e-25f;
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 10000; ++i)
Packit 8dc392
    {
Packit 8dc392
	Line3f ray1 (ray);
Packit 8dc392
	ray1.dir += e * solidSphereRand<V3f> (random);
Packit 8dc392
Packit 8dc392
	V3f r, s;
Packit 8dc392
	assert (result == findEntryAndExitPoints (ray1, box, r, s));
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
entryAndExitPoints2 ()
Packit 8dc392
{
Packit 8dc392
Packit 8dc392
    cout << "  ray-box entry and exit, nearly axis-parallel rays" << endl;
Packit 8dc392
Packit 8dc392
    Box3f box (V3f (-1e15f, -1e15f, -1e15f), V3f (1e15f, 1e15f, 1e15f));
Packit 8dc392
    Line3f ray;
Packit 8dc392
    V3f r, s;
Packit 8dc392
    bool b;
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (-2e15f, 0, 0), V3f (2e15f, 0, 0));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (b && r == V3f (-1e15f, 0, 0) && s == V3f (1e15f, 0, 0));
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (2e15f, 0, 0), V3f (-2e15f, 0, 0));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (b && r == V3f (1e15f, 0, 0) && s == V3f (-1e15f, 0, 0));
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (-2e15f, 2e15f, 0), V3f (2e15f, 2e15f, 0));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, false);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (2e15f, 2e15f, 0), V3f (-2e15f, 2e15f, 0));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, false);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, -2e15f, 0), V3f (0, 2e15f, 0));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (b && r == V3f (0, -1e15f, 0) && s == V3f (0, 1e15f, 0));
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, 2e15f, 0), V3f (0, -2e15f, 0));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (b && r == V3f (0, 1e15f, 0) && s == V3f (0, -1e15f, 0));
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, -2e15f, 2e15f), V3f (0, 2e15f, 2e15f));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, false);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, 2e15f, 2e15f), V3f (0, -2e15f, 2e15f));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, false);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, 0, -2e15f), V3f (0, 0, 2e15f));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (b && r == V3f (0, 0, -1e15f) && s == V3f (0, 0, 1e15f));
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, 0, 2e15f), V3f (0, 0, -2e15f));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (b && r == V3f (0, 0, 1e15f) && s == V3f (0, 0, -1e15f));
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (2e15f, 0, -2e15f), V3f (2e15f, 0, 2e15f));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, false);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (2e15f, 0, 2e15f), V3f (2e15f, 0, -2e15f));
Packit 8dc392
    b = findEntryAndExitPoints (ray, box, r, s);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBoxEntryExit (box, ray, false);
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testRayBoxIntersection (const Box3f &box)
Packit 8dc392
{
Packit 8dc392
    Rand48 random (2007);
Packit 8dc392
Packit 8dc392
    float e = 50 * limits<float>::epsilon();
Packit 8dc392
Packit 8dc392
    if (box.isEmpty())
Packit 8dc392
    {
Packit 8dc392
	cout << "    empty box, no rays intersect" << endl;
Packit 8dc392
Packit 8dc392
	for (int i = 0; i < 100000; ++i)
Packit 8dc392
	{
Packit 8dc392
	    V3f p1 (random.nextf (box.max.x, box.min.x),
Packit 8dc392
		    random.nextf (box.max.y, box.min.y),
Packit 8dc392
		    random.nextf (box.max.z, box.min.z));
Packit 8dc392
Packit 8dc392
	    V3f p2 (p1 + hollowSphereRand<V3f> (random));
Packit 8dc392
Packit 8dc392
	    V3f ip;
Packit 8dc392
	    assert (!intersects (box, Line3f (p1, p2), ip));
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	return;
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    cout << "    box = (" << box.min << " " << box.max << ")" << endl;
Packit 8dc392
Packit 8dc392
    if (box.max == box.min)
Packit 8dc392
    {
Packit 8dc392
	cout << "    single-point box, ray intersects" << endl;
Packit 8dc392
Packit 8dc392
	static const float off[6][3] =
Packit 8dc392
	{
Packit 8dc392
	    {-1, 0, 0}, {1, 0, 0},
Packit 8dc392
	    {0, -1, 0}, {0, 1, 0},
Packit 8dc392
	    {0, 0, -1}, {0, 0, 1}
Packit 8dc392
	};
Packit 8dc392
Packit 8dc392
	for (int i = 0; i < 6; ++i)
Packit 8dc392
	{
Packit 8dc392
	    V3f p1 (box.min.x + off[i][0],
Packit 8dc392
		    box.min.y + off[i][1],
Packit 8dc392
		    box.min.z + off[i][2]);
Packit 8dc392
Packit 8dc392
	    V3f ip;
Packit 8dc392
	    assert (intersects (box, Line3f (p1, box.min), ip));
Packit 8dc392
	    assert (ip == box.min);
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	cout << "    single-point box, ray does not intersect" << endl;
Packit 8dc392
Packit 8dc392
	for (int i = 0; i < 100000; ++i)
Packit 8dc392
	{
Packit 8dc392
	    //
Packit 8dc392
	    // The ray starts at a distance of r2 from the of the
Packit 8dc392
	    // box, and it passes the box at a minimum distance of r1.
Packit 8dc392
	    //
Packit 8dc392
Packit 8dc392
	    const float r1 = 0.00001;
Packit 8dc392
	    const float r2 = 1.0;
Packit 8dc392
Packit 8dc392
	    V3f p1 = box.min + r2 * hollowSphereRand<V3f> (random);
Packit 8dc392
	    V3f p2;
Packit 8dc392
	    float r3;
Packit 8dc392
Packit 8dc392
	    do
Packit 8dc392
	    {
Packit 8dc392
		do 
Packit 8dc392
		{
Packit 8dc392
		    p2 = box.min + r2 * hollowSphereRand<V3f> (random);
Packit 8dc392
		}
Packit 8dc392
		while (approximatelyEqual (p1, p2, e));
Packit 8dc392
Packit 8dc392
		V3f d1 = (p2 - p1).normalized();
Packit 8dc392
		V3f d2 = (box.min - p1);
Packit 8dc392
		r3 = (d2 - d1 * (d1 ^ d2)).length();
Packit 8dc392
	    }
Packit 8dc392
	    while (r3 < r1);
Packit 8dc392
Packit 8dc392
	    Line3f ray (p1, p2);
Packit 8dc392
	    V3f ip;
Packit 8dc392
Packit 8dc392
	    assert (!intersects (box, ray, ip));
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	return;
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    cout << "    ray starts inside box" << endl;
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 1000; ++i)
Packit 8dc392
    {
Packit 8dc392
	V3f p1 (random.nextf (box.min.x, box.max.x),
Packit 8dc392
	        random.nextf (box.min.y, box.max.y),
Packit 8dc392
		random.nextf (box.min.z, box.max.z));
Packit 8dc392
Packit 8dc392
	V3f p2 (p1 + hollowSphereRand<V3f> (random));
Packit 8dc392
Packit 8dc392
	V3f ip;
Packit 8dc392
	bool b = intersects (box, Line3f (p1, p2), ip);
Packit 8dc392
Packit 8dc392
	assert (b && ip == p1);
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    cout << "    ray starts outside box, intersects" << endl;
Packit 8dc392
Packit 8dc392
    Box3f bigBox (box.min - (box.max - box.min),
Packit 8dc392
                  box.max + (box.max - box.min));
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 100000; ++i)
Packit 8dc392
    {
Packit 8dc392
	//
Packit 8dc392
	// Find starting point outside the box, end point inside the box
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	V3f p1;
Packit 8dc392
Packit 8dc392
	do
Packit 8dc392
	{
Packit 8dc392
	    p1 = V3f (random.nextf (bigBox.min.x, bigBox.max.x),
Packit 8dc392
		      random.nextf (bigBox.min.y, bigBox.max.y),
Packit 8dc392
		      random.nextf (bigBox.min.z, bigBox.max.z));
Packit 8dc392
	}
Packit 8dc392
	while (box.intersects (p1));
Packit 8dc392
Packit 8dc392
	V3f p2;
Packit 8dc392
	
Packit 8dc392
	do
Packit 8dc392
	{
Packit 8dc392
	    p2 = V3f (random.nextf (box.min.x, box.max.x),
Packit 8dc392
		      random.nextf (box.min.y, box.max.y),
Packit 8dc392
		      random.nextf (box.min.z, box.max.z));
Packit 8dc392
	}
Packit 8dc392
	while (approximatelyEqual (p1, p2, e));
Packit 8dc392
Packit 8dc392
	Line3f ray (p1, p2);
Packit 8dc392
Packit 8dc392
	V3f ip;
Packit 8dc392
	bool b = intersects (box, ray, ip);
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Ray and box must intersect, intersection point
Packit 8dc392
	// must be on the surface of the box.
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	assert (b);
Packit 8dc392
Packit 8dc392
	assert (ip.x == box.min.x || ip.x == box.max.x ||
Packit 8dc392
		ip.y == box.min.y || ip.y == box.max.y ||
Packit 8dc392
		ip.z == box.min.z || ip.z == box.max.z);
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Intersection point must be consistent with the origin
Packit 8dc392
	// and direction of the ray
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	if (ip.x == box.min.x)
Packit 8dc392
	    assert (ray.pos.x <= box.min.x && ray.dir.x >= 0);
Packit 8dc392
Packit 8dc392
	if (ip.x == box.max.x)
Packit 8dc392
	    assert (ray.pos.x >= box.max.x && ray.dir.x <= 0);
Packit 8dc392
Packit 8dc392
	if (ip.y == box.min.y)
Packit 8dc392
	    assert (ray.pos.y <= box.min.y && ray.dir.y >= 0);
Packit 8dc392
Packit 8dc392
	if (ip.y == box.max.y)
Packit 8dc392
	    assert (ray.pos.y >= box.max.y && ray.dir.y <= 0);
Packit 8dc392
Packit 8dc392
	if (ip.z == box.min.z)
Packit 8dc392
	    assert (ray.pos.z <= box.min.z && ray.dir.z >= 0);
Packit 8dc392
Packit 8dc392
	if (ip.z == box.max.z)
Packit 8dc392
	    assert (ray.pos.z >= box.max.z && ray.dir.z <= 0);
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Intersection point must be approximately on the ray
Packit 8dc392
	// How far it can be off depends on how far p1 and ip
Packit 8dc392
	// are from the origin.
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	V3f p3 = p1 + ray.dir * (ray.dir ^ (ip - p1));
Packit 8dc392
	float m = 0;
Packit 8dc392
Packit 8dc392
	for (int j = 0; j < 3; ++j)
Packit 8dc392
	{
Packit 8dc392
	    m = max (abs (p1[j]), m);
Packit 8dc392
	    m = max (abs (ip[j]), m);
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	float err = 30 * m * limits<float>::epsilon();
Packit 8dc392
	assert (p3.equalWithAbsError (ip, err));
Packit 8dc392
Packit 8dc392
	//
Packit 8dc392
	// Try same starting point, opposite direction
Packit 8dc392
	// 
Packit 8dc392
Packit 8dc392
	ray.dir *= -1;
Packit 8dc392
	V3f ip2;
Packit 8dc392
Packit 8dc392
	assert (!intersects (box, ray, ip2));
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    cout << "    ray starts outside box, does not intersect" << endl;
Packit 8dc392
Packit 8dc392
    V3f center = (box.min + box.max) * 0.5f;
Packit 8dc392
    float r1 = (box.max - box.min).length() * 0.51f;
Packit 8dc392
    float r2 = 2 * r1;
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 100000; ++i)
Packit 8dc392
    {
Packit 8dc392
	//
Packit 8dc392
	// The ray starts at a distance of r2 from the center
Packit 8dc392
	// of the box, and it passes the center at a minimum
Packit 8dc392
	// distance of r1.  (r1 and r2 are both greater than
Packit 8dc392
	// the distance between the center and the corners
Packit 8dc392
	// of the box.)
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	V3f p1 = center + r2 * hollowSphereRand<V3f> (random);
Packit 8dc392
	V3f p2;
Packit 8dc392
	float r3;
Packit 8dc392
Packit 8dc392
	do
Packit 8dc392
	{
Packit 8dc392
	    do 
Packit 8dc392
	    {
Packit 8dc392
		p2 = center + r2 * hollowSphereRand<V3f> (random);
Packit 8dc392
	    }
Packit 8dc392
	    while (approximatelyEqual (p1, p2, e));
Packit 8dc392
Packit 8dc392
	    V3f d1 = (p2 - p1).normalized();
Packit 8dc392
	    V3f d2 = (center - p1);
Packit 8dc392
	    r3 = (d2 - d1 * (d1 ^ d2)).length();
Packit 8dc392
	}
Packit 8dc392
	while (r3 < r1);
Packit 8dc392
Packit 8dc392
	Line3f ray (p1, p2);
Packit 8dc392
	V3f ip;
Packit 8dc392
Packit 8dc392
	assert (!intersects (box, ray, ip));
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
rayBoxIntersection1 ()
Packit 8dc392
{
Packit 8dc392
    cout << "  ray-box intersection, random rays" << endl;
Packit 8dc392
Packit 8dc392
    Box3f boxes[] =
Packit 8dc392
    {
Packit 8dc392
	// Boxes with a positive volume
Packit 8dc392
Packit 8dc392
	Box3f (V3f (-1, -1, -1), V3f (1, 1, 1)),
Packit 8dc392
	Box3f (V3f (10, 20, 30), V3f (1010, 21, 31)),
Packit 8dc392
	Box3f (V3f (10, 20, 30), V3f (11, 1020, 31)),
Packit 8dc392
	Box3f (V3f (10, 20, 30), V3f (11, 21, 1030)),
Packit 8dc392
	Box3f (V3f (-1e10f, -2e10f, -3e10f), V3f (5e15f, 6e15f, 7e15f)),
Packit 8dc392
Packit 8dc392
	// Non-empty, zero-volume boxes
Packit 8dc392
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (2, 1, 1)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (1, 2, 1)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (1, 1, 2)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (1, 2, 3)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (2, 3, 1)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (2, 1, 3)),
Packit 8dc392
	Box3f (V3f (-1, -2, 1), V3f (-1, -2, 1)),
Packit 8dc392
	Box3f (V3f (1, 1, 1), V3f (1, 1, 1)),
Packit 8dc392
	Box3f (V3f (0, 0, 0), V3f (0, 0, 0)),
Packit 8dc392
Packit 8dc392
	// empty box
Packit 8dc392
Packit 8dc392
	Box3f ()
Packit 8dc392
    };
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < sizeof (boxes) / sizeof (boxes[0]); ++i)
Packit 8dc392
	testRayBoxIntersection (boxes[i]);
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testPerturbedRayBox
Packit 8dc392
    (const Box3f &box,
Packit 8dc392
     const Line3f &ray,
Packit 8dc392
     bool result)
Packit 8dc392
{
Packit 8dc392
    cout << "    dir ~ " << ray.dir << ", result = " << result << endl;
Packit 8dc392
Packit 8dc392
    {
Packit 8dc392
	V3f ip;
Packit 8dc392
	assert (result == intersects (box, ray, ip));
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    Rand48 random (19);
Packit 8dc392
    const float e = 1e-25f;
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 10000; ++i)
Packit 8dc392
    {
Packit 8dc392
	Line3f ray1 (ray);
Packit 8dc392
	ray1.dir += e * solidSphereRand<V3f> (random);
Packit 8dc392
Packit 8dc392
	V3f ip;
Packit 8dc392
	assert (result == intersects (box, ray1, ip));
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
rayBoxIntersection2 ()
Packit 8dc392
{
Packit 8dc392
Packit 8dc392
    cout << "  ray-box intersection, nearly axis-parallel rays" << endl;
Packit 8dc392
Packit 8dc392
    Box3f box (V3f (-1e15f, -1e15f, -1e15f), V3f (1e15f, 1e15f, 1e15f));
Packit 8dc392
    Line3f ray;
Packit 8dc392
    V3f ip;
Packit 8dc392
    bool b;
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (-2e15f, 0, 0), V3f (2e15f, 0, 0));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (b && ip == V3f (-1e15f, 0, 0));
Packit 8dc392
    testPerturbedRayBox (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (2e15f, 0, 0), V3f (-2e15f, 0, 0));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (b && ip == V3f (1e15f, 0, 0));
Packit 8dc392
    testPerturbedRayBox (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (-2e15f, 2e15f, 0), V3f (2e15f, 2e15f, 0));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBox (box, ray, false);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (2e15f, 2e15f, 0), V3f (-2e15f, 2e15f, 0));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBox (box, ray, false);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, -2e15f, 0), V3f (0, 2e15f, 0));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (b && ip == V3f (0, -1e15f, 0));
Packit 8dc392
    testPerturbedRayBox (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, 2e15f, 0), V3f (0, -2e15f, 0));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (b && ip == V3f (0, 1e15f, 0));
Packit 8dc392
    testPerturbedRayBox (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, -2e15f, 2e15f), V3f (0, 2e15f, 2e15f));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBox (box, ray, false);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, 2e15f, 2e15f), V3f (0, -2e15f, 2e15f));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBox (box, ray, false);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, 0, -2e15f), V3f (0, 0, 2e15f));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (b && ip == V3f (0, 0, -1e15f));
Packit 8dc392
    testPerturbedRayBox (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (0, 0, 2e15f), V3f (0, 0, -2e15f));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (b && ip == V3f (0, 0, 1e15f));
Packit 8dc392
    testPerturbedRayBox (box, ray, true);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (2e15f, 0, -2e15f), V3f (2e15f, 0, 2e15f));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBox (box, ray, false);
Packit 8dc392
Packit 8dc392
    ray = Line3f (V3f (2e15f, 0, 2e15f), V3f (2e15f, 0, -2e15f));
Packit 8dc392
    b = intersects (box, ray, ip);
Packit 8dc392
    assert (!b);
Packit 8dc392
    testPerturbedRayBox (box, ray, false);
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
Box3f
Packit 8dc392
transformSimple (const Box3f &b, const M44f &M)
Packit 8dc392
{
Packit 8dc392
    Box3f b1;
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 8; ++i)
Packit 8dc392
    {
Packit 8dc392
	V3f p;
Packit 8dc392
Packit 8dc392
	for (int j = 0; j < 3; ++j)
Packit 8dc392
	    p[j] = ((i >> j) & 1)? b.max[j]: b.min[j];
Packit 8dc392
Packit 8dc392
	b1.extendBy (p * M);
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
    return b1;
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
boxMatrixTransform ()
Packit 8dc392
{
Packit 8dc392
    cout << "  transform box by matrix" << endl;
Packit 8dc392
Packit 8dc392
    const float e = 5 * limits<float>::epsilon();
Packit 8dc392
Packit 8dc392
    Box3f b1 (V3f (4, 5, 6), V3f (7, 8, 9));
Packit 8dc392
Packit 8dc392
    M44f M;
Packit 8dc392
    M.setEulerAngles (V3f (1, 2, 3));
Packit 8dc392
    M.translate (V3f (20, -15, 2));
Packit 8dc392
Packit 8dc392
    Box3f b2 = transform (b1, M);
Packit 8dc392
    Box3f b3 = affineTransform (b1, M);
Packit 8dc392
    Box3f b4 = transformSimple (b1, M);
Packit 8dc392
    Box3f b21;
Packit 8dc392
    Box3f b31;
Packit 8dc392
Packit 8dc392
    transform (b1, M, b21);
Packit 8dc392
    affineTransform (b1, M, b31);
Packit 8dc392
Packit 8dc392
    assert (approximatelyEqual (b2.min, b4.min, e));
Packit 8dc392
    assert (approximatelyEqual (b2.max, b4.max, e));
Packit 8dc392
    assert (approximatelyEqual (b3.max, b4.max, e));
Packit 8dc392
    assert (approximatelyEqual (b3.max, b4.max, e));
Packit 8dc392
Packit 8dc392
    assert (b21 == b2);
Packit 8dc392
    assert (b31 == b3);
Packit 8dc392
Packit 8dc392
    M[0][3] = 1;
Packit 8dc392
    M[1][3] = 2;
Packit 8dc392
    M[2][3] = 3;
Packit 8dc392
    M[3][3] = 4;
Packit 8dc392
Packit 8dc392
    Box3f b5 = transform (b1, M);
Packit 8dc392
    Box3f b6 = transformSimple (b1, M);
Packit 8dc392
    Box3f b51;
Packit 8dc392
Packit 8dc392
    transform (b1, M, b51);
Packit 8dc392
Packit 8dc392
    assert (approximatelyEqual (b5.min, b6.min, e));
Packit 8dc392
    assert (approximatelyEqual (b5.max, b6.max, e));
Packit 8dc392
    assert (b51 == b5);
Packit 8dc392
    
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
pointInBox ()
Packit 8dc392
{
Packit 8dc392
    cout << "  closest point in box" << endl;
Packit 8dc392
Packit 8dc392
    Box3f box (V3f (1, 2, 3), V3f (5, 4, 6));
Packit 8dc392
Packit 8dc392
    //
Packit 8dc392
    // Points outside the box
Packit 8dc392
    //
Packit 8dc392
Packit 8dc392
    assert (closestPointInBox (V3f (0, 0, 0), box) == V3f (1, 2, 3));
Packit 8dc392
    assert (closestPointInBox (V3f (7, 7, 7), box) == V3f (5, 4, 6));
Packit 8dc392
Packit 8dc392
    assert (closestPointInBox (V3f (2, 3, 0), box) == V3f (2, 3, 3));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 3, 7), box) == V3f (2, 3, 6));
Packit 8dc392
Packit 8dc392
    assert (closestPointInBox (V3f (2, 0, 4), box) == V3f (2, 2, 4));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 7, 4), box) == V3f (2, 4, 4));
Packit 8dc392
Packit 8dc392
    assert (closestPointInBox (V3f (0, 3, 4), box) == V3f (1, 3, 4));
Packit 8dc392
    assert (closestPointInBox (V3f (7, 3, 4), box) == V3f (5, 3, 4));
Packit 8dc392
Packit 8dc392
    //
Packit 8dc392
    // Points inside the box
Packit 8dc392
    //
Packit 8dc392
Packit 8dc392
    assert (closestPointInBox (V3f (1.5, 3, 5), box) == V3f (1.5, 3, 5));
Packit 8dc392
    assert (closestPointInBox (V3f (4.5, 3, 5), box) == V3f (4.5, 3, 5));
Packit 8dc392
Packit 8dc392
    assert (closestPointInBox (V3f (2, 2.5, 4), box) == V3f (2, 2.5, 4));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 3.5, 4), box) == V3f (2, 3.5, 4));
Packit 8dc392
Packit 8dc392
    assert (closestPointInBox (V3f (2, 3, 3.5), box) == V3f (2, 3, 3.5));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 3, 5.5), box) == V3f (2, 3, 5.5));
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
pointInAndOnBox ()
Packit 8dc392
{
Packit 8dc392
    cout << "  closest points in and on box" << endl;
Packit 8dc392
Packit 8dc392
    Box3f box (V3f (1, 2, 3), V3f (5, 4, 6));
Packit 8dc392
Packit 8dc392
    //
Packit 8dc392
    // Points outside the box
Packit 8dc392
    //
Packit 8dc392
Packit 8dc392
    assert (closestPointOnBox (V3f (0, 0, 0), box) == V3f (1, 2, 3));
Packit 8dc392
    assert (closestPointInBox (V3f (0, 0, 0), box) == V3f (1, 2, 3));
Packit 8dc392
    assert (closestPointOnBox (V3f (7, 7, 7), box) == V3f (5, 4, 6));
Packit 8dc392
    assert (closestPointInBox (V3f (7, 7, 7), box) == V3f (5, 4, 6));
Packit 8dc392
Packit 8dc392
    assert (closestPointOnBox (V3f (2, 3, 0), box) == V3f (2, 3, 3));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 3, 0), box) == V3f (2, 3, 3));
Packit 8dc392
    assert (closestPointOnBox (V3f (2, 3, 7), box) == V3f (2, 3, 6));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 3, 7), box) == V3f (2, 3, 6));
Packit 8dc392
Packit 8dc392
    assert (closestPointOnBox (V3f (2, 0, 4), box) == V3f (2, 2, 4));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 0, 4), box) == V3f (2, 2, 4));
Packit 8dc392
    assert (closestPointOnBox (V3f (2, 7, 4), box) == V3f (2, 4, 4));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 7, 4), box) == V3f (2, 4, 4));
Packit 8dc392
Packit 8dc392
    assert (closestPointOnBox (V3f (0, 3, 4), box) == V3f (1, 3, 4));
Packit 8dc392
    assert (closestPointInBox (V3f (0, 3, 4), box) == V3f (1, 3, 4));
Packit 8dc392
    assert (closestPointOnBox (V3f (7, 3, 4), box) == V3f (5, 3, 4));
Packit 8dc392
    assert (closestPointInBox (V3f (7, 3, 4), box) == V3f (5, 3, 4));
Packit 8dc392
Packit 8dc392
    //
Packit 8dc392
    // Points inside the box
Packit 8dc392
    //
Packit 8dc392
Packit 8dc392
    assert (closestPointOnBox (V3f (1.5, 3, 5), box) == V3f (1, 3, 5));
Packit 8dc392
    assert (closestPointInBox (V3f (1.5, 3, 5), box) == V3f (1.5, 3, 5));
Packit 8dc392
    assert (closestPointOnBox (V3f (4.5, 3, 5), box) == V3f (5, 3, 5));
Packit 8dc392
    assert (closestPointInBox (V3f (4.5, 3, 5), box) == V3f (4.5, 3, 5));
Packit 8dc392
Packit 8dc392
    assert (closestPointOnBox (V3f (2, 2.5, 4), box) == V3f (2, 2, 4));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 2.5, 4), box) == V3f (2, 2.5, 4));
Packit 8dc392
    assert (closestPointOnBox (V3f (2, 3.5, 4), box) == V3f (2, 4, 4));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 3.5, 4), box) == V3f (2, 3.5, 4));
Packit 8dc392
Packit 8dc392
    assert (closestPointOnBox (V3f (2, 3, 3.5), box) == V3f (2, 3, 3));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 3, 3.5), box) == V3f (2, 3, 3.5));
Packit 8dc392
    assert (closestPointOnBox (V3f (2, 3, 5.5), box) == V3f (2, 3, 6));
Packit 8dc392
    assert (closestPointInBox (V3f (2, 3, 5.5), box) == V3f (2, 3, 5.5));
Packit 8dc392
Packit 8dc392
    //
Packit 8dc392
    // Point at the center of the box.  "Closest point on box" is
Packit 8dc392
    // in at the center of +Y side
Packit 8dc392
    //
Packit 8dc392
Packit 8dc392
    assert (closestPointOnBox (V3f (3, 3, 4.5), box) == V3f (3, 4, 4.5));
Packit 8dc392
    assert (closestPointInBox (V3f (3, 3, 4.5), box) == V3f (3, 3, 4.5));
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
} // namespace
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testBoxAlgo ()
Packit 8dc392
{
Packit 8dc392
    cout << "Testing box algorithms" << endl;
Packit 8dc392
Packit 8dc392
    entryAndExitPoints1();
Packit 8dc392
    entryAndExitPoints2();
Packit 8dc392
    rayBoxIntersection1();
Packit 8dc392
    rayBoxIntersection2();
Packit 8dc392
    boxMatrixTransform();
Packit 8dc392
    pointInAndOnBox();
Packit 8dc392
Packit 8dc392
    cout << "ok\n" << endl;
Packit 8dc392
}