From 9e796a9664946edc08e50a71b025b8f71ad2c3d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 18 Oct 2022 12:37:07 +0200 Subject: [PATCH] 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. --- src/Magnum/Math/Distance.h | 18 +++++++++++------- src/Magnum/Math/Vector2.h | 18 +++++++++++------- src/Magnum/Math/Vector3.h | 6 ++++-- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/Magnum/Math/Distance.h b/src/Magnum/Math/Distance.h index 3f41c6530..5109b5e3f 100644 --- a/src/Magnum/Math/Distance.h +++ b/src/Magnum/Math/Distance.h @@ -120,12 +120,14 @@ template inline T linePointSquared(const Vector2& a, const Vector2&, const Vector2&) "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&, const Vector2&, const Vector2&) +@see @ref linePointSquared(const Vector2&, const Vector2&, const Vector2&), + @ref linePoint(const Vector3&, const Vector3&, const Vector3&) */ template inline T linePoint(const Vector2& a, const Vector2& b, const Vector2& point) { const Vector2 bMinusA = b - a; @@ -140,7 +142,8 @@ for comparing distance with other values, because it doesn't calculate the square root. */ template inline T linePointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { - return cross(point - a, point - b).dot()/(b - a).dot(); + const Vector3 bMinusA = b - a; + return cross(bMinusA, a - point).dot()/bMinusA.dot(); } /** @@ -150,12 +153,13 @@ template inline T linePointSquared(const Vector3& a, const Vector3&, const Vector3&) "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&, const Vector3&, const Vector3&) +@see @ref linePointSquared(const Vector3&, const Vector3&, const Vector3&), + @ref linePoint(const Vector2&, const Vector2&, const Vector2&) */ template inline T linePoint(const Vector3& a, const Vector3& b, const Vector3& point) { return std::sqrt(linePointSquared(a, b, point)); diff --git a/src/Magnum/Math/Vector2.h b/src/Magnum/Math/Vector2.h index f3588d2f5..2b44be4d1 100644 --- a/src/Magnum/Math/Vector2.h +++ b/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&, const Vector3&) 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&, const Vector3&) 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&, const Vector2&, const Vector2&) +for more information. @see @ref Vector2::perpendicular(), @ref dot(const Vector&, const Vector&) - */ +*/ template inline T cross(const Vector2& a, const Vector2& b) { return a._data[0]*b._data[1] - a._data[1]*b._data[0]; } diff --git a/src/Magnum/Math/Vector3.h b/src/Magnum/Math/Vector3.h index 1a814a5e3..25bab9263 100644 --- a/src/Magnum/Math/Vector3.h +++ b/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&, const Vector3&, const Vector3&) +for more information. @see @ref cross(const Vector2&, const Vector2&), @ref planeEquation() */ template inline Vector3 cross(const Vector3& a, const Vector3& b) {