diff --git a/src/Math/GeometryUtils.h b/src/Math/GeometryUtils.h new file mode 100644 index 000000000..0471fa6fa --- /dev/null +++ b/src/Math/GeometryUtils.h @@ -0,0 +1,81 @@ +#ifndef Magnum_Math_GeometryUtils_h +#define Magnum_Math_GeometryUtils_h +/* + Copyright © 2010, 2011 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::Math::GeometryUtils + */ + +#include "Matrix3.h" + +namespace Magnum { namespace Math { + +/** +@brief Geometry utils +*/ +template class GeometryUtils { + public: + /** + * @brief Intersection of a plane and line + * @param plane Plane defined by three points + * @param a Starting point of the line + * @param b Ending point of the line + * @return Value, NaN if the line lies on the plane or infinity if the + * intersection doesn't exist. Intersection point can be then computed + * with a+intersection(...)*b. If returned value is in range + * @f$ [ 0 ; 1 ] @f$, the intersection is inside the line segment + * defined by @c a and @c b. + * + * First the parametric equation of the plane is computed, + * @f$ cx + dy + ez = f @f$. Parameters @f$ (c, d, e) @f$ are cross + * product of two vectors defining the plane, parameter @f$ f @f$ is + * computed using @f$ (c, d, e) @f$ and one of points defining the + * plane. + * @f[ + * \begin{array}{lcl} + * (g, h, i) & = & plane \\ + * (c, d, e) & = & (h - g) \times (i - g) \\ + * f & = & (c, d, e) \cdot g + * \end{array} + * @f] + * + * Using parametric equation and points @f$ a @f$ and @f$ b @f$, value + * of @f$ t @f$ is computed and returned. + * @f[ + * \begin{array}{lcl} + * \Delta b & = & b - a \\ + * f & = & (c, d, e) \cdot (a + \Delta b \cdot t) \\ + * t & = & \frac{f - (c, d, e) \cdot a} + * {(c, d, e) \cdot \Delta b} + * \end{array} + * @f] + */ + static T intersection(const Matrix3& plane, const Vector3& a, const Vector3& b) { + /* Cross product of two vectors defining the plane */ + Vector3 crossProduct = Vector3::cross(plane.at(1)-plane.at(0), plane.at(2)-plane.at(0)); + + /* Compute f with cross product and one of the points defining the + plane */ + T f = crossProduct*plane.at(0); + + /* Compute t */ + return (f-crossProduct*a)/(crossProduct*(b-a)); + } +}; + +}} + +#endif diff --git a/src/Math/Test/CMakeLists.txt b/src/Math/Test/CMakeLists.txt index b7cab2843..b885014da 100644 --- a/src/Math/Test/CMakeLists.txt +++ b/src/Math/Test/CMakeLists.txt @@ -4,3 +4,5 @@ magnum_add_test(Vector4Test Vector4Test.h Vector4Test.cpp) magnum_add_test(MatrixTest MatrixTest.h MatrixTest.cpp) magnum_add_test(Matrix4Test Matrix4Test.h Matrix4Test.cpp) + +magnum_add_test(GeometryUtilsTest GeometryUtilsTest.h GeometryUtilsTest.cpp) diff --git a/src/Math/Test/GeometryUtilsTest.cpp b/src/Math/Test/GeometryUtilsTest.cpp new file mode 100644 index 000000000..0e19c4558 --- /dev/null +++ b/src/Math/Test/GeometryUtilsTest.cpp @@ -0,0 +1,71 @@ +/* + Copyright © 2010, 2011 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "GeometryUtilsTest.h" + +#include +#include + +#include "Matrix3.h" +#include "GeometryUtils.h" + +QTEST_APPLESS_MAIN(Magnum::Math::Test::GeometryUtilsTest) + +typedef Magnum::Math::Matrix3 Matrix3; +typedef Magnum::Math::Vector3 Vector3; + +Q_DECLARE_METATYPE(Matrix3) +Q_DECLARE_METATYPE(Vector3) + +using namespace std; + +namespace Magnum { namespace Math { namespace Test { + +using ::Matrix3; +using ::Vector3; + +void GeometryUtilsTest::intersection_data() { + QTest::addColumn("plane"); + QTest::addColumn("a"); + QTest::addColumn("b"); + QTest::addColumn("expected"); + + float plane[] = { + 0, 0, 0, + 1, 0, 0, + 0, 1, 0 + }; + QTest::newRow("inside") << Matrix3(plane) << Vector3(0, 0, -1) << Vector3(0, 0, 1) << 0.5f; + QTest::newRow("outside") << Matrix3(plane) << Vector3(0, 0, 1) << Vector3(0, 0, 2) << -1.0f; + QTest::newRow("NaN") << Matrix3(plane) << Vector3(1, 0, 0) << Vector3(0, 1, 0) << numeric_limits::quiet_NaN(); + QTest::newRow("inf") << Matrix3(plane) << Vector3(1, 0, 1) << Vector3(0, 0, 1) << numeric_limits::infinity(); +} + +void GeometryUtilsTest::intersection() { + QFETCH(Matrix3, plane); + QFETCH(Vector3, a); + QFETCH(Vector3, b); + QFETCH(float, expected); + + /* Handling also NaN, which cannot be fuzzy compared */ + float actual = GeometryUtils::intersection(plane, a, b); + + /* All possible workarounds for comparing to inf and NaN */ + if(expected > numeric_limits::max()) QCOMPARE(actual, expected); + else if(expected != expected) QVERIFY(actual != actual); + else QVERIFY(actual == expected); +} + +}}} diff --git a/src/Math/Test/GeometryUtilsTest.h b/src/Math/Test/GeometryUtilsTest.h new file mode 100644 index 000000000..afe392e6a --- /dev/null +++ b/src/Math/Test/GeometryUtilsTest.h @@ -0,0 +1,32 @@ +#ifndef Magnum_Math_Test_GeometryUtilsTest_h +#define Magnum_Math_Test_GeometryUtilsTest_h +/* + Copyright © 2010, 2011 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include + +namespace Magnum { namespace Math { namespace Test { + +class GeometryUtilsTest: public QObject { + Q_OBJECT + + private slots: + void intersection_data(); + void intersection(); +}; + +}}} + +#endif