Browse Source

2D equivalents of Geometry::Distance functions.

Also using std::sqrt() instead of sqrt() (has overloads for float).
vectorfields
Vladimír Vondruš 14 years ago
parent
commit
2c0995cf26
  1. 114
      src/Math/Geometry/Distance.h
  2. 60
      src/Math/Geometry/Test/DistanceTest.cpp
  3. 6
      src/Math/Geometry/Test/DistanceTest.h

114
src/Math/Geometry/Distance.h

@ -19,6 +19,8 @@
* @brief Class Magnum::Math::Geometry::Distance
*/
#include "Math/Math.h"
#include "Math/Matrix.h"
#include "Math/Vector3.h"
namespace Magnum { namespace Math { namespace Geometry {
@ -27,7 +29,39 @@ namespace Magnum { namespace Math { namespace Geometry {
class Distance {
public:
/**
* @brief %Distance of line and point
* @brief %Distance of line and point in 2D
* @param a First point of the line
* @param b Second point of the line
* @param point Point
*
* The distance *d* is computed from point **p** and line defined by **a**
* and **b** using @ref Matrix::determinant() "determinant": @f[
* d = \frac{|det(b - a a - point)|} {|b - a|}
* @f]
* Source: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
* @see linePointSquared(const Vector2&, const Vector2&, const Vector2&)
*/
template<class T> inline static T linePoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
return std::abs(Matrix<2, T>::from(b - a, a - point).determinant())/(b - a).length();
}
/**
* @brief %Distance of line and point in 2D, squared
* @param a First point of the line
* @param b Second point of the line
* @param point Point
*
* More efficient than linePoint(const Vector2&, const Vector2&, const Vector2&)
* for comparing distance with other values, because it doesn't
* compute the square root.
*/
template<class T> inline static T linePointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
Vector2<T> bMinusA = b - a;
return Math::pow<2>(Matrix<2, T>::from(bMinusA, a - point).determinant())/bMinusA.dot();
}
/**
* @brief %Distance of line and point in 3D
* @param a First point of the line
* @param b Second point of the line
* @param point Point
@ -37,25 +71,26 @@ class Distance {
* d = \frac{|(\boldsymbol p - \boldsymbol a) \times (\boldsymbol p - \boldsymbol b)|}
* {|\boldsymbol b - \boldsymbol a|}
* @f]
*
* @see linePointSquared()
* Source: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
* @see linePointSquared(const Vector3&, const Vector3&, const Vector3&)
*/
template<class T> inline static T linePoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return sqrt(linePointSquared(a, b, point));
return std::sqrt(linePointSquared(a, b, point));
}
/**
* @brief %Distance of line and point, squared
* @brief %Distance of line and point in 3D, squared
*
* More efficient than linePoint() for comparing distance with other
* values, because it doesn't compute the square root.
* More efficient than linePoint(const Vector3&, const Vector3&, const Vector3&)
* for comparing distance with other values, because it doesn't
* compute the square root.
*/
template<class T> static T linePointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return Vector3<T>::cross(point - a, point - b).dot()/(b - a).dot();
}
/**
* @brief %Dístance of point from line segment
* @brief %Dístance of point from line segment in 2D
* @param a Starting point of the line
* @param b Ending point of the line
* @param point Point
@ -80,16 +115,73 @@ class Distance {
*
* @see lineSegmentPointSquared()
*/
template<class T> inline static T lineSegmentPoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return sqrt(lineSegmentPointSquared(a, b, point));
template<class T> inline static T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
Vector2<T> pointMinusA = point - a;
Vector2<T> pointMinusB = point - b;
Vector2<T> bMinusA = b - a;
T pointDistanceA = pointMinusA.dot();
T pointDistanceB = pointMinusB.dot();
T bDistanceA = bMinusA.dot();
/* Point is before A */
if(pointDistanceB > bDistanceA + pointDistanceA)
return std::sqrt(pointDistanceA);
/* Point is after B */
if(pointDistanceA > bDistanceA + pointDistanceB)
return std::sqrt(pointDistanceB);
/* Between A and B */
return std::abs(Matrix<2, T>::from(bMinusA, -pointMinusA).determinant())/std::sqrt(bDistanceA);
}
/**
* @brief %Distance of point from line segment, squared
* @brief %Distance of point from line segment in 2D, squared
*
* More efficient than lineSegmentPoint() for comparing distance with
* other values, because it doesn't compute the square root.
*/
template<class T> static T lineSegmentPointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
Vector2<T> pointMinusA = point - a;
Vector2<T> pointMinusB = point - b;
Vector2<T> bMinusA = b - a;
T pointDistanceA = pointMinusA.dot();
T pointDistanceB = pointMinusB.dot();
T bDistanceA = bMinusA.dot();
/* Point is before A */
if(pointDistanceB > bDistanceA + pointDistanceA)
return pointDistanceA;
/* Point is after B */
if(pointDistanceA > bDistanceA + pointDistanceB)
return pointDistanceB;
/* Between A and B */
return Math::pow<2>(Matrix<2, T>::from(bMinusA, -pointMinusA).determinant())/bDistanceA;
}
/**
* @brief %Dístance of point from line segment in 3D
* @param a Starting point of the line
* @param b Ending point of the line
* @param point Point
*
* Similar to 2D implementation
* lineSegmentPoint(const Vector2&, const Vector2&, const Vector2&).
*
* @see lineSegmentPointSquared(const Vector3&, const Vector3&, const Vector3&)
*/
template<class T> inline static T lineSegmentPoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return std::sqrt(lineSegmentPointSquared(a, b, point));
}
/**
* @brief %Distance of point from line segment in 3D, squared
*
* More efficient than lineSegmentPoint(const Vector3&, const Vector3&, const Vector3&) for comparing distance with
* other values, because it doesn't compute the square root.
*/
template<class T> static T lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
Vector3<T> pointMinusA = point - a;
Vector3<T> pointMinusB = point - b;

