Browse Source

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.
pull/255/head
Vladimír Vondruš 8 years ago
parent
commit
5d60f0d350
  1. 35
      doc/changelog.dox
  2. 26
      doc/namespaces.dox
  3. 6
      src/Magnum/Math/CMakeLists.txt
  4. 276
      src/Magnum/Math/Distance.h
  5. 4
      src/Magnum/Math/Frustum.h
  6. 4
      src/Magnum/Math/Geometry/CMakeLists.txt
  7. 295
      src/Magnum/Math/Geometry/Distance.h
  8. 625
      src/Magnum/Math/Geometry/Intersection.h
  9. 40
      src/Magnum/Math/Geometry/Test/CMakeLists.txt
  10. 625
      src/Magnum/Math/Intersection.h
  11. 11
      src/Magnum/Math/Test/CMakeLists.txt
  12. 8
      src/Magnum/Math/Test/DistanceTest.cpp
  13. 9
      src/Magnum/Math/Test/IntersectionBenchmark.cpp
  14. 9
      src/Magnum/Math/Test/IntersectionTest.cpp
  15. 8
      src/Magnum/Shapes/Capsule.cpp
  16. 8
      src/Magnum/Shapes/Cylinder.cpp
  17. 8
      src/Magnum/Shapes/Plane.cpp
  18. 8
      src/Magnum/Shapes/Sphere.cpp

35
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

