Blame ImathTest/testLineAlgo.cpp

Packit 8dc392
///////////////////////////////////////////////////////////////////////////
Packit 8dc392
//
Packit 8dc392
// Copyright (c) 2006, 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 <testLineAlgo.h>
Packit 8dc392
#include "ImathLineAlgo.h"
Packit 8dc392
#include "ImathRandom.h"
Packit 8dc392
#include <iostream>
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
void
Packit 8dc392
testClosestPoints
Packit 8dc392
    (const Line3f &line1,
Packit 8dc392
     const Line3f &line2,
Packit 8dc392
     bool returnValue,
Packit 8dc392
     const V3f &point1,
Packit 8dc392
     const V3f &point2)
Packit 8dc392
{
Packit 8dc392
    V3f p1;
Packit 8dc392
    V3f p2;
Packit 8dc392
    bool rv = closestPoints (line1, line2, p1, p2);
Packit 8dc392
Packit 8dc392
    assert (rv == returnValue);
Packit 8dc392
Packit 8dc392
    if (rv)
Packit 8dc392
    {
Packit 8dc392
	float e = 10 * limits<float>::epsilon();
Packit 8dc392
	assert (point1.equalWithAbsError (p1, e));
Packit 8dc392
	assert (point2.equalWithAbsError (p2, e));
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testClosestPoints ()
Packit 8dc392
{
Packit 8dc392
    cout << "closest points on two lines" << endl;
Packit 8dc392
Packit 8dc392
    cout << "  non-intersecting, non-parallel lines" << endl;
Packit 8dc392
Packit 8dc392
    testClosestPoints
Packit 8dc392
	(Line3f (V3f ( 0, -1, -1), V3f ( 0,  1, -1)),
Packit 8dc392
	 Line3f (V3f (-1,  0,  1), V3f ( 1,  0,  1)),
Packit 8dc392
	 true,
Packit 8dc392
	 V3f ( 0,  0, -1),
Packit 8dc392
	 V3f ( 0,  0,  1));
Packit 8dc392
Packit 8dc392
    testClosestPoints
Packit 8dc392
	(Line3f (V3f ( 2, -1, -1), V3f ( 2,  1, -1)),
Packit 8dc392
	 Line3f (V3f (-1,  3,  1), V3f ( 1,  3,  1)),
Packit 8dc392
	 true,
Packit 8dc392
	 V3f ( 2,  3, -1),
Packit 8dc392
	 V3f ( 2,  3,  1));
Packit 8dc392
Packit 8dc392
    cout << "  intersecting, non-parallel lines" << endl;
Packit 8dc392
Packit 8dc392
    testClosestPoints
Packit 8dc392
	(Line3f (V3f ( 2, -1,  0), V3f ( 2,  1,  0)),
Packit 8dc392
	 Line3f (V3f (-1,  3,  0), V3f ( 1,  3,  0)),
Packit 8dc392
	 true,
Packit 8dc392
	 V3f ( 2,  3,  0),
Packit 8dc392
	 V3f ( 2,  3,  0));
Packit 8dc392
Packit 8dc392
    cout << "  parallel lines" << endl;
Packit 8dc392
Packit 8dc392
    testClosestPoints
Packit 8dc392
	(Line3f (V3f ( 2, -1,  0), V3f ( 2,  1,  0)),
Packit 8dc392
	 Line3f (V3f ( 2, -1,  1), V3f ( 2,  1,  1)),
Packit 8dc392
	 false,
Packit 8dc392
	 V3f ( 0,  0,  0),
Packit 8dc392
	 V3f ( 0,  0,  0));
Packit 8dc392
Packit 8dc392
    testClosestPoints
Packit 8dc392
	(Line3f (V3f ( 2, -1,  0), V3f ( 2,  1,  0)),
Packit 8dc392
	 Line3f (V3f ( 2,  1,  1), V3f ( 2, -1,  1)),
Packit 8dc392
	 false,
Packit 8dc392
	 V3f ( 0,  0,  0),
Packit 8dc392
	 V3f ( 0,  0,  0));
Packit 8dc392
Packit 8dc392
    cout << "  coincident lines" << endl;
Packit 8dc392
Packit 8dc392
    testClosestPoints
Packit 8dc392
	(Line3f (V3f ( 2, -1,  0), V3f ( 2, -1,  1)),
Packit 8dc392
	 Line3f (V3f ( 2, -1,  0), V3f ( 2, -1,  1)),
Packit 8dc392
	 false,
Packit 8dc392
	 V3f ( 0,  0,  0),
Packit 8dc392
	 V3f ( 0,  0,  0));
Packit 8dc392
Packit 8dc392
    cout << "  random lines" << endl;
Packit 8dc392
Packit 8dc392
    Rand48 rand (7);
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 10000; ++i)
Packit 8dc392
    {
Packit 8dc392
	Line3f line1 (solidSphereRand<V3f> (rand) * 100.f,
Packit 8dc392
		      solidSphereRand<V3f> (rand) * 100.f);
Packit 8dc392
Packit 8dc392
	Line3f line2 (solidSphereRand<V3f> (rand) * 100.f,
Packit 8dc392
		      solidSphereRand<V3f> (rand) * 100.f);
Packit 8dc392
Packit 8dc392
	V3f point1;
Packit 8dc392
	V3f point2;
Packit 8dc392
	bool rv = closestPoints (line1, line2, point1, point2);
Packit 8dc392
Packit 8dc392
	if (rv)
Packit 8dc392
	{
Packit 8dc392
	    //
Packit 8dc392
	    // We test if the line that connects point1 and point2
Packit 8dc392
	    // is perpendicular to line1 and line2.  The numerical
Packit 8dc392
	    // accuracy of point1 and point2 depends strongly on
Packit 8dc392
	    // the relative directions of line1 and line2; accuracy
Packit 8dc392
	    // degrades rather quickly if line1 and line2 become
Packit 8dc392
	    // close to parallel.
Packit 8dc392
	    //
Packit 8dc392
Packit 8dc392
	    float e = 2000 * limits<float>::epsilon();
Packit 8dc392
	    float d = 1 - (line1.dir ^ line2.dir) * (line1.dir ^ line2.dir);
Packit 8dc392
	    V3f n = point1 - point2;
Packit 8dc392
Packit 8dc392
	    assert (equalWithAbsError (0.0f, (line1.dir ^ n) * d, e));
Packit 8dc392
	    assert (equalWithAbsError (0.0f, (line2.dir ^ n) * d, e));
Packit 8dc392
	}
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testIntersect
Packit 8dc392
    (const Line3f &line,
Packit 8dc392
     const V3f &v0,
Packit 8dc392
     const V3f &v1,
Packit 8dc392
     const V3f &v2,
Packit 8dc392
     const V3f &point,
Packit 8dc392
     bool front,
Packit 8dc392
     bool returnValue)
Packit 8dc392
{
Packit 8dc392
    V3f pt;
Packit 8dc392
    V3f bary;
Packit 8dc392
    bool fr;
Packit 8dc392
Packit 8dc392
    bool rv = intersect (line, v0, v1, v2, pt, bary, fr);
Packit 8dc392
Packit 8dc392
    assert (rv == returnValue);
Packit 8dc392
Packit 8dc392
    float e = 10 * limits<float>::epsilon();
Packit 8dc392
Packit 8dc392
    if (rv)
Packit 8dc392
    {
Packit 8dc392
	assert (front == fr);
Packit 8dc392
	assert (pt.equalWithAbsError (point, e));
Packit 8dc392
	V3f pt2 = v0 * bary.x + v1 * bary.y + v2 * bary.z;
Packit 8dc392
	assert (pt.equalWithAbsError (pt2, e));
Packit 8dc392
    }
Packit 8dc392
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testIntersect ()
Packit 8dc392
{
Packit 8dc392
    cout << "line-triangle intersection" << endl;
Packit 8dc392
Packit 8dc392
    cout << "  line-plane intersection inside triangle" << endl;
Packit 8dc392
    
Packit 8dc392
    testIntersect (Line3f (V3f (0, 0, -1), V3f (0, 0, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 7),
Packit 8dc392
		   true,
Packit 8dc392
		   true);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (0, 0, -1), V3f (-1, -2, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (-1, -2, 7),
Packit 8dc392
		   true,
Packit 8dc392
		   true);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (0, 0, -1), V3f (-1, 1, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (-1, 1, 7),
Packit 8dc392
		   true,
Packit 8dc392
		   true);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (0, 0, -1), V3f (-1, 1, 7)),
Packit 8dc392
		   V3f (4, -4, 7), V3f (-4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (-1, 1, 7),
Packit 8dc392
		   false,
Packit 8dc392
		   true);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (1, 1, 2), V3f (0, 0, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 7),
Packit 8dc392
		   true,
Packit 8dc392
		   true);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (2, 3, -5), V3f (-1, -2, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (-1, -2, 7),
Packit 8dc392
		   true,
Packit 8dc392
		   true);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (2, 8, -10), V3f (-1, 1, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (-1, 1, 7),
Packit 8dc392
		   true,
Packit 8dc392
		   true);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (-10, 2, -1), V3f (-1, 1, 7)),
Packit 8dc392
		   V3f (4, -4, 7), V3f (-4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (-1, 1, 7),
Packit 8dc392
		   false,
Packit 8dc392
		   true);
Packit 8dc392
Packit 8dc392
    cout << "  line-plane intersection outside triangle" << endl;
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (0, 0, -1), V3f (4, 0, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 0),
Packit 8dc392
		   false,
Packit 8dc392
		   false);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (0, 0, -1), V3f (-4, 1, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 0),
Packit 8dc392
		   false,
Packit 8dc392
		   false);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (0, 0, -1), V3f (0, -5, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 0),
Packit 8dc392
		   false,
Packit 8dc392
		   false);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (0, 0, -1), V3f (0, -7, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 0),
