From a77b08471eacce7beac0ffb434ae1b88f740fd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 25 Apr 2018 10:46:35 +0200 Subject: [PATCH] Math/Geometry: various cleanup. Spacing, indentation, overly wide lines, some const etc. Minor stuff, except for renaming function arguments for consistency. That affects everything. --- src/Magnum/Math/Geometry/Intersection.h | 493 +++++++++--------- .../Geometry/Test/IntersectionBenchmark.cpp | 27 +- .../Math/Geometry/Test/IntersectionTest.cpp | 37 +- 3 files changed, 289 insertions(+), 268 deletions(-) diff --git a/src/Magnum/Math/Geometry/Intersection.h b/src/Magnum/Math/Geometry/Intersection.h index 02d008007..65fb550d5 100644 --- a/src/Magnum/Math/Geometry/Intersection.h +++ b/src/Magnum/Math/Geometry/Intersection.h @@ -148,8 +148,8 @@ template inline T planeLine(const Vector3& planePosition, const Vect @brief Intersection of a point and a frustum @param point Point @param frustum Frustum planes with normals pointing outwards - -Returns @cpp true @ce if the point is on or inside the frustum. +@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(). @@ -160,12 +160,12 @@ template bool pointFrustum(const Vector3& point, const Frustum& f @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 -Returns @cpp true @ce if the box intersects with the frustum. - -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[ +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) \\ @@ -181,9 +181,9 @@ template bool rangeFrustum(const Range3D& range, const Frustum& f #ifdef MAGNUM_BUILD_DEPRECATED /** -@brief @copybrief rangeFrustum() -@deprecated Use @ref rangeFrustum() instead. -*/ + * @brief @copybrief rangeFrustum() + * @deprecated Use @ref rangeFrustum() instead. + */ template CORRADE_DEPRECATED("use rangeFrustum() instead") bool boxFrustum(const Range3D& box, const Frustum& frustum) { return rangeFrustum(box, frustum); } @@ -191,223 +191,246 @@ template CORRADE_DEPRECATED("use rangeFrustum() instead") bool boxFrust /** @brief Intersection of an axis-aligned box and a frustum -@param box Axis-aligned box -@param frustum Frustum planes with normals pointing outwards - -Returns @cpp true @ce if the box intersects with the frustum. - -Uses the same method as @ref rangeFrustum() "rangeFrustum()", but does not need to -convert to center/extents representation. +@param aabbCenter Center of the AABB +@param aabbExtents (Half-)extents of the AABB +@param frustum Frustum planes with normals pointing outwards +@return @cpp true @ce if the box intersects with the frustum, @cpp false @ce + otherwise + +Uses the same method as @ref rangeFrustum(), but does not need to convert to +center/extents representation. */ -template bool aabbFrustum(const Vector3& center, const Vector3& extents, const Frustum& frustum); +template bool aabbFrustum(const Vector3& aabbCenter, const Vector3& aabbExtents, const Frustum& frustum); /** @brief Intersection of a sphere and a frustum -@param center Sphere center -@param radius Sphere radius -@param frustum Frustum planes with normals pointing outwards - -Returns @cpp true @ce if the sphere intersects the frustum. - -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(). +@param sphereCenter Sphere center +@param sphereRadius Sphere radius +@param frustum Frustum planes with normals pointing outwards +@return @cpp true @ce if the sphere intersects the frustum, @cpp false @ce + otherwise + +Checks for each plane of the frustum whether the sphere is behind the plane +(the points distance larger than the sphere's radius) using +@ref Distance::pointPlaneScaled(). */ -template bool sphereFrustum(const Vector3& center, T radius, const Frustum& frustum); +template bool sphereFrustum(const Vector3& sphereCenter, T sphereRadius, const Frustum& frustum); /** @brief Intersection of a point and a cone -@param p The point -@param origin Cone origin -@param normal Cone normal -@param angle Apex angle of the cone - -Returns @cpp true @ce if the point is inside the 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 angle and calls -@ref pointCone(const Vector3&, const Vector3&, const Vector3&, T) +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref pointCone(const Vector3&, const Vector3&, const Vector3&, T). */ -template bool pointCone(const Vector3& p, const Vector3& origin, const Vector3& normal, Rad angle); +template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); /** @brief Intersection of a point and a cone using precomputed values -@param p The point +@param point The point @param coneOrigin Cone origin @param coneNormal Cone normal -@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation: - @cpp T(1) + Math::pow(Math::tan(angle/T(2)), T(2)) @ce +@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation +@return @cpp true @ce if the point is inside the cone, @cpp false @ce + otherwise -Returns @cpp true @ce if the point is inside the cone. +The @p tanAngleSqPlusOne parameter can be calculated as: + +@code{.cpp} +Math::pow<2>(Math::tan(angle*T(0.5))) + T(1) +@endcode */ -template bool pointCone(const Vector3& p, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); +template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); /** @brief Intersection of a point and a double cone -@param p The point +@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 -Returns @cpp true @ce if the point is inside the double cone. - -Precomputes a portion of the intersection equation from @p angle and calls -@ref pointDoubleCone(const Vector3&, const Vector3&, const Vector3&, T) +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref pointDoubleCone(const Vector3&, const Vector3&, const Vector3&, T). */ -template bool pointDoubleCone(const Vector3& p, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); +template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); /** @brief Intersection of a point and a double cone using precomputed values -@param p The point +@param point The point @param coneOrigin Cone origin @param coneNormal Cone normal -@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation: - @cpp T(1) + Math::pow(Math::tan(angle/T(2)), T(2)) @ce +@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 -Returns @cpp true @ce if the point is inside the double cone. +The @p tanAngleSqPlusOne parameter can be precomputed like this: -Uses the result of precomputing @f$ x = \tan^2{\theta} + 1 @f$. +@code{.cpp} +T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); +@endcode */ -template bool pointDoubleCone(const Vector3& p, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); +template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); /** @brief Intersection of a sphere and a cone view -@param sphereCenter Center of the sphere -@param radius Radius of the sphere -@param coneView View matrix with translation and rotation of the cone -@param coneAngle Cone opening angle - -Returns @cpp true @ce if the sphere intersects the cone. - -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. - -Precomputes a portion of the intersection equation from @p angle and calls -@ref sphereConeView(const Vector3&, T, const Matrix4&, T, T, T) +@param sphereCenter Center of the sphere +@param sphereRadius Radius of the sphere +@param coneView View matrix with translation and rotation of the cone +@param coneAngle Apex angle of the cone (@f$ 0 < \Theta < \pi @f$) +@return @cpp true @ce if the sphere intersects the cone, @cpp false @ce + otherwise + +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref sphereConeView(const Vector3&, T, const Matrix4&, T, T, T). */ -template bool sphereConeView(const Vector3& sphereCenter, T radius, const Matrix4& coneView, Rad coneAngle); +template bool sphereConeView(const Vector3& sphereCenter, T sphereRadius, const Matrix4& coneView, Rad coneAngle); /** @brief Intersection of a sphere and a cone view @param sphereCenter Sphere center -@param radius Sphere radius -@param coneView View matrix with translation and rotation of the cone -@param sinAngle Precomputed sine of half the cone's opening angle: @cpp Math::sin(angle/T(2)) @ce -@param cosAngle Precomputed cosine of half the cone's opening angle: @cpp Math::cos(angle/T(2)) @ce -@param tanAngle Precomputed tangens of half the cone's opening angle: @cpp Math::tan(angle/T(2)) @ce +@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 cosAngle Precomputed cosine of half the cone's opening angle +@param tanAngle Precomputed tangens of half the cone's opening angle +@return @cpp true @ce if the sphere intersects the cone, @cpp false @ce + otherwise -Returns @cpp true @ce if the sphere intersects the cone. +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 cosAngle = Math::cos(angle*T(0.5)); +T tanAngle = Math::tan(angle*T(0.5)); +@endcode */ -template bool sphereConeView(const Vector3& sphereCenter, T radius, const Matrix4& coneView, T sinAngle, T cosAngle, T tanAngle); +template bool sphereConeView(const Vector3& sphereCenter, T sphereRadius, const Matrix4& coneView, T sinAngle, T cosAngle, T tanAngle); /** @brief Intersection of a sphere and a cone -@param sphereCenter Sphere center -@param radius Sphere Sphere radius -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param coneAngle Cone opening angle (@f$ 0 < \text{angle} < \pi @f$). - -Returns @cpp true @ce if the sphere intersects with the cone. - -Offsets the cone plane by @f$ -r\sin{\theta} \cdot \boldsymbol n @f$ (with @f$ \theta @f$ -the cone's half-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. - -Precomputes a portion of the intersection equation from @p angle and calls -@ref sphereCone(const Vector3& sphereCenter, T, const Vector3&, const Vector3&, T, T) +@param sphereCenter Sphere center +@param sphereRadius Sphere radius +@param coneOrigin Cone origin +@param coneNormal Cone normal +@param coneAngle Apex angle of the cone (@f$ 0 < \Theta < \pi @f$) +@return @cpp true @ce if the sphere intersects with the cone, @cpp false @ce + otherwise + +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref sphereCone(const Vector3& sphereCenter, T, const Vector3&, const Vector3&, T, T). */ -template bool sphereCone(const Vector3& sphereCenter, T radius, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); +template bool sphereCone(const Vector3& sphereCenter, T sphereRadius, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); /** @brief Intersection of a sphere and a cone using precomputed values @param sphereCenter Sphere center -@param radius Sphere radius +@param sphereRadius Sphere radius @param coneOrigin Cone origin @param coneNormal Cone normal -@param sinAngle Precomputed sine of half the cone's opening angle: - @cpp Math::sin(angle/T(2)) @ce -@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation: - @cpp Math::pow(Math::tan(angle/T(2)), 2) + 1 @ce - -Returns @cpp true @ce if the sphere intersects with the cone. +@param sinAngle Precomputed sine of half the cone's opening angle +@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation +@return @cpp true @ce if the sphere intersects with the cone, @cpp false @ce + otherwise + +Offsets the cone plane by @f$ -r\sin{\frac{\Theta}{2}} \cdot \boldsymbol n @f$ +(with @f$ \Theta @f$ being the cone apex angle) which separates two +half-spaces: In front of the plane, in which the sphere cone intersection test +is equivalent to testing the sphere's center against a similarly offset cone +(which is equivalent the cone with surface expanded by @f$ r @f$ in surface +normal direction), and behind the plane, where the test is equivalent to +testing whether the origin of the original cone intersects the sphere. The +@p sinAngle and @p tanAngleSqPlusOne parameters can be precomputed like this: + +@code{.cpp} +T sinAngle = Math::sin(angle*T(0.5)); +T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); +@endcode */ -template bool sphereCone(const Vector3& sphereCenter, T radius, const Vector3& coneOrigin, const Vector3& coneNormal, T sinAngle, T tanAngleSqPlusOne); +template bool sphereCone(const Vector3& sphereCenter, T sphereRadius, const Vector3& coneOrigin, const Vector3& coneNormal, T sinAngle, T tanAngleSqPlusOne); /** @brief Intersection of an axis aligned bounding box and a cone -@param center Center of the AABB -@param extents (Half-)extents of the AABB -@param coneOrigin Cone origin -@param coneNormal Cone normal -@param coneAngle Cone opening angle +@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 -Returns @cpp true @ce if the axis aligned bounding box intersects the cone. +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref aabbCone(const Vector3&, const Vector3&, const Vector3&, const Vector3&, T). +*/ +template bool aabbCone(const Vector3& aabbCenter, const Vector3& aabbExtents, const Vector3& coneOrigin, const Vector3& coneNormal, Rad coneAngle); -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. +/** +@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 -The intersection points on the planes perpendicular to axis @f$ a \in {0, 1, 2} @f$ -are given by @f[ +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$ n @f$, cone origin @f$ o @f$, box center @f$ x @f$ and box extents @f$ e @f$. - -The points on the faces that are closest to this intersection point are the closest -to the cone's axis and are tested for intersection with the cone using -@ref pointCone(const Vector3&, const Vector3&, const Vector3&, const T) "pointCone()". +with normal @f$ \boldsymbol n @f$, cone origin @f$ \boldsymbol o @f$, box +center @f$ \boldsymbol c @f$ and box extents @f$ \boldsymbol e @f$. The points +on the faces that are closest to this intersection point are the closest to the +cone's axis and are tested for intersection with the cone using +@ref pointCone(const Vector3&, const Vector3&, const Vector3&, const T) "pointCone()". As soon as an intersecting point is found, the function returns +@cpp true @ce. If all points lie outside of the cone, it will return +@cpp false @ce. -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: -Precomputes a portion of the intersection equation from @p angle and calls -@ref aabbCone(const Vector3&, const Vector3&, const Vector3&, const Vector3&, T) +@code{.cpp} +T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); +@endcode */ -template bool aabbCone(const Vector3& center, const Vector3& extents, const Vector3& origin, const Vector3& normal, Rad angle); - -/** -@brief Intersection of an axis aligned bounding box and a cone using precomputed values -@param center Center of the AABB -@param extents (Half-)extents of the AABB -@param origin Cone origin -@param normal Cone normal -@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation: - @cpp T(1) + Math::pow(Math::tan(angle/T(2)), T(2)) @ce - -Returns @cpp true @ce if the axis aligned bounding box intersects the cone. -*/ -template bool aabbCone(const Vector3& center, const Vector3& extents, const Vector3& origin, const Vector3& normal, T tanAngleSqPlusOne); +template bool aabbCone(const Vector3& aabbCenter, const Vector3& aabbExtents, const Vector3& coneOrigin, const Vector3& coneNormal, T tanAngleSqPlusOne); /** @brief Intersection of a range and a cone - @param range Range @param coneOrigin Cone origin @param coneNormal Cone normal -@param coneAngle Cone opening angle - -Returns @cpp true @ce if the range intersects the cone. +@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 -Converts the range into center/extents representation and passes it on to -@ref aabbCone(const Vector3&, const Vector3&, const Vector3&, const Vector3&, T) "aabbCone()". +Precomputes a portion of the intersection equation from @p coneAngle and calls +@ref rangeCone(const Range3D&, const Vector3&, const Vector3&, T). */ -template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad angle); +template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle); /** @brief Intersection of a range and a cone using precomputed values @param range Range @param coneOrigin Cone origin @param coneNormal Cone normal -@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation: - @cpp T(1) + Math::pow(Math::tan(angle/T(2)), T(2)) @ce - -Returns @cpp true @ce if the range intersects the cone. +@param tanAngleSqPlusOne Precomputed portion of the cone intersection equation +@return @cpp true @ce if the range intersects the cone, @cpp false @ce + otherwise Converts the range into center/extents representation and passes it on to -@ref aabbCone(const Vector3&, const Vector3&, const Vector3&, const Vector3&, T) "aabbCone()". +@ref aabbCone(const Vector3&, const Vector3&, const Vector3&, const Vector3&, T) "aabbCone()". The @p tanAngleSqPlusOne parameter can be precomputed like this: + +@code{.cpp} +T tanAngleSqPlusOne = Math::pow<2>(Math::tan(angle*T(0.5))) + T(1); +@endcode */ template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne); @@ -422,48 +445,42 @@ template bool pointFrustum(const Vector3& point, const Frustum& f return true; } -template bool rangeFrustum(const Range3D& box, const Frustum& frustum) { +template bool rangeFrustum(const Range3D& range, const Frustum& frustum) { /* Convert to center/extent, avoiding division by 2 and instead comparing to 2*-plane.w() later */ - const Vector3 center = box.min() + box.max(); - const Vector3 extent = box.max() - box.min(); + const Vector3 center = range.min() + range.max(); + const Vector3 extent = range.max() - range.min(); for(const Vector4& plane: frustum.planes()) { const Vector3 absPlaneNormal = Math::abs(plane.xyz()); const Float d = Math::dot(center, plane.xyz()); const Float r = Math::dot(extent, absPlaneNormal); - if(d + r < -T(2)*plane.w()) { - return false; - } + if(d + r < -T(2)*plane.w()) return false; } return true; } -template bool aabbFrustum( - const Vector3& center, const Vector3& extents, const Frustum& frustum) -{ +template bool aabbFrustum(const Vector3& aabbCenter, const Vector3& aabbExtents, const Frustum& frustum) { for(const Vector4& plane: frustum.planes()) { const Vector3 absPlaneNormal = Math::abs(plane.xyz()); - const Float d = Math::dot(center, plane.xyz()); - const Float r = Math::dot(extents, absPlaneNormal); - if(d + r < -plane.w()) { - return false; - } + const Float d = Math::dot(aabbCenter, plane.xyz()); + const Float r = Math::dot(aabbExtents, absPlaneNormal); + if(d + r < -plane.w()) return false; } return true; } -template bool sphereFrustum(const Vector3& center, const T radius, const Frustum& frustum) { - const T radiusSq = radius*radius; +template bool sphereFrustum(const Vector3& sphereCenter, const T sphereRadius, const Frustum& frustum) { + const T radiusSq = sphereRadius*sphereRadius; for(const Vector4& plane: frustum.planes()) { /* The sphere is in front of one of the frustum planes (normals point outwards) */ - if(Distance::pointPlaneScaled(center, plane) < -radiusSq) + if(Distance::pointPlaneScaled(sphereCenter, plane) < -radiusSq) return false; } @@ -471,112 +488,114 @@ template bool sphereFrustum(const Vector3& center, const T radius, c } -template bool pointCone(const Vector3& p, const Vector3& origin, const Vector3& normal, const Rad angle) { - const T x = T(1) + Math::pow(Math::tan(angle/T(2)), T(2)); - - return pointCone(p, origin, normal, x); +template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { + const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1); + return pointCone(point, coneOrigin, coneNormal, tanAngleSqPlusOne); } -template bool pointCone(const Vector3& p, const Vector3& origin, const Vector3& normal, const T tanAngleSqPlusOne) { - const Vector3 c = p - origin; - const T lenA = dot(c, normal); +template bool pointCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) { + const Vector3 c = point - coneOrigin; + const T lenA = dot(c, coneNormal); return lenA >= 0 && c.dot() <= lenA*lenA*tanAngleSqPlusOne; } -template bool pointDoubleCone(const Vector3& p, const Vector3& origin, const Vector3& normal, const Rad angle) { - const T x = T(1) + Math::pow(Math::tan(angle/T(2)), T(2)); - - return pointDoubleCone(p, origin, normal, x); +template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { + const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1); + return pointDoubleCone(point, coneOrigin, coneNormal, tanAngleSqPlusOne); } -template bool pointDoubleCone(const Vector3& p, const Vector3& origin, const Vector3& normal, const T tanAngleSqPlusOne) { - const Vector3 c = p - origin; - const T lenA = dot(c, normal); +template bool pointDoubleCone(const Vector3& point, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) { + const Vector3 c = point - coneOrigin; + const T lenA = dot(c, coneNormal); return c.dot() <= lenA*lenA*tanAngleSqPlusOne; } -template bool sphereConeView(const Vector3& sphereCenter, const T radius, const Matrix4& coneView, const Rad angle) { - const T sinAngle = Math::sin(angle/T(2)); - const T cosAngle = Math::cos(angle/T(2)); - const T tanAngle = Math::tan(angle/T(2)); +template bool sphereConeView(const Vector3& sphereCenter, const T sphereRadius, const Matrix4& coneView, const Rad coneAngle) { + const Rad halfAngle = coneAngle*T(0.5); + const T sinAngle = Math::sin(halfAngle); + const T cosAngle = Math::cos(halfAngle); + const T tanAngle = Math::tan(halfAngle); - return sphereConeView(sphereCenter, radius, coneView, sinAngle, cosAngle, tanAngle); + return sphereConeView(sphereCenter, sphereRadius, coneView, sinAngle, cosAngle, tanAngle); } template bool sphereConeView( - const Vector3& sphereCenter, const T radius, const Matrix4& coneView, + const Vector3& sphereCenter, const T sphereRadius, const Matrix4& coneView, const T sinAngle, const T cosAngle, const T tanAngle) { CORRADE_ASSERT(coneView.isRigidTransformation(), "Math::Geometry::Intersection::sphereConeView(): coneView must be rigid", false); - /* Transform the sphere so that we can test against Z axis aligned origin cone instead */ + /* Transform the sphere so that we can test against Z axis aligned origin + cone instead */ const Vector3 center = coneView.transformPoint(sphereCenter); - /* Test against plane which determines whether to test against shifted cone or center-sphere */ - if (-center.z() > -radius*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() - radius/sinAngle); + /* 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() <= radius*radius; + return center.dot() <= sphereRadius*sphereRadius; } return false; } template bool sphereCone( - const Vector3& sCenter, const T radius, - const Vector3& origin, const Vector3& normal, const Rad angle) + const Vector3& sphereCenter, const T sphereRadius, + const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { - const T sinAngle = Math::sin(angle/T(2)); - const T tanAngleSqPlusOne = T(1) + Math::pow(Math::tan(angle/T(2)), T(2)); + const Rad halfAngle = coneAngle*T(0.5); + const T sinAngle = Math::sin(halfAngle); + const T tanAngleSqPlusOne = T(1) + Math::pow(Math::tan(halfAngle), T(2)); - return sphereCone(sCenter, radius, origin, normal, sinAngle, tanAngleSqPlusOne); + return sphereCone(sphereCenter, sphereRadius, coneOrigin, coneNormal, sinAngle, tanAngleSqPlusOne); } template bool sphereCone( - const Vector3& sCenter, const T radius, - const Vector3& origin, const Vector3& normal, + const Vector3& sphereCenter, const T sphereRadius, + const Vector3& coneOrigin, const Vector3& coneNormal, const T sinAngle, const T tanAngleSqPlusOne) { - const Vector3 diff = sCenter - origin; + const Vector3 diff = sphereCenter - coneOrigin; - if (dot(diff - radius*sinAngle*normal, normal) > T(0)) { - /* point - cone test */ - const Vector3 c = sinAngle*diff + normal*radius; - const T lenA = dot(c, normal); + /* Point - cone test */ + if(Math::dot(diff - sphereRadius*sinAngle*coneNormal, coneNormal) > T(0)) { + const Vector3 c = sinAngle*diff + coneNormal*sphereRadius; + const T lenA = Math::dot(c, coneNormal); - return c.dot() <= lenA*lenA*(tanAngleSqPlusOne); - } else { - /* Simple sphere point check */ - return diff.dot() <= radius*radius; - } + return c.dot() <= lenA*lenA*tanAngleSqPlusOne; + + /* Simple sphere point check */ + } else return diff.dot() <= sphereRadius*sphereRadius; } template bool aabbCone( - const Vector3& center, const Vector3& extents, const Vector3& origin, - const Vector3& normal, const Rad angle) + const Vector3& aabbCenter, const Vector3& aabbExtents, + const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { - const T x = T(1) + Math::pow(Math::tan(angle/T(2)), T(2)); - return aabbCone(center, extents, origin, normal, x); + const T tanAngleSqPlusOne = Math::pow(Math::tan(coneAngle*T(0.5)), T(2)) + T(1); + return aabbCone(aabbCenter, aabbExtents, coneOrigin, coneNormal, tanAngleSqPlusOne); } template bool aabbCone( - const Vector3& center, const Vector3& extents, + const Vector3& aabbCenter, const Vector3& aabbExtents, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) { - const Vector3 c = center - coneOrigin; + const Vector3 c = aabbCenter - coneOrigin; - for (const Int axis: {0, 1, 2}) { + 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)) { - Float t0 = ((c[z] - extents[z])/coneNormal[z]); - Float t1 = ((c[z] + extents[z])/coneNormal[z]); + const Float t0 = ((c[z] - aabbExtents[z])/coneNormal[z]); + const Float t1 = ((c[z] + aabbExtents[z])/coneNormal[z]); const Vector3 i0 = coneNormal*t0; const Vector3 i1 = coneNormal*t1; @@ -584,42 +603,36 @@ template bool aabbCone( for(const auto& i : {i0, i1}) { Vector3 closestPoint = i; - if(i[x] - c[x] > extents[x]) { - closestPoint[x] = c[x] + extents[x]; - } else if(i[x] - c[x] < -extents[x]) { - closestPoint[x] = c[x] - extents[x]; - } - /* Else: normal intersects within x bounds */ - - if(i[y] - c[y] > extents[y]) { - closestPoint[y] = c[y] + extents[y]; - } else if(i[y] - c[y] < -extents[y]) { - closestPoint[y] = c[y] - extents[y]; - } - /* Else: normal intersects within Y bounds */ - - if (pointCone(closestPoint, {}, coneNormal, tanAngleSqPlusOne)) { - /* Found a point in cone and aabb */ + if(i[x] - c[x] > aabbExtents[x]) { + closestPoint[x] = c[x] + aabbExtents[x]; + } else if(i[x] - c[x] < -aabbExtents[x]) { + closestPoint[x] = c[x] - aabbExtents[x]; + } /* Else: normal intersects within x bounds */ + + if(i[y] - c[y] > aabbExtents[y]) { + closestPoint[y] = c[y] + aabbExtents[y]; + } else if(i[y] - c[y] < -aabbExtents[y]) { + closestPoint[y] = c[y] - aabbExtents[y]; + } /* Else: normal intersects within Y bounds */ + + /* Found a point in cone and aabb */ + if(pointCone(closestPoint, {}, coneNormal, tanAngleSqPlusOne)) return true; - } } - } - /* else: normal will intersect one of the other planes */ + } /* Else: normal will intersect one of the other planes */ } return false; } -template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad angle) { - const Vector3 center = (range.min() + range.max())/T(2); - const Vector3 extents = (range.max() - range.min())/T(2); - const T x = T(1) + Math::pow(Math::tan(angle/T(2)), T(2)); - return aabbCone(center, extents, coneOrigin, coneNormal, x); +template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const Rad coneAngle) { + const T tanAngleSqPlusOne = Math::pow<2>(Math::tan(coneAngle*T(0.5))) + T(1); + return rangeCone(range, coneOrigin, coneNormal, tanAngleSqPlusOne); } template bool rangeCone(const Range3D& range, const Vector3& coneOrigin, const Vector3& coneNormal, const T tanAngleSqPlusOne) { - const Vector3 center = (range.min() + range.max())/T(2); - const Vector3 extents = (range.max() - range.min())/T(2); + const Vector3 center = (range.min() + range.max())*T(0.5); + const Vector3 extents = (range.max() - range.min())*T(0.5); return aabbCone(center, extents, coneOrigin, coneNormal, tanAngleSqPlusOne); } diff --git a/src/Magnum/Math/Geometry/Test/IntersectionBenchmark.cpp b/src/Magnum/Math/Geometry/Test/IntersectionBenchmark.cpp index 432371e5e..91f5a6579 100644 --- a/src/Magnum/Math/Geometry/Test/IntersectionBenchmark.cpp +++ b/src/Magnum/Math/Geometry/Test/IntersectionBenchmark.cpp @@ -24,11 +24,10 @@ DEALINGS IN THE SOFTWARE. */ -#include - #include #include #include +#include #include "Magnum/Math/Geometry/Intersection.h" #include "Magnum/Math/Angle.h" @@ -56,15 +55,18 @@ template bool rangeFrustumNaive(const Math::Range3D& box, const Math return true; } -/* @brief Ground truth, slow sphere cone intersection - calculating exact distances, - * no optimizations, no precomputations - * @param sphereCenter Sphere center - * @param radius Sphere radius - * @param origin Origin of the cone - * @param normal Cone normal - * @param angle Cone opening angle (0 < angle < pi). - * - * Returns `true` if the sphere intersects with the cone. */ +/* + Ground truth, slow sphere cone intersection - calculating exact distances, + no optimizations, no precomputations + + sphereCenter Sphere center + radius Sphere radius + origin Origin of the cone + normal Cone normal + angle Cone opening angle (0 < angle < pi) + + Returns true if the sphere intersects with the cone. +*/ template bool sphereConeGT( const Math::Vector3& sphereCenter, const T radius, const Math::Vector3& origin, const Math::Vector3& normal, const Math::Rad angle) { @@ -78,7 +80,8 @@ template bool sphereConeGT( /* Distance from cone surface */ const T distanceFromCone = Math::sin(actual - halfAngle)*diff.length(); - /* Either the sphere center lies in cone, or cone is max radius away from the cone */ + /* Either the sphere center lies in cone, or cone is max radius away from + the cone */ return actual <= halfAngle || distanceFromCone <= radius; } diff --git a/src/Magnum/Math/Geometry/Test/IntersectionTest.cpp b/src/Magnum/Math/Geometry/Test/IntersectionTest.cpp index 014532fe0..fcdb4f8ba 100644 --- a/src/Magnum/Math/Geometry/Test/IntersectionTest.cpp +++ b/src/Magnum/Math/Geometry/Test/IntersectionTest.cpp @@ -378,28 +378,33 @@ void IntersectionTest::rangeCone() { const Rad angle{72.0_degf}; /* Box fully inside cone */ - CORRADE_VERIFY(Intersection::rangeCone(Range3D::fromSize(15.0f*normal - Vector3{1.0f}, Vector3{2.0f}), - center, normal, angle)); + CORRADE_VERIFY(Intersection::rangeCone(Range3D::fromSize( + 15.0f*normal - Vector3{1.0f}, Vector3{2.0f}), center, normal, angle)); /* Box intersecting cone */ - CORRADE_VERIFY(Intersection::rangeCone(Range3D::fromSize(5.0f*normal - Vector3{10.0f, 10.0f, 0.5f}, Vector3{20.0f, 20.0f, 1.0f}), - center, normal, angle)); - CORRADE_VERIFY(Intersection::rangeCone(Range3D{{-1.0f, -2.0f, -3.0f}, {1.0f, 2.0f, 3.0f}}, - center, normal, angle)); + CORRADE_VERIFY(Intersection::rangeCone(Range3D::fromSize( + 5.0f*normal - Vector3{10.0f, 10.0f, 0.5f}, Vector3{20.0f, 20.0f, 1.0f}), + center, normal, angle)); + CORRADE_VERIFY(Intersection::rangeCone( + Range3D{{-1.0f, -2.0f, -3.0f}, {1.0f, 2.0f, 3.0f}}, center, normal, angle)); /* Cone inside large box */ - CORRADE_VERIFY(Intersection::rangeCone(Range3D::fromSize(12.0f*normal - Vector3{20.0f}, Vector3{40.0f}), - center, normal, angle)); + CORRADE_VERIFY(Intersection::rangeCone(Range3D::fromSize( + 12.0f*normal - Vector3{20.0f}, Vector3{40.0f}), center, normal, angle)); /* Same corner chosen on all intersecting faces */ - CORRADE_VERIFY(Intersection::rangeCone(Range3D{{2.0f, -0.1f, -1.5f}, {3.0f, 0.1f, 1.5f}}, - center, {0.353553f, 0.707107f, 0.612372f}, angle)); + CORRADE_VERIFY(Intersection::rangeCone( + Range3D{{2.0f, -0.1f, -1.5f}, {3.0f, 0.1f, 1.5f}}, + center, {0.353553f, 0.707107f, 0.612372f}, angle)); /* Boxes outside cone */ - CORRADE_VERIFY(!Intersection::rangeCone(Range3D{Vector3{2.0f, 2.0f, -2.0f}, Vector3{8.0f, 7.0f, 2.0f}}, - center, normal, angle)); - CORRADE_VERIFY(!Intersection::rangeCone(Range3D{Vector3{6.0f, 5.0f, -7.0f}, Vector3{5.0f, 9.0f, -3.0f}}, - center, normal, angle)); + CORRADE_VERIFY(!Intersection::rangeCone( + Range3D{Vector3{2.0f, 2.0f, -2.0f}, Vector3{8.0f, 7.0f, 2.0f}}, + center, normal, angle)); + CORRADE_VERIFY(!Intersection::rangeCone( + Range3D{Vector3{6.0f, 5.0f, -7.0f}, Vector3{5.0f, 9.0f, -3.0f}}, + center, normal, angle)); /* Box fully contained in double cone */ - CORRADE_VERIFY(!Intersection::rangeCone(Range3D::fromSize(-15.0f*normal - Vector3{1.0f}, Vector3{2.0f}), - center, normal, angle)); + CORRADE_VERIFY(!Intersection::rangeCone( + Range3D::fromSize(-15.0f*normal - Vector3{1.0f}, Vector3{2.0f}), + center, normal, angle)); } void IntersectionTest::aabbCone() {