60
src/Math/Geometry/Test/DistanceTest.cpp

@ -26,14 +26,35 @@ using namespace std;
namespace Magnum { namespace Math { namespace Geometry { namespace Test {
typedef Magnum::Math::Vector2<float> Vector2;
typedef Magnum::Math::Vector3<float> Vector3;
DistanceTest::DistanceTest() {
addTests(&DistanceTest::linePoint,
&DistanceTest::lineSegmentPoint);
addTests(&DistanceTest::linePoint2D,
&DistanceTest::linePoint3D,
&DistanceTest::lineSegmentPoint2D,
&DistanceTest::lineSegmentPoint3D);
}
void DistanceTest::linePoint() {
void DistanceTest::linePoint2D() {
Vector2 a(0.0f);
Vector2 b(1.0f);
/* Point on the line */
CORRADE_COMPARE((Distance::linePoint(a, b, Vector2(0.25f))), 0.0f);
/* The distance should be the same for all equidistant points */
CORRADE_COMPARE((Distance::linePoint(a, b, Vector2(1.0f, 0.0f))),
1.0f/Constants<float>::sqrt2());
CORRADE_COMPARE((Distance::linePoint(a, b, Vector2(1.0f, 0.0f)+Vector2(100.0f))),
1.0f/Constants<float>::sqrt2());
/* Be sure that *Squared() works the same, as it has slightly different implementation */
CORRADE_COMPARE((Distance::linePointSquared(a, b, Vector2(1.0f, 0.0f))),
0.5f);
}
void DistanceTest::linePoint3D() {
Vector3 a(0.0f);
Vector3 b(1.0f);
@ -47,7 +68,38 @@ void DistanceTest::linePoint() {
Constants<float>::sqrt2()/Constants<float>::sqrt3());
}
void DistanceTest::lineSegmentPoint() {
void DistanceTest::lineSegmentPoint2D() {
Vector2 a(0.0f);
Vector2 b(1.0f);
/* Point on the line segment */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(0.25f))), 0.0f);
/* Point on the line, outside the segment, closer to A */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(-1.0f))), Constants<float>::sqrt2());
/* Be sure that *Squared() works the same, as it has slightly different implementation */
CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(-1.0f))), 2.0f);
/* Point on the line, outside the segment, closer to B */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f+1.0f/Constants<float>::sqrt2()))), 1.0f);
CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f+1.0f/Constants<float>::sqrt2()))), 1.0f);
/* Point next to the line segment */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f))),
1.0f/Constants<float>::sqrt2());
CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f))),
0.5f);
/* Point outside the line segment, closer to A */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f)-Vector2(1.0f, 0.5f))), 0.5f);
CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f)-Vector2(1.0f, 0.5f))), 0.25f);
/* Point outside the line segment, closer to B */
CORRADE_COMPARE((Distance::lineSegmentPoint(a, b, Vector2(1.0f, 0.0f)+Vector2(0.5f, 1.0f))), 0.5f);
CORRADE_COMPARE((Distance::lineSegmentPointSquared(a, b, Vector2(1.0f, 0.0f)+Vector2(0.5f, 1.0f))), 0.25f);
}
void DistanceTest::lineSegmentPoint3D() {
Vector3 a(0.0f);
Vector3 b(1.0f);

6
src/Math/Geometry/Test/DistanceTest.h

@ -23,8 +23,10 @@ class DistanceTest: public Corrade::TestSuite::Tester<DistanceTest> {
public:
DistanceTest();
void linePoint();
void lineSegmentPoint();
void linePoint2D();
void linePoint3D();
void lineSegmentPoint2D();
void lineSegmentPoint3D();
};
}}}}

Loading…
Cancel
Save