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
*/
#include "Matrix3.h"
#include "Vector3.h"
namespace Magnum { namespace Math {
/**
@brief Geometry utils
*/
template<class T> class GeometryUtils {
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 `a` and `b`.
* @param planePosition Plane position
* @param planeNormal Plane normal
* @param a Starting point of the line
* @param b Ending point of the line
* @return Intersection point position, NaN if the line lies on the
* plane or infinity if the intersection doesn't exist. Intersection
* point can be computed from the position with `a+intersection(...)*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,
* @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.
* First the parameter *f* of parametric equation of the plane
* is computed from plane normal **n** and plane position:
* @f[
* \begin{array}{lcl}
* (g, h, i) & = & plane \\
* (c, d, e) & = & (h - g) \times (i - g) \\
* f & = & (c, d, e) \cdot g
* \end{array}
* \begin{pmatrix} n_0 \\ n_1 \\ n_2 \end{pmatrix} \cdot
* \begin{pmatrix} x \\ y \\ z \end{pmatrix} - f = 0
* @f]
*
* Using parametric equation and points @f$ a @f$ and @f$ b @f$, value
* of @f$ t @f$ is computed and returned.
* Using plane normal **n**, parameter *f* and points **a** and **b**,
* value of *t* 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}
* \begin{array}{rcl}
* \Delta \boldsymbol b & = & \boldsymbol b - \boldsymbol a \\
* f & = & \boldsymbol n \cdot (\boldsymbol a + \Delta \boldsymbol b \cdot t) \\
* \Rightarrow t & = & \cfrac{f - \boldsymbol n \cdot \boldsymbol a}{\boldsymbol n \cdot \Delta \boldsymbol b}
* \end{array}
* @f]
*/
static T intersection(const Matrix3<T>& plane, const Vector3<T>& a, const Vector3<T>& b) {
/* Cross product of two vectors defining the plane */
Vector3<T> crossProduct = Vector3<T>::cross(plane[1]-plane[0], plane[2]-plane[0]);
/* Compute f with cross product and one of the points defining the
plane */
T f = Vector3<T>::dot(crossProduct, plane[0]);
template<class T> static T intersection(const Vector3<T>& planePosition, const Vector3<T>& planeNormal, const Vector3<T>& a, const Vector3<T>& b) {
/* Compute f from normal and plane position */
T f = Vector3<T>::dot(planePosition, planeNormal);
/* 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 <QtTest/QTest>
#include "Matrix3.h"
#include "GeometryUtils.h"
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;
namespace Magnum { namespace Math { namespace Test {
using ::Matrix3;
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();
}
typedef Magnum::Math::Vector3<float> Vector3;
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<float>::intersection(plane, a, b);
/* All possible workarounds for comparing to inf and NaN */
if(expected > numeric_limits<float>::max()) QCOMPARE(actual, expected);
else if(expected != expected) QVERIFY(actual != actual);
else QVERIFY(actual == expected);
Vector3 planePosition;
Vector3 planeNormal(0.0f, 0.0f, 1.0f);
/* Inside line segment */
QCOMPARE((GeometryUtils::intersection(planePosition, planeNormal,
Vector3(0, 0, -1), Vector3(0, 0, 1))), 0.5f);
/* Outside line segment */
QCOMPARE((GeometryUtils::intersection(planePosition, planeNormal,
Vector3(0, 0, 1), Vector3(0, 0, 2))), -1.0f);
/* 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
private slots:
void intersection_data();
void intersection();
};

Loading…
Cancel
Save