26
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`

6
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)

276
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š <mosra@centrum.cz>
Copyright © 2016 Jonathan Hale <squareys@googlemail.com>
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<T>&, const Vector2<T>&, const Vector2<T>&)
for comparing distance with other values, because it doesn't calculate the
square root.
*/
template<class T> inline T linePointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> 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<T>&, const Vector2<T>&) "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<T>&, const Vector2<T>&, const Vector2<T>&)
*/
template<class T> inline T linePoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> bMinusA = b - a;
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<T>&, const Vector3<T>&, const Vector3<T>&)
for comparing distance with other values, because it doesn't calculate the
square root.
*/
template<class T> inline T linePointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return cross(point - a, point - b).dot()/(b - a).dot();
}
/**
@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<T>&, const Vector3<T>&) "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<T>&, const Vector3<T>&, const Vector3<T>&)
*/
template<class T> inline T linePoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return std::sqrt(linePointSquared(a, b, point));
}
/**
@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<class T> T lineSegmentPointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& 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<class T> T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point);
/**
@brief Distance of point from line segment in 3D, squared
More efficient than @ref lineSegmentPoint(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
for comparing distance with other values, because it doesn't calculate the
square root.
*/
template<class T> T lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& 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<T>&, const Vector2<T>&, const Vector2<T>&).
@see @ref lineSegmentPointSquared(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
*/
template<class T> inline T lineSegmentPoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& 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<class T> inline T pointPlaneScaled(const Vector3<T>& point, const Vector4<T>& 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<class T> inline T pointPlane(const Vector3<T>& point, const Vector4<T>& plane) {
return pointPlaneScaled<T>(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<class T> inline T pointPlaneNormalized(const Vector3<T>& point, const Vector4<T>& plane) {
CORRADE_ASSERT(plane.xyz().isNormalized(),
"Math::Geometry::Distance::pointPlaneNormalized(): plane normal is not an unit vector", {});
return pointPlaneScaled<T>(point, plane);
}
template<class T> T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> pointMinusA = point - a;
const Vector2<T> pointMinusB = point - b;
const Vector2<T> 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<class T> T lineSegmentPointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> pointMinusA = point - a;
const Vector2<T> pointMinusB = point - b;
const Vector2<T> 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<class T> T lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
const Vector3<T> pointMinusA = point - a;
const Vector3<T> 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

4
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 T> class Frustum {
public:

4
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()

295
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<T>&, const Vector2<T>&, const Vector2<T>&)
for comparing distance with other values, because it doesn't calculate the
square root.
*/
template<class T> inline T linePointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> 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<T>&, const Vector2<T>&) "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<T>&, const Vector2<T>&, const Vector2<T>&)
*/
template<class T> inline T linePoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> bMinusA = b - a;
return std::abs(cross(bMinusA, a - point))/bMinusA.length();
/** @brief @copybrief Math::Distance::linePointSquared(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* @deprecated Use @ref Math::Distance::linePointSquared(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::linePointSquared() instead") T linePointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
return Math::Distance::linePointSquared(a, b, point);
}
/**
@brief Distance of line and point in 3D, squared
More efficient than @ref linePoint(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
for comparing distance with other values, because it doesn't calculate the
square root.
*/
template<class T> inline T linePointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return cross(point - a, point - b).dot()/(b - a).dot();
/** @brief @copybrief Math::Distance::linePoint(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* @deprecated Use @ref Math::Distance::linePoint(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::linePoint() instead") T linePoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& 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<T>&, const Vector3<T>&) "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<T>&, const Vector3<T>&, const Vector3<T>&)
*/
template<class T> inline T linePoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return std::sqrt(linePointSquared(a, b, point));
/** @brief @copybrief Math::Distance::linePointSquared(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
* @deprecated Use @ref Math::Distance::linePointSquared(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::linePointSquared() instead") T linePointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& 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<class T> T lineSegmentPointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& 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<class T> T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point);
/**
@brief Distance of point from line segment in 3D, squared
More efficient than @ref lineSegmentPoint(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
for comparing distance with other values, because it doesn't calculate the
square root.
*/
template<class T> T lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& 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<T>&, const Vector2<T>&, const Vector2<T>&).
@see @ref lineSegmentPointSquared(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
*/
template<class T> inline T lineSegmentPoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return std::sqrt(lineSegmentPointSquared(a, b, point));
/** @brief @copybrief Math::Distance::linePoint(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
* @deprecated Use @ref Math::Distance::linePoint(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::linePoint() instead") T linePoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& 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<class T> inline T pointPlaneScaled(const Vector3<T>& point, const Vector4<T>& plane) {
return dot(plane.xyz(), point) + plane.w();
/** @brief @copybrief Math::Distance::lineSegmentPointSquared(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* @deprecated Use @ref Math::Distance::lineSegmentPointSquared(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::lineSegmentPointSquared() instead") T lineSegmentPointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& 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<class T> inline T pointPlane(const Vector3<T>& point, const Vector4<T>& plane) {
return pointPlaneScaled<T>(point, plane)/plane.xyz().length();
/** @brief @copybrief Math::Distance::lineSegmentPoint(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* @deprecated Use @ref Math::Distance::lineSegmentPoint(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::lineSegmentPoint() instead") T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& 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<class T> inline T pointPlaneNormalized(const Vector3<T>& point, const Vector4<T>& plane) {
CORRADE_ASSERT(plane.xyz().isNormalized(),
"Math::Geometry::Distance::pointPlaneNormalized(): plane normal is not an unit vector", {});
return pointPlaneScaled<T>(point, plane);
/** @brief @copybrief Math::Distance::lineSegmentPointSquared(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
* @deprecated Use @ref Math::Distance::lineSegmentPointSquared(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::lineSegmentPointSquared() instead") T lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return Math::Distance::lineSegmentPointSquared(a, b, point);
}
template<class T> T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> pointMinusA = point - a;
const Vector2<T> pointMinusB = point - b;
const Vector2<T> 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<T>&, const Vector3<T>&, const Vector3<T>&)
* @deprecated Use @ref Math::Distance::lineSegmentPoint(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::lineSegmentPointSquared() instead") T lineSegmentPoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return Math::Distance::lineSegmentPoint(a, b, point);
}
template<class T> T lineSegmentPointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> pointMinusA = point - a;
const Vector2<T> pointMinusB = point - b;
const Vector2<T> 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<T>&, const Vector4<T>&)
* @deprecated Use @ref Math::Distance::pointPlaneScaled(const Vector3<T>&, const Vector4<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::pointPlaneScaled() instead") T pointPlaneScaled(const Vector3<T>& point, const Vector4<T>& plane) {
return Math::Distance::pointPlaneScaled(point, plane);
}
template<class T> T lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
const Vector3<T> pointMinusA = point - a;
const Vector3<T> 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<T>&, const Vector4<T>&)
* @deprecated Use @ref Math::Distance::pointPlane(const Vector3<T>&, const Vector4<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::pointPlane() instead") T pointPlane(const Vector3<T>& point, const Vector4<T>& plane) {
return Math::Distance::pointPlane(point, plane);
}
/* Between A and B */
return cross(pointMinusA, pointMinusB).dot()/bDistanceA;
/** @brief @copybrief Math::Distance::pointPlaneNormalized(const Vector3<T>&, const Vector4<T>&)
* @deprecated Use @ref Math::Distance::pointPlaneNormalized(const Vector3<T>&, const Vector4<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Distance::pointPlaneNormalized() instead") T pointPlaneNormalized(const Vector3<T>& point, const Vector4<T>& plane) {
return Math::Distance::pointPlaneNormalized(point, plane);
}
}}}}
#else
#error use Magnum/Math/Distance.h instead
#endif
#endif

625
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<class T> inline std::pair<T, T> lineSegmentLineSegment(const Vector2<T>& p, const Vector2<T>& r, const Vector2<T>& q, const Vector2<T>& s) {
const Vector2<T> qp = q - p;
const T rs = cross(r, s);
return {cross(qp, s)/rs, cross(qp, r)/rs};
/** @brief @copybrief Math::Intersection::lineSegmentLineSegment(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* @deprecated Use @ref Math::Intersection::lineSegmentLineSegment(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Intersection::lineSegmentLineSegment() instead") std::pair<T, T> lineSegmentLineSegment(const Vector2<T>& p, const Vector2<T>& r, const Vector2<T>& q, const Vector2<T>& 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<class T> inline T lineSegmentLine(const Vector2<T>& p, const Vector2<T>& r, const Vector2<T>& q, const Vector2<T>& s) {
return cross(q - p, s)/cross(r, s);
/** @brief @copybrief Math::Intersection::lineSegmentLine(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* @deprecated Use @ref Math::Intersection::lineSegmentLine(const Vector2<T>&, const Vector2<T>&, const Vector2<T>&, const Vector2<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Intersection::lineSegmentLine() instead") T lineSegmentLine(const Vector2<T>& p, const Vector2<T>& r, const Vector2<T>& q, const Vector2<T>& 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<class T> inline T planeLine(const Vector3<T>& planePosition, const Vector3<T>& planeNormal, const Vector3<T>& p, const Vector3<T>& r) {
const T f = dot(planePosition, planeNormal);
return (f - dot(planeNormal, p))/dot(planeNormal, r);
/** @brief @copybrief Math::Intersection::planeLine(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
* @deprecated Use @ref Math::Intersection::planeLine(const Vector3<T>&, const Vector3<T>&, const Vector3<T>&, const Vector3<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Intersection::planeLine() instead") T planeLine(const Vector3<T>& planePosition, const Vector3<T>& planeNormal, const Vector3<T>& p, const Vector3<T>& 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<class T> bool pointFrustum(const Vector3<T>& point, const Frustum<T>& 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<class T> bool rangeFrustum(const Range3D<T>& range, const Frustum<T>& frustum);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @brief @copybrief rangeFrustum()
* @deprecated Use @ref rangeFrustum() instead.
/** @brief @copybrief Math::Intersection::pointFrustum(const Vector3<T>&, const Frustum<T>&)
* @deprecated Use @ref Math::Intersection::pointFrustum(const Vector3<T>&, const Frustum<T>&)
* instead.
*/
template<class T> CORRADE_DEPRECATED("use rangeFrustum() instead") bool boxFrustum(const Range3D<T>& box, const Frustum<T>& frustum) {
return rangeFrustum(box, frustum);
template<class T> inline CORRADE_DEPRECATED("use Math::Intersection::pointFrustum() instead") bool pointFrustum(const Vector3<T>& point, const Frustum<T>& 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<class T> bool aabbFrustum(const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents, const Frustum<T>& 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<class T> bool sphereFrustum(const Vector3<T>& sphereCenter, T sphereRadius, const Frustum<T>& 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<class T> bool pointCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, Rad<T> 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<class T> bool pointCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& 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<class T> bool pointDoubleCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, Rad<T> 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<class T> bool pointDoubleCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& 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>&, T, const Matrix4<T>&, T, T).
*/
template<class T> bool sphereConeView(const Vector3<T>& sphereCenter, T sphereRadius, const Matrix4<T>& coneView, Rad<T> 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<class T> bool sphereConeView(const Vector3<T>& sphereCenter, T sphereRadius, const Matrix4<T>& 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<T>& sphereCenter, T, const Vector3<T>&, const Vector3<T>&, T, T).
*/
template<class T> bool sphereCone(const Vector3<T>& sphereCenter, T sphereRadius, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, Rad<T> 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<class T> bool sphereCone(const Vector3<T>& sphereCenter, T sphereRadius, const Vector3<T>& coneOrigin, const Vector3<T>& 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<T>&, const Vector3<T>&, const Vector3<T>&, const Vector3<T>&, T).
*/
template<class T> bool aabbCone(const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, Rad<T> 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<T>&, const Vector3<T>&, const Vector3<T>&, 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<class T> bool aabbCone(const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents, const Vector3<T>& coneOrigin, const Vector3<T>& 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<T>&, const Vector3<T>&, const Vector3<T>&, T).
*/
template<class T> bool rangeCone(const Range3D<T>& range, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> 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<T>&, const Vector3<T>&, const Vector3<T>&, const Vector3<T>&, 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<class T> bool rangeCone(const Range3D<T>& range, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const T tanAngleSqPlusOne);
template<class T> bool pointFrustum(const Vector3<T>& point, const Frustum<T>& frustum) {
for(const Vector4<T>& plane: frustum.planes()) {
/* The point is in front of one of the frustum planes (normals point
outwards) */
if(Distance::pointPlaneScaled<T>(point, plane) < T(0))
return false;
}
return true;
}
template<class T> bool rangeFrustum(const Range3D<T>& range, const Frustum<T>& frustum) {
/* Convert to center/extent, avoiding division by 2 and instead comparing
to 2*-plane.w() later */
const Vector3<T> center = range.min() + range.max();
const Vector3<T> extent = range.max() - range.min();
for(const Vector4<T>& plane: frustum.planes()) {
const Vector3<T> 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<class T> bool aabbFrustum(const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents, const Frustum<T>& frustum) {
for(const Vector4<T>& plane: frustum.planes()) {
const Vector3<T> 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<class T> bool sphereFrustum(const Vector3<T>& sphereCenter, const T sphereRadius, const Frustum<T>& frustum) {
const T radiusSq = sphereRadius*sphereRadius;
for(const Vector4<T>& plane: frustum.planes()) {
/* The sphere is in front of one of the frustum planes (normals point
outwards) */
if(Distance::pointPlaneScaled<T>(sphereCenter, plane) < -radiusSq)
return false;
}
return true;
}
template<class T> bool pointCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> coneAngle) {
const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1);
return pointCone(point, coneOrigin, coneNormal, tanAngleSqPlusOne);
}
template<class T> bool pointCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const T tanAngleSqPlusOne) {
const Vector3<T> c = point - coneOrigin;
const T lenA = dot(c, coneNormal);
return lenA >= 0 && c.dot() <= lenA*lenA*tanAngleSqPlusOne;
}
template<class T> bool pointDoubleCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> coneAngle) {
const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1);
return pointDoubleCone(point, coneOrigin, coneNormal, tanAngleSqPlusOne);
}
template<class T> bool pointDoubleCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const T tanAngleSqPlusOne) {
const Vector3<T> c = point - coneOrigin;
const T lenA = dot(c, coneNormal);
return c.dot() <= lenA*lenA*tanAngleSqPlusOne;
}
template<class T> bool sphereConeView(const Vector3<T>& sphereCenter, const T sphereRadius, const Matrix4<T>& coneView, const Rad<T> coneAngle) {
const Rad<T> 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<class T> bool sphereConeView(const Vector3<T>& sphereCenter, const T sphereRadius, const Matrix4<T>& 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<T> 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<class T> bool sphereCone(
const Vector3<T>& sphereCenter, const T sphereRadius,
const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> coneAngle)
{
const Rad<T> halfAngle = coneAngle*T(0.5);
const T sinAngle = Math::sin(halfAngle);
const T tanAngleSqPlusOne = T(1) + Math::pow<T>(Math::tan<T>(halfAngle), T(2));
return sphereCone(sphereCenter, sphereRadius, coneOrigin, coneNormal, sinAngle, tanAngleSqPlusOne);
}
template<class T> bool sphereCone(
const Vector3<T>& sphereCenter, const T sphereRadius,
const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal,
const T sinAngle, const T tanAngleSqPlusOne)
{
const Vector3<T> diff = sphereCenter - coneOrigin;
/* Point - cone test */
if(Math::dot(diff - sphereRadius*sinAngle*coneNormal, coneNormal) > T(0)) {
const Vector3<T> 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<class T> bool aabbCone(
const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents,
const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> coneAngle)
{
const T tanAngleSqPlusOne = Math::pow<T>(Math::tan<T>(coneAngle*T(0.5)), T(2)) + T(1);
return aabbCone(aabbCenter, aabbExtents, coneOrigin, coneNormal, tanAngleSqPlusOne);
}
template<class T> bool aabbCone(
const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents,
const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const T tanAngleSqPlusOne)
{
const Vector3<T> 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<T> i0 = coneNormal*t0;
const Vector3<T> i1 = coneNormal*t1;
for(const auto& i : {i0, i1}) {
Vector3<T> 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<T>(closestPoint, {}, coneNormal, tanAngleSqPlusOne))
return true;
}
} /* Else: normal will intersect one of the other planes */
}
return false;
}
template<class T> bool rangeCone(const Range3D<T>& range, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> coneAngle) {
const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1);
return rangeCone(range, coneOrigin, coneNormal, tanAngleSqPlusOne);
}
template<class T> bool rangeCone(const Range3D<T>& range, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const T tanAngleSqPlusOne) {
const Vector3<T> center = (range.min() + range.max())*T(0.5);
const Vector3<T> extents = (range.max() - range.min())*T(0.5);
return aabbCone(center, extents, coneOrigin, coneNormal, tanAngleSqPlusOne);
* @brief @copybrief Math::Intersection::rangeFrustum(const Range3D<T>&, const Frustum<T>&)
* @deprecated Use Math::Intersection::rangeFrustum(const Range3D<T>&, const Frustum<T>&)
* instead.
*/
template<class T> inline CORRADE_DEPRECATED("use Math::Intersection::rangeFrustum() instead") bool boxFrustum(const Range3D<T>& box, const Frustum<T>& frustum) {
return Math::Intersection::rangeFrustum(box, frustum);
}
}}}}
#else
#error use Magnum/Math/Intesection.h instead
#endif
#endif

40
src/Magnum/Math/Geometry/Test/CMakeLists.txt

@ -1,40 +0,0 @@
#
# This file is part of Magnum.
#
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
# Vladimír Vondruš <mosra@centrum.cz>
#
# 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")

625
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š <mosra@centrum.cz>
Copyright © 2016, 2018 Jonathan Hale <squareys@googlemail.com>
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<class T> inline std::pair<T, T> lineSegmentLineSegment(const Vector2<T>& p, const Vector2<T>& r, const Vector2<T>& q, const Vector2<T>& s) {
const Vector2<T> qp = q - p;
const T rs = 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<class T> inline T lineSegmentLine(const Vector2<T>& p, const Vector2<T>& r, const Vector2<T>& q, const Vector2<T>& 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<class T> inline T planeLine(const Vector3<T>& planePosition, const Vector3<T>& planeNormal, const Vector3<T>& p, const Vector3<T>& 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<class T> bool pointFrustum(const Vector3<T>& point, const Frustum<T>& 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<class T> bool rangeFrustum(const Range3D<T>& range, const Frustum<T>& 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<class T> bool aabbFrustum(const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents, const Frustum<T>& 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<class T> bool sphereFrustum(const Vector3<T>& sphereCenter, T sphereRadius, const Frustum<T>& 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<class T> bool pointCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, Rad<T> 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<class T> bool pointCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& 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<class T> bool pointDoubleCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, Rad<T> 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<class T> bool pointDoubleCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& 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>&, T, const Matrix4<T>&, T, T).
*/
template<class T> bool sphereConeView(const Vector3<T>& sphereCenter, T sphereRadius, const Matrix4<T>& coneView, Rad<T> 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<class T> bool sphereConeView(const Vector3<T>& sphereCenter, T sphereRadius, const Matrix4<T>& 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<T>& sphereCenter, T, const Vector3<T>&, const Vector3<T>&, T, T).
*/
template<class T> bool sphereCone(const Vector3<T>& sphereCenter, T sphereRadius, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, Rad<T> 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<class T> bool sphereCone(const Vector3<T>& sphereCenter, T sphereRadius, const Vector3<T>& coneOrigin, const Vector3<T>& 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<T>&, const Vector3<T>&, const Vector3<T>&, const Vector3<T>&, T).
*/
template<class T> bool aabbCone(const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, Rad<T> 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<T>&, const Vector3<T>&, const Vector3<T>&, 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<class T> bool aabbCone(const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents, const Vector3<T>& coneOrigin, const Vector3<T>& 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<T>&, const Vector3<T>&, const Vector3<T>&, T).
*/
template<class T> bool rangeCone(const Range3D<T>& range, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> 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<T>&, const Vector3<T>&, const Vector3<T>&, const Vector3<T>&, 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<class T> bool rangeCone(const Range3D<T>& range, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const T tanAngleSqPlusOne);
template<class T> bool pointFrustum(const Vector3<T>& point, const Frustum<T>& frustum) {
for(const Vector4<T>& plane: frustum.planes()) {
/* The point is in front of one of the frustum planes (normals point
outwards) */
if(Distance::pointPlaneScaled<T>(point, plane) < T(0))
return false;
}
return true;
}
template<class T> bool rangeFrustum(const Range3D<T>& range, const Frustum<T>& frustum) {
/* Convert to center/extent, avoiding division by 2 and instead comparing
to 2*-plane.w() later */
const Vector3<T> center = range.min() + range.max();
const Vector3<T> extent = range.max() - range.min();
for(const Vector4<T>& plane: frustum.planes()) {
const Vector3<T> 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<class T> bool aabbFrustum(const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents, const Frustum<T>& frustum) {
for(const Vector4<T>& plane: frustum.planes()) {
const Vector3<T> 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<class T> bool sphereFrustum(const Vector3<T>& sphereCenter, const T sphereRadius, const Frustum<T>& frustum) {
const T radiusSq = sphereRadius*sphereRadius;
for(const Vector4<T>& plane: frustum.planes()) {
/* The sphere is in front of one of the frustum planes (normals point
outwards) */
if(Distance::pointPlaneScaled<T>(sphereCenter, plane) < -radiusSq)
return false;
}
return true;
}
template<class T> bool pointCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> coneAngle) {
const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1);
return pointCone(point, coneOrigin, coneNormal, tanAngleSqPlusOne);
}
template<class T> bool pointCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const T tanAngleSqPlusOne) {
const Vector3<T> c = point - coneOrigin;
const T lenA = dot(c, coneNormal);
return lenA >= 0 && c.dot() <= lenA*lenA*tanAngleSqPlusOne;
}
template<class T> bool pointDoubleCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> coneAngle) {
const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1);
return pointDoubleCone(point, coneOrigin, coneNormal, tanAngleSqPlusOne);
}
template<class T> bool pointDoubleCone(const Vector3<T>& point, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const T tanAngleSqPlusOne) {
const Vector3<T> c = point - coneOrigin;
const T lenA = dot(c, coneNormal);
return c.dot() <= lenA*lenA*tanAngleSqPlusOne;
}
template<class T> bool sphereConeView(const Vector3<T>& sphereCenter, const T sphereRadius, const Matrix4<T>& coneView, const Rad<T> coneAngle) {
const Rad<T> 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<class T> bool sphereConeView(const Vector3<T>& sphereCenter, const T sphereRadius, const Matrix4<T>& 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<T> 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<class T> bool sphereCone(
const Vector3<T>& sphereCenter, const T sphereRadius,
const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> coneAngle)
{
const Rad<T> halfAngle = coneAngle*T(0.5);
const T sinAngle = Math::sin(halfAngle);
const T tanAngleSqPlusOne = T(1) + Math::pow<T>(Math::tan<T>(halfAngle), T(2));
return sphereCone(sphereCenter, sphereRadius, coneOrigin, coneNormal, sinAngle, tanAngleSqPlusOne);
}
template<class T> bool sphereCone(
const Vector3<T>& sphereCenter, const T sphereRadius,
const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal,
const T sinAngle, const T tanAngleSqPlusOne)
{
const Vector3<T> diff = sphereCenter - coneOrigin;
/* Point - cone test */
if(Math::dot(diff - sphereRadius*sinAngle*coneNormal, coneNormal) > T(0)) {
const Vector3<T> 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<class T> bool aabbCone(
const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents,
const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> coneAngle)
{
const T tanAngleSqPlusOne = Math::pow<T>(Math::tan<T>(coneAngle*T(0.5)), T(2)) + T(1);
return aabbCone(aabbCenter, aabbExtents, coneOrigin, coneNormal, tanAngleSqPlusOne);
}
template<class T> bool aabbCone(
const Vector3<T>& aabbCenter, const Vector3<T>& aabbExtents,
const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const T tanAngleSqPlusOne)
{
const Vector3<T> 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<T> i0 = coneNormal*t0;
const Vector3<T> i1 = coneNormal*t1;
for(const auto& i : {i0, i1}) {
Vector3<T> 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<T>(closestPoint, {}, coneNormal, tanAngleSqPlusOne))
return true;
}
} /* Else: normal will intersect one of the other planes */
}
return false;
}
template<class T> bool rangeCone(const Range3D<T>& range, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const Rad<T> coneAngle) {
const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1);
return rangeCone(range, coneOrigin, coneNormal, tanAngleSqPlusOne);
}
template<class T> bool rangeCone(const Range3D<T>& range, const Vector3<T>& coneOrigin, const Vector3<T>& coneNormal, const T tanAngleSqPlusOne) {
const Vector3<T> center = (range.min() + range.max())*T(0.5);
const Vector3<T> extents = (range.max() - range.min())*T(0.5);
return aabbCone(center, extents, coneOrigin, coneNormal, tanAngleSqPlusOne);
}
}}}
#endif

11
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")

8
src/Magnum/Math/Geometry/Test/DistanceTest.cpp → src/Magnum/Math/Test/DistanceTest.cpp

@ -28,9 +28,9 @@
#include <Corrade/TestSuite/Tester.h>
#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)

9
src/Magnum/Math/Geometry/Test/IntersectionBenchmark.cpp → src/Magnum/Math/Test/IntersectionBenchmark.cpp

@ -29,11 +29,10 @@
#include <utility>
#include <Corrade/TestSuite/Tester.h>
#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<class T> bool rangeFrustumNaive(const Math::Range3D<T>& box, const Math::Frustum<T>& frustum) {
for(const Math::Vector4<T>& 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)

9
src/Magnum/Math/Geometry/Test/IntersectionTest.cpp → src/Magnum/Math/Test/IntersectionTest.cpp

@ -27,10 +27,9 @@
#include <sstream>
#include <Corrade/TestSuite/Tester.h>
#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)

8
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<UnsignedInt dimensions> Capsule<dimensions> Capsule<dimensions>::transformed(const MatrixTypeFor<dimensions, Float>& matrix) const {
@ -42,12 +40,12 @@ template<UnsignedInt dimensions> Capsule<dimensions> Capsule<dimensions>::transf
}
template<UnsignedInt dimensions> bool Capsule<dimensions>::operator%(const Point<dimensions>& other) const {
return Distance::lineSegmentPointSquared(_a, _b, other.position()) <
return Math::Distance::lineSegmentPointSquared(_a, _b, other.position()) <
Math::pow<2>(_radius);
}
template<UnsignedInt dimensions> bool Capsule<dimensions>::operator%(const Sphere<dimensions>& other) const {
return Distance::lineSegmentPointSquared(_a, _b, other.position()) <
return Math::Distance::lineSegmentPointSquared(_a, _b, other.position()) <
Math::pow<2>(_radius+other.radius());
}

8
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<UnsignedInt dimensions> Cylinder<dimensions> Cylinder<dimensions>::transformed(const MatrixTypeFor<dimensions, Float>& matrix) const {
@ -42,12 +40,12 @@ template<UnsignedInt dimensions> Cylinder<dimensions> Cylinder<dimensions>::tran
}
template<UnsignedInt dimensions> bool Cylinder<dimensions>::operator%(const Point<dimensions>& other) const {
return Distance::linePointSquared(_a, _b, other.position()) <
return Math::Distance::linePointSquared(_a, _b, other.position()) <
Math::pow<2>(_radius);
}
template<UnsignedInt dimensions> bool Cylinder<dimensions>::operator%(const Sphere<dimensions>& other) const {
return Distance::linePointSquared(_a, _b, other.position()) <
return Math::Distance::linePointSquared(_a, _b, other.position()) <
Math::pow<2>(_radius+other.radius());
}

8
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;
}

8
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<UnsignedInt dimensions> Sphere<dimensions> Sphere<dimensions>::transformed(const MatrixTypeFor<dimensions, Float>& matrix) const {
@ -88,11 +86,11 @@ template<UnsignedInt dimensions> Collision<dimensions> InvertedSphere<dimensions
}
template<UnsignedInt dimensions> bool Sphere<dimensions>::operator%(const Line<dimensions>& 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<UnsignedInt dimensions> bool Sphere<dimensions>::operator%(const LineSegment<dimensions>& 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<UnsignedInt dimensions> bool Sphere<dimensions>::operator%(const Sphere<dimensions>& other) const {

Loading…
Cancel
Save