Browse Source

Math: clarify relation of distances and cross products.

I spent a significant amount of time reinventing the wheel, i.e.
figuring out how to use a cross product to calculate distance of a point
to a line. Only to subseqently have a breakthrough discovery of
Distance::linePoint() that actually does the same.

The distance APIs and 2D and 3D cross-products are now linked together
the math snippet is clarified, and both the 2D and 3D distance use the
same equation, saving one unnecessary vector subtraction. The
equivalence of the two equations is listed directly on that Wolfram
link.
pull/603/head
Vladimír Vondruš 4 years ago
parent
commit
9e796a9664
  1. 18
      src/Magnum/Math/Distance.h
  2. 18
      src/Magnum/Math/Vector2.h
  3. 6
      src/Magnum/Math/Vector3.h

18
src/Magnum/Math/Distance.h

@ -120,12 +120,14 @@ template<class T> inline T linePointSquared(const Vector2<T>& a, const Vector2<T
@param point Point
The distance @f$ d @f$ is calculated from point @f$ \boldsymbol{p} @f$ and line
defined by @f$ \boldsymbol{a} @f$ and @f$ \boldsymbol{b} @f$ using
defined by @f$ \boldsymbol{a} @f$ and @f$ \boldsymbol{b} @f$ using a
@ref cross(const Vector2<T>&, const Vector2<T>&) "perp-dot product": @f[
d = \frac{|(\boldsymbol b - \boldsymbol a)_\bot \cdot (\boldsymbol a - \boldsymbol p)|}{|\boldsymbol b - \boldsymbol a|}
d = \frac{|(\boldsymbol b - \boldsymbol a) \times (\boldsymbol a - \boldsymbol p)|}{|\boldsymbol b - \boldsymbol a|}
= \frac{|(\boldsymbol b - \boldsymbol a)_\bot \cdot (\boldsymbol a - \boldsymbol p)|}{|\boldsymbol b - \boldsymbol a|}
@f]
Source: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
@see @ref linePointSquared(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
@see @ref linePointSquared(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&),
@ref linePoint(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
*/
template<class T> inline T linePoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> bMinusA = b - a;
@ -140,7 +142,8 @@ for comparing distance with other values, because it doesn't calculate the
square root.
*/
template<class T> inline T linePointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return cross(point - a, point - b).dot()/(b - a).dot();
const Vector3<T> bMinusA = b - a;
return cross(bMinusA, a - point).dot()/bMinusA.dot();
}
/**
@ -150,12 +153,13 @@ template<class T> inline T linePointSquared(const Vector3<T>& a, const Vector3<T
@param point Point
The distance @f$ d @f$ is calculated from point @f$ \boldsymbol{p} @f$ and line
defined by @f$ \boldsymbol{a} @f$ and @f$ \boldsymbol{b} @f$ using
defined by @f$ \boldsymbol{a} @f$ and @f$ \boldsymbol{b} @f$ using a
@ref cross(const Vector3<T>&, const Vector3<T>&) "cross product": @f[
d = \frac{|(\boldsymbol p - \boldsymbol a) \times (\boldsymbol p - \boldsymbol b)|}{|\boldsymbol b - \boldsymbol a|}
d = \frac{|(\boldsymbol b - \boldsymbol a) \times (\boldsymbol a - \boldsymbol p)|}{|\boldsymbol b - \boldsymbol a|}
@f]
Source: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
@see @ref linePointSquared(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
@see @ref linePointSquared(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&),
@ref linePoint(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
*/
template<class T> inline T linePoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return std::sqrt(linePointSquared(a, b, point));

18
src/Magnum/Math/Vector2.h

@ -36,17 +36,21 @@ namespace Magnum { namespace Math {
/**
@brief 2D cross product
2D version of cross product, also called perp-dot product, equivalent to
calling @ref cross(const Vector3<T>&, const Vector3<T>&) with Z coordinate set
to `0` and extracting only Z coordinate from the result (X and Y coordinates
are always zero). Returns `0` either when one of the vectors is zero or they
are parallel or antiparallel and `1` when two *normalized* vectors are
perpendicular. @f[
2D version of a cross product, also called a [perp-dot product](https://en.wikipedia.org/wiki/Vector_projection#Scalar_rejection),
equivalent to calling @ref cross(const Vector3<T>&, const Vector3<T>&) with Z
coordinate set to `0` and extracting only Z coordinate from the result (X and Y
coordinates are always zero). Returns `0` either when one of the vectors is
zero or they are parallel or antiparallel and `1` when two *normalized* vectors
are perpendicular. @f[
\boldsymbol a \times \boldsymbol b = \boldsymbol a_\bot \cdot \boldsymbol b = a_xb_y - a_yb_x
@f]
Value of a 2D cross product is related to a distance of a point and a line, see
@ref Distance::linePoint(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
for more information.
@see @ref Vector2::perpendicular(),
@ref dot(const Vector<size, T>&, const Vector<size, T>&)
*/
*/
template<class T> inline T cross(const Vector2<T>& a, const Vector2<T>& b) {
return a._data[0]*b._data[1] - a._data[1]*b._data[0];
}

6
src/Magnum/Math/Vector3.h

@ -34,7 +34,7 @@
namespace Magnum { namespace Math {
/**
@brief Cross product
@brief [Cross product](https://en.wikipedia.org/wiki/Cross_product)
Result has length of @cpp 0 @ce either when one of them is zero or they are
parallel or antiparallel and length of @cpp 1 @ce when two *normalized* vectors
@ -45,7 +45,9 @@ are perpendicular. @f[
If @f$ \boldsymbol{a} @f$, @f$ \boldsymbol{b} @f$ and @f$ \boldsymbol{c} @f$
are corners of a triangle in a counterclockwise order,
@f$ (\boldsymbol{c} - \boldsymbol{b}) \times (\boldsymbol{a} - \boldsymbol{b}) @f$
gives the direction of its normal.
gives the direction of its normal. Length of a cross product is related to a
distance of a point and a line, see @ref Distance::linePoint(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
for more information.
@see @ref cross(const Vector2<T>&, const Vector2<T>&), @ref planeEquation()
*/
template<class T> inline Vector3<T> cross(const Vector3<T>& a, const Vector3<T>& b) {

Loading…
Cancel
Save