Packit 8dc392
		   false,
Packit 8dc392
		   false);
Packit 8dc392
Packit 8dc392
    cout << "  line parallel to triangle" << endl;
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (0, 0, -1), V3f (4, 0, -1)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 0),
Packit 8dc392
		   false,
Packit 8dc392
		   false);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (0, 4, 7), V3f (4, 0, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 0),
Packit 8dc392
		   false,
Packit 8dc392
		   false);
Packit 8dc392
Packit 8dc392
    cout << "  zero-area triangle" << endl;
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (2, 3, -5), V3f (-1, -2, 7)),
Packit 8dc392
		   V3f (0, 6, 7), V3f (4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 0),
Packit 8dc392
		   false,
Packit 8dc392
		   false);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (2, 3, -5), V3f (-1, -2, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (-4, -4, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 0),
Packit 8dc392
		   false,
Packit 8dc392
		   false);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (2, 3, -5), V3f (-1, -2, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (0, 6, 7), V3f (0, 6, 7),
Packit 8dc392
		   V3f (0, 0, 0),
Packit 8dc392
		   false,
Packit 8dc392
		   false);
Packit 8dc392
Packit 8dc392
    testIntersect (Line3f (V3f (2, 3, -5), V3f (-1, -2, 7)),
Packit 8dc392
		   V3f (-4, -4, 7), V3f (-4, -4, 7), V3f (-4, -4, 7),
Packit 8dc392
		   V3f (0, 0, 0),
Packit 8dc392
		   false,
Packit 8dc392
		   false);
