Browse Source

Merge 26f4d664ab into f239823e9a

pull/697/merge
ICOM725 1 week ago committed by GitHub
parent
commit
28d81e3f62
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      src/Magnum/Math/Intersection.h
  2. 63
      src/Magnum/Math/Test/IntersectionTest.cpp

2
src/Magnum/Math/Intersection.h

@ -621,7 +621,7 @@ template<class T> bool sphereCone(
const Vector3<T> diff = sphereCenter - coneOrigin; const Vector3<T> diff = sphereCenter - coneOrigin;
/* Point - cone test */ /* Point - cone test */
if(Math::dot(diff - sphereRadius*sinAngle*coneNormal, coneNormal) > T(0)) { if(Math::dot(diff + sphereRadius*sinAngle*coneNormal, coneNormal) > T(0)) {
const Vector3<T> c = sinAngle*diff + coneNormal*sphereRadius; const Vector3<T> c = sinAngle*diff + coneNormal*sphereRadius;
const T lenA = Math::dot(c, coneNormal); const T lenA = Math::dot(c, coneNormal);

63
src/Magnum/Math/Test/IntersectionTest.cpp

@ -26,6 +26,7 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/String.h> #include <Corrade/Containers/String.h>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
@ -53,6 +54,7 @@ struct IntersectionTest: TestSuite::Tester {
void pointCone(); void pointCone();
void pointDoubleCone(); void pointDoubleCone();
void sphereCone(); void sphereCone();
template<class T> void sphereConeNearApex();
void sphereConeView(); void sphereConeView();
void sphereConeViewNotRigid(); void sphereConeViewNotRigid();
void rangeCone(); void rangeCone();
@ -68,6 +70,25 @@ using Magnum::Constants;
using Magnum::Range3D; using Magnum::Range3D;
using Magnum::Rad; using Magnum::Rad;
constexpr struct {
const char* name;
Float angle;
Vector3 center;
Float radius;
bool intersects;
} SphereConeNearApexData[]{
{"wide cone, beside apex", 120.0f, {1.5f, 0.0f, 0.0f}, 1.0f, true},
{"wide cone, behind apex", 120.0f, {1.1f, 0.0f, -0.2f}, 1.0f, true},
{"wide cone, in front of apex", 120.0f, {1.5f, 0.0f, 0.2f}, 1.0f, true},
{"narrow cone, beside apex", 60.0f, {1.1f, 0.0f, 0.0f}, 1.0f, true},
{"outside side", 120.0f, {2.5f, 0.0f, 0.0f}, 1.0f, false},
{"outside behind apex", 120.0f, {0.0f, 0.0f, -1.5f}, 1.0f, false},
{"contains apex", 120.0f, {0.0f, 0.0f, -0.5f}, 1.0f, true},
{"touches apex", 120.0f, {0.0f, 0.0f, -1.0f}, 1.0f, true},
{"inside cone", 120.0f, {0.0f, 0.0f, 3.0f}, 1.0f, true},
{"zero radius outside", 120.0f, {1.0f, 0.0f, 0.0f}, 0.0f, false}
};
IntersectionTest::IntersectionTest() { IntersectionTest::IntersectionTest() {
addTests({&IntersectionTest::pointCircle, addTests({&IntersectionTest::pointCircle,
&IntersectionTest::pointSphere, &IntersectionTest::pointSphere,
@ -88,6 +109,10 @@ IntersectionTest::IntersectionTest() {
&IntersectionTest::sphereConeViewNotRigid, &IntersectionTest::sphereConeViewNotRigid,
&IntersectionTest::rangeCone, &IntersectionTest::rangeCone,
&IntersectionTest::aabbCone}); &IntersectionTest::aabbCone});
addInstancedTests<IntersectionTest>({&IntersectionTest::sphereConeNearApex<Float>,
&IntersectionTest::sphereConeNearApex<Double>},
Containers::arraySize(SphereConeNearApexData));
} }
void IntersectionTest::pointCircle() { void IntersectionTest::pointCircle() {
@ -407,6 +432,44 @@ void IntersectionTest::sphereCone() {
CORRADE_VERIFY(!Intersection::sphereCone(center - 4.0f*surface, 0.5f, center, normal, angle)); CORRADE_VERIFY(!Intersection::sphereCone(center - 4.0f*surface, 0.5f, center, normal, angle));
} }
template<class T> void IntersectionTest::sphereConeNearApex() {
auto&& data = SphereConeNearApexData[testCaseInstanceId()];
setTestCaseDescription(data.name);
setTestCaseTemplateName(TypeTraits<T>::name());
const Math::Vector3<T> sphereCenter{data.center};
const T radius = T(data.radius);
const Math::Rad<T> angle{Math::Deg<T>{T(data.angle)}};
const T sinAngle = Math::sin(angle/T(2));
const T tanAngle = Math::tan(angle/T(2));
const Math::Vector3<T> normal = Math::Vector3<T>::zAxis();
/* A sphere beside the apex can intersect the cone's side without
containing the apex. For example, at (1.5, 0, 0) the distance to the
side of a 120-degree cone is 1.5*cos(60 degrees) = 0.75. */
CORRADE_COMPARE(Intersection::sphereCone(sphereCenter, radius,
Math::Vector3<T>{}, normal, angle), data.intersects);
CORRADE_COMPARE(Intersection::sphereCone(sphereCenter, radius,
Math::Vector3<T>{}, normal, sinAngle, T(1) + tanAngle*tanAngle), data.intersects);
/* The view-based overload should agree, also after rotating and
translating the cone and the sphere together. */
const Math::Vector3<T> origin{T(1), T(-2), T(3)};
const Math::Vector3<T> rotatedNormal = Math::Vector3<T>::yAxis();
const Math::Vector3<T> transformedCenter = origin +
Math::Vector3<T>{sphereCenter.x(), sphereCenter.z(), -sphereCenter.y()};
const Math::Matrix4<T> view = Math::Matrix4<T>::lookAt(origin,
origin + rotatedNormal, Math::Vector3<T>::zAxis()).invertedRigid();
CORRADE_COMPARE(Intersection::sphereCone(transformedCenter, radius,
origin, rotatedNormal, angle), data.intersects);
CORRADE_COMPARE(Intersection::sphereCone(transformedCenter, radius,
origin, rotatedNormal, sinAngle, T(1) + tanAngle*tanAngle), data.intersects);
CORRADE_COMPARE(Intersection::sphereConeView(transformedCenter, radius,
view, angle), data.intersects);
CORRADE_COMPARE(Intersection::sphereConeView(transformedCenter, radius,
view, sinAngle, tanAngle), data.intersects);
}
void IntersectionTest::sphereConeView() { void IntersectionTest::sphereConeView() {
const Vector3 center{1.0f, -2.0f, 1.3f}; const Vector3 center{1.0f, -2.0f, 1.3f};
const Vector3 normal{Vector3{0.5f, 1.0f, 2.0f}.normalized()}; const Vector3 normal{Vector3{0.5f, 1.0f, 2.0f}.normalized()};

Loading…
Cancel
Save