Browse Source

Math: algorithm for computing intersection of two lines in 2D.

pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
3f696533ff
  1. 57
      src/Math/Geometry/Intersection.h
  2. 37
      src/Math/Geometry/Test/IntersectionTest.cpp

57
src/Math/Geometry/Intersection.h

@ -37,6 +37,63 @@ class Intersection {
public:
Intersection() = delete;
/**
* @brief %Intersection of two line segments in 2D
* @param p Starting point of first line segment
* @param r Direction of first line segment
* @param q Starting point of second line segment
* @param s Direction of second line segment
* @return %Intersection point positions `t`, `u` on both lines, NaN if
* the lines are collinear or infinity if they are parallel.
* %Intersection point can be then computed with `p + t*r` or
* `q + u*s`. If `t` is in range @f$ [ 0 ; 1 ] @f$, the
* intersection is inside the line segment defined by `p` and
* `p + r`, if `u` is in range @f$ [ 0 ; 1 ] @f$, the intersection
* is inside the line segment defined by `q` and `q + s`.
*
* The two lines intersect if **t** and **u** exist such that: @f[
* \boldsymbol p + t \boldsymbol r = \boldsymbol q + u \boldsymbol s
* @f]
* Crossing both sides with **s**, distributing the cross product and
* eliminating @f$ \boldsymbol s \times \boldsymbol s = 0 @f$, then
* solving for **t** and similarly for **u**: @f[
* \begin{array}{rcl}
* (\boldsymbol p + t \boldsymbol r) \times s & = & (\boldsymbol q + u \boldsymbol s) \times s \\
* t (\boldsymbol r \times s) & = & (\boldsymbol q - \boldsymbol p) \times s \\
* t & = & \cfrac{(\boldsymbol q - \boldsymbol p) \times s}{\boldsymbol r \times \boldsymbol s} \\
* u & = & \cfrac{(\boldsymbol q - \boldsymbol p) \times r}{\boldsymbol r \times \boldsymbol s}
* \end{array}
* @f]
*
* See also lineSegmentLine() which computes only **t**, which is
* useful if you don't need to test that the intersection lies inside
* line segment defined by `q` and `q + s`.
*/
template<class T> static std::pair<T, T> lineSegmentLineSegment(const Vector2<T>& p, const Vector2<T>& r, const Vector2<T>& q, const Vector2<T>& s) {
const Vector2<T> qp = q - p;
const T rs = Vector2<T>::cross(r, s);
return {Vector2<T>::cross(qp, s)/rs,
Vector2<T>::cross(qp, r)/rs};
}
/**
* @brief %Intersection of line segment and line in 2D
* @param p Starting point of first line segment
* @param r Direction of first line segment
* @param q Starting point of second line
* @param s Direction of second line
* @return %Intersection point position `t` on first line, NaN if the
* lines are collinear or infinity if they are parallel.
* %Intersection point can be then with `p + t*r`. If returned
* value is in range @f$ [ 0 ; 1 ] @f$, the intersection is inside
* the line segment defined by `p` and `p + r`.
*
* Unlike lineSegmentLineSegment() computes only **t**.
*/
template<class T> static T lineSegmentLine(const Vector2<T>& p, const Vector2<T>& r, const Vector2<T>& q, const Vector2<T>& s) {
return Vector2<T>::cross(q - p, s)/Vector2<T>::cross(r, s);
}
/**
* @brief %Intersection of a plane and line
* @param planePosition Plane position

37
src/Math/Geometry/Test/IntersectionTest.cpp

@ -34,12 +34,15 @@ class IntersectionTest: public Corrade::TestSuite::Tester {
IntersectionTest();
void planeLine();
void lineLine();
};
typedef Math::Vector2<Float> Vector2;
typedef Math::Vector3<Float> Vector3;
IntersectionTest::IntersectionTest() {
addTests({&IntersectionTest::planeLine});
addTests({&IntersectionTest::planeLine,
&IntersectionTest::lineLine});
}
void IntersectionTest::planeLine() {
@ -63,6 +66,38 @@ void IntersectionTest::planeLine() {
{1.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}), -std::numeric_limits<Float>::infinity());
}
void IntersectionTest::lineLine() {
const Vector2 p(-1.0f, -1.0f);
const Vector2 r(1.0, 2.0f);
/* Inside both line segments */
CORRADE_COMPARE(Intersection::lineSegmentLineSegment(p, r,
{0.0f, 0.0f}, {-1.0f, 0.0f}), std::make_pair(0.5f, 0.5f));
CORRADE_COMPARE(Intersection::lineSegmentLine(p, r,
{0.0f, 0.0f}, {-1.0f, 0.0f}), 0.5);
/* Outside both line segments */
CORRADE_COMPARE(Intersection::lineSegmentLineSegment(p, r,
{0.0f, -2.0f}, {-1.0f, 0.0f}), std::make_pair(-0.5f, 1.5f));
CORRADE_COMPARE(Intersection::lineSegmentLine(p, r,
{0.0f, -2.0f}, {-1.0f, 0.0f}), -0.5f);
/* Collinear lines */
const auto tu = Intersection::lineSegmentLineSegment(p, r,
{0.0f, 1.0f}, {-1.0f, -2.0f});
CORRADE_COMPARE(tu.first, -std::numeric_limits<Float>::quiet_NaN());
CORRADE_COMPARE(tu.second, -std::numeric_limits<Float>::quiet_NaN());
CORRADE_COMPARE(Intersection::lineSegmentLine(p, r,
{0.0f, 1.0f}, {-1.0f, -2.0f}), -std::numeric_limits<Float>::quiet_NaN());
/* Parallel lines */
CORRADE_COMPARE(Intersection::lineSegmentLineSegment(p, r,
{0.0f, 0.0f}, {1.0f, 2.0f}), std::make_pair(std::numeric_limits<Float>::infinity(),
std::numeric_limits<Float>::infinity()));
CORRADE_COMPARE(Intersection::lineSegmentLine(p, r,
{0.0f, 0.0f}, {1.0f, 2.0f}), std::numeric_limits<Float>::infinity());
}
}}}}
CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::IntersectionTest)

Loading…
Cancel
Save