From e9f2101b15db3141bab5ff92eaba89ada5dcfdbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 23 Sep 2021 14:57:33 +0200 Subject: [PATCH] Math: added Distance::pointPoint() and Intersection::pointSphere(). Those add nothing of value as they only wrap trivial code, but make the operations easier to discover, and that's what matters. --- doc/changelog.dox | 4 ++ src/Magnum/Math/Distance.h | 62 +++++++++++++++++++++++ src/Magnum/Math/Intersection.h | 48 ++++++++++++++++++ src/Magnum/Math/Test/DistanceTest.cpp | 44 +++++++++++++++- src/Magnum/Math/Test/IntersectionTest.cpp | 30 ++++++++++- src/Magnum/Math/Vector.h | 6 ++- 6 files changed, 190 insertions(+), 4 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index cb33b28fd..512623a10 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -127,6 +127,10 @@ See also: - Added @ref Math::RectangularMatrix::RectangularMatrix(IdentityInitT, T) constructor as it might be useful to create non-square identity matrices as well +- Added @ref Math::Distance::pointPoint() and + @ref Math::Intersection::pointCircle() / + @relativeref{Math::Intersection,pointSphere()}, which are just wrappers + over trivial code but easier to discover @subsubsection changelog-latest-new-meshtools MeshTools library diff --git a/src/Magnum/Math/Distance.h b/src/Magnum/Math/Distance.h index fcde232b1..21b1d1bf4 100644 --- a/src/Magnum/Math/Distance.h +++ b/src/Magnum/Math/Distance.h @@ -36,6 +36,68 @@ namespace Magnum { namespace Math { namespace Distance { +/** +@brief Distance of two points in 2D, squared +@param a First point +@param b Second point +@m_since_latest + +Same as @cpp (b - a).dot() @ce. More efficient than @ref pointPoint(const Vector2&, const Vector2&) +for comparing distance with other values, because it doesn't calculate the +square root. +@see @ref Vector::dot() +*/ +template T pointPointSquared(const Vector2& a, const Vector2& b) { + return (b - a).dot(); +} + +/** +@brief Distance of two points in 2D +@param a First point +@param b Second point +@m_since_latest + +Same as @cpp (b - a).length() @ce: @f[ + d = |\boldsymbol{b} - \boldsymbol{a}| +@f] + +@see @ref pointPointSquared(const Vector2&, const Vector2&), + @ref Vector::length() +*/ +template T pointPoint(const Vector2& a, const Vector2& b) { + return (b - a).length(); +} + +/** +@brief Distance of two points in 3D, squared +@param a First point +@param b Second point +@m_since_latest + +Same as @cpp (b - a).dot() @ce. More efficient than @ref pointPoint(const Vector3&, const Vector3&) +for comparing distance with other values, because it doesn't calculate the +square root. +*/ +template T pointPointSquared(const Vector3& a, const Vector3& b) { + return (b - a).dot(); +} + +/** +@brief Distance of two points in 3D +@param a First point +@param b Second point +@m_since_latest + +Same as @cpp (b - a).length() @ce: @f[ + d = |\boldsymbol{b} - \boldsymbol{a}| +@f] + +@see @ref pointPointSquared(const Vector3&, const Vector3&) +*/ +template T pointPoint(const Vector3& a, const Vector3& b) { + return (b - a).length(); +} + /** @brief Distance of line and point in 2D, squared @param a First point of the line diff --git a/src/Magnum/Math/Intersection.h b/src/Magnum/Math/Intersection.h index 4f6060087..94f57a399 100644 --- a/src/Magnum/Math/Intersection.h +++ b/src/Magnum/Math/Intersection.h @@ -40,6 +40,54 @@ namespace Magnum { namespace Math { namespace Intersection { +/** +@brief Intersection of a point and a circle in 2D +@param point Point +@param circleCenter Circle center +@param circleRadius Circle radius +@return @cpp true @ce if the the point intersects the sphere, @cpp false @ce + otherwise +@m_since_latest + +Same as @cpp (circleCenter - point).dot() <= Math::pow<2>(circleRadius) @ce. A +point @f$ \boldsymbol{p} @f$ intersects with a circle of a center +@f$ \boldsymbol{c} @f$ and radius @f$ r @f$ if the following holds: @f[ + \begin{array}{rcl} + |\boldsymbol{c} - \boldsymbol{p}| & < & r \\ + (\boldsymbol{c} - \boldsymbol{p}) \cdot (\boldsymbol{c} - \boldsymbol{p}) & < & r^2 + \end{array} +@f] + +@see @ref Distance::pointPointSquared(), @ref Vector::dot(), @ref pow(T) +*/ +template inline bool pointCircle(const Vector2& point, const Vector2& circleCenter, T circleRadius) { + return (circleCenter - point).dot() <= circleRadius*circleRadius; +} + +/** +@brief Intersection of a point and a sphere in 3D +@param point Point +@param sphereCenter Sphere center +@param sphereRadius Sphere radius +@return @cpp true @ce if the the point intersects the sphere, @cpp false @ce + otherwise +@m_since_latest + +Same as @cpp (sphereCenter - point).dot() <= Math::pow<2>(sphereRadius) @ce. A +point @f$ \boldsymbol{p} @f$ intersects with a sphere of a center +@f$ \boldsymbol{c} @f$ and radius @f$ r @f$ if the following holds: @f[ + \begin{array}{rcl} + |\boldsymbol{c} - \boldsymbol{p}| & < & r \\ + (\boldsymbol{c} - \boldsymbol{p}) \cdot (\boldsymbol{c} - \boldsymbol{p}) & < & r^2 + \end{array} +@f] + +@see @ref Distance::pointPointSquared(), @ref Vector::dot(), @ref pow(T) +*/ +template inline bool pointSphere(const Vector3& point, const Vector3& sphereCenter, T sphereRadius) { + return (sphereCenter - point).dot() <= sphereRadius*sphereRadius; +} + /** @brief Intersection of two line segments in 2D @param p Starting point of first line segment diff --git a/src/Magnum/Math/Test/DistanceTest.cpp b/src/Magnum/Math/Test/DistanceTest.cpp index b152b35c5..b8a87432a 100644 --- a/src/Magnum/Math/Test/DistanceTest.cpp +++ b/src/Magnum/Math/Test/DistanceTest.cpp @@ -36,6 +36,9 @@ namespace Magnum { namespace Math { namespace Test { namespace { struct DistanceTest: Corrade::TestSuite::Tester { explicit DistanceTest(); + void pointPoint2D(); + void pointPoint3D(); + void linePoint2D(); void linePoint3D(); void lineSegmentPoint2D(); @@ -53,7 +56,10 @@ typedef Math::Vector4 Vector4; typedef Math::Constants Constants; DistanceTest::DistanceTest() { - addTests({&DistanceTest::linePoint2D, + addTests({&DistanceTest::pointPoint2D, + &DistanceTest::pointPoint3D, + + &DistanceTest::linePoint2D, &DistanceTest::linePoint3D, &DistanceTest::lineSegmentPoint2D, &DistanceTest::lineSegmentPoint3D, @@ -64,6 +70,42 @@ DistanceTest::DistanceTest() { &DistanceTest::pointPlaneNormalizedNotNormalized}); } +void DistanceTest::pointPoint2D() { + CORRADE_COMPARE(Distance::pointPoint(Vector2{5.0f, 1.0f}, + Vector2{6.0f, 1.0f}), 1.0f); + CORRADE_COMPARE(Distance::pointPointSquared(Vector2{5.0f, 1.0f}, + Vector2{6.0f, 1.0f}), 1.0f); + CORRADE_COMPARE(Distance::pointPoint(Vector2{5.0f, 1.0f}, + Vector2{5.0f, 2.0f}), 1.0f); + CORRADE_COMPARE(Distance::pointPointSquared(Vector2{5.0f, 1.0f}, + Vector2{5.0f, 2.0f}), 1.0f); + CORRADE_COMPARE(Distance::pointPoint(Vector2{5.0f, 1.0f}, + Vector2{6.0f, 2.0f}), + Constants::sqrt2()); + CORRADE_COMPARE(Distance::pointPointSquared(Vector2{5.0f, 1.0f}, + Vector2{6.0f, 2.0f}), 2.0f); +} + +void DistanceTest::pointPoint3D() { + CORRADE_COMPARE(Distance::pointPoint(Vector3{5.0f, 1.0f, -2.0f}, + Vector3{6.0f, 1.0f, -2.0f}), 1.0f); + CORRADE_COMPARE(Distance::pointPointSquared(Vector3{5.0f, 1.0f, -2.0f}, + Vector3{6.0f, 1.0f, -2.0f}), 1.0f); + CORRADE_COMPARE(Distance::pointPoint(Vector3{5.0f, 1.0f, -2.0f}, + Vector3{5.0f, 2.0f, -2.0f}), 1.0f); + CORRADE_COMPARE(Distance::pointPointSquared(Vector3{5.0f, 1.0f, -2.0f}, + Vector3{5.0f, 2.0f, -2.0f}), 1.0f); + CORRADE_COMPARE(Distance::pointPoint(Vector3{5.0f, 1.0f, -2.0f}, + Vector3{5.0f, 1.0f, -3.0f}), 1.0f); + CORRADE_COMPARE(Distance::pointPointSquared(Vector3{5.0f, 1.0f, -2.0f}, + Vector3{5.0f, 1.0f, -3.0f}), 1.0f); + CORRADE_COMPARE(Distance::pointPoint(Vector3{5.0f, 1.0f, -2.0f}, + Vector3{6.0f, 2.0f, -3.0f}), + Constants::sqrt3()); + CORRADE_COMPARE(Distance::pointPointSquared(Vector3{5.0f, 1.0f, -2.0f}, + Vector3{6.0f, 2.0f, -3.0f}), 3.0f); +} + void DistanceTest::linePoint2D() { Vector2 a(0.0f); Vector2 b(1.0f); diff --git a/src/Magnum/Math/Test/IntersectionTest.cpp b/src/Magnum/Math/Test/IntersectionTest.cpp index bca0d2b7e..9f74aa8aa 100644 --- a/src/Magnum/Math/Test/IntersectionTest.cpp +++ b/src/Magnum/Math/Test/IntersectionTest.cpp @@ -38,6 +38,9 @@ using namespace Literals; struct IntersectionTest: Corrade::TestSuite::Tester { explicit IntersectionTest(); + void pointCircle(); + void pointSphere(); + void planeLine(); void lineLine(); @@ -69,7 +72,10 @@ typedef Math::Rad Rad; typedef Math::Rad Radd; IntersectionTest::IntersectionTest() { - addTests({&IntersectionTest::planeLine, + addTests({&IntersectionTest::pointCircle, + &IntersectionTest::pointSphere, + + &IntersectionTest::planeLine, &IntersectionTest::lineLine, &IntersectionTest::pointFrustum, @@ -87,6 +93,28 @@ IntersectionTest::IntersectionTest() { &IntersectionTest::aabbCone}); } +void IntersectionTest::pointCircle() { + CORRADE_VERIFY(Intersection::pointCircle( + Vector2{5.0f, 1.0f}, + Vector2{6.0f, 2.0f}, + Constants::sqrt2() + TypeTraits::epsilon())); + CORRADE_VERIFY(!Intersection::pointCircle( + Vector2{5.0f, 1.0f}, + Vector2{6.0f, 2.0f}, + Constants::sqrt2() - TypeTraits::epsilon())); +} + +void IntersectionTest::pointSphere() { + CORRADE_VERIFY(Intersection::pointSphere( + Vector3{5.0f, 1.0f, -2.0f}, + Vector3{6.0f, 2.0f, -3.0f}, + Constants::sqrt3() + TypeTraits::epsilon())); + CORRADE_VERIFY(!Intersection::pointSphere( + Vector3{5.0f, 1.0f, -2.0f}, + Vector3{6.0f, 2.0f, -3.0f}, + Constants::sqrt3() - TypeTraits::epsilon())); +} + void IntersectionTest::planeLine() { const Vector3 planePosition(-1.0f, 1.0f, 0.5f); const Vector3 planeNormal(0.0f, 0.0f, 1.0f); diff --git a/src/Magnum/Math/Vector.h b/src/Magnum/Math/Vector.h index 5aac086ce..374e6f492 100644 --- a/src/Magnum/Math/Vector.h +++ b/src/Magnum/Math/Vector.h @@ -500,7 +500,8 @@ template class Vector { * \boldsymbol a \cdot \boldsymbol a = \sum_{i=0}^{n-1} \boldsymbol a_i^2 * @f] * @see @ref dot(const Vector&, const Vector&), - * @ref isNormalized() + * @ref isNormalized(), @ref Distance::pointPointSquared(), + * @ref Intersection::pointSphere() */ T dot() const { return Math::dot(*this, *this); } @@ -525,7 +526,8 @@ template class Vector { * @snippet MagnumMath.cpp Vector-length-manhattan * * @see @ref lengthInverted(), @ref Math::sqrt(), @ref normalized(), - * @ref resized() + * @ref resized(), @ref Distance::pointPoint(), + * @ref Intersection::pointSphere() * @todo something like std::hypot() for possibly better precision? */ T length() const { return T(std::sqrt(dot())); }