From 5d60f0d350fd1089144f772f04f3c91bd354ffef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 8 Jun 2018 13:48:43 +0200 Subject: [PATCH] Math: moved Geometry::Distance and Intersection directly into Math. Too deep nesting, too much typing. Colon cancer. Fully preserving backwards compatibility, except for the recently added cone/frustum intersection functions, which were not in master yet. --- doc/changelog.dox | 35 +- doc/namespaces.dox | 26 +- src/Magnum/Math/CMakeLists.txt | 6 +- src/Magnum/Math/Distance.h | 276 ++++++++ src/Magnum/Math/Frustum.h | 4 +- src/Magnum/Math/Geometry/CMakeLists.txt | 4 - src/Magnum/Math/Geometry/Distance.h | 295 +++------ src/Magnum/Math/Geometry/Intersection.h | 625 ++---------------- src/Magnum/Math/Geometry/Test/CMakeLists.txt | 40 -- src/Magnum/Math/Intersection.h | 625 ++++++++++++++++++ src/Magnum/Math/Test/CMakeLists.txt | 11 + .../Math/{Geometry => }/Test/DistanceTest.cpp | 8 +- .../Test/IntersectionBenchmark.cpp | 9 +- .../{Geometry => }/Test/IntersectionTest.cpp | 9 +- src/Magnum/Shapes/Capsule.cpp | 8 +- src/Magnum/Shapes/Cylinder.cpp | 8 +- src/Magnum/Shapes/Plane.cpp | 8 +- src/Magnum/Shapes/Sphere.cpp | 8 +- 18 files changed, 1090 insertions(+), 915 deletions(-) create mode 100644 src/Magnum/Math/Distance.h delete mode 100644 src/Magnum/Math/Geometry/Test/CMakeLists.txt create mode 100644 src/Magnum/Math/Intersection.h rename src/Magnum/Math/{Geometry => }/Test/DistanceTest.cpp (97%) rename src/Magnum/Math/{Geometry => }/Test/IntersectionBenchmark.cpp (97%) rename src/Magnum/Math/{Geometry => }/Test/IntersectionTest.cpp (98%) diff --git a/doc/changelog.dox b/doc/changelog.dox index b6e35fceb..8093a19bc 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -42,15 +42,15 @@ See also: @subsubsection changelog-latest-new-math Math library -- Added @ref Math::Geometry::Intersection::rangeFrustum(), - @ref Math::Geometry::Intersection::aabbFrustum(), - @ref Math::Geometry::Intersection::sphereFrustum(), - @ref Math::Geometry::Intersection::pointCone(), - @ref Math::Geometry::Intersection::pointDoubleCone(), - @ref Math::Geometry::Intersection::sphereConeView(), - @ref Math::Geometry::Intersection::sphereCone(), - @ref Math::Geometry::Intersection::aabbCone(), - @ref Math::Geometry::Intersection::rangeCone() +- Added @ref Math::Intersection::rangeFrustum(), + @ref Math::Intersection::aabbFrustum(), + @ref Math::Intersection::sphereFrustum(), + @ref Math::Intersection::pointCone(), + @ref Math::Intersection::pointDoubleCone(), + @ref Math::Intersection::sphereConeView(), + @ref Math::Intersection::sphereCone(), + @ref Math::Intersection::aabbCone(), + @ref Math::Intersection::rangeCone() - Added @ref Math::Constants::piQuarter() - Ability to convert @ref Math::BoolVector from and to external representation @@ -80,8 +80,11 @@ See also: @subsection changelog-latest-deprecated Deprecated APIs +- `Math::Geometry`, `Math::Geometry::Distance` and + `Math::Geometry::Intersection` namespaces are deprecated for being too + deeply nested, use @ref Math::Distance and @ref Math::Intersection instead - `Math::Geometry::Intersection::boxFrustum()` is deprecated, use - @ref Math::Geometry::Intersection::rangeFrustum() instead + @ref Math::Intersection::rangeFrustum() instead @section changelog-2018-04 2018.04 @@ -751,9 +754,9 @@ a high-level overview. - Added @ref Math::pow(), @ref Math::log() and @ref Math::exp() - Added @ref Math::Algorithms::qr(), @ref Math::Algorithms::gaussJordanInverted(), @ref Math::Algorithms::kahanSum() -- Added @ref Math::Geometry::Distance::pointPlane(), - @ref Math::Geometry::Distance::pointPlaneScaled(), - @ref Math::Geometry::Distance::pointPlaneNormalized() functions +- Added `Math::Geometry::Distance::pointPlane()`, + `Math::Geometry::Distance::pointPlaneScaled()`, + `Math::Geometry::Distance::pointPlaneNormalized()` functions - Added @ref Math::Range::contains() and @ref Math::join() to join two ranges - Ability to convert @ref Math::Complex, @ref Math::DualComplex, @ref Math::Quaternion, @ref Math::DualQuaternion, @ref Math::Color3, @@ -1166,9 +1169,9 @@ a high-level overview. @subsection changelog-2018-02-compatibility Potential compatibility breakages, removed APIs -- The @ref Math::Geometry::Distance and @ref Math::Geometry::Intersection - classes are now a namespace (might break `using` declarations, but - otherwise it's fully source-compatible) +- The `Math::Geometry::Distance` and `Math::Geometry::Intersection` classes + are now a namespace (might break `using` declarations, but otherwise it's + fully source-compatible) - Removed `Context::majorVersion()` and `Context::minorVersion()` functions, use @ref Context::version() instead - Removed deprecated `Magnum/DebugMarker.h` header, use diff --git a/doc/namespaces.dox b/doc/namespaces.dox index 67b57789f..37a5efb53 100644 --- a/doc/namespaces.dox +++ b/doc/namespaces.dox @@ -136,25 +136,15 @@ See @ref building and @ref cmake for more information. /** @dir Magnum/Math/Geometry * @brief Namespace @ref Magnum::Math::Geometry + * @deprecated Use @ref Magnum/Math/Distance.h and + @ref Magnum/Math/Intersection.h instead. */ /** @namespace Magnum::Math::Geometry -@brief Geometry library - -This library is built as part of Magnum by default. To use this library with -CMake, you need to find the `Magnum` package and link to the `Magnum::Magnum` -target: - -@code{.cmake} -find_package(Magnum REQUIRED) - -# ... -target_link_libraries(your-app Magnum::Magnum) -@endcode - -See @ref building and @ref cmake for more information. -*/ + * @deprecated Use @ref Magnum::Math::Distance and + @ref Magnum::Math::Intersection namespaces instead. + */ -/** @namespace Magnum::Math::Geometry::Distance +/** @namespace Magnum::Math::Distance @brief Functions for calculating distances This library is built as part of Magnum by default. To use this library with @@ -171,8 +161,8 @@ target_link_libraries(your-app Magnum::Magnum) See @ref building and @ref cmake for more information. */ -/** @namespace Magnum::Math::Geometry::Intersection -@brief Function for calculating intersections +/** @namespace Magnum::Math::Intersection +@brief Functions for calculating intersections This library is built as part of Magnum by default. To use this library with CMake, you need to find the `Magnum` package and link to the `Magnum::Magnum` diff --git a/src/Magnum/Math/CMakeLists.txt b/src/Magnum/Math/CMakeLists.txt index 741e06f35..744599e03 100644 --- a/src/Magnum/Math/CMakeLists.txt +++ b/src/Magnum/Math/CMakeLists.txt @@ -30,12 +30,14 @@ set(MagnumMath_HEADERS Color.h Complex.h Constants.h + Distance.h Dual.h DualComplex.h DualQuaternion.h Frustum.h Functions.h Half.h + Intersection.h Math.h TypeTraits.h Matrix.h @@ -60,7 +62,9 @@ set_target_properties(MagnumMath PROPERTIES FOLDER "Magnum/Math") install(FILES ${MagnumMath_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Math) add_subdirectory(Algorithms) -add_subdirectory(Geometry) +if(BUILD_DEPRECATED) + add_subdirectory(Geometry) +endif() if(BUILD_TESTS) add_subdirectory(Test) diff --git a/src/Magnum/Math/Distance.h b/src/Magnum/Math/Distance.h new file mode 100644 index 000000000..b87fbe78e --- /dev/null +++ b/src/Magnum/Math/Distance.h @@ -0,0 +1,276 @@ +#ifndef Magnum_Math_Distance_h +#define Magnum_Math_Distance_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + Copyright © 2016 Jonathan Hale + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Namespace @ref Magnum::Math::Distance + */ + +#include "Magnum/Math/Functions.h" +#include "Magnum/Math/Vector3.h" +#include "Magnum/Math/Vector4.h" + +namespace Magnum { namespace Math { namespace Distance { + +/** +@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 @ref linePoint(const Vector2&, const Vector2&, const Vector2&) +for comparing distance with other values, because it doesn't calculate the +square root. +*/ +template inline T linePointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { + const Vector2 bMinusA = b - a; + return Math::pow<2>(cross(bMinusA, a - point))/bMinusA.dot(); +} + +/** +@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 @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 +@ref cross(const Vector2&, const Vector2&) "perp-dot product": @f[ + d = \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&) +*/ +template inline T linePoint(const Vector2& a, const Vector2& b, const Vector2& point) { + const Vector2 bMinusA = b - a; + return std::abs(cross(bMinusA, a - point))/bMinusA.length(); +} + +/** +@brief Distance of line and point in 3D, squared + +More efficient than @ref linePoint(const Vector3&, const Vector3&, const Vector3&) +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(); +} + +/** +@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 + +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 +@ref cross(const Vector3&, const Vector3&) "cross product": @f[ + d = \frac{|(\boldsymbol p - \boldsymbol a) \times (\boldsymbol p - \boldsymbol b)|}{|\boldsymbol b - \boldsymbol a|} +@f] +Source: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html +@see @ref linePointSquared(const Vector3&, const Vector3&, const Vector3&) +*/ +template inline T linePoint(const Vector3& a, const Vector3& b, const Vector3& point) { + return std::sqrt(linePointSquared(a, b, point)); +} + +/** +@brief Distance of point from line segment in 2D, squared + +More efficient than @ref lineSegmentPoint() for comparing distance with other +values, because it doesn't calculate the square root. +*/ +template T lineSegmentPointSquared(const Vector2& a, const Vector2& b, const Vector2& point); + +/** +@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 + +Returns distance of point from line segment or from its starting/ending point, +depending on where the point lies. + +Determining whether the point lies next to line segment or outside is done +using Pythagorean theorem. If the following equation applies, the point +@f$ \boldsymbol{p} @f$ lies outside line segment closer to @f$ \boldsymbol{a} @f$: @f[ + |\boldsymbol p - \boldsymbol b|^2 > |\boldsymbol b - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol a|^2 +@f] +On the other hand, if the following equation applies, the point lies outside +line segment closer to @f$ \boldsymbol{b} @f$: @f[ + |\boldsymbol p - \boldsymbol a|^2 > |\boldsymbol b - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol b|^2 +@f] +The last alternative is when the following equation applies. The point then +lies between @f$ \boldsymbol{a} @f$ and @f$ \boldsymbol{b} @f$ and the distance +is calculated the same way as in @ref linePoint(). @f[ + |\boldsymbol b - \boldsymbol a|^2 > |\boldsymbol p - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol b|^2 +@f] + +@see @ref lineSegmentPointSquared() +*/ +template T lineSegmentPoint(const Vector2& a, const Vector2& b, const Vector2& point); + +/** +@brief Distance of point from line segment in 3D, squared + +More efficient than @ref lineSegmentPoint(const Vector3&, const Vector3&, const Vector3&) +for comparing distance with other values, because it doesn't calculate the +square root. +*/ +template T lineSegmentPointSquared(const Vector3& a, const Vector3& b, const Vector3& point); + +/** +@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 @ref lineSegmentPoint(const Vector2&, const Vector2&, const Vector2&). +@see @ref lineSegmentPointSquared(const Vector3&, const Vector3&, const Vector3&) +*/ +template inline T lineSegmentPoint(const Vector3& a, const Vector3& b, const Vector3& point) { + return std::sqrt(lineSegmentPointSquared(a, b, point)); +} + +/** +@brief Distance of point from plane, scaled by the length of the planes normal + +The distance @f$ d @f$ is calculated from point @f$ \boldsymbol{p} @f$ and +plane with normal @f$ \boldsymbol{n} @f$ and @f$ w @f$ using: @f[ + d = \boldsymbol{p} \cdot \boldsymbol{n} + w +@f] +The distance is negative if the point lies behind the plane. + +More efficient than @ref pointPlane() when merely the sign of the distance is +of interest, for example when testing on which half space of the plane the +point lies. +@see @ref pointPlaneNormalized() + */ +template inline T pointPlaneScaled(const Vector3& point, const Vector4& plane) { + return dot(plane.xyz(), point) + plane.w(); +} + +/** +@brief Distance of point from plane + +The distance @f$ d @f$ is calculated from point @f$ \boldsymbol{p} @f$ and +plane with normal @f$ \boldsymbol{n} @f$ and @f$ w @f$ using: @f[ + d = \frac{\boldsymbol{p} \cdot \boldsymbol{n} + w}{\left| \boldsymbol{n} \right|} +@f] +The distance is negative if the point lies behind the plane. + +In cases where the planes normal is a unit vector, @ref pointPlaneNormalized() +is more efficient. If merely the sign of the distance is of interest, +@ref pointPlaneScaled() is more efficient. +*/ +template inline T pointPlane(const Vector3& point, const Vector4& plane) { + return pointPlaneScaled(point, plane)/plane.xyz().length(); +} + +/** +@brief Distance of point from plane with normalized normal + +The distance @f$ d @f$ is calculated from point @f$ \boldsymbol{p} @f$ and plane +with normal @f$ \boldsymbol{n} @f$ and @f$ w @f$ using: @f[ + d = \boldsymbol{p} \cdot \boldsymbol{n} + w +@f] +The distance is negative if the point lies behind the plane. Expects that +@p plane normal is normalized. + +More efficient than @ref pointPlane() in cases where the plane's normal is +normalized. Equivalent to @ref pointPlaneScaled() but with assertion added on +top. +*/ +template inline T pointPlaneNormalized(const Vector3& point, const Vector4& plane) { + CORRADE_ASSERT(plane.xyz().isNormalized(), + "Math::Geometry::Distance::pointPlaneNormalized(): plane normal is not an unit vector", {}); + return pointPlaneScaled(point, plane); +} + +template T lineSegmentPoint(const Vector2& a, const Vector2& b, const Vector2& point) { + const Vector2 pointMinusA = point - a; + const Vector2 pointMinusB = point - b; + const Vector2 bMinusA = b - a; + const T pointDistanceA = pointMinusA.dot(); + const T pointDistanceB = pointMinusB.dot(); + const 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(cross(bMinusA, -pointMinusA))/std::sqrt(bDistanceA); +} + +template T lineSegmentPointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { + const Vector2 pointMinusA = point - a; + const Vector2 pointMinusB = point - b; + const Vector2 bMinusA = b - a; + const T pointDistanceA = pointMinusA.dot(); + const T pointDistanceB = pointMinusB.dot(); + const 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>(cross(bMinusA, -pointMinusA))/bDistanceA; +} + +template T lineSegmentPointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { + const Vector3 pointMinusA = point - a; + const Vector3 pointMinusB = point - b; + const T pointDistanceA = pointMinusA.dot(); + const T pointDistanceB = pointMinusB.dot(); + const T bDistanceA = (b - a).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 cross(pointMinusA, pointMinusB).dot()/bDistanceA; +} + +}}} + +#endif diff --git a/src/Magnum/Math/Frustum.h b/src/Magnum/Math/Frustum.h index 0a659850d..7311354e9 100644 --- a/src/Magnum/Math/Frustum.h +++ b/src/Magnum/Math/Frustum.h @@ -49,8 +49,8 @@ namespace Implementation { Stores camera frustum planes in order left (index `0`), right (index `1`), bottom (index `2`), top (index `3`), near (index `4`) and far (index `5`). @see @ref Magnum::Frustum, @ref Magnum::Frustumd, - @ref Geometry::Intersection::pointFrustum(), - @ref Geometry::Intersection::boxFrustum() + @ref Intersection::pointFrustum(), @ref Intersection::rangeFrustum(), + @ref Intersection::aabbFrustum(), @ref Intersection::sphereFrustum() */ template class Frustum { public: diff --git a/src/Magnum/Math/Geometry/CMakeLists.txt b/src/Magnum/Math/Geometry/CMakeLists.txt index c80b761e4..4ab0b3b8e 100644 --- a/src/Magnum/Math/Geometry/CMakeLists.txt +++ b/src/Magnum/Math/Geometry/CMakeLists.txt @@ -32,7 +32,3 @@ add_custom_target(MagnumMathGeometry SOURCES ${MagnumMathGeometry_HEADERS}) set_target_properties(MagnumMathGeometry PROPERTIES FOLDER "Magnum/Math/Geometry") install(FILES ${MagnumMathGeometry_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Math/Geometry) - -if(BUILD_TESTS) - add_subdirectory(Test) -endif() diff --git a/src/Magnum/Math/Geometry/Distance.h b/src/Magnum/Math/Geometry/Distance.h index fa5f7bb7c..12b93d3f1 100644 --- a/src/Magnum/Math/Geometry/Distance.h +++ b/src/Magnum/Math/Geometry/Distance.h @@ -27,250 +27,113 @@ */ /** @file - * @brief Namespace @ref Magnum::Math::Geometry::Distance + * @deprecated Use @ref Magnum/Math/Distance.h instead. */ -#include "Magnum/Math/Functions.h" -#include "Magnum/Math/Vector3.h" -#include "Magnum/Math/Vector4.h" +#include "Magnum/configure.h" -namespace Magnum { namespace Math { namespace Geometry { namespace Distance { +#ifdef MAGNUM_BUILD_DEPRECATED +#include "Magnum/Math/Distance.h" -/** -@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 +CORRADE_DEPRECATED_FILE("use Magnum/Math/Distance.h instead") -More efficient than @ref linePoint(const Vector2&, const Vector2&, const Vector2&) -for comparing distance with other values, because it doesn't calculate the -square root. -*/ -template inline T linePointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { - const Vector2 bMinusA = b - a; - return Math::pow<2>(cross(bMinusA, a - point))/bMinusA.dot(); -} +/** @namespace Magnum::Math::Geometry::Distance + * @deprecated Use @ref Magnum::Math::Distance instead. + */ -/** -@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 +namespace Magnum { namespace Math { namespace Geometry { namespace Distance { -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 -@ref cross(const Vector2&, const Vector2&) "perp-dot product": @f[ - d = \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&) -*/ -template inline T linePoint(const Vector2& a, const Vector2& b, const Vector2& point) { - const Vector2 bMinusA = b - a; - return std::abs(cross(bMinusA, a - point))/bMinusA.length(); +/** @brief @copybrief Math::Distance::linePointSquared(const Vector2&, const Vector2&, const Vector2&) + * @deprecated Use @ref Math::Distance::linePointSquared(const Vector2&, const Vector2&, const Vector2&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::linePointSquared() instead") T linePointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { + return Math::Distance::linePointSquared(a, b, point); } -/** -@brief Distance of line and point in 3D, squared - -More efficient than @ref linePoint(const Vector3&, const Vector3&, const Vector3&) -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(); +/** @brief @copybrief Math::Distance::linePoint(const Vector2&, const Vector2&, const Vector2&) + * @deprecated Use @ref Math::Distance::linePoint(const Vector2&, const Vector2&, const Vector2&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::linePoint() instead") T linePoint(const Vector2& a, const Vector2& b, const Vector2& point) { + return Math::Distance::linePoint(a, b, point); } -/** -@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 - -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 -@ref cross(const Vector3&, const Vector3&) "cross product": @f[ - d = \frac{|(\boldsymbol p - \boldsymbol a) \times (\boldsymbol p - \boldsymbol b)|}{|\boldsymbol b - \boldsymbol a|} -@f] -Source: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html -@see @ref linePointSquared(const Vector3&, const Vector3&, const Vector3&) -*/ -template inline T linePoint(const Vector3& a, const Vector3& b, const Vector3& point) { - return std::sqrt(linePointSquared(a, b, point)); +/** @brief @copybrief Math::Distance::linePointSquared(const Vector3&, const Vector3&, const Vector3&) + * @deprecated Use @ref Math::Distance::linePointSquared(const Vector3&, const Vector3&, const Vector3&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::linePointSquared() instead") T linePointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { + return Math::Distance::linePointSquared(a, b, point); } -/** -@brief Distance of point from line segment in 2D, squared - -More efficient than @ref lineSegmentPoint() for comparing distance with other -values, because it doesn't calculate the square root. -*/ -template T lineSegmentPointSquared(const Vector2& a, const Vector2& b, const Vector2& point); - -/** -@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 - -Returns distance of point from line segment or from its starting/ending point, -depending on where the point lies. - -Determining whether the point lies next to line segment or outside is done -using Pythagorean theorem. If the following equation applies, the point -@f$ \boldsymbol{p} @f$ lies outside line segment closer to @f$ \boldsymbol{a} @f$: @f[ - |\boldsymbol p - \boldsymbol b|^2 > |\boldsymbol b - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol a|^2 -@f] -On the other hand, if the following equation applies, the point lies outside -line segment closer to @f$ \boldsymbol{b} @f$: @f[ - |\boldsymbol p - \boldsymbol a|^2 > |\boldsymbol b - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol b|^2 -@f] -The last alternative is when the following equation applies. The point then -lies between @f$ \boldsymbol{a} @f$ and @f$ \boldsymbol{b} @f$ and the distance -is calculated the same way as in @ref linePoint(). @f[ - |\boldsymbol b - \boldsymbol a|^2 > |\boldsymbol p - \boldsymbol a|^2 + |\boldsymbol p - \boldsymbol b|^2 -@f] - -@see @ref lineSegmentPointSquared() -*/ -template T lineSegmentPoint(const Vector2& a, const Vector2& b, const Vector2& point); - -/** -@brief Distance of point from line segment in 3D, squared - -More efficient than @ref lineSegmentPoint(const Vector3&, const Vector3&, const Vector3&) -for comparing distance with other values, because it doesn't calculate the -square root. -*/ -template T lineSegmentPointSquared(const Vector3& a, const Vector3& b, const Vector3& point); - -/** -@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 @ref lineSegmentPoint(const Vector2&, const Vector2&, const Vector2&). -@see @ref lineSegmentPointSquared(const Vector3&, const Vector3&, const Vector3&) -*/ -template inline T lineSegmentPoint(const Vector3& a, const Vector3& b, const Vector3& point) { - return std::sqrt(lineSegmentPointSquared(a, b, point)); +/** @brief @copybrief Math::Distance::linePoint(const Vector3&, const Vector3&, const Vector3&) + * @deprecated Use @ref Math::Distance::linePoint(const Vector3&, const Vector3&, const Vector3&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::linePoint() instead") T linePoint(const Vector3& a, const Vector3& b, const Vector3& point) { + return Math::Distance::linePoint(a, b, point); } -/** -@brief Distance of point from plane, scaled by the length of the planes normal - -The distance @f$ d @f$ is calculated from point @f$ \boldsymbol{p} @f$ and -plane with normal @f$ \boldsymbol{n} @f$ and @f$ w @f$ using: @f[ - d = \boldsymbol{p} \cdot \boldsymbol{n} + w -@f] -The distance is negative if the point lies behind the plane. - -More efficient than @ref pointPlane() when merely the sign of the distance is -of interest, for example when testing on which half space of the plane the -point lies. -@see @ref pointPlaneNormalized() - */ -template inline T pointPlaneScaled(const Vector3& point, const Vector4& plane) { - return dot(plane.xyz(), point) + plane.w(); +/** @brief @copybrief Math::Distance::lineSegmentPointSquared(const Vector2&, const Vector2&, const Vector2&) + * @deprecated Use @ref Math::Distance::lineSegmentPointSquared(const Vector2&, const Vector2&, const Vector2&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::lineSegmentPointSquared() instead") T lineSegmentPointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { + return Math::Distance::lineSegmentPointSquared(a, b, point); } -/** -@brief Distance of point from plane - -The distance @f$ d @f$ is calculated from point @f$ \boldsymbol{p} @f$ and -plane with normal @f$ \boldsymbol{n} @f$ and @f$ w @f$ using: @f[ - d = \frac{\boldsymbol{p} \cdot \boldsymbol{n} + w}{\left| \boldsymbol{n} \right|} -@f] -The distance is negative if the point lies behind the plane. - -In cases where the planes normal is a unit vector, @ref pointPlaneNormalized() -is more efficient. If merely the sign of the distance is of interest, -@ref pointPlaneScaled() is more efficient. -*/ -template inline T pointPlane(const Vector3& point, const Vector4& plane) { - return pointPlaneScaled(point, plane)/plane.xyz().length(); +/** @brief @copybrief Math::Distance::lineSegmentPoint(const Vector2&, const Vector2&, const Vector2&) + * @deprecated Use @ref Math::Distance::lineSegmentPoint(const Vector2&, const Vector2&, const Vector2&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::lineSegmentPoint() instead") T lineSegmentPoint(const Vector2& a, const Vector2& b, const Vector2& point) { + return Math::Distance::lineSegmentPoint(a, b, point); } -/** -@brief Distance of point from plane with normalized normal - -The distance @f$ d @f$ is calculated from point @f$ \boldsymbol{p} @f$ and plane -with normal @f$ \boldsymbol{n} @f$ and @f$ w @f$ using: @f[ - d = \boldsymbol{p} \cdot \boldsymbol{n} + w -@f] -The distance is negative if the point lies behind the plane. Expects that -@p plane normal is normalized. - -More efficient than @ref pointPlane() in cases where the plane's normal is -normalized. Equivalent to @ref pointPlaneScaled() but with assertion added on -top. -*/ -template inline T pointPlaneNormalized(const Vector3& point, const Vector4& plane) { - CORRADE_ASSERT(plane.xyz().isNormalized(), - "Math::Geometry::Distance::pointPlaneNormalized(): plane normal is not an unit vector", {}); - return pointPlaneScaled(point, plane); +/** @brief @copybrief Math::Distance::lineSegmentPointSquared(const Vector3&, const Vector3&, const Vector3&) + * @deprecated Use @ref Math::Distance::lineSegmentPointSquared(const Vector3&, const Vector3&, const Vector3&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::lineSegmentPointSquared() instead") T lineSegmentPointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { + return Math::Distance::lineSegmentPointSquared(a, b, point); } -template T lineSegmentPoint(const Vector2& a, const Vector2& b, const Vector2& point) { - const Vector2 pointMinusA = point - a; - const Vector2 pointMinusB = point - b; - const Vector2 bMinusA = b - a; - const T pointDistanceA = pointMinusA.dot(); - const T pointDistanceB = pointMinusB.dot(); - const 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(cross(bMinusA, -pointMinusA))/std::sqrt(bDistanceA); +/** @brief @copybrief Math::Distance::lineSegmentPoint(const Vector3&, const Vector3&, const Vector3&) + * @deprecated Use @ref Math::Distance::lineSegmentPoint(const Vector3&, const Vector3&, const Vector3&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::lineSegmentPointSquared() instead") T lineSegmentPoint(const Vector3& a, const Vector3& b, const Vector3& point) { + return Math::Distance::lineSegmentPoint(a, b, point); } -template T lineSegmentPointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { - const Vector2 pointMinusA = point - a; - const Vector2 pointMinusB = point - b; - const Vector2 bMinusA = b - a; - const T pointDistanceA = pointMinusA.dot(); - const T pointDistanceB = pointMinusB.dot(); - const 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>(cross(bMinusA, -pointMinusA))/bDistanceA; +/** @brief @copybrief Math::Distance::pointPlaneScaled(const Vector3&, const Vector4&) + * @deprecated Use @ref Math::Distance::pointPlaneScaled(const Vector3&, const Vector4&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::pointPlaneScaled() instead") T pointPlaneScaled(const Vector3& point, const Vector4& plane) { + return Math::Distance::pointPlaneScaled(point, plane); } -template T lineSegmentPointSquared(const Vector3& a, const Vector3& b, const Vector3& point) { - const Vector3 pointMinusA = point - a; - const Vector3 pointMinusB = point - b; - const T pointDistanceA = pointMinusA.dot(); - const T pointDistanceB = pointMinusB.dot(); - const T bDistanceA = (b - a).dot(); - - /* Point is before A */ - if(pointDistanceB > bDistanceA + pointDistanceA) - return pointDistanceA; - - /* Point is after B */ - if(pointDistanceA > bDistanceA + pointDistanceB) - return pointDistanceB; +/** @brief @copybrief Math::Distance::pointPlane(const Vector3&, const Vector4&) + * @deprecated Use @ref Math::Distance::pointPlane(const Vector3&, const Vector4&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::pointPlane() instead") T pointPlane(const Vector3& point, const Vector4& plane) { + return Math::Distance::pointPlane(point, plane); +} - /* Between A and B */ - return cross(pointMinusA, pointMinusB).dot()/bDistanceA; +/** @brief @copybrief Math::Distance::pointPlaneNormalized(const Vector3&, const Vector4&) + * @deprecated Use @ref Math::Distance::pointPlaneNormalized(const Vector3&, const Vector4&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Distance::pointPlaneNormalized() instead") T pointPlaneNormalized(const Vector3& point, const Vector4& plane) { + return Math::Distance::pointPlaneNormalized(point, plane); } }}}} +#else +#error use Magnum/Math/Distance.h instead +#endif #endif diff --git a/src/Magnum/Math/Geometry/Intersection.h b/src/Magnum/Math/Geometry/Intersection.h index c68f27ecb..0e08882fa 100644 --- a/src/Magnum/Math/Geometry/Intersection.h +++ b/src/Magnum/Math/Geometry/Intersection.h @@ -27,609 +27,66 @@ */ /** @file - * @brief Namespace @ref Magnum::Math::Geometry::Intersection + * @deprecated Use @ref Magnum/Math/Intersection.h instead. */ -#include "Magnum/Math/Frustum.h" -#include "Magnum/Math/Geometry/Distance.h" -#include "Magnum/Math/Range.h" -#include "Magnum/Math/Vector2.h" -#include "Magnum/Math/Vector3.h" -#include "Magnum/Math/Matrix4.h" +#include "Magnum/configure.h" -namespace Magnum { namespace Math { namespace Geometry { namespace Intersection { - -/** -@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 - -Returns intersection point positions @f$ t @f$, @f$ u @f$ on both lines: +#ifdef MAGNUM_BUILD_DEPRECATED +#include "Magnum/Math/Intersection.h" -- @f$ t, u = \mathrm{NaN} @f$ if the lines are collinear -- @f$ t \in [ 0 ; 1 ] @f$ if the intersection is inside the line segment - defined by @f$ \boldsymbol{p} @f$ and @f$ \boldsymbol{p} + \boldsymbol{r} @f$ -- @f$ t \notin [ 0 ; 1 ] @f$ if the intersection is outside the line segment -- @f$ u \in [ 0 ; 1 ] @f$ if the intersection is inside the line segment - defined by @f$ \boldsymbol{q} @f$ and @f$ \boldsymbol{q} + \boldsymbol{s} @f$ -- @f$ u \notin [ 0 ; 1 ] @f$ if the intersection is outside the line segment -- @f$ t, u \in \{-\infty, \infty\} @f$ if the intersection doesn't exist (the - 2D lines are parallel) +CORRADE_DEPRECATED_FILE("use Magnum/Math/Intersection.h instead") -The two lines intersect if @f$ t @f$ and @f$ u @f$ exist such that: @f[ - \boldsymbol p + t \boldsymbol r = \boldsymbol q + u \boldsymbol s -@f] -Crossing both sides with @f$ \boldsymbol{s} @f$, distributing the cross product -and eliminating @f$ \boldsymbol s \times \boldsymbol s = 0 @f$, then solving -for @f$ t @f$ and similarly for @f$ u @f$: @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] +/** @namespace Magnum::Math::Geometry::Intersection + * @deprecated Use @ref Magnum::Math::Intersection instead. + */ -See also @ref lineSegmentLine() which calculates only @f$ t @f$, useful if you -don't need to test that the intersection lies inside line segment defined by -@f$ \boldsymbol{q} @f$ and @f$ \boldsymbol{q} + \boldsymbol{s} @f$. +namespace Magnum { namespace Math { namespace Geometry { namespace Intersection { -@see @ref isInf(), @ref isNan() -*/ -template inline std::pair lineSegmentLineSegment(const Vector2& p, const Vector2& r, const Vector2& q, const Vector2& s) { - const Vector2 qp = q - p; - const T rs = cross(r, s); - return {cross(qp, s)/rs, cross(qp, r)/rs}; +/** @brief @copybrief Math::Intersection::lineSegmentLineSegment(const Vector2&, const Vector2&, const Vector2&, const Vector2&) + * @deprecated Use @ref Math::Intersection::lineSegmentLineSegment(const Vector2&, const Vector2&, const Vector2&, const Vector2&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Intersection::lineSegmentLineSegment() instead") std::pair lineSegmentLineSegment(const Vector2& p, const Vector2& r, const Vector2& q, const Vector2& s) { + return Math::Intersection::lineSegmentLineSegment(p, r, q, s); } -/** -@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 - -Returns intersection point position @f$ t @f$ on the first line: - -- @f$ t = \mathrm{NaN} @f$ if the lines are collinear -- @f$ t \in [ 0 ; 1 ] @f$ if the intersection is inside the line segment - defined by @f$ \boldsymbol{p} @f$ and @f$ \boldsymbol{p} + \boldsymbol{r} @f$ -- @f$ t \notin [ 0 ; 1 ] @f$ if the intersection is outside the line segment -- @f$ t \in \{-\infty, \infty\} @f$ if the intersection doesn't exist (the 2D - lines are parallel) - -Unlike @ref lineSegmentLineSegment() calculates only @f$ t @f$. - -@see @ref isInf(), @ref isNan() -*/ -template inline T lineSegmentLine(const Vector2& p, const Vector2& r, const Vector2& q, const Vector2& s) { - return cross(q - p, s)/cross(r, s); +/** @brief @copybrief Math::Intersection::lineSegmentLine(const Vector2&, const Vector2&, const Vector2&, const Vector2&) + * @deprecated Use @ref Math::Intersection::lineSegmentLine(const Vector2&, const Vector2&, const Vector2&, const Vector2&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Intersection::lineSegmentLine() instead") T lineSegmentLine(const Vector2& p, const Vector2& r, const Vector2& q, const Vector2& s) { + return Math::Intersection::lineSegmentLine(p, r, q, s); } -/** -@brief Intersection of a plane and line -@param planePosition Plane position -@param planeNormal Plane normal -@param p Starting point of the line -@param r Direction of the line - -Returns intersection point position @f$ t @f$ on the line: - -- @f$ t = \mathrm{NaN} @f$ if the line lies on the plane -- @f$ t \in [ 0 ; 1 ] @f$ if the intersection is inside the line segment - defined by @f$ \boldsymbol{p} @f$ and @f$ \boldsymbol{p} + \boldsymbol{r} @f$ -- @f$ t \notin [ 0 ; 1 ] @f$ if the intersection is outside the line segment -- @f$ t \in \{-\infty, \infty\} @f$ if the intersection doesn't exist - -First the parameter @f$ f @f$ of parametric equation of the plane is calculated -from plane normal @f$ \boldsymbol{n} @f$ and plane position: @f[ - \begin{pmatrix} n_0 \\ n_1 \\ n_2 \end{pmatrix} \cdot - \begin{pmatrix} x \\ y \\ z \end{pmatrix} - f = 0 -@f] -Using plane normal @f$ \boldsymbol{n} @f$, parameter @f$ f @f$ and line defined -by @f$ \boldsymbol{p} @f$ and @f$ \boldsymbol{r} @f$, value of @f$ t @f$ is -calculated and returned. @f[ - \begin{array}{rcl} - f & = & \boldsymbol n \cdot (\boldsymbol p + t \boldsymbol r) \\ - \Rightarrow t & = & \cfrac{f - \boldsymbol n \cdot \boldsymbol p}{\boldsymbol n \cdot \boldsymbol r} - \end{array} -@f] - -@see @ref isInf(), @ref isNan() -*/ -template inline T planeLine(const Vector3& planePosition, const Vector3& planeNormal, const Vector3& p, const Vector3& r) { - const T f = dot(planePosition, planeNormal); - return (f - dot(planeNormal, p))/dot(planeNormal, r); +/** @brief @copybrief Math::Intersection::planeLine(const Vector3&, const Vector3&, const Vector3&, const Vector3&) + * @deprecated Use @ref Math::Intersection::planeLine(const Vector3&, const Vector3&, const Vector3&, const Vector3&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Intersection::planeLine() instead") T planeLine(const Vector3& planePosition, const Vector3& planeNormal, const Vector3& p, const Vector3& r) { + return Math::Intersection::planeLine(planePosition, planeNormal, p, r); } -/** -@brief Intersection of a point and a frustum -@param point Point -@param frustum Frustum planes with normals pointing outwards -@return @cpp true @ce if the point is on or inside the frustum, @cpp false @ce - otherwise - -Checks for each plane of the frustum whether the point is behind the plane (the -points distance from the plane is negative) using @ref Distance::pointPlaneScaled(). -*/ -template bool pointFrustum(const Vector3& point, const Frustum& frustum); - -/** -@brief Intersection of a range and a frustum -@param range Range -@param frustum Frustum planes with normals pointing outwards -@return @cpp true @ce if the box intersects with the frustum, @cpp false @ce - otherwise - -Uses the "p/n-vertex" approach: First converts the @ref Range3D into a -representation using center and extent which allows using the following -condition for whether the plane is intersecting the box: @f[ - \begin{array}{rcl} - d & = & \boldsymbol c \cdot \boldsymbol n \\ - r & = & \boldsymbol c \cdot \text{abs}(\boldsymbol n) \\ - d + r & < & -w - \end{array} -@f] - -for plane normal @f$ \boldsymbol n @f$ and determinant @f$ w @f$. - -@see @ref aabbFrustum() -*/ -template bool rangeFrustum(const Range3D& range, const Frustum& frustum); - -#ifdef MAGNUM_BUILD_DEPRECATED -/** - * @brief @copybrief rangeFrustum() - * @deprecated Use @ref rangeFrustum() instead. +/** @brief @copybrief Math::Intersection::pointFrustum(const Vector3&, const Frustum&) + * @deprecated Use @ref Math::Intersection::pointFrustum(const Vector3&, const Frustum&) + * instead. */ -template CORRADE_DEPRECATED("use rangeFrustum() instead") bool boxFrustum(const Range3D& box, const Frustum& frustum) { - return rangeFrustum(box, frustum); +template inline CORRADE_DEPRECATED("use Math::Intersection::pointFrustum() instead") bool pointFrustum(const Vector3& point, const Frustum& frustum) { + return Math::Intersection::pointFrustum(point, frustum); } -#endif - -/** -@brief Intersection of an axis-aligned box and a frustum -@param aabbCenter Center of the AABB -@param aabbExtents (Half-)extents of the AABB -@param frustum Frustum planes with normals pointing outwards -@return @cpp true @ce if the box intersects with the frustum, @cpp false @ce - otherwise - -Uses the same method as @ref rangeFrustum(), but does not need to convert to -center/extents representation. -*/ -template bool aabbFrustum(const Vector3& aabbCenter, const Vector3& aabbExtents, const Frustum& frustum); /** -@brief Intersection of a sphere and a frustum -@param sphereCenter Sphere center -@param sphereRadius Sphere radius -@param frustum Frustum planes with normals pointing outwards -@return @cpp true @ce if the sphere intersects the frustum, @cpp false @ce - otherwise - -Checks for each plane of the frustum whether the sphere is behind the plane -(the points distance larger than the sphere's radius) using -@ref Distance::pointPlaneScaled(). -*/ -template bool sphereFrustum(const Vector3& sphereCenter, T sphereRadius, const Frustum& frustum); - -/** -@brief Intersection of a point and a cone -@param point The point -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param coneAngle Apex angle of the cone -@return @cpp true @ce if the point is inside the cone, @cpp false @ce otherwise - -Precomputes a portion of the intersection equation from @p coneAngle and calls -@ref pointCone(const Vector3&, const Vector3&, const Vector3&, T). -*/ -template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); - -/** -@brief Intersection of a point and a cone using precomputed values -@param point The point -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation -@return @cpp true @ce if the point is inside the cone, @cpp false @ce - otherwise - -The @p tanAngleSqPlusOne parameter can be calculated as: - -@code{.cpp} -Math::pow<2>(Math::tan(angle*T(0.5))) + T(1) -@endcode -*/ -template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); - -/** -@brief Intersection of a point and a double cone -@param point The point -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param coneAngle Apex angle of the cone -@return @cpp true @ce if the point is inside the double cone, @cpp false @ce - otherwise - -Precomputes a portion of the intersection equation from @p coneAngle and calls -@ref pointDoubleCone(const Vector3&, const Vector3&, const Vector3&, T). -*/ -template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); - -/** -@brief Intersection of a point and a double cone using precomputed values -@param point The point -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation -@return @cpp true @ce if the point is inside the double cone, @cpp false @ce - otherwise - -The @p tanAngleSqPlusOne parameter can be precomputed like this: - -@code{.cpp} -T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); -@endcode -*/ -template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); - -/** -@brief Intersection of a sphere and a cone view -@param sphereCenter Center of the sphere -@param sphereRadius Radius of the sphere -@param coneView View matrix with translation and rotation of the cone -@param coneAngle Apex angle of the cone (@f$ 0 < \Theta < \pi @f$) -@return @cpp true @ce if the sphere intersects the cone, @cpp false @ce - otherwise - -Precomputes a portion of the intersection equation from @p coneAngle and calls -@ref sphereConeView(const Vector3&, T, const Matrix4&, T, T). -*/ -template bool sphereConeView(const Vector3& sphereCenter, T sphereRadius, const Matrix4& coneView, Rad coneAngle); - -/** -@brief Intersection of a sphere and a cone view -@param sphereCenter Sphere center -@param sphereRadius Sphere radius -@param coneView View matrix with translation and rotation of the cone -@param sinAngle Precomputed sine of half the cone's opening angle -@param tanAngle Precomputed tangent of half the cone's opening angle -@return @cpp true @ce if the sphere intersects the cone, @cpp false @ce - otherwise - -Transforms the sphere center into cone space (using the cone view matrix) and -performs sphere-cone intersection with the zero-origin -Z axis-aligned cone. -The @p sinAngle, @p cosAngle, @p tanAngle can be precomputed like this: - -@code{.cpp} -T sinAngle = Math::sin(angle*T(0.5)); -T tanAngle = Math::tan(angle*T(0.5)); -@endcode -*/ -template bool sphereConeView(const Vector3& sphereCenter, T sphereRadius, const Matrix4& coneView, T sinAngle, T tanAngle); - -/** -@brief Intersection of a sphere and a cone -@param sphereCenter Sphere center -@param sphereRadius Sphere radius -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param coneAngle Apex angle of the cone (@f$ 0 < \Theta < \pi @f$) -@return @cpp true @ce if the sphere intersects with the cone, @cpp false @ce - otherwise - -Precomputes a portion of the intersection equation from @p coneAngle and calls -@ref sphereCone(const Vector3& sphereCenter, T, const Vector3&, const Vector3&, T, T). -*/ -template bool sphereCone(const Vector3& sphereCenter, T sphereRadius, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); - -/** -@brief Intersection of a sphere and a cone using precomputed values -@param sphereCenter Sphere center -@param sphereRadius Sphere radius -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param sinAngle Precomputed sine of half the cone's opening angle -@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation -@return @cpp true @ce if the sphere intersects with the cone, @cpp false @ce - otherwise - -Offsets the cone plane by @f$ -r\sin{\frac{\Theta}{2}} \cdot \boldsymbol n @f$ -(with @f$ \Theta @f$ being the cone apex angle) which separates two -half-spaces: In front of the plane, in which the sphere cone intersection test -is equivalent to testing the sphere's center against a similarly offset cone -(which is equivalent the cone with surface expanded by @f$ r @f$ in surface -normal direction), and behind the plane, where the test is equivalent to -testing whether the origin of the original cone intersects the sphere. The -@p sinAngle and @p tanAngleSqPlusOne parameters can be precomputed like this: - -@code{.cpp} -T sinAngle = Math::sin(angle*T(0.5)); -T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); -@endcode -*/ -template bool sphereCone(const Vector3& sphereCenter, T sphereRadius, const Vector3& coneOrigin, const Vector3& coneNormal, T sinAngle, T tanAngleSqPlusOne); - -/** -@brief Intersection of an axis aligned bounding box and a cone -@param aabbCenter Center of the AABB -@param aabbExtents (Half-)extents of the AABB -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param coneAngle Apex angle of the cone (@f$ 0 < \Theta < \pi @f$) -@return @cpp true @ce if the box intersects the cone, @cpp false @ce otherwise - -Precomputes a portion of the intersection equation from @p coneAngle and calls -@ref aabbCone(const Vector3&, const Vector3&, const Vector3&, const Vector3&, T). -*/ -template bool aabbCone(const Vector3& aabbCenter, const Vector3& aabbExtents, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); - -/** -@brief Intersection of an axis aligned bounding box and a cone using precomputed values -@param aabbCenter Center of the AABB -@param aabbExtents (Half-)extents of the AABB -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation -@return @cpp true @ce if the box intersects the cone, @cpp false @ce otherwise - -On each axis finds the intersection points of the cone's axis with infinite -planes obtained by extending the two faces of the box that are perpendicular to -that axis. The intersection points on the planes perpendicular to axis -@f$ a \in \{ 0, 1, 2 \} @f$ are given by @f[ - \boldsymbol i = \boldsymbol n \cdot \frac{(\boldsymbol c_a - \boldsymbol o_a) \pm \boldsymbol e_a}{\boldsymbol n_a} -@f] - -with normal @f$ \boldsymbol n @f$, cone origin @f$ \boldsymbol o @f$, box -center @f$ \boldsymbol c @f$ and box extents @f$ \boldsymbol e @f$. The points -on the faces that are closest to this intersection point are the closest to the -cone's axis and are tested for intersection with the cone using -@ref pointCone(const Vector3&, const Vector3&, const Vector3&, const T) "pointCone()". As soon as an intersecting point is found, the function returns -@cpp true @ce. If all points lie outside of the cone, it will return -@cpp false @ce. - -The @p tanAngleSqPlusOne parameter can be precomputed like this: - -@code{.cpp} -T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); -@endcode -*/ -template bool aabbCone(const Vector3& aabbCenter, const Vector3& aabbExtents, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); - -/** -@brief Intersection of a range and a cone -@param range Range -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param coneAngle Apex angle of the cone (@f$ 0 < \Theta < \pi @f$) -@return @cpp true @ce if the range intersects the cone, @cpp false @ce - otherwise - -Precomputes a portion of the intersection equation from @p coneAngle and calls -@ref rangeCone(const Range3D&, const Vector3&, const Vector3&, T). -*/ -template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle); - -/** -@brief Intersection of a range and a cone using precomputed values -@param range Range -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation -@return @cpp true @ce if the range intersects the cone, @cpp false @ce - otherwise - -Converts the range into center/extents representation and passes it on to -@ref aabbCone(const Vector3&, const Vector3&, const Vector3&, const Vector3&, T) "aabbCone()". The @p tanAngleSqPlusOne parameter can be precomputed like this: - -@code{.cpp} -T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); -@endcode -*/ -template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne); - -template bool pointFrustum(const Vector3& point, const Frustum& frustum) { - for(const Vector4& plane: frustum.planes()) { - /* The point is in front of one of the frustum planes (normals point - outwards) */ - if(Distance::pointPlaneScaled(point, plane) < T(0)) - return false; - } - - return true; -} - -template bool rangeFrustum(const Range3D& range, const Frustum& frustum) { - /* Convert to center/extent, avoiding division by 2 and instead comparing - to 2*-plane.w() later */ - const Vector3 center = range.min() + range.max(); - const Vector3 extent = range.max() - range.min(); - - for(const Vector4& plane: frustum.planes()) { - const Vector3 absPlaneNormal = Math::abs(plane.xyz()); - - const Float d = Math::dot(center, plane.xyz()); - const Float r = Math::dot(extent, absPlaneNormal); - if(d + r < -T(2)*plane.w()) return false; - } - - return true; -} - -template bool aabbFrustum(const Vector3& aabbCenter, const Vector3& aabbExtents, const Frustum& frustum) { - for(const Vector4& plane: frustum.planes()) { - const Vector3 absPlaneNormal = Math::abs(plane.xyz()); - - const Float d = Math::dot(aabbCenter, plane.xyz()); - const Float r = Math::dot(aabbExtents, absPlaneNormal); - if(d + r < -plane.w()) return false; - } - - return true; -} - -template bool sphereFrustum(const Vector3& sphereCenter, const T sphereRadius, const Frustum& frustum) { - const T radiusSq = sphereRadius*sphereRadius; - - for(const Vector4& plane: frustum.planes()) { - /* The sphere is in front of one of the frustum planes (normals point - outwards) */ - if(Distance::pointPlaneScaled(sphereCenter, plane) < -radiusSq) - return false; - } - - return true; -} - - -template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { - const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1); - return pointCone(point, coneOrigin, coneNormal, tanAngleSqPlusOne); -} - -template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) { - const Vector3 c = point - coneOrigin; - const T lenA = dot(c, coneNormal); - - return lenA >= 0 && c.dot() <= lenA*lenA*tanAngleSqPlusOne; -} - -template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { - const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1); - return pointDoubleCone(point, coneOrigin, coneNormal, tanAngleSqPlusOne); -} - -template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) { - const Vector3 c = point - coneOrigin; - const T lenA = dot(c, coneNormal); - - return c.dot() <= lenA*lenA*tanAngleSqPlusOne; -} - -template bool sphereConeView(const Vector3& sphereCenter, const T sphereRadius, const Matrix4& coneView, const Rad coneAngle) { - const Rad halfAngle = coneAngle*T(0.5); - const T sinAngle = Math::sin(halfAngle); - const T tanAngle = Math::tan(halfAngle); - - return sphereConeView(sphereCenter, sphereRadius, coneView, sinAngle, tanAngle); -} - -template bool sphereConeView(const Vector3& sphereCenter, const T sphereRadius, const Matrix4& coneView, const T sinAngle, const T tanAngle) { - CORRADE_ASSERT(coneView.isRigidTransformation(), "Math::Geometry::Intersection::sphereConeView(): coneView does not represent a rigid transformation", false); - - /* Transform the sphere so that we can test against Z axis aligned origin - cone instead */ - const Vector3 center = coneView.transformPoint(sphereCenter); - - /* Test against plane which determines whether to test against shifted cone - or center-sphere */ - if (-center.z() > -sphereRadius*sinAngle) { - /* Point - axis aligned cone test, shifted so that the cone's surface - is extended by the radius of the sphere */ - const T coneRadius = tanAngle*(center.z() - sphereRadius/sinAngle); - return center.xy().dot() <= coneRadius*coneRadius; - } else { - /* Simple sphere point check */ - return center.dot() <= sphereRadius*sphereRadius; - } - - return false; -} - -template bool sphereCone( - const Vector3& sphereCenter, const T sphereRadius, - const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) -{ - const Rad halfAngle = coneAngle*T(0.5); - const T sinAngle = Math::sin(halfAngle); - const T tanAngleSqPlusOne = T(1) + Math::pow(Math::tan(halfAngle), T(2)); - - return sphereCone(sphereCenter, sphereRadius, coneOrigin, coneNormal, sinAngle, tanAngleSqPlusOne); -} - -template bool sphereCone( - const Vector3& sphereCenter, const T sphereRadius, - const Vector3& coneOrigin, const Vector3& coneNormal, - const T sinAngle, const T tanAngleSqPlusOne) -{ - const Vector3 diff = sphereCenter - coneOrigin; - - /* Point - cone test */ - if(Math::dot(diff - sphereRadius*sinAngle*coneNormal, coneNormal) > T(0)) { - const Vector3 c = sinAngle*diff + coneNormal*sphereRadius; - const T lenA = Math::dot(c, coneNormal); - - return c.dot() <= lenA*lenA*tanAngleSqPlusOne; - - /* Simple sphere point check */ - } else return diff.dot() <= sphereRadius*sphereRadius; -} - -template bool aabbCone( - const Vector3& aabbCenter, const Vector3& aabbExtents, - const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) -{ - const T tanAngleSqPlusOne = Math::pow(Math::tan(coneAngle*T(0.5)), T(2)) + T(1); - return aabbCone(aabbCenter, aabbExtents, coneOrigin, coneNormal, tanAngleSqPlusOne); -} - -template bool aabbCone( - const Vector3& aabbCenter, const Vector3& aabbExtents, - const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) -{ - const Vector3 c = aabbCenter - coneOrigin; - - for(const Int axis: {0, 1, 2}) { - const Int z = axis; - const Int x = (axis + 1) % 3; - const Int y = (axis + 2) % 3; - if(coneNormal[z] != T(0)) { - const Float t0 = ((c[z] - aabbExtents[z])/coneNormal[z]); - const Float t1 = ((c[z] + aabbExtents[z])/coneNormal[z]); - - const Vector3 i0 = coneNormal*t0; - const Vector3 i1 = coneNormal*t1; - - for(const auto& i : {i0, i1}) { - Vector3 closestPoint = i; - - if(i[x] - c[x] > aabbExtents[x]) { - closestPoint[x] = c[x] + aabbExtents[x]; - } else if(i[x] - c[x] < -aabbExtents[x]) { - closestPoint[x] = c[x] - aabbExtents[x]; - } /* Else: normal intersects within x bounds */ - - if(i[y] - c[y] > aabbExtents[y]) { - closestPoint[y] = c[y] + aabbExtents[y]; - } else if(i[y] - c[y] < -aabbExtents[y]) { - closestPoint[y] = c[y] - aabbExtents[y]; - } /* Else: normal intersects within Y bounds */ - - /* Found a point in cone and aabb */ - if(pointCone(closestPoint, {}, coneNormal, tanAngleSqPlusOne)) - return true; - } - } /* Else: normal will intersect one of the other planes */ - } - - return false; -} - -template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { - const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1); - return rangeCone(range, coneOrigin, coneNormal, tanAngleSqPlusOne); -} - -template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) { - const Vector3 center = (range.min() + range.max())*T(0.5); - const Vector3 extents = (range.max() - range.min())*T(0.5); - return aabbCone(center, extents, coneOrigin, coneNormal, tanAngleSqPlusOne); + * @brief @copybrief Math::Intersection::rangeFrustum(const Range3D&, const Frustum&) + * @deprecated Use Math::Intersection::rangeFrustum(const Range3D&, const Frustum&) + * instead. + */ +template inline CORRADE_DEPRECATED("use Math::Intersection::rangeFrustum() instead") bool boxFrustum(const Range3D& box, const Frustum& frustum) { + return Math::Intersection::rangeFrustum(box, frustum); } }}}} +#else +#error use Magnum/Math/Intesection.h instead +#endif #endif diff --git a/src/Magnum/Math/Geometry/Test/CMakeLists.txt b/src/Magnum/Math/Geometry/Test/CMakeLists.txt deleted file mode 100644 index d4d8d42eb..000000000 --- a/src/Magnum/Math/Geometry/Test/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -# -# This file is part of Magnum. -# -# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 -# Vladimír Vondruš -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -# - -corrade_add_test(MathGeometryDistanceTest DistanceTest.cpp LIBRARIES MagnumMathTestLib) -target_compile_definitions(MathGeometryDistanceTest PRIVATE "CORRADE_GRACEFUL_ASSERT") - -corrade_add_test(MathGeometryIntersectionTest IntersectionTest.cpp LIBRARIES MagnumMathTestLib) -corrade_add_test(MathGeometryIntersectionBenchmark IntersectionBenchmark.cpp LIBRARIES MagnumMathTestLib) - -set_target_properties( - MathGeometryDistanceTest - MathGeometryIntersectionTest - MathGeometryIntersectionBenchmark - PROPERTIES FOLDER "Magnum/Math/Geometry/Test") - -set_property(TARGET - MathGeometryIntersectionTest - APPEND PROPERTY COMPILE_DEFINITIONS "CORRADE_GRACEFUL_ASSERT") diff --git a/src/Magnum/Math/Intersection.h b/src/Magnum/Math/Intersection.h new file mode 100644 index 000000000..5ca03b9c0 --- /dev/null +++ b/src/Magnum/Math/Intersection.h @@ -0,0 +1,625 @@ +#ifndef Magnum_Math_Intersection_h +#define Magnum_Math_Intersection_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + Vladimír Vondruš + Copyright © 2016, 2018 Jonathan Hale + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Namespace @ref Magnum::Math::Intersection + */ + +#include "Magnum/Math/Distance.h" +#include "Magnum/Math/Frustum.h" +#include "Magnum/Math/Range.h" +#include "Magnum/Math/Vector2.h" +#include "Magnum/Math/Vector3.h" +#include "Magnum/Math/Matrix4.h" + +namespace Magnum { namespace Math { namespace Intersection { + +/** +@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 + +Returns intersection point positions @f$ t @f$, @f$ u @f$ on both lines: + +- @f$ t, u = \mathrm{NaN} @f$ if the lines are collinear +- @f$ t \in [ 0 ; 1 ] @f$ if the intersection is inside the line segment + defined by @f$ \boldsymbol{p} @f$ and @f$ \boldsymbol{p} + \boldsymbol{r} @f$ +- @f$ t \notin [ 0 ; 1 ] @f$ if the intersection is outside the line segment +- @f$ u \in [ 0 ; 1 ] @f$ if the intersection is inside the line segment + defined by @f$ \boldsymbol{q} @f$ and @f$ \boldsymbol{q} + \boldsymbol{s} @f$ +- @f$ u \notin [ 0 ; 1 ] @f$ if the intersection is outside the line segment +- @f$ t, u \in \{-\infty, \infty\} @f$ if the intersection doesn't exist (the + 2D lines are parallel) + +The two lines intersect if @f$ t @f$ and @f$ u @f$ exist such that: @f[ + \boldsymbol p + t \boldsymbol r = \boldsymbol q + u \boldsymbol s +@f] +Crossing both sides with @f$ \boldsymbol{s} @f$, distributing the cross product +and eliminating @f$ \boldsymbol s \times \boldsymbol s = 0 @f$, then solving +for @f$ t @f$ and similarly for @f$ u @f$: @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 @ref lineSegmentLine() which calculates only @f$ t @f$, useful if you +don't need to test that the intersection lies inside line segment defined by +@f$ \boldsymbol{q} @f$ and @f$ \boldsymbol{q} + \boldsymbol{s} @f$. + +@see @ref isInf(), @ref isNan() +*/ +template inline std::pair lineSegmentLineSegment(const Vector2& p, const Vector2& r, const Vector2& q, const Vector2& s) { + const Vector2 qp = q - p; + const T rs = cross(r, s); + return {cross(qp, s)/rs, 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 + +Returns intersection point position @f$ t @f$ on the first line: + +- @f$ t = \mathrm{NaN} @f$ if the lines are collinear +- @f$ t \in [ 0 ; 1 ] @f$ if the intersection is inside the line segment + defined by @f$ \boldsymbol{p} @f$ and @f$ \boldsymbol{p} + \boldsymbol{r} @f$ +- @f$ t \notin [ 0 ; 1 ] @f$ if the intersection is outside the line segment +- @f$ t \in \{-\infty, \infty\} @f$ if the intersection doesn't exist (the 2D + lines are parallel) + +Unlike @ref lineSegmentLineSegment() calculates only @f$ t @f$. + +@see @ref isInf(), @ref isNan() +*/ +template inline T lineSegmentLine(const Vector2& p, const Vector2& r, const Vector2& q, const Vector2& s) { + return cross(q - p, s)/cross(r, s); +} + +/** +@brief Intersection of a plane and line +@param planePosition Plane position +@param planeNormal Plane normal +@param p Starting point of the line +@param r Direction of the line + +Returns intersection point position @f$ t @f$ on the line: + +- @f$ t = \mathrm{NaN} @f$ if the line lies on the plane +- @f$ t \in [ 0 ; 1 ] @f$ if the intersection is inside the line segment + defined by @f$ \boldsymbol{p} @f$ and @f$ \boldsymbol{p} + \boldsymbol{r} @f$ +- @f$ t \notin [ 0 ; 1 ] @f$ if the intersection is outside the line segment +- @f$ t \in \{-\infty, \infty\} @f$ if the intersection doesn't exist + +First the parameter @f$ f @f$ of parametric equation of the plane is calculated +from plane normal @f$ \boldsymbol{n} @f$ and plane position: @f[ + \begin{pmatrix} n_0 \\ n_1 \\ n_2 \end{pmatrix} \cdot + \begin{pmatrix} x \\ y \\ z \end{pmatrix} - f = 0 +@f] +Using plane normal @f$ \boldsymbol{n} @f$, parameter @f$ f @f$ and line defined +by @f$ \boldsymbol{p} @f$ and @f$ \boldsymbol{r} @f$, value of @f$ t @f$ is +calculated and returned. @f[ + \begin{array}{rcl} + f & = & \boldsymbol n \cdot (\boldsymbol p + t \boldsymbol r) \\ + \Rightarrow t & = & \cfrac{f - \boldsymbol n \cdot \boldsymbol p}{\boldsymbol n \cdot \boldsymbol r} + \end{array} +@f] + +@see @ref isInf(), @ref isNan() +*/ +template inline T planeLine(const Vector3& planePosition, const Vector3& planeNormal, const Vector3& p, const Vector3& r) { + const T f = dot(planePosition, planeNormal); + return (f - dot(planeNormal, p))/dot(planeNormal, r); +} + +/** +@brief Intersection of a point and a frustum +@param point Point +@param frustum Frustum planes with normals pointing outwards +@return @cpp true @ce if the point is on or inside the frustum, @cpp false @ce + otherwise + +Checks for each plane of the frustum whether the point is behind the plane (the +points distance from the plane is negative) using @ref Distance::pointPlaneScaled(). +*/ +template bool pointFrustum(const Vector3& point, const Frustum& frustum); + +/** +@brief Intersection of a range and a frustum +@param range Range +@param frustum Frustum planes with normals pointing outwards +@return @cpp true @ce if the box intersects with the frustum, @cpp false @ce + otherwise + +Uses the "p/n-vertex" approach: First converts the @ref Range3D into a +representation using center and extent which allows using the following +condition for whether the plane is intersecting the box: @f[ + \begin{array}{rcl} + d & = & \boldsymbol c \cdot \boldsymbol n \\ + r & = & \boldsymbol c \cdot \text{abs}(\boldsymbol n) \\ + d + r & < & -w + \end{array} +@f] + +for plane normal @f$ \boldsymbol n @f$ and determinant @f$ w @f$. + +@see @ref aabbFrustum() +*/ +template bool rangeFrustum(const Range3D& range, const Frustum& frustum); + +/** +@brief Intersection of an axis-aligned box and a frustum +@param aabbCenter Center of the AABB +@param aabbExtents (Half-)extents of the AABB +@param frustum Frustum planes with normals pointing outwards +@return @cpp true @ce if the box intersects with the frustum, @cpp false @ce + otherwise + +Uses the same method as @ref rangeFrustum(), but does not need to convert to +center/extents representation. +*/ +template bool aabbFrustum(const Vector3& aabbCenter, const Vector3& aabbExtents, const Frustum& frustum); + +/** +@brief Intersection of a sphere and a frustum +@param sphereCenter Sphere center +@param sphereRadius Sphere radius +@param frustum Frustum planes with normals pointing outwards +@return @cpp true @ce if the sphere intersects the frustum, @cpp false @ce + otherwise + +Checks for each plane of the frustum whether the sphere is behind the plane +(the points distance larger than the sphere's radius) using +@ref Distance::pointPlaneScaled(). +*/ +template bool sphereFrustum(const Vector3& sphereCenter, T sphereRadius, const Frustum& frustum); + +/** +@brief Intersection of a point and a cone +@param point The point +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param coneAngle Apex angle of the cone +@return @cpp true @ce if the point is inside the cone, @cpp false @ce otherwise + +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref pointCone(const Vector3&, const Vector3&, const Vector3&, T). +*/ +template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); + +/** +@brief Intersection of a point and a cone using precomputed values +@param point The point +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation +@return @cpp true @ce if the point is inside the cone, @cpp false @ce + otherwise + +The @p tanAngleSqPlusOne parameter can be calculated as: + +@code{.cpp} +Math::pow<2>(Math::tan(angle*T(0.5))) + T(1) +@endcode +*/ +template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); + +/** +@brief Intersection of a point and a double cone +@param point The point +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param coneAngle Apex angle of the cone +@return @cpp true @ce if the point is inside the double cone, @cpp false @ce + otherwise + +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref pointDoubleCone(const Vector3&, const Vector3&, const Vector3&, T). +*/ +template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); + +/** +@brief Intersection of a point and a double cone using precomputed values +@param point The point +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation +@return @cpp true @ce if the point is inside the double cone, @cpp false @ce + otherwise + +The @p tanAngleSqPlusOne parameter can be precomputed like this: + +@code{.cpp} +T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); +@endcode +*/ +template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); + +/** +@brief Intersection of a sphere and a cone view +@param sphereCenter Center of the sphere +@param sphereRadius Radius of the sphere +@param coneView View matrix with translation and rotation of the cone +@param coneAngle Apex angle of the cone (@f$ 0 < \Theta < \pi @f$) +@return @cpp true @ce if the sphere intersects the cone, @cpp false @ce + otherwise + +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref sphereConeView(const Vector3&, T, const Matrix4&, T, T). +*/ +template bool sphereConeView(const Vector3& sphereCenter, T sphereRadius, const Matrix4& coneView, Rad coneAngle); + +/** +@brief Intersection of a sphere and a cone view +@param sphereCenter Sphere center +@param sphereRadius Sphere radius +@param coneView View matrix with translation and rotation of the cone +@param sinAngle Precomputed sine of half the cone's opening angle +@param tanAngle Precomputed tangent of half the cone's opening angle +@return @cpp true @ce if the sphere intersects the cone, @cpp false @ce + otherwise + +Transforms the sphere center into cone space (using the cone view matrix) and +performs sphere-cone intersection with the zero-origin -Z axis-aligned cone. +The @p sinAngle, @p cosAngle, @p tanAngle can be precomputed like this: + +@code{.cpp} +T sinAngle = Math::sin(angle*T(0.5)); +T tanAngle = Math::tan(angle*T(0.5)); +@endcode +*/ +template bool sphereConeView(const Vector3& sphereCenter, T sphereRadius, const Matrix4& coneView, T sinAngle, T tanAngle); + +/** +@brief Intersection of a sphere and a cone +@param sphereCenter Sphere center +@param sphereRadius Sphere radius +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param coneAngle Apex angle of the cone (@f$ 0 < \Theta < \pi @f$) +@return @cpp true @ce if the sphere intersects with the cone, @cpp false @ce + otherwise + +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref sphereCone(const Vector3& sphereCenter, T, const Vector3&, const Vector3&, T, T). +*/ +template bool sphereCone(const Vector3& sphereCenter, T sphereRadius, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); + +/** +@brief Intersection of a sphere and a cone using precomputed values +@param sphereCenter Sphere center +@param sphereRadius Sphere radius +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param sinAngle Precomputed sine of half the cone's opening angle +@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation +@return @cpp true @ce if the sphere intersects with the cone, @cpp false @ce + otherwise + +Offsets the cone plane by @f$ -r\sin{\frac{\Theta}{2}} \cdot \boldsymbol n @f$ +(with @f$ \Theta @f$ being the cone apex angle) which separates two +half-spaces: In front of the plane, in which the sphere cone intersection test +is equivalent to testing the sphere's center against a similarly offset cone +(which is equivalent the cone with surface expanded by @f$ r @f$ in surface +normal direction), and behind the plane, where the test is equivalent to +testing whether the origin of the original cone intersects the sphere. The +@p sinAngle and @p tanAngleSqPlusOne parameters can be precomputed like this: + +@code{.cpp} +T sinAngle = Math::sin(angle*T(0.5)); +T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); +@endcode +*/ +template bool sphereCone(const Vector3& sphereCenter, T sphereRadius, const Vector3& coneOrigin, const Vector3& coneNormal, T sinAngle, T tanAngleSqPlusOne); + +/** +@brief Intersection of an axis aligned bounding box and a cone +@param aabbCenter Center of the AABB +@param aabbExtents (Half-)extents of the AABB +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param coneAngle Apex angle of the cone (@f$ 0 < \Theta < \pi @f$) +@return @cpp true @ce if the box intersects the cone, @cpp false @ce otherwise + +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref aabbCone(const Vector3&, const Vector3&, const Vector3&, const Vector3&, T). +*/ +template bool aabbCone(const Vector3& aabbCenter, const Vector3& aabbExtents, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); + +/** +@brief Intersection of an axis aligned bounding box and a cone using precomputed values +@param aabbCenter Center of the AABB +@param aabbExtents (Half-)extents of the AABB +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation +@return @cpp true @ce if the box intersects the cone, @cpp false @ce otherwise + +On each axis finds the intersection points of the cone's axis with infinite +planes obtained by extending the two faces of the box that are perpendicular to +that axis. The intersection points on the planes perpendicular to axis +@f$ a \in \{ 0, 1, 2 \} @f$ are given by @f[ + \boldsymbol i = \boldsymbol n \cdot \frac{(\boldsymbol c_a - \boldsymbol o_a) \pm \boldsymbol e_a}{\boldsymbol n_a} +@f] + +with normal @f$ \boldsymbol n @f$, cone origin @f$ \boldsymbol o @f$, box +center @f$ \boldsymbol c @f$ and box extents @f$ \boldsymbol e @f$. The points +on the faces that are closest to this intersection point are the closest to the +cone's axis and are tested for intersection with the cone using +@ref pointCone(const Vector3&, const Vector3&, const Vector3&, const T) "pointCone()". As soon as an intersecting point is found, the function returns +@cpp true @ce. If all points lie outside of the cone, it will return +@cpp false @ce. + +The @p tanAngleSqPlusOne parameter can be precomputed like this: + +@code{.cpp} +T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); +@endcode +*/ +template bool aabbCone(const Vector3& aabbCenter, const Vector3& aabbExtents, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); + +/** +@brief Intersection of a range and a cone +@param range Range +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param coneAngle Apex angle of the cone (@f$ 0 < \Theta < \pi @f$) +@return @cpp true @ce if the range intersects the cone, @cpp false @ce + otherwise + +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref rangeCone(const Range3D&, const Vector3&, const Vector3&, T). +*/ +template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle); + +/** +@brief Intersection of a range and a cone using precomputed values +@param range Range +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation +@return @cpp true @ce if the range intersects the cone, @cpp false @ce + otherwise + +Converts the range into center/extents representation and passes it on to +@ref aabbCone(const Vector3&, const Vector3&, const Vector3&, const Vector3&, T) "aabbCone()". The @p tanAngleSqPlusOne parameter can be precomputed like this: + +@code{.cpp} +T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); +@endcode +*/ +template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne); + +template bool pointFrustum(const Vector3& point, const Frustum& frustum) { + for(const Vector4& plane: frustum.planes()) { + /* The point is in front of one of the frustum planes (normals point + outwards) */ + if(Distance::pointPlaneScaled(point, plane) < T(0)) + return false; + } + + return true; +} + +template bool rangeFrustum(const Range3D& range, const Frustum& frustum) { + /* Convert to center/extent, avoiding division by 2 and instead comparing + to 2*-plane.w() later */ + const Vector3 center = range.min() + range.max(); + const Vector3 extent = range.max() - range.min(); + + for(const Vector4& plane: frustum.planes()) { + const Vector3 absPlaneNormal = Math::abs(plane.xyz()); + + const Float d = Math::dot(center, plane.xyz()); + const Float r = Math::dot(extent, absPlaneNormal); + if(d + r < -T(2)*plane.w()) return false; + } + + return true; +} + +template bool aabbFrustum(const Vector3& aabbCenter, const Vector3& aabbExtents, const Frustum& frustum) { + for(const Vector4& plane: frustum.planes()) { + const Vector3 absPlaneNormal = Math::abs(plane.xyz()); + + const Float d = Math::dot(aabbCenter, plane.xyz()); + const Float r = Math::dot(aabbExtents, absPlaneNormal); + if(d + r < -plane.w()) return false; + } + + return true; +} + +template bool sphereFrustum(const Vector3& sphereCenter, const T sphereRadius, const Frustum& frustum) { + const T radiusSq = sphereRadius*sphereRadius; + + for(const Vector4& plane: frustum.planes()) { + /* The sphere is in front of one of the frustum planes (normals point + outwards) */ + if(Distance::pointPlaneScaled(sphereCenter, plane) < -radiusSq) + return false; + } + + return true; +} + + +template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { + const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1); + return pointCone(point, coneOrigin, coneNormal, tanAngleSqPlusOne); +} + +template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) { + const Vector3 c = point - coneOrigin; + const T lenA = dot(c, coneNormal); + + return lenA >= 0 && c.dot() <= lenA*lenA*tanAngleSqPlusOne; +} + +template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { + const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1); + return pointDoubleCone(point, coneOrigin, coneNormal, tanAngleSqPlusOne); +} + +template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) { + const Vector3 c = point - coneOrigin; + const T lenA = dot(c, coneNormal); + + return c.dot() <= lenA*lenA*tanAngleSqPlusOne; +} + +template bool sphereConeView(const Vector3& sphereCenter, const T sphereRadius, const Matrix4& coneView, const Rad coneAngle) { + const Rad halfAngle = coneAngle*T(0.5); + const T sinAngle = Math::sin(halfAngle); + const T tanAngle = Math::tan(halfAngle); + + return sphereConeView(sphereCenter, sphereRadius, coneView, sinAngle, tanAngle); +} + +template bool sphereConeView(const Vector3& sphereCenter, const T sphereRadius, const Matrix4& coneView, const T sinAngle, const T tanAngle) { + CORRADE_ASSERT(coneView.isRigidTransformation(), "Math::Geometry::Intersection::sphereConeView(): coneView does not represent a rigid transformation", false); + + /* Transform the sphere so that we can test against Z axis aligned origin + cone instead */ + const Vector3 center = coneView.transformPoint(sphereCenter); + + /* Test against plane which determines whether to test against shifted cone + or center-sphere */ + if (-center.z() > -sphereRadius*sinAngle) { + /* Point - axis aligned cone test, shifted so that the cone's surface + is extended by the radius of the sphere */ + const T coneRadius = tanAngle*(center.z() - sphereRadius/sinAngle); + return center.xy().dot() <= coneRadius*coneRadius; + } else { + /* Simple sphere point check */ + return center.dot() <= sphereRadius*sphereRadius; + } + + return false; +} + +template bool sphereCone( + const Vector3& sphereCenter, const T sphereRadius, + const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) +{ + const Rad halfAngle = coneAngle*T(0.5); + const T sinAngle = Math::sin(halfAngle); + const T tanAngleSqPlusOne = T(1) + Math::pow(Math::tan(halfAngle), T(2)); + + return sphereCone(sphereCenter, sphereRadius, coneOrigin, coneNormal, sinAngle, tanAngleSqPlusOne); +} + +template bool sphereCone( + const Vector3& sphereCenter, const T sphereRadius, + const Vector3& coneOrigin, const Vector3& coneNormal, + const T sinAngle, const T tanAngleSqPlusOne) +{ + const Vector3 diff = sphereCenter - coneOrigin; + + /* Point - cone test */ + if(Math::dot(diff - sphereRadius*sinAngle*coneNormal, coneNormal) > T(0)) { + const Vector3 c = sinAngle*diff + coneNormal*sphereRadius; + const T lenA = Math::dot(c, coneNormal); + + return c.dot() <= lenA*lenA*tanAngleSqPlusOne; + + /* Simple sphere point check */ + } else return diff.dot() <= sphereRadius*sphereRadius; +} + +template bool aabbCone( + const Vector3& aabbCenter, const Vector3& aabbExtents, + const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) +{ + const T tanAngleSqPlusOne = Math::pow(Math::tan(coneAngle*T(0.5)), T(2)) + T(1); + return aabbCone(aabbCenter, aabbExtents, coneOrigin, coneNormal, tanAngleSqPlusOne); +} + +template bool aabbCone( + const Vector3& aabbCenter, const Vector3& aabbExtents, + const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) +{ + const Vector3 c = aabbCenter - coneOrigin; + + for(const Int axis: {0, 1, 2}) { + const Int z = axis; + const Int x = (axis + 1) % 3; + const Int y = (axis + 2) % 3; + if(coneNormal[z] != T(0)) { + const Float t0 = ((c[z] - aabbExtents[z])/coneNormal[z]); + const Float t1 = ((c[z] + aabbExtents[z])/coneNormal[z]); + + const Vector3 i0 = coneNormal*t0; + const Vector3 i1 = coneNormal*t1; + + for(const auto& i : {i0, i1}) { + Vector3 closestPoint = i; + + if(i[x] - c[x] > aabbExtents[x]) { + closestPoint[x] = c[x] + aabbExtents[x]; + } else if(i[x] - c[x] < -aabbExtents[x]) { + closestPoint[x] = c[x] - aabbExtents[x]; + } /* Else: normal intersects within x bounds */ + + if(i[y] - c[y] > aabbExtents[y]) { + closestPoint[y] = c[y] + aabbExtents[y]; + } else if(i[y] - c[y] < -aabbExtents[y]) { + closestPoint[y] = c[y] - aabbExtents[y]; + } /* Else: normal intersects within Y bounds */ + + /* Found a point in cone and aabb */ + if(pointCone(closestPoint, {}, coneNormal, tanAngleSqPlusOne)) + return true; + } + } /* Else: normal will intersect one of the other planes */ + } + + return false; +} + +template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { + const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1); + return rangeCone(range, coneOrigin, coneNormal, tanAngleSqPlusOne); +} + +template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) { + const Vector3 center = (range.min() + range.max())*T(0.5); + const Vector3 extents = (range.max() - range.min())*T(0.5); + return aabbCone(center, extents, coneOrigin, coneNormal, tanAngleSqPlusOne); +} + +}}} + +#endif diff --git a/src/Magnum/Math/Test/CMakeLists.txt b/src/Magnum/Math/Test/CMakeLists.txt index 3a760700f..9563699da 100644 --- a/src/Magnum/Math/Test/CMakeLists.txt +++ b/src/Magnum/Math/Test/CMakeLists.txt @@ -56,6 +56,10 @@ corrade_add_test(MathDualQuaternionTest DualQuaternionTest.cpp LIBRARIES MagnumM corrade_add_test(MathBezierTest BezierTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MathFrustumTest FrustumTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathDistanceTest DistanceTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathIntersectionTest IntersectionTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(MathIntersectionBenchmark IntersectionBenchmark.cpp LIBRARIES MagnumMathTestLib) + set_property(TARGET MathVectorTest MathMatrixTest @@ -65,6 +69,9 @@ set_property(TARGET MathDualComplexTest MathQuaternionTest MathDualQuaternionTest + + MathDistanceTest + MathIntersectionTest APPEND PROPERTY COMPILE_DEFINITIONS "CORRADE_GRACEFUL_ASSERT") set_target_properties( @@ -100,4 +107,8 @@ set_target_properties( MathBezierTest MathFrustumTest + + MathDistanceTest + MathIntersectionTest + MathIntersectionBenchmark PROPERTIES FOLDER "Magnum/Math/Test") diff --git a/src/Magnum/Math/Geometry/Test/DistanceTest.cpp b/src/Magnum/Math/Test/DistanceTest.cpp similarity index 97% rename from src/Magnum/Math/Geometry/Test/DistanceTest.cpp rename to src/Magnum/Math/Test/DistanceTest.cpp index e731c5703..273a34f0d 100644 --- a/src/Magnum/Math/Geometry/Test/DistanceTest.cpp +++ b/src/Magnum/Math/Test/DistanceTest.cpp @@ -28,9 +28,9 @@ #include #include "Magnum/Math/Constants.h" -#include "Magnum/Math/Geometry/Distance.h" +#include "Magnum/Math/Distance.h" -namespace Magnum { namespace Math { namespace Geometry { namespace Test { +namespace Magnum { namespace Math { namespace Test { struct DistanceTest: Corrade::TestSuite::Tester { explicit DistanceTest(); @@ -194,6 +194,6 @@ void DistanceTest::pointPlaneNormalized() { CORRADE_COMPARE(o.str(), "Math::Geometry::Distance::pointPlaneNormalized(): plane normal is not an unit vector\n"); } -}}}} +}}} -CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::DistanceTest) +CORRADE_TEST_MAIN(Magnum::Math::Test::DistanceTest) diff --git a/src/Magnum/Math/Geometry/Test/IntersectionBenchmark.cpp b/src/Magnum/Math/Test/IntersectionBenchmark.cpp similarity index 97% rename from src/Magnum/Math/Geometry/Test/IntersectionBenchmark.cpp rename to src/Magnum/Math/Test/IntersectionBenchmark.cpp index 4a946b35e..cb12d0685 100644 --- a/src/Magnum/Math/Geometry/Test/IntersectionBenchmark.cpp +++ b/src/Magnum/Math/Test/IntersectionBenchmark.cpp @@ -29,11 +29,10 @@ #include #include -#include "Magnum/Math/Geometry/Intersection.h" #include "Magnum/Math/Angle.h" -#include "Magnum/Math/Matrix4.h" +#include "Magnum/Math/Intersection.h" -namespace Magnum { namespace Math { namespace Geometry { namespace Test { +namespace Magnum { namespace Math { namespace Test { template bool rangeFrustumNaive(const Math::Range3D& box, const Math::Frustum& frustum) { for(const Math::Vector4& plane: frustum.planes()) { @@ -219,6 +218,6 @@ void IntersectionBenchmark::sphereConeView() { } } -}}}} +}}} -CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::IntersectionBenchmark) +CORRADE_TEST_MAIN(Magnum::Math::Test::IntersectionBenchmark) diff --git a/src/Magnum/Math/Geometry/Test/IntersectionTest.cpp b/src/Magnum/Math/Test/IntersectionTest.cpp similarity index 98% rename from src/Magnum/Math/Geometry/Test/IntersectionTest.cpp rename to src/Magnum/Math/Test/IntersectionTest.cpp index 95071deb1..d47368693 100644 --- a/src/Magnum/Math/Geometry/Test/IntersectionTest.cpp +++ b/src/Magnum/Math/Test/IntersectionTest.cpp @@ -27,10 +27,9 @@ #include #include -#include "Magnum/Math/Geometry/Intersection.h" -#include "Magnum/Math/Angle.h" +#include "Magnum/Math/Intersection.h" -namespace Magnum { namespace Math { namespace Geometry { namespace Test { +namespace Magnum { namespace Math { namespace Test { using namespace Literals; @@ -440,6 +439,6 @@ void IntersectionTest::aabbCone() { CORRADE_VERIFY(!Intersection::aabbCone(-15.0f*normal, Vector3{1.0f}, center, normal, angle)); } -}}}} +}}} -CORRADE_TEST_MAIN(Magnum::Math::Geometry::Test::IntersectionTest) +CORRADE_TEST_MAIN(Magnum::Math::Test::IntersectionTest) diff --git a/src/Magnum/Shapes/Capsule.cpp b/src/Magnum/Shapes/Capsule.cpp index ae6495a5b..1bd576ffb 100644 --- a/src/Magnum/Shapes/Capsule.cpp +++ b/src/Magnum/Shapes/Capsule.cpp @@ -26,15 +26,13 @@ #include "Capsule.h" #include "Magnum/Magnum.h" +#include "Magnum/Math/Distance.h" #include "Magnum/Math/Functions.h" #include "Magnum/Math/Matrix3.h" #include "Magnum/Math/Matrix4.h" -#include "Magnum/Math/Geometry/Distance.h" #include "Magnum/Shapes/Point.h" #include "Magnum/Shapes/Sphere.h" -using namespace Magnum::Math::Geometry; - namespace Magnum { namespace Shapes { template Capsule Capsule::transformed(const MatrixTypeFor& matrix) const { @@ -42,12 +40,12 @@ template Capsule Capsule::transf } template bool Capsule::operator%(const Point& other) const { - return Distance::lineSegmentPointSquared(_a, _b, other.position()) < + return Math::Distance::lineSegmentPointSquared(_a, _b, other.position()) < Math::pow<2>(_radius); } template bool Capsule::operator%(const Sphere& other) const { - return Distance::lineSegmentPointSquared(_a, _b, other.position()) < + return Math::Distance::lineSegmentPointSquared(_a, _b, other.position()) < Math::pow<2>(_radius+other.radius()); } diff --git a/src/Magnum/Shapes/Cylinder.cpp b/src/Magnum/Shapes/Cylinder.cpp index 746f5895b..01a6db035 100644 --- a/src/Magnum/Shapes/Cylinder.cpp +++ b/src/Magnum/Shapes/Cylinder.cpp @@ -26,15 +26,13 @@ #include "Cylinder.h" #include "Magnum/Magnum.h" +#include "Magnum/Math/Distance.h" #include "Magnum/Math/Functions.h" #include "Magnum/Math/Matrix3.h" #include "Magnum/Math/Matrix4.h" -#include "Magnum/Math/Geometry/Distance.h" #include "Magnum/Shapes/Point.h" #include "Magnum/Shapes/Sphere.h" -using namespace Magnum::Math::Geometry; - namespace Magnum { namespace Shapes { template Cylinder Cylinder::transformed(const MatrixTypeFor& matrix) const { @@ -42,12 +40,12 @@ template Cylinder Cylinder::tran } template bool Cylinder::operator%(const Point& other) const { - return Distance::linePointSquared(_a, _b, other.position()) < + return Math::Distance::linePointSquared(_a, _b, other.position()) < Math::pow<2>(_radius); } template bool Cylinder::operator%(const Sphere& other) const { - return Distance::linePointSquared(_a, _b, other.position()) < + return Math::Distance::linePointSquared(_a, _b, other.position()) < Math::pow<2>(_radius+other.radius()); } diff --git a/src/Magnum/Shapes/Plane.cpp b/src/Magnum/Shapes/Plane.cpp index f11b6f758..c001d789c 100644 --- a/src/Magnum/Shapes/Plane.cpp +++ b/src/Magnum/Shapes/Plane.cpp @@ -25,12 +25,10 @@ #include "Plane.h" +#include "Magnum/Math/Intersection.h" #include "Magnum/Math/Matrix4.h" -#include "Magnum/Math/Geometry/Intersection.h" #include "Magnum/Shapes/LineSegment.h" -using namespace Magnum::Math::Geometry; - namespace Magnum { namespace Shapes { Plane Plane::transformed(const Matrix4& matrix) const { @@ -42,12 +40,12 @@ Plane Plane::transformed(const Matrix4& matrix) const { } bool Plane::operator%(const Line3D& other) const { - Float t = Intersection::planeLine(_position, _normal, other.a(), other.b()-other.a()); + Float t = Math::Intersection::planeLine(_position, _normal, other.a(), other.b()-other.a()); return t != t || (t != Constants::inf() && t != -Constants::inf()); } bool Plane::operator%(const LineSegment3D& other) const { - Float t = Intersection::planeLine(_position, _normal, other.a(), other.b()-other.a()); + Float t = Math::Intersection::planeLine(_position, _normal, other.a(), other.b()-other.a()); return t > 0.0f && t < 1.0f; } diff --git a/src/Magnum/Shapes/Sphere.cpp b/src/Magnum/Shapes/Sphere.cpp index 57ed03cef..d636513de 100644 --- a/src/Magnum/Shapes/Sphere.cpp +++ b/src/Magnum/Shapes/Sphere.cpp @@ -26,15 +26,13 @@ #include "Sphere.h" #include "Magnum/Magnum.h" +#include "Magnum/Math/Distance.h" #include "Magnum/Math/Functions.h" #include "Magnum/Math/Matrix3.h" #include "Magnum/Math/Matrix4.h" -#include "Magnum/Math/Geometry/Distance.h" #include "Magnum/Shapes/LineSegment.h" #include "Magnum/Shapes/Point.h" -using namespace Magnum::Math::Geometry; - namespace Magnum { namespace Shapes { template Sphere Sphere::transformed(const MatrixTypeFor& matrix) const { @@ -88,11 +86,11 @@ template Collision InvertedSphere bool Sphere::operator%(const Line& other) const { - return Distance::linePointSquared(other.a(), other.b(), _position) < Math::pow<2>(_radius); + return Math::Distance::linePointSquared(other.a(), other.b(), _position) < Math::pow<2>(_radius); } template bool Sphere::operator%(const LineSegment& other) const { - return Distance::lineSegmentPointSquared(other.a(), other.b(), _position) < Math::pow<2>(_radius); + return Math::Distance::lineSegmentPointSquared(other.a(), other.b(), _position) < Math::pow<2>(_radius); } template bool Sphere::operator%(const Sphere& other) const {