From e92343b1185b4bdd3887c228c3b853a94b34da91 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 6 Mar 2013 07:30:33 +0100 Subject: [PATCH 1/9] Add files for tests --- test/CMakeLists.txt | 20 +++++++ test/Test.cpp | 52 ++++++++++++++++++ test/Test.h | 125 ++++++++++++++++++++++++++++++++++++++++++++ test/TestSuite.cpp | 24 +++++++++ test/TestSuite.h | 35 +++++++++++++ 5 files changed, 256 insertions(+) create mode 100755 test/CMakeLists.txt create mode 100644 test/Test.cpp create mode 100644 test/Test.h create mode 100644 test/TestSuite.cpp create mode 100644 test/TestSuite.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100755 index 00000000..ba27baba --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,20 @@ +# Minimum cmake version required +cmake_minimum_required(VERSION 2.6) + +# Project configuration +PROJECT(TESTS) + +# Headers +INCLUDE_DIRECTORIES(${REACTPHYSICS3D_SOURCE_DIR}/test) + +# Sources files of tests +file ( + GLOB_RECURSE + TESTS_SOURCE_FILES + ${REACTPHYSICS3D_SOURCE_DIR}/test/* +) + +# Create the tests executable +ADD_EXECUTABLE(tests ${REACTPHYSICS3D_SOURCE_DIR}) + +TARGET_LINK_LIBRARIES(tests reactphysics3d) diff --git a/test/Test.cpp b/test/Test.cpp new file mode 100644 index 00000000..073a8242 --- /dev/null +++ b/test/Test.cpp @@ -0,0 +1,52 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +// Libraries +#include "Test.h" + +using namespace reactphysics3d; + +/// Constructor +Test::Test(std::ostream* stream) : mOutputStream(stream), mNbPassedTests(0), mNbFailedTests(0) { + +} + +/// Destructor +Test::~Test() { + +} + +/// Display the report of the unit test and return the number of failed tests +uint Test::report() const { + + if(mOutputStream) { + *osptr << "Test \"" << + typeid(*this).name() + << "\":\n\tPassed: " << mNbPassedTests << "\tFailed: " << mNbFailedTests << endl; + } + + // Return the number of failed tests + return mNbFailedTests; +} diff --git a/test/Test.h b/test/Test.h new file mode 100644 index 00000000..6d06a3be --- /dev/null +++ b/test/Test.h @@ -0,0 +1,125 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TEST_H +#define TEST_H + +// Libraries +#include +#include +#include + +/// Reactphysics3D namespace +namespace reactphysics3d { + +/** + * This abstract class represents a unit test + */ +class Test { + + private : + + // ---------- Attributes ---------- // + + /// Number of tests that passed + uint mNbPassedTests; + + /// Number of tests that failed + uint mNbFailedTests; + + /// Output stream + std::ostream* mOutputStream; + + // ---------- Methods ---------- // + + /// Copy constructor is private + Test(const Test&); + + /// Assignment operator is private + Test& operator=(const Test& test); + + protected : + + public : + + // ---------- Methods ---------- // + + /// Constructor + Test(std::ostream* stream = &std::cout); + + /// Destructor + ~Test(); + + /// Return the number of passed tests + uint getNbPassedTests() const; + + /// Return the number of failed tests + uint getNbFailedTests() const; + + /// Return the output stream + const std::ostream* getOutputStream() const; + + /// Set the output stream + void setOutputStream(const std::ostream* stream); + + /// Run the unit test + virtual void run() = 0; + + /// Reset the unit test + virtual void reset(); + + /// Display the report of the unit test and return the number of failed tests + uint report() const; +}; + +/// Reset the unit test +inline void Test::reset() { + mNbPassedTests = 0; + mNbFailedTests = 0; +} + +/// Return the number of passed tests +inline uint Test::getNbPassedTests() const { + return mNbPassedTests; +} + +/// Return the number of failed tests +inline uint Test::getNbFailedTests() const { + return mNbFailedTests; +} + +/// Return the output stream +inline const std::ostream* Test::getOutputStream() const { + return mOutputStream; +} + +/// Set the output stream +inline void Test::setOutputStream(const std::ostream* stream) { + mOutputStream = stream; +} + +} + +#endif diff --git a/test/TestSuite.cpp b/test/TestSuite.cpp new file mode 100644 index 00000000..15a541cc --- /dev/null +++ b/test/TestSuite.cpp @@ -0,0 +1,24 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ diff --git a/test/TestSuite.h b/test/TestSuite.h new file mode 100644 index 00000000..7f64e271 --- /dev/null +++ b/test/TestSuite.h @@ -0,0 +1,35 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TESTSUITE_H +#define TESTSUITE_H + +// Libraries + +class TestSuite { + +}; + +#endif From a178a3c0b974aca29e3ee4f2d2309af27c882e58 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 9 Mar 2013 08:34:57 +0100 Subject: [PATCH 2/9] Start to implement unit tests for the mathematics classes --- test/CMakeLists.txt | 2 +- test/Test.cpp | 40 ++++- test/Test.h | 58 ++++-- test/TestSuite.cpp | 121 +++++++++++++ test/TestSuite.h | 94 +++++++++- test/main.cpp | 56 ++++++ test/tests/mathematics/TestMatrix3x3.h | 72 ++++++++ test/tests/mathematics/TestQuaternion.h | 101 +++++++++++ test/tests/mathematics/TestTransform.h | 205 +++++++++++++++++++++ test/tests/mathematics/TestVector3.h | 225 ++++++++++++++++++++++++ 10 files changed, 953 insertions(+), 21 deletions(-) mode change 100755 => 100644 test/CMakeLists.txt create mode 100644 test/main.cpp create mode 100644 test/tests/mathematics/TestMatrix3x3.h create mode 100644 test/tests/mathematics/TestQuaternion.h create mode 100644 test/tests/mathematics/TestTransform.h create mode 100644 test/tests/mathematics/TestVector3.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt old mode 100755 new mode 100644 index ba27baba..ff69eb31 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,6 +15,6 @@ file ( ) # Create the tests executable -ADD_EXECUTABLE(tests ${REACTPHYSICS3D_SOURCE_DIR}) +ADD_EXECUTABLE(tests ${TESTS_SOURCE_FILES}) TARGET_LINK_LIBRARIES(tests reactphysics3d) diff --git a/test/Test.cpp b/test/Test.cpp index 073a8242..a1c71b91 100644 --- a/test/Test.cpp +++ b/test/Test.cpp @@ -38,13 +38,47 @@ Test::~Test() { } +// Called to test a boolean condition. +// This method should not be called directly in your test but you should call test() instead (macro) +void Test::applyTest(bool condition, const std::string& testText, + const char* filename, long lineNumber) { + + // If the boolean condition is true + if (condition) { + + // The test passed, call the succeed() method + succeed(); + } + else { // If the boolean condition is false + + // The test failed, call the applyFail() method + applyFail(testText, filename, lineNumber); + } +} + +// Called when a test has failed. +// This method should not be called directly in your test buy you should call fail() instead (macro) +void Test::applyFail(const std::string& testText, const char* filename, long lineNumber) { + + if (mOutputStream) { + + // Display the failure message + *mOutputStream << typeid(*this).name() << "failure : (" << testText << "), " << + filename << "(line " << lineNumber << ")" << std::endl; + } + + // Increase the number of failed tests + mNbFailedTests++; +} + /// Display the report of the unit test and return the number of failed tests -uint Test::report() const { +long Test::report() const { if(mOutputStream) { - *osptr << "Test \"" << + *mOutputStream << "Test \"" << typeid(*this).name() - << "\":\n\tPassed: " << mNbPassedTests << "\tFailed: " << mNbFailedTests << endl; + << "\":\n\tPassed: " << mNbPassedTests << "\tFailed: " << + mNbFailedTests << std::endl; } // Return the number of failed tests diff --git a/test/Test.h b/test/Test.h index 6d06a3be..19861876 100644 --- a/test/Test.h +++ b/test/Test.h @@ -34,8 +34,15 @@ /// Reactphysics3D namespace namespace reactphysics3d { +// Macros +#define test(condition) applyTest(condition, #condition, __FILE__, __LINE__) +#define fail(text) applyFail(text, __FILE__, __LINE__); + +// Class Test /** - * This abstract class represents a unit test + * This abstract class represents a unit test. To create a unit test, you simply + * need to create a class that inherits from the Test class, override the run() method and + * use the test() and fail() macros. */ class Test { @@ -44,10 +51,10 @@ class Test { // ---------- Attributes ---------- // /// Number of tests that passed - uint mNbPassedTests; + long mNbPassedTests; /// Number of tests that failed - uint mNbFailedTests; + long mNbFailedTests; /// Output stream std::ostream* mOutputStream; @@ -62,6 +69,19 @@ class Test { protected : + // ---------- Methods ---------- // + + /// Called to test a boolean condition. + /// This method should not be called directly in your test but you should + /// call test() instead (macro) + void applyTest(bool condition, const std::string& testText, + const char* filename, long lineNumber); + + /// Called when a test has failed. + /// This method should not be called directly in your test buy you should + /// call fail() instead (macro) + void applyFail(const std::string& testText, const char* filename, long lineNumber); + public : // ---------- Methods ---------- // @@ -73,50 +93,58 @@ class Test { ~Test(); /// Return the number of passed tests - uint getNbPassedTests() const; + long getNbPassedTests() const; /// Return the number of failed tests - uint getNbFailedTests() const; + long getNbFailedTests() const; /// Return the output stream const std::ostream* getOutputStream() const; /// Set the output stream - void setOutputStream(const std::ostream* stream); + void setOutputStream(std::ostream *stream); /// Run the unit test virtual void run() = 0; + /// Called when a test passed + void succeed(); + /// Reset the unit test virtual void reset(); /// Display the report of the unit test and return the number of failed tests - uint report() const; + long report() const; }; -/// Reset the unit test +// Called when a test passed +inline void Test::succeed() { + mNbPassedTests++; +} + +// Reset the unit test inline void Test::reset() { mNbPassedTests = 0; mNbFailedTests = 0; } -/// Return the number of passed tests -inline uint Test::getNbPassedTests() const { +// Return the number of passed tests +inline long Test::getNbPassedTests() const { return mNbPassedTests; } -/// Return the number of failed tests -inline uint Test::getNbFailedTests() const { +// Return the number of failed tests +inline long Test::getNbFailedTests() const { return mNbFailedTests; } -/// Return the output stream +// Return the output stream inline const std::ostream* Test::getOutputStream() const { return mOutputStream; } -/// Set the output stream -inline void Test::setOutputStream(const std::ostream* stream) { +// Set the output stream +inline void Test::setOutputStream(std::ostream* stream) { mOutputStream = stream; } diff --git a/test/TestSuite.cpp b/test/TestSuite.cpp index 15a541cc..f8d97363 100644 --- a/test/TestSuite.cpp +++ b/test/TestSuite.cpp @@ -22,3 +22,124 @@ * 3. This notice may not be removed or altered from any source distribution. * * * ********************************************************************************/ + +// Librairies +#include "TestSuite.h" + +using namespace reactphysics3d; + +// Constructor +TestSuite::TestSuite(const std::string& name, std::ostream* outputStream) + : mName(name), mOutputStream(outputStream) { + +} + +// Return the number of passed tests +long TestSuite::getNbPassedTests() const { + + long nbPassedTests = 0; + + for (size_t i=0; igetNbPassedTests(); + } + + return nbPassedTests; +} + +// Return the number of failed tests +long TestSuite::getNbFailedTests() const { + long nbFailedTests = 0; + + for (size_t i=0; igetNbFailedTests(); + } + + return nbFailedTests; +} + +// Add a unit test in the test suite +void TestSuite::addTest(Test* test) { + if (test == NULL) { + throw std::invalid_argument("Error : You cannot add a NULL test in the test suite."); + } + else if (mOutputStream != NULL && test->getOutputStream() == NULL) { + test->setOutputStream(mOutputStream); + } + + // Add the test to the suite + mTests.push_back(test); + + // Reset the added test + test->reset(); +} + +// Add a test suite to the current test suite +void TestSuite::addTestSuite(const TestSuite& testSuite) { + + // Add each test of the test suite to the current one + for (size_t i =0; i < testSuite.mTests.size(); i++) { + assert(testSuite.mTests[i] != NULL); + addTest(testSuite.mTests[i]); + } +} + +// Launch the tests of the test suite +void TestSuite::run() { + + // Reset all the tests + reset(); + + // Run all the tests + for (size_t i=0; i < mTests.size(); i++) { + assert(mTests[i] != NULL); + mTests[i]->run(); + } +} + +// Reset the test suite +void TestSuite::reset() { + for(size_t i=0; i < mTests.size(); ++i) { + assert(mTests[i]); + mTests[i]->reset(); + } +} + +// Display the tests report and return the number of failed tests +long TestSuite::report() const { + if (mOutputStream != NULL) { + long nbFailedTests = 0; + + *mOutputStream << "Test Suite \"" << mName << "\"\n====="; + size_t i; + for (i=0; i < mName.size(); i++) { + *mOutputStream << "="; + } + *mOutputStream << "=" << std::endl; + for (i=0; i < mTests.size(); i++) { + assert(mTests[i] != NULL); + nbFailedTests += mTests[i]->report(); + } + *mOutputStream << "====="; + for (i=0; i < mName.size(); i++) { + *mOutputStream << "="; + } + *mOutputStream << "=" << std::endl; + + // Return the number of failed tests + return nbFailedTests; + } + else { + return getNbFailedTests(); + } +} + +// Delete all the tests +void TestSuite::clear() { + + for (size_t i=0; i +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestSuite +/** + * This class represents a test suite that can + * contains multiple unit tests. You can also add a test suite inside + * another test suite (all the tests of the first test suite will be added + * to the second one). + */ class TestSuite { + private : + + // ---------- Attributes ---------- // + + /// Name of the test suite + std::string mName; + + /// Output stream + std::ostream* mOutputStream; + + /// All the tests of the test suite + std::vector mTests; + + // ---------- Methods ---------- // + + /// Reset the test suite + void reset(); + + /// Private copy-constructor + TestSuite(const TestSuite& testSuite); + + /// Private assigmnent operator + TestSuite& operator=(const TestSuite testSuite); + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestSuite(const std::string& name, std::ostream* outputStream = &std::cout); + + /// Return the name of the test suite + std::string getName() const; + + /// Return the number of passed tests + long getNbPassedTests() const; + + /// Return the number of failed tests + long getNbFailedTests() const; + + /// Return the output stream + const std::ostream* getOutputStream() const; + + /// Set the output stream + void setOutputStream(std::ostream* outputStream); + + /// Add a unit test in the test suite + void addTest(Test* test); + + /// Add a test suite to the current test suite + void addTestSuite(const TestSuite& testSuite); + + /// Launch the tests of the test suite + void run(); + + /// Display the tests report and return the number of failed tests + long report() const; + + // Delete all the tests + void clear(); + }; +// Return the name of the test suite +inline std::string TestSuite::getName() const { + return mName; +} + +// Return the output stream +inline const std::ostream* TestSuite::getOutputStream() const { + return mOutputStream; +} + +// Set the output stream +inline void TestSuite::setOutputStream(std::ostream* outputStream) { + mOutputStream = outputStream; +} + +} + #endif diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 00000000..91a2c47e --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,56 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +// Libraries +#include "TestSuite.h" +#include "tests/mathematics/TestVector3.h" +#include "tests/mathematics/TestTransform.h" +#include "tests/mathematics/TestQuaternion.h" + +using namespace reactphysics3d; + +int main() { + + TestSuite testSuite("ReactPhysics3D tests"); + + // ---------- Mathematics tests ---------- // + + testSuite.addTest(new TestVector3); + testSuite.addTest(new TestTransform); + testSuite.addTest(new TestQuaternion); + + // ----------------------------- --------- // + + // Run the tests + testSuite.run(); + + // Display the report + long nbFailedTests = testSuite.report(); + + // Clear the tests from the test suite + testSuite.clear(); + + return nbFailedTests; +} diff --git a/test/tests/mathematics/TestMatrix3x3.h b/test/tests/mathematics/TestMatrix3x3.h new file mode 100644 index 00000000..325f9861 --- /dev/null +++ b/test/tests/mathematics/TestMatrix3x3.h @@ -0,0 +1,72 @@ + +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TEST_MATRIX3X3_H +#define TEST_MATRIX3X3_H + +#endif + +// Libraries +#include "../../Test.h" +#include "../../../src/mathematics/Matrix3x3.h" + +using namespace reactphysics3d; + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestMatrix3x3 +/** + * Unit test for the Matrix3x3 class + */ +class TestMatrix3x3 : public Test { + + private : + + // ---------- Atributes ---------- // + + /// Identity transform + Matrix3x3 mIdentity; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestMatrix3x3() : mIdentity(Matrix3x3::identity()){ + + + } + + /// Run the tests + void run() { + + } + + + }; + +} diff --git a/test/tests/mathematics/TestQuaternion.h b/test/tests/mathematics/TestQuaternion.h new file mode 100644 index 00000000..66ff0266 --- /dev/null +++ b/test/tests/mathematics/TestQuaternion.h @@ -0,0 +1,101 @@ + +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TEST_QUATERNION_H +#define TEST_QUATERNION_H + +#endif + +// Libraries +#include "../../Test.h" +#include "../../../src/mathematics/Quaternion.h" + +using namespace reactphysics3d; + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestQuaternion +/** + * Unit test for the Quaternion class + */ +class TestQuaternion : public Test { + + private : + + // ---------- Atributes ---------- // + + /// Identity Quaternion + Quaternion mIdentity; + + /// First test quaternion + Quaternion mQuaternion1; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestQuaternion() : mIdentity(Quaternion::identity()) { + + decimal sinA = sin(PI/8.0f); + decimal cosA = cos(PI/8.0f); + mQuaternion1 = Quaternion(sinA, sinA, sinA, cosA); + } + + /// Run the tests + void run() { + testConstructors(); + } + + /// Test the constructors + void testConstructors() { + Quaternion quaternion1(mQuaternion1); + test(mQuaternion1== quaternion1); + + Quaternion quaternion2(4, 5, 6, 7); + test(quaternion2 == Quaternion(4, 5, 6, 7)); + + Quaternion quaternion3(8, Vector3(3, 5, 2)); + test(quaternion3 == Quaternion(5, 6, 7, 4)); + + Matrix3x3 matrix(2, 3, 4, 5, 6, 7, 8, 9, 10); + Quaternion quaternion4(matrix); + Matrix3x3 result = quaternion4.getMatrix(); + test(approxEqual(matrix.getValue(0, 0), result.getValue(0, 0), 0.1)); + std::cout << "matrix : " << matrix.getValue(0, 0) << ", " << result.getValue(0, 0) << std::endl; + test(approxEqual(matrix.getValue(0, 1), result.getValue(0, 1), 0.1)); + test(approxEqual(matrix.getValue(0, 2), result.getValue(0, 2), 0.1)); + test(approxEqual(matrix.getValue(1, 0), result.getValue(1, 0), 0.1)); + test(approxEqual(matrix.getValue(1, 1), result.getValue(1, 1), 0.1)); + test(approxEqual(matrix.getValue(1, 2), result.getValue(1, 2), 0.1)); + test(approxEqual(matrix.getValue(2, 0), result.getValue(2, 0), 0.1)); + test(approxEqual(matrix.getValue(2, 1), result.getValue(2, 1), 0.1)); + test(approxEqual(matrix.getValue(2, 2), result.getValue(2, 2), 0.1)); + } + }; + +} diff --git a/test/tests/mathematics/TestTransform.h b/test/tests/mathematics/TestTransform.h new file mode 100644 index 00000000..2de02d79 --- /dev/null +++ b/test/tests/mathematics/TestTransform.h @@ -0,0 +1,205 @@ + +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TEST_TRANSFORM_H +#define TEST_TRANSFORM_H + +#endif + +// Libraries +#include "../../Test.h" +#include "../../../src/mathematics/Transform.h" + +using namespace reactphysics3d; + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestTransform +/** + * Unit test for the Transform class + */ +class TestTransform : public Test { + + private : + + // ---------- Atributes ---------- // + + /// Identity transform + Transform mIdentityTransform; + + /// First example transform + Transform mTransform1; + + /// Second example transform + Transform mTransform2; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestTransform() { + + mIdentityTransform.setToIdentity(); + + decimal sinA = sin(PI/8.0f); + decimal cosA = cos(PI/8.0f); + mTransform1 = Transform(Vector3(4, 5, 6), Quaternion(sinA, sinA, sinA, cosA)); + + decimal sinB = sin(PI/3.0f); + decimal cosB = cos(PI/3.0f); + mTransform2 = Transform(Vector3(8, 45, -6), Quaternion(sinB, sinB, sinB, cosB)); + } + + /// Run the tests + void run() { + testConstructors(); + testGetSet(); + testInverse(); + testGetSetOpenGLMatrix(); + testInterpolateTransform(); + testOperators(); + } + + /// Test the constructors + void testConstructors() { + Transform transform1(Vector3(1, 2, 3), Quaternion(6, 7, 8, 9)); + Transform transform2(Vector3(4, 5, 6), Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1)); + Transform transform3(transform1); + test(transform1.getPosition() == Vector3(1, 2, 3)); + test(transform1.getOrientation() == Quaternion(6, 7, 8, 9)); + test(transform2.getPosition() == Vector3(4, 5, 6)); + test(transform2.getOrientation() == Quaternion::identity()); + test(transform3 == transform1); + } + + /// Test getter and setter + void testGetSet() { + test(mIdentityTransform.getPosition() == Vector3(0, 0, 0)); + test(mIdentityTransform.getOrientation() == Quaternion::identity()); + Transform transform; + transform.setPosition(Vector3(5, 7, 8)); + transform.setOrientation(Quaternion(1, 2, 3, 1)); + test(transform.getPosition() == Vector3(5, 7, 8)); + test(transform.getOrientation() == Quaternion(1, 2, 3, 1)); + transform.setToIdentity(); + test(transform.getPosition() == Vector3(0, 0, 0)); + test(transform.getOrientation() == Quaternion::identity()); + } + + /// Test the inverse + void testInverse() { + Transform inverseTransform = mTransform1.inverse(); + Vector3 vector(2, 3, 4); + Vector3 tempVector = mTransform1 * vector; + Vector3 tempVector2 = inverseTransform * tempVector; + test(approxEqual(tempVector2.x, vector.x, decimal(10e-6))); + test(approxEqual(tempVector2.y, vector.y, decimal(10e-6))); + test(approxEqual(tempVector2.z, vector.z, decimal(10e-6))); + } + + /// Test methods to set and get transform matrix from and to OpenGL + void testGetSetOpenGLMatrix() { + Transform transform; + Vector3 position = mTransform1.getPosition(); + Matrix3x3 orientation = mTransform1.getOrientation().getMatrix(); + decimal openglMatrix[16] = {orientation.getValue(0,0), orientation.getValue(1,0), + orientation.getValue(2,0), 0, + orientation.getValue(0,1), orientation.getValue(1,1), + orientation.getValue(2,1), 0, + orientation.getValue(0,2), orientation.getValue(1,2), + orientation.getValue(2,2), 0, + position.x, position.y, position.z, 1}; + transform.setFromOpenGL(openglMatrix); + decimal openglMatrix2[16]; + transform.getOpenGLMatrix(openglMatrix2); + test(approxEqual(openglMatrix2[0], orientation.getValue(0,0))); + test(approxEqual(openglMatrix2[1], orientation.getValue(1,0))); + test(approxEqual(openglMatrix2[2], orientation.getValue(2,0))); + test(approxEqual(openglMatrix2[3], 0)); + test(approxEqual(openglMatrix2[4], orientation.getValue(0,1))); + test(approxEqual(openglMatrix2[5], orientation.getValue(1,1))); + test(approxEqual(openglMatrix2[6], orientation.getValue(2,1))); + test(approxEqual(openglMatrix2[7], 0)); + test(approxEqual(openglMatrix2[8], orientation.getValue(0,2))); + test(approxEqual(openglMatrix2[9], orientation.getValue(1,2))); + test(approxEqual(openglMatrix2[10], orientation.getValue(2,2))); + test(approxEqual(openglMatrix2[11], 0)); + test(approxEqual(openglMatrix2[12], position.x)); + test(approxEqual(openglMatrix2[13], position.y)); + test(approxEqual(openglMatrix2[14], position.z)); + test(approxEqual(openglMatrix2[15], 1)); + } + + /// Test the method to interpolate transforms + void testInterpolateTransform() { + Transform transformStart = Transform::interpolateTransforms(mTransform1, mTransform2,0); + Transform transformEnd = Transform::interpolateTransforms(mTransform1, mTransform2,1); + test(transformStart == mTransform1); + test(transformEnd == mTransform2); + + decimal sinA = sin(PI/3.0f); + decimal cosA = cos(PI/3.0f); + decimal sinB = sin(PI/6.0f); + decimal cosB = cos(PI/6.0f); + Transform transform1(Vector3(4, 5, 6), Quaternion::identity()); + Transform transform2(Vector3(8, 11, 16), Quaternion(sinA, sinA, sinA, cosA)); + Transform transform = Transform::interpolateTransforms(transform1, transform2, 0.5); + Vector3 position = transform.getPosition(); + Quaternion orientation = transform.getOrientation(); + test(approxEqual(position.x, 6)); + test(approxEqual(position.y, 8)); + test(approxEqual(position.z, 11)); + test(approxEqual(orientation.x, sinB)); + test(approxEqual(orientation.y, sinB)); + test(approxEqual(orientation.z, sinB)); + test(approxEqual(orientation.w, cosB)); + } + + /// Test the overloaded operators + void testOperators() { + + // Equality, inequality operator + test(mTransform1 == mTransform1); + test(mTransform1 != mTransform2); + + // Assignment operator + Transform transform; + transform = mTransform1; + test(transform == mTransform1); + + // Multiplication + Vector3 vector(7, 53, 5); + Vector3 vector2 = mTransform2 * (mTransform1 * vector); + Vector3 vector3 = (mTransform2 * mTransform1) * vector; + test(approxEqual(vector2.x, vector3.x, decimal(10e-6))); + test(approxEqual(vector2.y, vector3.y, decimal(10e-6))); + test(approxEqual(vector2.z, vector3.z, decimal(10e-6))); + } + }; + +} diff --git a/test/tests/mathematics/TestVector3.h b/test/tests/mathematics/TestVector3.h new file mode 100644 index 00000000..4097e730 --- /dev/null +++ b/test/tests/mathematics/TestVector3.h @@ -0,0 +1,225 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef TEST_VECTOR3_H +#define TEST_VECTOR3_H + +#endif + +// Libraries +#include "../../Test.h" +#include "../../../src/mathematics/Vector3.h" + +using namespace reactphysics3d; + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestVector3 +/** + * Unit test for the Vector3 class + */ +class TestVector3 : public Test { + + private : + + // ---------- Atributes ---------- // + + /// Zero vector + Vector3 mVectorZero; + + // Vector (3, 4, 5) + Vector3 mVector345; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestVector3() : mVectorZero(0, 0, 0), mVector345(3, 4, 5) {} + + /// Run the tests + void run() { + testConstructors(); + testLengthMethods(); + testDotCrossProducts(); + testOthersMethods(); + testOperators(); + } + + /// Test the constructors, getter and setter + void testConstructors() { + + // Test constructor + test(mVectorZero.x == 0.0); + test(mVectorZero.y == 0.0); + test(mVectorZero.z == 0.0); + test(mVector345.x == 3.0); + test(mVector345.y == 4.0); + test(mVector345.z == 5.0); + + // Test copy-constructor + Vector3 newVector(mVector345); + test(newVector.x == 3.0); + test(newVector.y == 4.0); + test(newVector.z == 5.0); + + // Test method to set values + Vector3 newVector2; + newVector2.setAllValues(decimal(6.1), decimal(7.2), decimal(8.6)); + test(approxEqual(newVector2.x, decimal(6.1))); + test(approxEqual(newVector2.y, decimal(7.2))); + test(approxEqual(newVector2.z, decimal(8.6))); + } + + /// Test the length, unit vector and normalize methods + void testLengthMethods() { + + // Test length methods + test(mVectorZero.length() == 0.0); + test(mVectorZero.lengthSquare() == 0.0); + test(Vector3(1, 0, 0).length() == 1.0); + test(Vector3(0, 1, 0).length() == 1.0); + test(Vector3(0, 0, 1).length() == 1.0); + test(mVector345.lengthSquare() == 50.0); + + // Test unit vector methods + test(Vector3(1, 0, 0).isUnit()); + test(Vector3(0, 1, 0).isUnit()); + test(Vector3(0, 0, 1).isUnit()); + test(!mVector345.isUnit()); + test(Vector3(5, 0, 0).getUnit() == Vector3(1, 0, 0)); + test(Vector3(0, 5, 0).getUnit() == Vector3(0, 1, 0)); + test(Vector3(0, 0, 5).getUnit() == Vector3(0, 0, 1)); + + test(!mVector345.isZero()); + test(mVectorZero.isZero()); + + // Test normalization method + Vector3 mVector100(1, 0, 0); + Vector3 mVector010(0, 1, 0); + Vector3 mVector001(0, 0, 1); + Vector3 mVector500(5, 0, 0); + Vector3 mVector050(0, 5, 0); + Vector3 mVector005(0, 0, 5); + mVector100.normalize(); + mVector010.normalize(); + mVector001.normalize(); + mVector500.normalize(); + mVector050.normalize(); + mVector005.normalize(); + test(mVector100 == Vector3(1, 0, 0)); + test(mVector010 == Vector3(0, 1, 0)); + test(mVector001 == Vector3(0, 0, 1)); + test(mVector500 == Vector3(1, 0, 0)); + test(mVector050 == Vector3(0, 1, 0)); + test(mVector005 == Vector3(0, 0, 1)); + } + + /// Test the dot and cross products + void testDotCrossProducts() { + + // Test the dot product + test(Vector3(5, 0, 0).dot(Vector3(0, 8, 0)) == 0); + test(Vector3(5, 8, 0).dot(Vector3(0, 0, 6)) == 0); + test(Vector3(12, 45, 83).dot(Vector3(0, 0, 0)) == 0); + test(Vector3(5, 7, 8).dot(Vector3(5, 7, 8)) == 138); + test(Vector3(3, 6, 78).dot(Vector3(-3, -6, -78)) == -6129); + test(Vector3(2, 3, 5).dot(Vector3(2, 3, 5)) == 38); + test(Vector3(4, 3, 2).dot(Vector3(8, 9, 10)) == 79); + + // Test the cross product + test(Vector3(0, 0, 0).cross(Vector3(0, 0, 0)) == Vector3(0, 0, 0)); + test(Vector3(6, 7, 2).cross(Vector3(6, 7, 2)) == Vector3(0, 0, 0)); + test(Vector3(1, 0, 0).cross(Vector3(0, 1, 0)) == Vector3(0, 0, 1)); + test(Vector3(0, 1, 0).cross(Vector3(0, 0, 1)) == Vector3(1, 0, 0)); + test(Vector3(0, 0, 1).cross(Vector3(0, 1, 0)) == Vector3(-1, 0, 0)); + test(Vector3(4, 7, 24).cross(Vector3(8, 13, 11)) == Vector3(-235, 148, -4)); + test(Vector3(-4, 42, -2).cross(Vector3(35, 7, -21)) == Vector3(-868, -154, -1498)); + } + + /// Test others methods + void testOthersMethods() { + + // Test the method that returns the absolute vector + test(Vector3(4, 5, 6).getAbsoluteVector() == Vector3(4, 5, 6)); + test(Vector3(-7, -24, -12).getAbsoluteVector() == Vector3(7, 24, 12)); + + // Test the method that returns the minimal element + test(Vector3(6, 35, 82).getMinAxis() == 0); + test(Vector3(564, 45, 532).getMinAxis() == 1); + test(Vector3(98, 23, 3).getMinAxis() == 2); + test(Vector3(-53, -25, -63).getMinAxis() == 2); + + // Test the method that returns the maximal element + test(Vector3(6, 35, 82).getMaxAxis() == 2); + test(Vector3(7, 533, 36).getMaxAxis() == 1); + test(Vector3(98, 23, 3).getMaxAxis() == 0); + test(Vector3(-53, -25, -63).getMaxAxis() == 1); + } + + /// Test the operators + void testOperators() { + + // Test the [] operator + test(mVector345[0] == 3); + test(mVector345[1] == 4); + test(mVector345[2] == 5); + + // Assignment operator + Vector3 newVector(6, 4, 2); + newVector = Vector3(7, 8, 9); + test(newVector == Vector3(7, 8, 9)); + + // Equality, inequality operators + test(Vector3(5, 7, 3) == Vector3(5, 7, 3)); + test(Vector3(63, 64, 24) != Vector3(63, 64, 5)); + test(Vector3(63, 64, 24) != Vector3(12, 64, 24)); + test(Vector3(63, 64, 24) != Vector3(63, 8, 24)); + + // Addition, substraction + Vector3 vector1(6, 33, 62); + Vector3 vector2(7, 68, 35); + test(Vector3(63, 24, 5) + Vector3(3, 4, 2) == Vector3(66, 28, 7)); + test(Vector3(63, 24, 5) - Vector3(3, 4, 2) == Vector3(60, 20, 3)); + vector1 += Vector3(5, 10, 12); + vector2 -= Vector3(10, 21, 5); + test(vector1 == Vector3(11, 43, 74)); + test(vector2 == Vector3(-3, 47, 30)); + + // Multiplication, division + Vector3 vector3(6, 33, 62); + Vector3 vector4(15, 60, 33); + test(Vector3(63, 24, 5) * 3 == Vector3(189, 72, 15)); + test(3 * Vector3(63, 24, 5) == Vector3(189, 72, 15)); + test(Vector3(14, 8, 50) / 2 == Vector3(7, 4, 25)); + vector3 *= 10; + vector4 /= 3; + test(vector3 == Vector3(60, 330, 620)); + test(vector4 == Vector3(5, 20, 11)); + } + }; + +} From bd0561acd9ce5dba8b98c848f12c93d95592e53a Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 9 Mar 2013 08:37:10 +0100 Subject: [PATCH 3/9] Remove the isParallelWith() method in Vector3 --- src/mathematics/Vector3.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/mathematics/Vector3.h b/src/mathematics/Vector3.h index a4a1eaa6..66ab9bd0 100644 --- a/src/mathematics/Vector3.h +++ b/src/mathematics/Vector3.h @@ -103,9 +103,6 @@ struct Vector3 { // Return the axis with the maximal value int getMaxAxis() const; - // Return true if two vectors are parallel - bool isParallelWith(const Vector3& vector) const; - // Overloaded operator for the equality condition bool operator== (const Vector3& vector) const; @@ -184,14 +181,7 @@ inline void Vector3::normalize() { // Return the corresponding absolute value vector inline Vector3 Vector3::getAbsoluteVector() const { return Vector3(std::abs(x), std::abs(y), std::abs(z)); -} - -// Return true if two vectors are parallel -inline bool Vector3::isParallelWith(const Vector3& vector) const { - decimal scalarProd = this->dot(vector); - return approxEqual(std::abs(scalarProd), length() * vector.length()); -} - +} // Return the axis with the minimal value inline int Vector3::getMinAxis() const { From 8107bbab8eb9c2384b52f9689ea7cbac590483bb Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 9 Mar 2013 08:37:40 +0100 Subject: [PATCH 4/9] Modify the epsilon parameter of the approxEqual() method --- src/mathematics/mathematics_functions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mathematics/mathematics_functions.h b/src/mathematics/mathematics_functions.h index 5557d0e3..9c95cbf8 100644 --- a/src/mathematics/mathematics_functions.h +++ b/src/mathematics/mathematics_functions.h @@ -37,7 +37,7 @@ namespace reactphysics3d { // function to test if two real numbers are (almost) equal // We test if two numbers a and b are such that (a-b) are in [-EPSILON; EPSILON] -inline bool approxEqual(decimal a, decimal b, decimal epsilon = 1.0e-10) { +inline bool approxEqual(decimal a, decimal b, decimal epsilon = MACHINE_EPSILON) { decimal difference = a - b; return (difference < epsilon && difference > -epsilon); } From 999bef7c8dd1736ae234180de71ae96862149c24 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 9 Mar 2013 08:39:09 +0100 Subject: [PATCH 5/9] Add definition to avoid redefinition of min() and max() macros when including windows.h on Windows --- src/engine/Timer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/Timer.h b/src/engine/Timer.h index 383cb9e2..075d6732 100644 --- a/src/engine/Timer.h +++ b/src/engine/Timer.h @@ -34,6 +34,7 @@ #include "../configuration.h" #if defined(WINDOWS_OS) // For Windows platform + #define NOMINMAX // This is used to avoid definition of max() and min() macros #include #else // For Mac OS or Linux platform #include From 02a3cd2db842912e1f1e19be74f68bdb4494ac3b Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 9 Mar 2013 08:40:22 +0100 Subject: [PATCH 6/9] Modify CMakeLists.txt file to compile the tests --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) mode change 100755 => 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100755 new mode 100644 index 6a3bc7aa..f874bc4d --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ SET(LIBRARY_OUTPUT_PATH lib/) # Options OPTION(COMPILE_EXAMPLES "Select this if you want to build the examples" OFF) +OPTION(COMPILE_TESTS "Select this if you want to build the tests" OFF) # Headers INCLUDE_DIRECTORIES(src) @@ -31,3 +32,8 @@ ADD_LIBRARY ( IF (COMPILE_EXAMPLES) add_subdirectory(examples/fallingcubes) ENDIF (COMPILE_EXAMPLES) + +# If we need to compile the tests +IF (COMPILE_TESTS) + add_subdirectory(test/) +ENDIF (COMPILE_TESTS) From a3c6fa07e8e926c4459fe1d6e3e0a1f3ab65af68 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 13 Mar 2013 20:52:59 +0100 Subject: [PATCH 7/9] Add unit tests for the mathematics classes --- test/main.cpp | 4 +- test/tests/mathematics/TestMatrix3x3.h | 212 +++++++++++++++++++++++- test/tests/mathematics/TestQuaternion.h | 164 ++++++++++++++++-- test/tests/mathematics/TestTransform.h | 43 +++-- test/tests/mathematics/TestVector3.h | 9 + 5 files changed, 397 insertions(+), 35 deletions(-) diff --git a/test/main.cpp b/test/main.cpp index 91a2c47e..11139b6f 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -28,18 +28,20 @@ #include "tests/mathematics/TestVector3.h" #include "tests/mathematics/TestTransform.h" #include "tests/mathematics/TestQuaternion.h" +#include "tests/mathematics/TestMatrix3x3.h" using namespace reactphysics3d; int main() { - TestSuite testSuite("ReactPhysics3D tests"); + TestSuite testSuite("ReactPhysics3D Tests"); // ---------- Mathematics tests ---------- // testSuite.addTest(new TestVector3); testSuite.addTest(new TestTransform); testSuite.addTest(new TestQuaternion); + testSuite.addTest(new TestMatrix3x3); // ----------------------------- --------- // diff --git a/test/tests/mathematics/TestMatrix3x3.h b/test/tests/mathematics/TestMatrix3x3.h index 325f9861..ccdda9a9 100644 --- a/test/tests/mathematics/TestMatrix3x3.h +++ b/test/tests/mathematics/TestMatrix3x3.h @@ -51,21 +51,229 @@ class TestMatrix3x3 : public Test { /// Identity transform Matrix3x3 mIdentity; + /// First example matrix + Matrix3x3 mMatrix1; + public : // ---------- Methods ---------- // /// Constructor - TestMatrix3x3() : mIdentity(Matrix3x3::identity()){ + TestMatrix3x3() : mIdentity(Matrix3x3::identity()), + mMatrix1(2, 24, 4, 5, -6, 234, -15, 11, 66) { } /// Run the tests void run() { - + testConstructors(); + testGetSet(); + testIdentity(); + testOthersMethods(); + testOperators(); } + /// Test the constructors + void testConstructors() { + + Matrix3x3 test1(5.0); + Matrix3x3 test2(2, 3, 4, 5, 6, 7, 8, 9, 10); + Matrix3x3 test3(mMatrix1); + test(test1[0][0] == 5); + test(test1[0][1] == 5); + test(test1[0][2] == 5); + test(test1[1][0] == 5); + test(test1[1][1] == 5); + test(test1[1][2] == 5); + test(test1[2][0] == 5); + test(test1[2][1] == 5); + test(test1[2][2] == 5); + + test(test2[0][0] == 2); + test(test2[0][1] == 3); + test(test2[0][2] == 4); + test(test2[1][0] == 5); + test(test2[1][1] == 6); + test(test2[1][2] == 7); + test(test2[2][0] == 8); + test(test2[2][1] == 9); + test(test2[2][2] == 10); + + test(test3 == mMatrix1); + } + + /// Test the getter and setter methods + void testGetSet() { + + // Test method to set all the values + Matrix3x3 test2; + test2.setAllValues(2, 24, 4, 5, -6, 234, -15, 11, 66); + test(test2 == mMatrix1); + + // Test method to set to zero + test2.setToZero(); + test(test2 == Matrix3x3(0, 0, 0, 0, 0, 0, 0, 0, 0)); + + // Test method that returns a column + Vector3 column1 = mMatrix1.getColumn(0); + Vector3 column2 = mMatrix1.getColumn(1); + Vector3 column3 = mMatrix1.getColumn(2); + test(column1 == Vector3(2, 5, -15)); + test(column2 == Vector3(24, -6, 11)); + test(column3 == Vector3(4, 234, 66)); + + // Test method that returns a row + Vector3 row1 = mMatrix1.getRow(0); + Vector3 row2 = mMatrix1.getRow(1); + Vector3 row3 = mMatrix1.getRow(2); + test(row1 == Vector3(2, 24, 4)); + test(row2 == Vector3(5, -6, 234)); + test(row3 == Vector3(-15, 11, 66)); + } + + /// Test the identity methods + void testIdentity() { + + Matrix3x3 identity = Matrix3x3::identity(); + Matrix3x3 test1; + test1.setToIdentity(); + + test(identity[0][0] == 1); + test(identity[0][1] == 0); + test(identity[0][2] == 0); + test(identity[1][0] == 0); + test(identity[1][1] == 1); + test(identity[1][2] == 0); + test(identity[2][0] == 0); + test(identity[2][1] == 0); + test(identity[2][2] == 1); + + test(test1 == Matrix3x3::identity()); + } + + /// Test others methods + void testOthersMethods() { + + // Test transpose + Matrix3x3 transpose = mMatrix1.getTranspose(); + test(transpose == Matrix3x3(2, 5, -15, 24, -6, 11, 4, 234, 66)); + + // Test trace + test(mMatrix1.getTrace() == 62); + test(Matrix3x3::identity().getTrace() == 3); + + // Test determinant + Matrix3x3 matrix(-24, 64, 253, -35, 52, 72, 21, -35, -363); + test(mMatrix1.getDeterminant() == -98240); + test(matrix.getDeterminant() == -290159); + test(mIdentity.getDeterminant() == 1); + + // Test inverse + Matrix3x3 inverseMatrix = matrix.getInverse(); + test(approxEqual(inverseMatrix[0][0], decimal(0.056369), decimal(10e-6))); + test(approxEqual(inverseMatrix[0][1], decimal(-0.049549), decimal(10e-6))); + test(approxEqual(inverseMatrix[0][2], decimal(0.029460), decimal(10e-6))); + test(approxEqual(inverseMatrix[1][0], decimal(0.038575), decimal(10e-6))); + test(approxEqual(inverseMatrix[1][1], decimal(-0.011714), decimal(10e-6))); + test(approxEqual(inverseMatrix[1][2], decimal(0.024562), decimal(10e-6))); + test(approxEqual(inverseMatrix[2][0], decimal(-0.000458), decimal(10e-6))); + test(approxEqual(inverseMatrix[2][1], decimal(-0.001737), decimal(10e-6))); + test(approxEqual(inverseMatrix[2][2], decimal(-0.003419), decimal(10e-6))); + Matrix3x3 inverseMatrix1 = mMatrix1.getInverse(); + test(approxEqual(inverseMatrix1[0][0], decimal(0.030232), decimal(10e-6))); + test(approxEqual(inverseMatrix1[0][1], decimal(0.015676), decimal(10e-6))); + test(approxEqual(inverseMatrix1[0][2], decimal(-0.057410), decimal(10e-6))); + test(approxEqual(inverseMatrix1[1][0], decimal(0.039088), decimal(10e-6))); + test(approxEqual(inverseMatrix1[1][1], decimal(-0.001954), decimal(10e-6))); + test(approxEqual(inverseMatrix1[1][2], decimal(0.004560), decimal(10e-6))); + test(approxEqual(inverseMatrix1[2][0], decimal(0.000356), decimal(10e-6))); + test(approxEqual(inverseMatrix1[2][1], decimal(0.003888), decimal(10e-6))); + test(approxEqual(inverseMatrix1[2][2], decimal(0.001344), decimal(10e-6))); + + // Test absolute matrix + Matrix3x3 matrix2(-2, -3, -4, -5, -6, -7, -8, -9, -10); + test(matrix.getAbsoluteMatrix() == Matrix3x3(24, 64, 253, 35, 52, 72, 21, 35, 363)); + Matrix3x3 absoluteMatrix = matrix2.getAbsoluteMatrix(); + test(absoluteMatrix == Matrix3x3(2, 3, 4, 5, 6, 7, 8, 9, 10)); + } + + /// Test the operators + void testOperators() { + + // Test addition + Matrix3x3 matrix1(2, 3, 4, 5, 6, 7, 8, 9, 10); + Matrix3x3 matrix2(-2, 3, -5, 10, 4, 7, 2, 5, 8); + Matrix3x3 addition1 = matrix1 + matrix2; + Matrix3x3 addition2(matrix1); + addition2 += matrix2; + test(addition1 == Matrix3x3(0, 6, -1, 15, 10, 14, 10, 14, 18)); + test(addition2 == Matrix3x3(0, 6, -1, 15, 10, 14, 10, 14, 18)); + + // Test substraction + Matrix3x3 substraction1 = matrix1 - matrix2; + Matrix3x3 substraction2(matrix1); + substraction2 -= matrix2; + test(substraction1 == Matrix3x3(4, 0, 9, -5, 2, 0, 6, 4, 2)); + test(substraction2 == Matrix3x3(4, 0, 9, -5, 2, 0, 6, 4, 2)); + + // Test negative operator + Matrix3x3 negative = -matrix1; + test(negative == Matrix3x3(-2, -3, -4, -5, -6, -7, -8, -9, -10)); + + // Test multiplication with a number + Matrix3x3 multiplication1 = 3 * matrix1; + Matrix3x3 multiplication2 = matrix1 * 3; + Matrix3x3 multiplication3(matrix1); + multiplication3 *= 3; + test(multiplication1 == Matrix3x3(6, 9, 12, 15, 18, 21, 24, 27, 30)); + test(multiplication2 == Matrix3x3(6, 9, 12, 15, 18, 21, 24, 27, 30)); + test(multiplication3 == Matrix3x3(6, 9, 12, 15, 18, 21, 24, 27, 30)); + + // Test multiplication with a matrix + Matrix3x3 multiplication4 = matrix1 * matrix2; + Matrix3x3 multiplication5 = matrix2 * matrix1; + test(multiplication4 == Matrix3x3(34, 38, 43, 64, 74, 73, 94, 110, 103)); + test(multiplication5 == Matrix3x3(-29, -33, -37, 96, 117, 138, 93, 108, 123)); + + // Test multiplication with a vector + Vector3 vector1(3, -32, 59); + Vector3 vector2(-31, -422, 34); + Vector3 test1 = matrix1 * vector1; + Vector3 test2 = matrix2 * vector2; + test(test1 == Vector3(146, 236, 326)); + test(test2 == Vector3(-1374, -1760, -1900)); + + // Test equality operators + test(Matrix3x3(34, 38, 43, 64, 74, 73, 94, 110, 103) == + Matrix3x3(34, 38, 43, 64, 74, 73, 94, 110, 103)); + test(Matrix3x3(34, 64, 43, 7, -1, 73, 94, 110, 103) != + Matrix3x3(34, 38, 43, 64, 74, 73, 94, 110, 103)); + + // Test operator to read a value + test(mMatrix1[0][0] == 2); + test(mMatrix1[0][1] == 24); + test(mMatrix1[0][2] == 4); + test(mMatrix1[1][0] == 5); + test(mMatrix1[1][1] == -6); + test(mMatrix1[1][2] == 234); + test(mMatrix1[2][0] == -15); + test(mMatrix1[2][1] == 11); + test(mMatrix1[2][2] == 66); + + // Test operator to set a value + Matrix3x3 test3; + test3[0][0] = 2; + test3[0][1] = 24; + test3[0][2] = 4; + test3[1][0] = 5; + test3[1][1] = -6; + test3[1][2] = 234; + test3[2][0] = -15; + test3[2][1] = 11; + test3[2][2] = 66; + test(test3 == mMatrix1); + } }; diff --git a/test/tests/mathematics/TestQuaternion.h b/test/tests/mathematics/TestQuaternion.h index 66ff0266..cc177eca 100644 --- a/test/tests/mathematics/TestQuaternion.h +++ b/test/tests/mathematics/TestQuaternion.h @@ -61,18 +61,25 @@ class TestQuaternion : public Test { /// Constructor TestQuaternion() : mIdentity(Quaternion::identity()) { - decimal sinA = sin(PI/8.0f); - decimal cosA = cos(PI/8.0f); - mQuaternion1 = Quaternion(sinA, sinA, sinA, cosA); + decimal sinA = sin(decimal(PI/8.0)); + decimal cosA = cos(decimal(PI/8.0)); + Vector3 vector(2, 3, 4); + vector.normalize(); + mQuaternion1 = Quaternion(vector.x * sinA, vector.y * sinA, vector.z * sinA, cosA); + mQuaternion1.normalize(); } /// Run the tests void run() { testConstructors(); + testUnitLengthNormalize(); + testOthersMethods(); + testOperators(); } /// Test the constructors void testConstructors() { + Quaternion quaternion1(mQuaternion1); test(mQuaternion1== quaternion1); @@ -80,21 +87,144 @@ class TestQuaternion : public Test { test(quaternion2 == Quaternion(4, 5, 6, 7)); Quaternion quaternion3(8, Vector3(3, 5, 2)); - test(quaternion3 == Quaternion(5, 6, 7, 4)); + test(quaternion3 == Quaternion(3, 5, 2, 8)); - Matrix3x3 matrix(2, 3, 4, 5, 6, 7, 8, 9, 10); - Quaternion quaternion4(matrix); - Matrix3x3 result = quaternion4.getMatrix(); - test(approxEqual(matrix.getValue(0, 0), result.getValue(0, 0), 0.1)); - std::cout << "matrix : " << matrix.getValue(0, 0) << ", " << result.getValue(0, 0) << std::endl; - test(approxEqual(matrix.getValue(0, 1), result.getValue(0, 1), 0.1)); - test(approxEqual(matrix.getValue(0, 2), result.getValue(0, 2), 0.1)); - test(approxEqual(matrix.getValue(1, 0), result.getValue(1, 0), 0.1)); - test(approxEqual(matrix.getValue(1, 1), result.getValue(1, 1), 0.1)); - test(approxEqual(matrix.getValue(1, 2), result.getValue(1, 2), 0.1)); - test(approxEqual(matrix.getValue(2, 0), result.getValue(2, 0), 0.1)); - test(approxEqual(matrix.getValue(2, 1), result.getValue(2, 1), 0.1)); - test(approxEqual(matrix.getValue(2, 2), result.getValue(2, 2), 0.1)); + Quaternion quaternion4(mQuaternion1.getMatrix()); + test(approxEqual(quaternion4.x, mQuaternion1.x)); + test(approxEqual(quaternion4.y, mQuaternion1.y)); + test(approxEqual(quaternion4.z, mQuaternion1.z)); + test(approxEqual(quaternion4.w, mQuaternion1.w)); + } + + /// Test unit, length, normalize methods + void testUnitLengthNormalize() { + + // Test method that returns the length + Quaternion quaternion(2, 3, -4, 5); + test(approxEqual(quaternion.length(), sqrt(decimal(54.0)))); + + // Test method that returns a unit quaternion + test(approxEqual(quaternion.getUnit().length(), 1.0)); + + // Test the normalization method + Quaternion quaternion2(4, 5, 6, 7); + quaternion2.normalize(); + test(approxEqual(quaternion2.length(), 1.0)); + } + + /// Test others methods + void testOthersMethods() { + + // Test the method to set the values + Quaternion quaternion; + quaternion.setAllValues(1, 2, 3, 4); + test(quaternion == Quaternion(1, 2, 3, 4)); + + // Test the method to set the quaternion to zero + quaternion.setToZero(); + test(quaternion == Quaternion(0, 0, 0, 0)); + + // Test the method to get the vector (x, y, z) + Vector3 v = mQuaternion1.getVectorV(); + test(v.x == mQuaternion1.x); + test(v.y == mQuaternion1.y); + test(v.z == mQuaternion1.z); + + // Test the conjugate method + Quaternion conjugate = mQuaternion1.getConjugate(); + test(conjugate.x == -mQuaternion1.x); + test(conjugate.y == -mQuaternion1.y); + test(conjugate.z == -mQuaternion1.z); + test(conjugate.w == mQuaternion1.w); + + // Test the inverse method + Quaternion inverse = mQuaternion1.getInverse(); + Quaternion product = mQuaternion1 * inverse; + test(approxEqual(product.x, mIdentity.x, decimal(10e-6))); + test(approxEqual(product.y, mIdentity.y, decimal(10e-6))); + test(approxEqual(product.z, mIdentity.z, decimal(10e-6))); + test(approxEqual(product.w, mIdentity.w, decimal(10e-6))); + + // Test the dot product + Quaternion quaternion1(2, 3, 4, 5); + Quaternion quaternion2(6, 7, 8, 9); + decimal dotProduct = quaternion1.dot(quaternion2); + test(dotProduct == 110); + + // Test the method that returns the rotation angle and axis + Vector3 axis; + decimal angle; + Vector3 originalAxis = Vector3(2, 3, 4).getUnit(); + mQuaternion1.getRotationAngleAxis(angle, axis); + test(approxEqual(axis.x, originalAxis.x)); + test(approxEqual(angle, decimal(PI/4.0), decimal(10e-6))); + + // Test the method that returns the corresponding matrix + Matrix3x3 matrix = mQuaternion1.getMatrix(); + Vector3 vector(56, -2, 82); + Vector3 vector1 = matrix * vector; + Vector3 vector2 = mQuaternion1 * vector; + test(approxEqual(vector1.x, vector2.x)); + test(approxEqual(vector1.y, vector2.y)); + test(approxEqual(vector1.z, vector2.z)); + + // Test slerp method + Quaternion quatStart = quaternion1.getUnit(); + Quaternion quatEnd = quaternion2.getUnit(); + Quaternion test1 = Quaternion::slerp(quatStart, quatEnd, 0.0); + Quaternion test2 = Quaternion::slerp(quatStart, quatEnd, 1.0); + test(test1 == quatStart); + test(test2 == quatEnd); + decimal sinA = sin(decimal(PI/4.0)); + decimal cosA = cos(decimal(PI/4.0)); + Quaternion quat(sinA, 0, 0, cosA); + Quaternion test3 = Quaternion::slerp(mIdentity, quat, decimal(0.5)); + test(approxEqual(test3.x, sin(decimal(PI/8.0)))); + test(approxEqual(test3.y, 0.0)); + test(approxEqual(test3.z, 0.0)); + test(approxEqual(test3.w, cos(decimal(PI/8.0)), decimal(10e-6))); + } + + /// Test overloaded operators + void testOperators() { + + // Test addition + Quaternion quat1(4, 5, 2, 10); + Quaternion quat2(-2, 7, 8, 3); + Quaternion test1 = quat1 + quat2; + test(test1 == Quaternion(2, 12, 10, 13)); + + // Test substraction + Quaternion test2 = quat1 - quat2; + test(test2 == Quaternion(6, -2, -6, 7)); + + // Test multiplication with a number + Quaternion test3 = quat1 * 3.0; + test(test3 == Quaternion(12, 15, 6, 30)); + + // Test multiplication between two quaternions + Quaternion test4 = quat1 * quat2; + Quaternion test5 = mQuaternion1 * mIdentity; + test(test4 == Quaternion(18, 49, 124, -13)); + test(test5 == mQuaternion1); + + // Test multiplication between a quaternion and a point + Vector3 point(5, -24, 563); + Vector3 vector1 = mIdentity * point; + Vector3 vector2 = mQuaternion1 * point; + Vector3 testVector2 = mQuaternion1.getMatrix() * point; + test(vector1 == point); + test(approxEqual(vector2.x, testVector2.x, decimal(10e-6))); + test(approxEqual(vector2.y, testVector2.y, decimal(10e-6))); + test(approxEqual(vector2.z, testVector2.z, decimal(10e-6))); + + // Test assignment operator + Quaternion quaternion; + quaternion = mQuaternion1; + test(quaternion == mQuaternion1); + + // Test equality operator + test(mQuaternion1 == mQuaternion1); } }; diff --git a/test/tests/mathematics/TestTransform.h b/test/tests/mathematics/TestTransform.h index 2de02d79..4c700a0d 100644 --- a/test/tests/mathematics/TestTransform.h +++ b/test/tests/mathematics/TestTransform.h @@ -82,6 +82,7 @@ class TestTransform : public Test { testInverse(); testGetSetOpenGLMatrix(); testInterpolateTransform(); + testIdentity(); testOperators(); } @@ -127,27 +128,27 @@ class TestTransform : public Test { Transform transform; Vector3 position = mTransform1.getPosition(); Matrix3x3 orientation = mTransform1.getOrientation().getMatrix(); - decimal openglMatrix[16] = {orientation.getValue(0,0), orientation.getValue(1,0), - orientation.getValue(2,0), 0, - orientation.getValue(0,1), orientation.getValue(1,1), - orientation.getValue(2,1), 0, - orientation.getValue(0,2), orientation.getValue(1,2), - orientation.getValue(2,2), 0, + decimal openglMatrix[16] = {orientation[0][0], orientation[1][0], + orientation[2][0], 0, + orientation[0][1], orientation[1][1], + orientation[2][1], 0, + orientation[0][2], orientation[1][2], + orientation[2][2], 0, position.x, position.y, position.z, 1}; transform.setFromOpenGL(openglMatrix); decimal openglMatrix2[16]; transform.getOpenGLMatrix(openglMatrix2); - test(approxEqual(openglMatrix2[0], orientation.getValue(0,0))); - test(approxEqual(openglMatrix2[1], orientation.getValue(1,0))); - test(approxEqual(openglMatrix2[2], orientation.getValue(2,0))); + test(approxEqual(openglMatrix2[0], orientation[0][0])); + test(approxEqual(openglMatrix2[1], orientation[1][0])); + test(approxEqual(openglMatrix2[2], orientation[2][0])); test(approxEqual(openglMatrix2[3], 0)); - test(approxEqual(openglMatrix2[4], orientation.getValue(0,1))); - test(approxEqual(openglMatrix2[5], orientation.getValue(1,1))); - test(approxEqual(openglMatrix2[6], orientation.getValue(2,1))); + test(approxEqual(openglMatrix2[4], orientation[0][1])); + test(approxEqual(openglMatrix2[5], orientation[1][1])); + test(approxEqual(openglMatrix2[6], orientation[2][1])); test(approxEqual(openglMatrix2[7], 0)); - test(approxEqual(openglMatrix2[8], orientation.getValue(0,2))); - test(approxEqual(openglMatrix2[9], orientation.getValue(1,2))); - test(approxEqual(openglMatrix2[10], orientation.getValue(2,2))); + test(approxEqual(openglMatrix2[8], orientation[0][2])); + test(approxEqual(openglMatrix2[9], orientation[1][2])); + test(approxEqual(openglMatrix2[10], orientation[2][2])); test(approxEqual(openglMatrix2[11], 0)); test(approxEqual(openglMatrix2[12], position.x)); test(approxEqual(openglMatrix2[13], position.y)); @@ -180,6 +181,18 @@ class TestTransform : public Test { test(approxEqual(orientation.w, cosB)); } + /// Test the identity methods + void testIdentity() { + Transform transform = Transform::identity(); + test(transform.getPosition() == Vector3(0, 0, 0)); + test(transform.getOrientation() == Quaternion::identity()); + + Transform transform2(Vector3(5, 6, 2), Quaternion(3, 5, 1, 6)); + transform2.setToIdentity(); + test(transform2.getPosition() == Vector3(0, 0, 0)); + test(transform2.getOrientation() == Quaternion::identity()); + } + /// Test the overloaded operators void testOperators() { diff --git a/test/tests/mathematics/TestVector3.h b/test/tests/mathematics/TestVector3.h index 4097e730..d8f42599 100644 --- a/test/tests/mathematics/TestVector3.h +++ b/test/tests/mathematics/TestVector3.h @@ -92,6 +92,10 @@ class TestVector3 : public Test { test(approxEqual(newVector2.x, decimal(6.1))); test(approxEqual(newVector2.y, decimal(7.2))); test(approxEqual(newVector2.z, decimal(8.6))); + + // Test method to set to zero + newVector2.setToZero(); + test(newVector2 == Vector3(0, 0, 0)); } /// Test the length, unit vector and normalize methods @@ -219,6 +223,11 @@ class TestVector3 : public Test { vector4 /= 3; test(vector3 == Vector3(60, 330, 620)); test(vector4 == Vector3(5, 20, 11)); + + // Negative operator + Vector3 vector5(-34, 5, 422); + Vector3 negative = -vector5; + test(negative == Vector3(34, -5, -422)); } }; From 669ca8ecca605d8defb7edd28197154f8c2ed1f7 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 13 Mar 2013 20:55:10 +0100 Subject: [PATCH 8/9] Add methods in the mathematics classes --- src/mathematics/Matrix3x3.cpp | 30 ++--- src/mathematics/Matrix3x3.h | 222 ++++++++++++++++++--------------- src/mathematics/Quaternion.cpp | 51 ++++---- src/mathematics/Quaternion.h | 59 ++++++++- src/mathematics/Transform.h | 20 ++- src/mathematics/Vector3.h | 10 ++ 6 files changed, 238 insertions(+), 154 deletions(-) diff --git a/src/mathematics/Matrix3x3.cpp b/src/mathematics/Matrix3x3.cpp index 1907371e..edb1aa3c 100644 --- a/src/mathematics/Matrix3x3.cpp +++ b/src/mathematics/Matrix3x3.cpp @@ -56,9 +56,9 @@ Matrix3x3::~Matrix3x3() { // Copy-constructor Matrix3x3::Matrix3x3(const Matrix3x3& matrix) { - setAllValues(matrix.mArray[0][0], matrix.mArray[0][1], matrix.mArray[0][2], - matrix.mArray[1][0], matrix.mArray[1][1], matrix.mArray[1][2], - matrix.mArray[2][0], matrix.mArray[2][1], matrix.mArray[2][2]); + setAllValues(matrix.mRows[0][0], matrix.mRows[0][1], matrix.mRows[0][2], + matrix.mRows[1][0], matrix.mRows[1][1], matrix.mRows[1][2], + matrix.mRows[2][0], matrix.mRows[2][1], matrix.mRows[2][2]); } // Assignment operator @@ -66,9 +66,9 @@ Matrix3x3& Matrix3x3::operator=(const Matrix3x3& matrix) { // Check for self-assignment if (&matrix != this) { - setAllValues(matrix.mArray[0][0], matrix.mArray[0][1], matrix.mArray[0][2], - matrix.mArray[1][0], matrix.mArray[1][1], matrix.mArray[1][2], - matrix.mArray[2][0], matrix.mArray[2][1], matrix.mArray[2][2]); + setAllValues(matrix.mRows[0][0], matrix.mRows[0][1], matrix.mRows[0][2], + matrix.mRows[1][0], matrix.mRows[1][1], matrix.mRows[1][2], + matrix.mRows[2][0], matrix.mRows[2][1], matrix.mRows[2][2]); } return *this; } @@ -84,15 +84,15 @@ Matrix3x3 Matrix3x3::getInverse() const { decimal invDeterminant = decimal(1.0) / determinant; - Matrix3x3 tempMatrix((mArray[1][1]*mArray[2][2]-mArray[2][1]*mArray[1][2]), - -(mArray[0][1]*mArray[2][2]-mArray[2][1]*mArray[0][2]), - (mArray[0][1]*mArray[1][2]-mArray[0][2]*mArray[1][1]), - -(mArray[1][0]*mArray[2][2]-mArray[2][0]*mArray[1][2]), - (mArray[0][0]*mArray[2][2]-mArray[2][0]*mArray[0][2]), - -(mArray[0][0]*mArray[1][2]-mArray[1][0]*mArray[0][2]), - (mArray[1][0]*mArray[2][1]-mArray[2][0]*mArray[1][1]), - -(mArray[0][0]*mArray[2][1]-mArray[2][0]*mArray[0][1]), - (mArray[0][0]*mArray[1][1]-mArray[0][1]*mArray[1][0])); + Matrix3x3 tempMatrix((mRows[1][1]*mRows[2][2]-mRows[2][1]*mRows[1][2]), + -(mRows[0][1]*mRows[2][2]-mRows[2][1]*mRows[0][2]), + (mRows[0][1]*mRows[1][2]-mRows[0][2]*mRows[1][1]), + -(mRows[1][0]*mRows[2][2]-mRows[2][0]*mRows[1][2]), + (mRows[0][0]*mRows[2][2]-mRows[2][0]*mRows[0][2]), + -(mRows[0][0]*mRows[1][2]-mRows[1][0]*mRows[0][2]), + (mRows[1][0]*mRows[2][1]-mRows[2][0]*mRows[1][1]), + -(mRows[0][0]*mRows[2][1]-mRows[2][0]*mRows[0][1]), + (mRows[0][0]*mRows[1][1]-mRows[0][1]*mRows[1][0])); // Return the inverse matrix return (invDeterminant * tempMatrix); diff --git a/src/mathematics/Matrix3x3.h b/src/mathematics/Matrix3x3.h index aceb7916..906a19fc 100644 --- a/src/mathematics/Matrix3x3.h +++ b/src/mathematics/Matrix3x3.h @@ -46,8 +46,8 @@ class Matrix3x3 { // -------------------- Attributes -------------------- // - // Array with the values of the matrix - decimal mArray[3][3]; + /// Rows of the matrix; + Vector3 mRows[3]; public : @@ -72,19 +72,19 @@ class Matrix3x3 { // Assignment operator Matrix3x3& operator=(const Matrix3x3& matrix); - // Get a value in the matrix - decimal getValue(int i, int j) const; - - // Set a value in the matrix - void setValue(int i, int j, decimal value); - // Set all the values in the matrix void setAllValues(decimal a1, decimal a2, decimal a3, decimal b1, decimal b2, decimal b3, decimal c1, decimal c2, decimal c3); + /// Set the matrix to zero + void setToZero(); + // Return a column Vector3 getColumn(int i) const; + /// Return a row + Vector3 getRow(int i) const; + // Return the transpose matrix Matrix3x3 getTranspose() const; @@ -141,110 +141,120 @@ class Matrix3x3 { // Overloaded operator for multiplication with a number with assignment Matrix3x3& operator*=(decimal nb); + + /// Overloaded operator to read element of the matrix. + const Vector3& operator[](int row) const; + + /// Overloaded operator to read/write element of the matrix. + Vector3& operator[](int row); }; - -// Method to get a value in the matrix (inline) -inline decimal Matrix3x3::getValue(int i, int j) const { - assert(i>=0 && i<3 && j>=0 && j<3); - return mArray[i][j]; -} - -// Method to set a value in the matrix (inline) -inline void Matrix3x3::setValue(int i, int j, decimal value) { - assert(i>=0 && i<3 && j>=0 && j<3); - mArray[i][j] = value; -} - // Method to set all the values in the matrix inline void Matrix3x3::setAllValues(decimal a1, decimal a2, decimal a3, decimal b1, decimal b2, decimal b3, decimal c1, decimal c2, decimal c3) { - mArray[0][0] = a1; mArray[0][1] = a2; mArray[0][2] = a3; - mArray[1][0] = b1; mArray[1][1] = b2; mArray[1][2] = b3; - mArray[2][0] = c1; mArray[2][1] = c2; mArray[2][2] = c3; + mRows[0][0] = a1; mRows[0][1] = a2; mRows[0][2] = a3; + mRows[1][0] = b1; mRows[1][1] = b2; mRows[1][2] = b3; + mRows[2][0] = c1; mRows[2][1] = c2; mRows[2][2] = c3; +} + +/// Set the matrix to zero +inline void Matrix3x3::setToZero() { + mRows[0].setToZero(); + mRows[1].setToZero(); + mRows[2].setToZero(); } // Return a column inline Vector3 Matrix3x3::getColumn(int i) const { assert(i>= 0 && i<3); - return Vector3(mArray[0][i], mArray[1][i], mArray[2][i]); + return Vector3(mRows[0][i], mRows[1][i], mRows[2][i]); +} + +/// Return a row +inline Vector3 Matrix3x3::getRow(int i) const { + assert(i>= 0 && i<3); + return mRows[i]; } // Return the transpose matrix inline Matrix3x3 Matrix3x3::getTranspose() const { + // Return the transpose matrix - return Matrix3x3(mArray[0][0], mArray[1][0], mArray[2][0], - mArray[0][1], mArray[1][1], mArray[2][1], - mArray[0][2], mArray[1][2], mArray[2][2]); + return Matrix3x3(mRows[0][0], mRows[1][0], mRows[2][0], + mRows[0][1], mRows[1][1], mRows[2][1], + mRows[0][2], mRows[1][2], mRows[2][2]); } // Return the determinant of the matrix inline decimal Matrix3x3::getDeterminant() const { + // Compute and return the determinant of the matrix - return (mArray[0][0]*(mArray[1][1]*mArray[2][2]-mArray[2][1]*mArray[1][2]) - - mArray[0][1]*(mArray[1][0]*mArray[2][2]-mArray[2][0]*mArray[1][2]) + - mArray[0][2]*(mArray[1][0]*mArray[2][1]-mArray[2][0]*mArray[1][1])); + return (mRows[0][0]*(mRows[1][1]*mRows[2][2]-mRows[2][1]*mRows[1][2]) - + mRows[0][1]*(mRows[1][0]*mRows[2][2]-mRows[2][0]*mRows[1][2]) + + mRows[0][2]*(mRows[1][0]*mRows[2][1]-mRows[2][0]*mRows[1][1])); } // Return the trace of the matrix inline decimal Matrix3x3::getTrace() const { + // Compute and return the trace - return (mArray[0][0] + mArray[1][1] + mArray[2][2]); + return (mRows[0][0] + mRows[1][1] + mRows[2][2]); } // Set the matrix to the identity matrix inline void Matrix3x3::setToIdentity() { - mArray[0][0] = 1.0; mArray[0][1] = 0.0; mArray[0][2] = 0.0; - mArray[1][0] = 0.0; mArray[1][1] = 1.0; mArray[1][2] = 0.0; - mArray[2][0] = 0.0; mArray[2][1] = 0.0; mArray[2][2] = 1.0; + mRows[0][0] = 1.0; mRows[0][1] = 0.0; mRows[0][2] = 0.0; + mRows[1][0] = 0.0; mRows[1][1] = 1.0; mRows[1][2] = 0.0; + mRows[2][0] = 0.0; mRows[2][1] = 0.0; mRows[2][2] = 1.0; } // Return the 3x3 identity matrix inline Matrix3x3 Matrix3x3::identity() { + // Return the isdentity matrix return Matrix3x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0); } // Return the matrix with absolute values inline Matrix3x3 Matrix3x3::getAbsoluteMatrix() const { - return Matrix3x3(fabs(mArray[0][0]), fabs(mArray[0][1]), fabs(mArray[0][2]), - fabs(mArray[1][0]), fabs(mArray[1][1]), fabs(mArray[1][2]), - fabs(mArray[2][0]), fabs(mArray[2][1]), fabs(mArray[2][2])); + return Matrix3x3(fabs(mRows[0][0]), fabs(mRows[0][1]), fabs(mRows[0][2]), + fabs(mRows[1][0]), fabs(mRows[1][1]), fabs(mRows[1][2]), + fabs(mRows[2][0]), fabs(mRows[2][1]), fabs(mRows[2][2])); } // Overloaded operator for addition inline Matrix3x3 operator+(const Matrix3x3& matrix1, const Matrix3x3& matrix2) { - return Matrix3x3(matrix1.mArray[0][0] + matrix2.mArray[0][0], matrix1.mArray[0][1] + - matrix2.mArray[0][1], matrix1.mArray[0][2] + matrix2.mArray[0][2], - matrix1.mArray[1][0] + matrix2.mArray[1][0], matrix1.mArray[1][1] + - matrix2.mArray[1][1], matrix1.mArray[1][2] + matrix2.mArray[1][2], - matrix1.mArray[2][0] + matrix2.mArray[2][0], matrix1.mArray[2][1] + - matrix2.mArray[2][1], matrix1.mArray[2][2] + matrix2.mArray[2][2]); + return Matrix3x3(matrix1.mRows[0][0] + matrix2.mRows[0][0], matrix1.mRows[0][1] + + matrix2.mRows[0][1], matrix1.mRows[0][2] + matrix2.mRows[0][2], + matrix1.mRows[1][0] + matrix2.mRows[1][0], matrix1.mRows[1][1] + + matrix2.mRows[1][1], matrix1.mRows[1][2] + matrix2.mRows[1][2], + matrix1.mRows[2][0] + matrix2.mRows[2][0], matrix1.mRows[2][1] + + matrix2.mRows[2][1], matrix1.mRows[2][2] + matrix2.mRows[2][2]); } // Overloaded operator for substraction inline Matrix3x3 operator-(const Matrix3x3& matrix1, const Matrix3x3& matrix2) { - return Matrix3x3(matrix1.mArray[0][0] - matrix2.mArray[0][0], matrix1.mArray[0][1] - - matrix2.mArray[0][1], matrix1.mArray[0][2] - matrix2.mArray[0][2], - matrix1.mArray[1][0] - matrix2.mArray[1][0], matrix1.mArray[1][1] - - matrix2.mArray[1][1], matrix1.mArray[1][2] - matrix2.mArray[1][2], - matrix1.mArray[2][0] - matrix2.mArray[2][0], matrix1.mArray[2][1] - - matrix2.mArray[2][1], matrix1.mArray[2][2] - matrix2.mArray[2][2]); + return Matrix3x3(matrix1.mRows[0][0] - matrix2.mRows[0][0], matrix1.mRows[0][1] - + matrix2.mRows[0][1], matrix1.mRows[0][2] - matrix2.mRows[0][2], + matrix1.mRows[1][0] - matrix2.mRows[1][0], matrix1.mRows[1][1] - + matrix2.mRows[1][1], matrix1.mRows[1][2] - matrix2.mRows[1][2], + matrix1.mRows[2][0] - matrix2.mRows[2][0], matrix1.mRows[2][1] - + matrix2.mRows[2][1], matrix1.mRows[2][2] - matrix2.mRows[2][2]); } // Overloaded operator for the negative of the matrix inline Matrix3x3 operator-(const Matrix3x3& matrix) { - return Matrix3x3(-matrix.mArray[0][0], -matrix.mArray[0][1], -matrix.mArray[0][2], - -matrix.mArray[1][0], -matrix.mArray[1][1], -matrix.mArray[1][2], - -matrix.mArray[2][0], -matrix.mArray[2][1], -matrix.mArray[2][2]); + return Matrix3x3(-matrix.mRows[0][0], -matrix.mRows[0][1], -matrix.mRows[0][2], + -matrix.mRows[1][0], -matrix.mRows[1][1], -matrix.mRows[1][2], + -matrix.mRows[2][0], -matrix.mRows[2][1], -matrix.mRows[2][2]); } // Overloaded operator for multiplication with a number inline Matrix3x3 operator*(decimal nb, const Matrix3x3& matrix) { - return Matrix3x3(matrix.mArray[0][0] * nb, matrix.mArray[0][1] * nb, matrix.mArray[0][2] * nb, - matrix.mArray[1][0] * nb, matrix.mArray[1][1] * nb, matrix.mArray[1][2] * nb, - matrix.mArray[2][0] * nb, matrix.mArray[2][1] * nb, matrix.mArray[2][2] * nb); + return Matrix3x3(matrix.mRows[0][0] * nb, matrix.mRows[0][1] * nb, matrix.mRows[0][2] * nb, + matrix.mRows[1][0] * nb, matrix.mRows[1][1] * nb, matrix.mRows[1][2] * nb, + matrix.mRows[2][0] * nb, matrix.mRows[2][1] * nb, matrix.mRows[2][2] * nb); } // Overloaded operator for multiplication with a matrix @@ -254,44 +264,44 @@ inline Matrix3x3 operator*(const Matrix3x3& matrix, decimal nb) { // Overloaded operator for matrix multiplication inline Matrix3x3 operator*(const Matrix3x3& matrix1, const Matrix3x3& matrix2) { - return Matrix3x3(matrix1.mArray[0][0]*matrix2.mArray[0][0] + matrix1.mArray[0][1] * - matrix2.mArray[1][0] + matrix1.mArray[0][2]*matrix2.mArray[2][0], - matrix1.mArray[0][0]*matrix2.mArray[0][1] + matrix1.mArray[0][1] * - matrix2.mArray[1][1] + matrix1.mArray[0][2]*matrix2.mArray[2][1], - matrix1.mArray[0][0]*matrix2.mArray[0][2] + matrix1.mArray[0][1] * - matrix2.mArray[1][2] + matrix1.mArray[0][2]*matrix2.mArray[2][2], - matrix1.mArray[1][0]*matrix2.mArray[0][0] + matrix1.mArray[1][1] * - matrix2.mArray[1][0] + matrix1.mArray[1][2]*matrix2.mArray[2][0], - matrix1.mArray[1][0]*matrix2.mArray[0][1] + matrix1.mArray[1][1] * - matrix2.mArray[1][1] + matrix1.mArray[1][2]*matrix2.mArray[2][1], - matrix1.mArray[1][0]*matrix2.mArray[0][2] + matrix1.mArray[1][1] * - matrix2.mArray[1][2] + matrix1.mArray[1][2]*matrix2.mArray[2][2], - matrix1.mArray[2][0]*matrix2.mArray[0][0] + matrix1.mArray[2][1] * - matrix2.mArray[1][0] + matrix1.mArray[2][2]*matrix2.mArray[2][0], - matrix1.mArray[2][0]*matrix2.mArray[0][1] + matrix1.mArray[2][1] * - matrix2.mArray[1][1] + matrix1.mArray[2][2]*matrix2.mArray[2][1], - matrix1.mArray[2][0]*matrix2.mArray[0][2] + matrix1.mArray[2][1] * - matrix2.mArray[1][2] + matrix1.mArray[2][2]*matrix2.mArray[2][2]); + return Matrix3x3(matrix1.mRows[0][0]*matrix2.mRows[0][0] + matrix1.mRows[0][1] * + matrix2.mRows[1][0] + matrix1.mRows[0][2]*matrix2.mRows[2][0], + matrix1.mRows[0][0]*matrix2.mRows[0][1] + matrix1.mRows[0][1] * + matrix2.mRows[1][1] + matrix1.mRows[0][2]*matrix2.mRows[2][1], + matrix1.mRows[0][0]*matrix2.mRows[0][2] + matrix1.mRows[0][1] * + matrix2.mRows[1][2] + matrix1.mRows[0][2]*matrix2.mRows[2][2], + matrix1.mRows[1][0]*matrix2.mRows[0][0] + matrix1.mRows[1][1] * + matrix2.mRows[1][0] + matrix1.mRows[1][2]*matrix2.mRows[2][0], + matrix1.mRows[1][0]*matrix2.mRows[0][1] + matrix1.mRows[1][1] * + matrix2.mRows[1][1] + matrix1.mRows[1][2]*matrix2.mRows[2][1], + matrix1.mRows[1][0]*matrix2.mRows[0][2] + matrix1.mRows[1][1] * + matrix2.mRows[1][2] + matrix1.mRows[1][2]*matrix2.mRows[2][2], + matrix1.mRows[2][0]*matrix2.mRows[0][0] + matrix1.mRows[2][1] * + matrix2.mRows[1][0] + matrix1.mRows[2][2]*matrix2.mRows[2][0], + matrix1.mRows[2][0]*matrix2.mRows[0][1] + matrix1.mRows[2][1] * + matrix2.mRows[1][1] + matrix1.mRows[2][2]*matrix2.mRows[2][1], + matrix1.mRows[2][0]*matrix2.mRows[0][2] + matrix1.mRows[2][1] * + matrix2.mRows[1][2] + matrix1.mRows[2][2]*matrix2.mRows[2][2]); } // Overloaded operator for multiplication with a vector inline Vector3 operator*(const Matrix3x3& matrix, const Vector3& vector) { - return Vector3(matrix.mArray[0][0]*vector.x + matrix.mArray[0][1]*vector.y + - matrix.mArray[0][2]*vector.z, - matrix.mArray[1][0]*vector.x + matrix.mArray[1][1]*vector.y + - matrix.mArray[1][2]*vector.z, - matrix.mArray[2][0]*vector.x + matrix.mArray[2][1]*vector.y + - matrix.mArray[2][2]*vector.z); + return Vector3(matrix.mRows[0][0]*vector.x + matrix.mRows[0][1]*vector.y + + matrix.mRows[0][2]*vector.z, + matrix.mRows[1][0]*vector.x + matrix.mRows[1][1]*vector.y + + matrix.mRows[1][2]*vector.z, + matrix.mRows[2][0]*vector.x + matrix.mRows[2][1]*vector.y + + matrix.mRows[2][2]*vector.z); } // Overloaded operator for equality condition inline bool Matrix3x3::operator==(const Matrix3x3& matrix) const { - return (mArray[0][0] == matrix.mArray[0][0] && mArray[0][1] == matrix.mArray[0][1] && - mArray[0][2] == matrix.mArray[0][2] && - mArray[1][0] == matrix.mArray[1][0] && mArray[1][1] == matrix.mArray[1][1] && - mArray[1][2] == matrix.mArray[1][2] && - mArray[2][0] == matrix.mArray[2][0] && mArray[2][1] == matrix.mArray[2][1] && - mArray[2][2] == matrix.mArray[2][2]); + return (mRows[0][0] == matrix.mRows[0][0] && mRows[0][1] == matrix.mRows[0][1] && + mRows[0][2] == matrix.mRows[0][2] && + mRows[1][0] == matrix.mRows[1][0] && mRows[1][1] == matrix.mRows[1][1] && + mRows[1][2] == matrix.mRows[1][2] && + mRows[2][0] == matrix.mRows[2][0] && mRows[2][1] == matrix.mRows[2][1] && + mRows[2][2] == matrix.mRows[2][2]); } // Overloaded operator for the is different condition @@ -301,32 +311,46 @@ inline bool Matrix3x3::operator!= (const Matrix3x3& matrix) const { // Overloaded operator for addition with assignment inline Matrix3x3& Matrix3x3::operator+=(const Matrix3x3& matrix) { - mArray[0][0] += matrix.mArray[0][0]; mArray[0][1] += matrix.mArray[0][1]; - mArray[0][2] += matrix.mArray[0][2]; mArray[1][0] += matrix.mArray[1][0]; - mArray[1][1] += matrix.mArray[1][1]; mArray[1][2] += matrix.mArray[1][2]; - mArray[2][0] += matrix.mArray[2][0]; mArray[2][1] += matrix.mArray[2][1]; - mArray[2][2] += matrix.mArray[2][2]; + mRows[0][0] += matrix.mRows[0][0]; mRows[0][1] += matrix.mRows[0][1]; + mRows[0][2] += matrix.mRows[0][2]; mRows[1][0] += matrix.mRows[1][0]; + mRows[1][1] += matrix.mRows[1][1]; mRows[1][2] += matrix.mRows[1][2]; + mRows[2][0] += matrix.mRows[2][0]; mRows[2][1] += matrix.mRows[2][1]; + mRows[2][2] += matrix.mRows[2][2]; return *this; } // Overloaded operator for substraction with assignment inline Matrix3x3& Matrix3x3::operator-=(const Matrix3x3& matrix) { - mArray[0][0] -= matrix.mArray[0][0]; mArray[0][1] -= matrix.mArray[0][1]; - mArray[0][2] -= matrix.mArray[0][2]; mArray[1][0] -= matrix.mArray[1][0]; - mArray[1][1] -= matrix.mArray[1][1]; mArray[1][2] -= matrix.mArray[1][2]; - mArray[2][0] -= matrix.mArray[2][0]; mArray[2][1] -= matrix.mArray[2][1]; - mArray[2][2] -= matrix.mArray[2][2]; + mRows[0][0] -= matrix.mRows[0][0]; mRows[0][1] -= matrix.mRows[0][1]; + mRows[0][2] -= matrix.mRows[0][2]; mRows[1][0] -= matrix.mRows[1][0]; + mRows[1][1] -= matrix.mRows[1][1]; mRows[1][2] -= matrix.mRows[1][2]; + mRows[2][0] -= matrix.mRows[2][0]; mRows[2][1] -= matrix.mRows[2][1]; + mRows[2][2] -= matrix.mRows[2][2]; return *this; } // Overloaded operator for multiplication with a number with assignment inline Matrix3x3& Matrix3x3::operator*=(decimal nb) { - mArray[0][0] *= nb; mArray[0][1] *= nb; mArray[0][2] *= nb; - mArray[1][0] *= nb; mArray[1][1] *= nb; mArray[1][2] *= nb; - mArray[2][0] *= nb; mArray[2][1] *= nb; mArray[2][2] *= nb; + mRows[0][0] *= nb; mRows[0][1] *= nb; mRows[0][2] *= nb; + mRows[1][0] *= nb; mRows[1][1] *= nb; mRows[1][2] *= nb; + mRows[2][0] *= nb; mRows[2][1] *= nb; mRows[2][2] *= nb; return *this; } +// Overloaded operator to return a row of the matrix. +/// This operator is also used to access a matrix value using the syntax +/// matrix[row][col]. +inline const Vector3& Matrix3x3::operator[](int row) const { + return mRows[row]; +} + +// Overloaded operator to return a row of the matrix. +/// This operator is also used to access a matrix value using the syntax +/// matrix[row][col]. +inline Vector3& Matrix3x3::operator[](int row) { + return mRows[row]; +} + } #endif diff --git a/src/mathematics/Quaternion.cpp b/src/mathematics/Quaternion.cpp index 8c5d0c81..4bb7e775 100644 --- a/src/mathematics/Quaternion.cpp +++ b/src/mathematics/Quaternion.cpp @@ -59,58 +59,51 @@ Quaternion::Quaternion(const Matrix3x3& matrix) { // Get the trace of the matrix decimal trace = matrix.getTrace(); - decimal array[3][3]; - for (int i=0; i<3; i++) { - for (int j=0; j<3; j++) { - array[i][j] = matrix.getValue(i, j); - } - } - decimal r; decimal s; if (trace < 0.0) { - if (array[1][1] > array[0][0]) { - if(array[2][2] > array[1][1]) { - r = sqrt(array[2][2] - array[0][0] - array[1][1] + 1.0); + if (matrix[1][1] > matrix[0][0]) { + if(matrix[2][2] > matrix[1][1]) { + r = sqrt(matrix[2][2] - matrix[0][0] - matrix[1][1] + 1.0); s = 0.5 / r; // Compute the quaternion - x = (array[2][0] + array[0][2])*s; - y = (array[1][2] + array[2][1])*s; + x = (matrix[2][0] + matrix[0][2])*s; + y = (matrix[1][2] + matrix[2][1])*s; z = 0.5*r; - w = (array[1][0] - array[0][1])*s; + w = (matrix[1][0] - matrix[0][1])*s; } else { - r = sqrt(array[1][1] - array[2][2] - array[0][0] + 1.0); + r = sqrt(matrix[1][1] - matrix[2][2] - matrix[0][0] + 1.0); s = 0.5 / r; // Compute the quaternion - x = (array[0][1] + array[1][0])*s; + x = (matrix[0][1] + matrix[1][0])*s; y = 0.5 * r; - z = (array[1][2] + array[2][1])*s; - w = (array[0][2] - array[2][0])*s; + z = (matrix[1][2] + matrix[2][1])*s; + w = (matrix[0][2] - matrix[2][0])*s; } } - else if (array[2][2] > array[0][0]) { - r = sqrt(array[2][2] - array[0][0] - array[1][1] + 1.0); + else if (matrix[2][2] > matrix[0][0]) { + r = sqrt(matrix[2][2] - matrix[0][0] - matrix[1][1] + 1.0); s = 0.5 / r; // Compute the quaternion - x = (array[2][0] + array[0][2])*s; - y = (array[1][2] + array[2][1])*s; + x = (matrix[2][0] + matrix[0][2])*s; + y = (matrix[1][2] + matrix[2][1])*s; z = 0.5 * r; - w = (array[1][0] - array[0][1])*s; + w = (matrix[1][0] - matrix[0][1])*s; } else { - r = sqrt(array[0][0] - array[1][1] - array[2][2] + 1.0); + r = sqrt(matrix[0][0] - matrix[1][1] - matrix[2][2] + 1.0); s = 0.5 / r; // Compute the quaternion x = 0.5 * r; - y = (array[0][1] + array[1][0])*s; - z = (array[2][0] - array[0][2])*s; - w = (array[2][1] - array[1][2])*s; + y = (matrix[0][1] + matrix[1][0])*s; + z = (matrix[2][0] - matrix[0][2])*s; + w = (matrix[2][1] - matrix[1][2])*s; } } else { @@ -118,9 +111,9 @@ Quaternion::Quaternion(const Matrix3x3& matrix) { s = 0.5/r; // Compute the quaternion - x = (array[2][1]-array[1][2])*s; - y = (array[0][2]-array[2][0])*s; - z = (array[1][0]-array[0][1])*s; + x = (matrix[2][1] - matrix[1][2]) * s; + y = (matrix[0][2] - matrix[2][0]) * s; + z = (matrix[1][0] - matrix[0][1]) * s; w = 0.5 * r; } } diff --git a/src/mathematics/Quaternion.h b/src/mathematics/Quaternion.h index c643b41f..52f58b05 100644 --- a/src/mathematics/Quaternion.h +++ b/src/mathematics/Quaternion.h @@ -70,12 +70,21 @@ struct Quaternion { // Destructor ~Quaternion(); + /// Set all the values + void setAllValues(decimal newX, decimal newY, decimal newZ, decimal newW); + + /// Set the quaternion to zero + void setToZero(); + // Return the vector v=(x y z) of the quaternion - Vector3 vectorV() const; + Vector3 getVectorV() const; // Return the length of the quaternion decimal length() const; + /// Normalize the quaternion + void normalize(); + // Return the unit quaternion Quaternion getUnit() const; @@ -113,6 +122,9 @@ struct Quaternion { // Overloaded operator for the multiplication Quaternion operator*(const Quaternion& quaternion) const; + /// Overloaded operator for the multiplication with a vector + Vector3 operator*(const Vector3& point); + // Overloaded operator for assignment Quaternion& operator=(const Quaternion& quaternion); @@ -120,8 +132,24 @@ struct Quaternion { bool operator==(const Quaternion& quaternion) const; }; +/// Set all the values +inline void Quaternion::setAllValues(decimal newX, decimal newY, decimal newZ, decimal newW) { + x = newX; + y = newY; + z = newZ; + w = newW; +} + +/// Set the quaternion to zero +inline void Quaternion::setToZero() { + x = 0; + y = 0; + z = 0; + w = 0; +} + // Return the vector v=(x y z) of the quaternion -inline Vector3 Quaternion::vectorV() const { +inline Vector3 Quaternion::getVectorV() const { // Return the vector v return Vector3(x, y, z); @@ -132,6 +160,20 @@ inline decimal Quaternion::length() const { return sqrt(x*x + y*y + z*z + w*w); } +// Normalize the quaternion +inline void Quaternion::normalize() { + + decimal l = length(); + + // Check if the length is not equal to zero + assert (l > MACHINE_EPSILON); + + x /= l; + y /= l; + z /= l; + w /= l; +} + // Return the unit quaternion inline Quaternion Quaternion::getUnit() const { decimal lengthQuaternion = length(); @@ -193,9 +235,16 @@ inline Quaternion Quaternion::operator*(decimal nb) const { // Overloaded operator for the multiplication of two quaternions inline Quaternion Quaternion::operator*(const Quaternion& quaternion) const { - return Quaternion(w * quaternion.w - vectorV().dot(quaternion.vectorV()), - w * quaternion.vectorV() + quaternion.w * vectorV() + - vectorV().cross(quaternion.vectorV())); + return Quaternion(w * quaternion.w - getVectorV().dot(quaternion.getVectorV()), + w * quaternion.getVectorV() + quaternion.w * getVectorV() + + getVectorV().cross(quaternion.getVectorV())); +} + +// Overloaded operator for the multiplication with a vector. +/// This methods rotates a point given the rotation of a quaternion. +inline Vector3 Quaternion::operator*(const Vector3& point) { + Quaternion p(point.x, point.y, point.z, 0.0); + return (((*this) * p) * getConjugate()).getVectorV(); } // Overloaded operator for the assignment diff --git a/src/mathematics/Transform.h b/src/mathematics/Transform.h index b5fe9f3a..bc94c758 100644 --- a/src/mathematics/Transform.h +++ b/src/mathematics/Transform.h @@ -100,6 +100,9 @@ class Transform { const Transform& newTransform, decimal interpolationFactor); + /// Return the identity transform + static Transform identity(); + // Return the transformed vector Vector3 operator*(const Vector3& vector) const; @@ -154,12 +157,12 @@ inline void Transform::setFromOpenGL(decimal* openglMatrix) { // Get the OpenGL matrix of the transform inline void Transform::getOpenGLMatrix(decimal* openglMatrix) const { const Matrix3x3& matrix = mOrientation.getMatrix(); - openglMatrix[0] = matrix.getValue(0, 0); openglMatrix[1] = matrix.getValue(1, 0); - openglMatrix[2] = matrix.getValue(2, 0); openglMatrix[3] = 0.0; - openglMatrix[4] = matrix.getValue(0, 1); openglMatrix[5] = matrix.getValue(1, 1); - openglMatrix[6] = matrix.getValue(2, 1); openglMatrix[7] = 0.0; - openglMatrix[8] = matrix.getValue(0, 2); openglMatrix[9] = matrix.getValue(1, 2); - openglMatrix[10] = matrix.getValue(2, 2); openglMatrix[11] = 0.0; + openglMatrix[0] = matrix[0][0]; openglMatrix[1] = matrix[1][0]; + openglMatrix[2] = matrix[2][0]; openglMatrix[3] = 0.0; + openglMatrix[4] = matrix[0][1]; openglMatrix[5] = matrix[1][1]; + openglMatrix[6] = matrix[2][1]; openglMatrix[7] = 0.0; + openglMatrix[8] = matrix[0][2]; openglMatrix[9] = matrix[1][2]; + openglMatrix[10] = matrix[2][2]; openglMatrix[11] = 0.0; openglMatrix[12] = mPosition.x; openglMatrix[13] = mPosition.y; openglMatrix[14] = mPosition.z; openglMatrix[15] = 1.0; } @@ -186,6 +189,11 @@ inline Transform Transform::interpolateTransforms(const Transform& oldTransform, return Transform(interPosition, interOrientation); } +// Return the identity transform +inline Transform Transform::identity() { + return Transform(Vector3(0, 0, 0), Quaternion::identity()); +} + // Return the transformed vector inline Vector3 Transform::operator*(const Vector3& vector) const { return (mOrientation.getMatrix() * vector) + mPosition; diff --git a/src/mathematics/Vector3.h b/src/mathematics/Vector3.h index 66ab9bd0..619cb346 100644 --- a/src/mathematics/Vector3.h +++ b/src/mathematics/Vector3.h @@ -67,6 +67,9 @@ struct Vector3 { // Set all the values of the vector void setAllValues(decimal newX, decimal newY, decimal newZ); + /// Set the vector to zero + void setToZero(); + // Return the lenght of the vector decimal length() const; @@ -140,6 +143,13 @@ struct Vector3 { friend Vector3 operator/(const Vector3& vector, decimal number); }; +// Set the vector to zero +inline void Vector3::setToZero() { + x = 0; + y = 0; + z = 0; +} + // Set all the values of the vector inline void Vector3::setAllValues(decimal newX, decimal newY, decimal newZ) { x = newX; From 409bbdaba5c9981790fa03f28a701cf99ca97113 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 13 Mar 2013 20:56:53 +0100 Subject: [PATCH 9/9] Add header in the ContactSolver.cpp file --- src/engine/ContactSolver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/ContactSolver.cpp b/src/engine/ContactSolver.cpp index caa2f636..f3a89386 100644 --- a/src/engine/ContactSolver.cpp +++ b/src/engine/ContactSolver.cpp @@ -27,6 +27,7 @@ #include "ContactSolver.h" #include "DynamicsWorld.h" #include "../body/RigidBody.h" +#include using namespace reactphysics3d; using namespace std;