mirror of https://github.com/mosra/magnum.git
Browse Source
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
18 changed files with 1090 additions and 915 deletions
@ -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 |
||||||
@ -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") |
|
||||||
@ -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 |
||||||
Loading…
Reference in new issue