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.
vectorfields
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