Blame ImathTest/testQuatSlerp.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 <testQuatSlerp.h>
Packit 8dc392
#include "ImathQuat.h"
Packit 8dc392
#include "ImathRandom.h"
Packit 8dc392
#include <iostream>
Packit 8dc392
#include <math.h>
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
compareQuats (const Quatf &q1, const Quatf &q2, float e)
Packit 8dc392
{
Packit 8dc392
    assert (equalWithAbsError (q1.v.x, q2.v.x, e));
Packit 8dc392
    assert (equalWithAbsError (q1.v.y, q2.v.y, e));
Packit 8dc392
    assert (equalWithAbsError (q1.v.z, q2.v.z, e));
Packit 8dc392
    assert (equalWithAbsError (q1.r,   q2.r,   e));
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
Quatd
Packit 8dc392
pow (const Quatd q, int n)
Packit 8dc392
{
Packit 8dc392
    Quatd result;
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < n; ++i)
Packit 8dc392
	result *= q;
Packit 8dc392
Packit 8dc392
    return result;
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testSlerp (const Quatf q1, const Quatf q2, int m, int n)
Packit 8dc392
{
Packit 8dc392
    //
Packit 8dc392
    // For two quaternions, q1 and q2, and the identity quaternion, qi,
Packit 8dc392
    //
Packit 8dc392
    //     slerp (q1, q2, f) == q1 * slerp (qi, q1.inverse() * q2, f);  (1)
Packit 8dc392
    //
Packit 8dc392
    // In addition, for integers m and n, with m >= 0, n > 0,
Packit 8dc392
    //
Packit 8dc392
    //     pow (slerp (qi, q3, m/n), n) == pow (q3, m)                  (2)
Packit 8dc392
    //
Packit 8dc392
    // This allows us to test if slerp (q1, q2, m/n) works correctly.
Packit 8dc392
    // Thanks to Dan Piponi for pointing this out.
Packit 8dc392
    //
Packit 8dc392
    // Note that e2, our upper bound for the numerical error in (2) is
Packit 8dc392
    // fairly large.  The reason for this is that testSlerp() will be
Packit 8dc392
    // called with m and n up to 16.  Taking quaternions to the 16th
Packit 8dc392
    // power amplifies any inaccuracies.
Packit 8dc392
    //
Packit 8dc392
Packit 8dc392
    Quatf qi;
Packit 8dc392
    Quatf q3 = q1.inverse() * q2;
Packit 8dc392
    Quatf q1q2 = slerp (q1, q2, float (m) / float (n));
Packit 8dc392
    Quatf qiq3 = slerp (qi, q3, float (m) / float (n));
Packit 8dc392
    float e1 = 60 * limits<float>::epsilon();
Packit 8dc392
    float e2 = 600 * limits<float>::epsilon();
Packit 8dc392
Packit 8dc392
    compareQuats (q1q2, q1 * qiq3, e1);
Packit 8dc392
    compareQuats (pow (qiq3, n), pow (q3, m), e2);
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testSlerp (const Quatf q1, const Quatf q2)
Packit 8dc392
{
Packit 8dc392
    const int n = 16;
Packit 8dc392
Packit 8dc392
    for (int m = 0; m <= n; ++m)
Packit 8dc392
	testSlerp (q1, q2, m, n);
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
specificRotations ()
Packit 8dc392
{
Packit 8dc392
    cout << "  combinations of 90-degree rotations around x, y and z" << endl;
Packit 8dc392
Packit 8dc392
    for (int x1 = 0; x1 < 3; ++x1)
Packit 8dc392
    {
Packit 8dc392
	V3f axis1 (0, 0, 0);
Packit 8dc392
	axis1[x1] = 1;
Packit 8dc392
Packit 8dc392
	for (int n1 = 0; n1 < 4; ++n1)
Packit 8dc392
	{
Packit 8dc392
	    float angle1 = n1 * M_PI / 2;
Packit 8dc392
Packit 8dc392
	    Quatf q1;
Packit 8dc392
	    q1.setAxisAngle (axis1, angle1);
Packit 8dc392
Packit 8dc392
	    for (int x2 = 0; x2 < 3; ++x2)
Packit 8dc392
	    {
Packit 8dc392
		V3f axis2 (0, 0, 0);
Packit 8dc392
		axis2[x2] = 1;
Packit 8dc392
Packit 8dc392
		for (int n2 = 0; n2 < 4; ++n2)
Packit 8dc392
		{
Packit 8dc392
		    float angle2 = n2 * M_PI / 2;
Packit 8dc392
Packit 8dc392
		    Quatf q2;
Packit 8dc392
		    q2.setAxisAngle (axis2, angle2);
Packit 8dc392
Packit 8dc392
		    testSlerp (q1, q2);
Packit 8dc392
		    testSlerp (-q1, -q2);
Packit 8dc392
Packit 8dc392
		    if ((q1 ^ q2) < 0.99)
Packit 8dc392
		    {
Packit 8dc392
			testSlerp (q1, -q2);
Packit 8dc392
			testSlerp (-q1, q2);
Packit 8dc392
		    }
Packit 8dc392
		}
Packit 8dc392
	    }
Packit 8dc392
	}
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
randomRotations ()
Packit 8dc392
{
Packit 8dc392
    cout << "  random rotations" << endl;
Packit 8dc392
Packit 8dc392
    Rand48 rand (53);
Packit 8dc392
Packit 8dc392
    for (int i = 0; i < 10000; ++i)
Packit 8dc392
    {
Packit 8dc392
	V3f axis1 = hollowSphereRand<V3f> (rand);
Packit 8dc392
	V3f axis2 = hollowSphereRand<V3f> (rand);
Packit 8dc392
	float angle1 = rand.nextf (0, M_PI);
Packit 8dc392
	float angle2 = rand.nextf (0, M_PI);
Packit 8dc392
Packit 8dc392
	Quatf q1, q2;
Packit 8dc392
	q1.setAxisAngle (axis1, angle1);
Packit 8dc392
	q2.setAxisAngle (axis2, angle2);
Packit 8dc392
Packit 8dc392
	testSlerp (q1, q2);
Packit 8dc392
	testSlerp (-q1, -q2);
Packit 8dc392
Packit 8dc392
	if ((q1 ^ q2) < 0.99)
Packit 8dc392
	{
Packit 8dc392
	    testSlerp (q1, -q2);
Packit 8dc392
	    testSlerp (-q1, q2);
Packit 8dc392
	}
Packit 8dc392
    }
Packit 8dc392
}
Packit 8dc392
Packit 8dc392
} // namespace
Packit 8dc392
Packit 8dc392
Packit 8dc392
void
Packit 8dc392
testQuatSlerp ()
Packit 8dc392
{
Packit 8dc392
    cout << "Testing quaternion spherical linear interpolation" << endl;
Packit 8dc392
Packit 8dc392
    specificRotations();
Packit 8dc392
    randomRotations();
Packit 8dc392
Packit 8dc392
    cout << "ok\n" << endl;
Packit 8dc392
}
Packit 8dc392