Browse Source

Simplified GeometryUtils::intersection(), updated documentation.

The function now takes only plane normal and position instead of three
points. Also greatly simplified unit test.
pull/279/head
Vladimír Vondruš 14 years ago
parent
commit
e921194601
  1. 61
      src/Math/GeometryUtils.h
  2. 56
      src/Math/Test/GeometryUtilsTest.cpp
  3. 1
      src/Math/Test/GeometryUtilsTest.h

61
src/Math/GeometryUtils.h

@ -19,60 +19,49 @@
* @brief Class Magnum::Math::GeometryUtils * @brief Class Magnum::Math::GeometryUtils
*/ */
#include "Matrix3.h" #include "Vector3.h"
namespace Magnum { namespace Math { namespace Magnum { namespace Math {
/** /**
@brief Geometry utils @brief Geometry utils
*/ */
template<class T> class GeometryUtils { class GeometryUtils {
public: public:
/** /**
* @brief Intersection of a plane and line * @brief Intersection of a plane and line
* @param plane Plane defined by three points * @param planePosition Plane position
* @param a Starting point of the line * @param planeNormal Plane normal
* @param b Ending point of the line * @param a Starting point of the line
* @return Value, NaN if the line lies on the plane or infinity if the * @param b Ending point of the line
* intersection doesn't exist. Intersection point can be then computed * @return Intersection point position, NaN if the line lies on the
* with `a+intersection(...)*b`. If returned value is in range * plane or infinity if the intersection doesn't exist. Intersection
* @f$ [ 0 ; 1 ] @f$, the intersection is inside the line segment * point can be computed from the position with `a+intersection(...)*b`.
* defined by `a` and `b`. * If returned value is in range @f$ [ 0 ; 1 ] @f$, the intersection
* is inside the line segment defined by `a` and `b`.
* *
* First the parametric equation of the plane is computed, * First the parameter *f* of parametric equation of the plane
* @f$ cx + dy + ez = f @f$. Parameters @f$ (c, d, e) @f$ are cross * is computed from plane normal **n** and plane position:
* 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[ * @f[
* \begin{array}{lcl} * \begin{pmatrix} n_0 \\ n_1 \\ n_2 \end{pmatrix} \cdot
* (g, h, i) & = & plane \\ * \begin{pmatrix} x \\ y \\ z \end{pmatrix} - f = 0
* (c, d, e) & = & (h - g) \times (i - g) \\
* f & = & (c, d, e) \cdot g
* \end{array}
* @f] * @f]
* * Using plane normal **n**, parameter *f* and points **a** and **b**,
* Using parametric equation and points @f$ a @f$ and @f$ b @f$, value * value of *t* is computed and returned.
* of @f$ t @f$ is computed and returned.
* @f[ * @f[
* \begin{array}{lcl} * \begin{array}{rcl}
* \Delta b & = & b - a \\ * \Delta \boldsymbol b & = & \boldsymbol b - \boldsymbol a \\
* f & = & (c, d, e) \cdot (a + \Delta b \cdot t) \\ * f & = & \boldsymbol n \cdot (\boldsymbol a + \Delta \boldsymbol b \cdot t) \\
* t & = & \frac{f - (c, d, e) \cdot a} * \Rightarrow t & = & \cfrac{f - \boldsymbol n \cdot \boldsymbol a}{\boldsymbol n \cdot \Delta \boldsymbol b}
* {(c, d, e) \cdot \Delta b}
* \end{array} * \end{array}
* @f] * @f]
*/ */
static T intersection(const Matrix3<T>& plane, const Vector3<T>& a, const Vector3<T>& b) { template<class T> static T intersection(const Vector3<T>& planePosition, const Vector3<T>& planeNormal, const Vector3<T>& a, const Vector3<T>& b) {
/* Cross product of two vectors defining the plane */ /* Compute f from normal and plane position */
Vector3<T> crossProduct = Vector3<T>::cross(plane[1]-plane[0], plane[2]-plane[0]); T f = Vector3<T>::dot(planePosition, planeNormal);
/* Compute f with cross product and one of the points defining the
plane */
T f = Vector3<T>::dot(crossProduct, plane[0]);
/* Compute t */ /* Compute t */
return (f-Vector3<T>::dot(crossProduct, a)/Vector3<T>::dot(crossProduct, b-a)); return (f-Vector3<T>::dot(planeNormal, a)/Vector3<T>::dot(planeNormal, b-a));
} }
}; };

56
src/Math/Test/GeometryUtilsTest.cpp

@ -18,52 +18,36 @@
#include <limits> #include <limits>
#include <QtTest/QTest> #include <QtTest/QTest>
#include "Matrix3.h"
#include "GeometryUtils.h" #include "GeometryUtils.h"
QTEST_APPLESS_MAIN(Magnum::Math::Test::GeometryUtilsTest) QTEST_APPLESS_MAIN(Magnum::Math::Test::GeometryUtilsTest)
typedef Magnum::Math::Matrix3<float> Matrix3;
typedef Magnum::Math::Vector3<float> Vector3;
Q_DECLARE_METATYPE(Matrix3)
Q_DECLARE_METATYPE(Vector3)
using namespace std; using namespace std;
namespace Magnum { namespace Math { namespace Test { namespace Magnum { namespace Math { namespace Test {
using ::Matrix3; typedef Magnum::Math::Vector3<float> Vector3;
using ::Vector3;
void GeometryUtilsTest::intersection_data() {
QTest::addColumn<Matrix3>("plane");
QTest::addColumn<Vector3>("a");
QTest::addColumn<Vector3>("b");
QTest::addColumn<float>("expected");
Matrix3 plane(0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
QTest::newRow("inside") << plane << Vector3(0, 0, -1) << Vector3(0, 0, 1) << 0.5f;
QTest::newRow("outside") << plane << Vector3(0, 0, 1) << Vector3(0, 0, 2) << -1.0f;
QTest::newRow("NaN") << plane << Vector3(1, 0, 0) << Vector3(0, 1, 0) << numeric_limits<float>::quiet_NaN();
QTest::newRow("inf") << plane << Vector3(1, 0, 1) << Vector3(0, 0, 1) << numeric_limits<float>::infinity();
}
void GeometryUtilsTest::intersection() { void GeometryUtilsTest::intersection() {
QFETCH(Matrix3, plane); Vector3 planePosition;
QFETCH(Vector3, a); Vector3 planeNormal(0.0f, 0.0f, 1.0f);
QFETCH(Vector3, b);
QFETCH(float, expected); /* Inside line segment */
QCOMPARE((GeometryUtils::intersection(planePosition, planeNormal,
/* Handling also NaN, which cannot be fuzzy compared */ Vector3(0, 0, -1), Vector3(0, 0, 1))), 0.5f);
float actual = GeometryUtils<float>::intersection(plane, a, b);
/* Outside line segment */
/* All possible workarounds for comparing to inf and NaN */ QCOMPARE((GeometryUtils::intersection(planePosition, planeNormal,
if(expected > numeric_limits<float>::max()) QCOMPARE(actual, expected); Vector3(0, 0, 1), Vector3(0, 0, 2))), -1.0f);
else if(expected != expected) QVERIFY(actual != actual);
else QVERIFY(actual == expected); /* Line lies on the plane */
float nan = GeometryUtils::intersection(planePosition, planeNormal,
Vector3(1, 0, 0), Vector3(0, 1, 0));
QVERIFY(nan != nan);
/* Line is parallell to the plane */
QCOMPARE((GeometryUtils::intersection(planePosition, planeNormal,
Vector3(1, 0, 1), Vector3(0, 0, 1))), numeric_limits<float>::infinity());
} }
}}} }}}

1
src/Math/Test/GeometryUtilsTest.h

@ -23,7 +23,6 @@ class GeometryUtilsTest: public QObject {
Q_OBJECT Q_OBJECT
private slots: private slots:
void intersection_data();
void intersection(); void intersection();
}; };

Loading…
Cancel
Save