Packit 8dc392
Packit 8dc392
    cout << "  random lines and triangles" << endl;
Packit 8dc392
Packit 8dc392
    Rand48 rand (8);
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 10000; ++i)
Packit 8dc392
    {
Packit 8dc392
	//
Packit 8dc392
	// Generate a random triangle with non-zero area
Packit 8dc392
	//
Packit 8dc392
Packit 8dc392
	V3f v0, v1, v2;
Packit 8dc392
	V3f normal;
Packit 8dc392
Packit 8dc392
	do
Packit 8dc392
	{
Packit 8dc392
	    v0 = solidSphereRand<V3f> (rand);
Packit 8dc392
	    v1 = solidSphereRand<V3f> (rand);
Packit 8dc392
	    v2 = solidSphereRand<V3f> (rand);
Packit 8dc392
	    normal = (v2 - v1) % (v1 - v0);
Packit 8dc392
	}
Packit 8dc392
	while (normal.length() < 0.01);
Packit 8dc392
Packit 8dc392
	{
Packit 8dc392
	    //
Packit 8dc392
	    // Generate a line that intersects inside the triangle
Packit 8dc392
	    //
Packit 8dc392
Packit 8dc392
	    V3f b;
Packit 8dc392
Packit 8dc392
	    do
Packit 8dc392
	    {
Packit 8dc392
		b.x = rand.nextf (0.001, 0.999);
Packit 8dc392
		b.y = rand.nextf (0.001, 0.999);
Packit 8dc392
		b.z = 1 - b.x - b.y;
Packit 8dc392
	    }
Packit 8dc392
	    while (b.x + b.y > 0.999);
Packit 8dc392
Packit 8dc392
	    V3f p1 = v0 * b.x + v1 * b.y + v2 * b.z;
Packit 8dc392
Packit 8dc392
	    V3f p0;
Packit 8dc392
Packit 8dc392
	    do
Packit 8dc392
	    {
Packit 8dc392
		p0 = solidSphereRand<V3f> (rand);
Packit 8dc392
	    }
Packit 8dc392
	    while (abs (normal.normalized() ^ (p1 - p0).normalized()) < 0.1);
Packit 8dc392
Packit 8dc392
	    //
Packit 8dc392
	    // Test for intersection
Packit 8dc392
	    //
Packit 8dc392
Packit 8dc392
	    V3f point;
Packit 8dc392
	    V3f bary;
Packit 8dc392
	    bool front;
Packit 8dc392
Packit 8dc392
	    bool rv = intersect (Line3f (p0, p1),
Packit 8dc392
	                         v0, v1, v2, point,
Packit 8dc392
				 bary, front);
Packit 8dc392
Packit 8dc392
	    assert (rv == true);
Packit 8dc392
Packit 8dc392
	    float nd = abs (normal.normalized() ^ (p1 - p0).normalized());
Packit 8dc392
	    float ep = 20 * limits<float>::epsilon() / nd;
Packit 8dc392
Packit 8dc392
	    assert (point.equalWithAbsError (p1, ep));
Packit 8dc392
	}
Packit 8dc392
Packit 8dc392
	{
Packit 8dc392
	    //
Packit 8dc392
	    // Generate a line that intersects the triangle's plane
Packit 8dc392
	    // but outside the triangle
Packit 8dc392
	    //
Packit 8dc392
Packit 8dc392
	    V3f b;
Packit 8dc392
Packit 8dc392
	    do
Packit 8dc392
	    {
Packit 8dc392
		b.x = rand.nextf (-3, 3);
Packit 8dc392
		b.y = rand.nextf (-3, 3);
Packit 8dc392
		b.z = 1 - b.x - b.y;
Packit 8dc392
	    }
Packit 8dc392
	    while (b.x > -0.001 && b.y > -0.001 && b.z > -0.001);
Packit 8dc392
Packit 8dc392
	    V3f p1 = v0 * b.x + v1 * b.y + v2 * b.z;
Packit 8dc392
Packit 8dc392
	    V3f p0;
Packit 8dc392
	    int j = 0;
Packit 8dc392
Packit 8dc392
	    do
Packit 8dc392
	    {
Packit 8dc392
		p0 = solidSphereRand<V3f> (rand) * 10;
Packit 8dc392
	    }
Packit 8dc392
	    while (abs (normal.normalized() ^ (p1 - p0).normalized()) < 0.1);
Packit 8dc392
Packit 8dc392
	    //
Packit 8dc392
	    // Test for intersection
Packit 8dc392
	    //
Packit 8dc392
Packit 8dc392
	    V3f point;
Packit 8dc392
	    V3f bary;
Packit 8dc392
	    bool front;
Packit 8dc392
Packit 8dc392
	    bool rv = intersect (Line3f (p0, p1),
Packit 8dc392
	                         v0, v1, v2, point,
Packit 8dc392
				 bary, front);
Packit 8dc392
Packit 8dc392
	    assert (rv == false);
Packit 8dc392
	}
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
} // namespace
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testLineAlgo ()
Packit 8dc392
{
Packit 8dc392
    cout << "Testing line algorithms" << endl;
Packit 8dc392
Packit 8dc392
    testClosestPoints();
Packit 8dc392
    testIntersect();
Packit 8dc392
Packit 8dc392
    cout << "ok\n" << endl;
Packit 8dc392
}