]> git.localhorst.tv Git - gong.git/commitdiff
sphere/sphere intersection test
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 2 Dec 2016 14:01:35 +0000 (15:01 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 2 Dec 2016 14:01:35 +0000 (15:01 +0100)
src/geometry/geometry.cpp
src/geometry/primitive.hpp
tst/geometry/IntersectionTest.cpp
tst/geometry/IntersectionTest.hpp

index 002c68f0d1ba69760b65d41049e069a2ef2d490a..1d7beeb20777747d500bbebf3e6a1300f60f1fee 100644 (file)
@@ -302,6 +302,31 @@ std::ostream &operator <<(std::ostream &out, const Sphere &s) {
        return out << "Sphere(" << s.origin << ", " << s.radius << ')';
 }
 
+bool Intersection(
+       const Sphere &a,
+       const Sphere &b,
+       float &dist,
+       glm::vec3 &norm
+) noexcept {
+       glm::vec3 diff(b.origin - a.origin);
+       float dist2 = glm::length2(diff);
+       if (dist2 < std::numeric_limits<float>::epsilon()) {
+               // origins coincide, use smaller of the diameters for
+               // depth and pick arbitrary normal
+               dist = 2.0f * std::min(a.radius, b.radius);
+               norm = glm::vec3(1.0f, 0.0f, 0.0f);
+               return true;
+       }
+       if (dist2 < (a.radius + b.radius) * (a.radius + b.radius)) {
+               dist = std::sqrt(dist2);
+               norm = diff / dist;
+               dist = a.radius - (dist - b.radius);
+               return true;
+       } else {
+               return false;
+       }
+}
+
 bool Intersection(
        const Sphere &sphere,
        const Plane &plane,
index c922506c40fa0e2281de5983bba01b11d36f8d90..e785c635cc1ecf15e7b63225eb12f4b968e7194f 100644 (file)
@@ -31,6 +31,11 @@ struct AABB {
                return glm::length(high);
        }
 
+       void Position(const glm::vec3 &center) noexcept {
+               const glm::vec3 halfsize((max - min) * 0.5f);
+               min = center - halfsize;
+               max = center + halfsize;
+       }
        void Move(const glm::vec3 &delta) noexcept {
                min += delta;
                max += delta;
@@ -170,12 +175,28 @@ bool CullTest(const AABB &box, const glm::mat4 &) noexcept;
 bool CullTest(const AABB &box, const Frustum &) noexcept;
 
 struct Sphere {
+
        glm::vec3 origin;
        float radius;
+
+       void Position(const glm::vec3 &center) noexcept {
+               origin = center;
+       }
+       void Move(const glm::vec3 &delta) noexcept {
+               origin += delta;
+       }
+
 };
 
 std::ostream &operator <<(std::ostream &, const Sphere &);
 
+/// Two spheres intersection test.
+bool Intersection(
+       const Sphere &,
+       const Sphere &,
+       float &dist,
+       glm::vec3 &norm) noexcept;
+
 /// Test for intersection of sphere with double sided infinite plane.
 /// If true, dist will hold the smaller interpenetration depth and norm
 /// the respective contact normal.
index 36cacdfa8bd309293c8224a0da636f9dd544e34d..550c0f257c65fc2bf33325d59b4aa7c939215031 100644 (file)
@@ -325,6 +325,59 @@ void IntersectionTest::testBoxBox() {
        );
 }
 
+void IntersectionTest::testSphereSphere() {
+       const float delta = std::numeric_limits<float>::epsilon();
+
+       Sphere a{{ 0.0f, 0.0f, 0.0f }, 1.0f};
+       Sphere b{{ 0.0f, 0.0f, 0.0f }, 1.0f};
+       float depth;
+       glm::vec3 normal;
+
+       CPPUNIT_ASSERT_MESSAGE(
+               "coincidental spheres should intersect",
+               Intersection(a, b, depth, normal)
+       );
+       CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+               "bad intersection distance",
+               2.0f, depth, delta
+       );
+       // normal can be just about anything
+
+       b.Move({ 1, 0, 0 });
+       CPPUNIT_ASSERT_MESSAGE(
+               "spheres should intersect",
+               Intersection(a, b, depth, normal)
+       );
+       CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+               "bad intersection distance",
+               1.0f, depth, delta
+       );
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "bad intersection normal",
+               glm::vec3(1, 0, 0), normal
+       );
+
+       b.Position({ -1.5, 0, 0 });
+       CPPUNIT_ASSERT_MESSAGE(
+               "spheres should intersect",
+               Intersection(a, b, depth, normal)
+       );
+       CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
+               "bad intersection distance",
+               0.5f, depth, delta
+       );
+       CPPUNIT_ASSERT_EQUAL_MESSAGE(
+               "bad intersection normal",
+               glm::vec3(-1, 0, 0), normal
+       );
+
+       b.Move({ -1, 0, 0 });
+       CPPUNIT_ASSERT_MESSAGE(
+               "spheres should not intersect",
+               !Intersection(a, b, depth, normal)
+       );
+}
+
 void IntersectionTest::testSpherePlane() {
        const float delta = std::numeric_limits<float>::epsilon();
 
index 4865c889047dbb91995c71c0ab17bc99d0ffcba8..680d4cadf7b2c3b2f4a1c05a1a32b8753b760d77 100644 (file)
@@ -17,6 +17,7 @@ CPPUNIT_TEST(testAABB);
 CPPUNIT_TEST(testSimpleRayBox);
 CPPUNIT_TEST(testRayBox);
 CPPUNIT_TEST(testBoxBox);
+CPPUNIT_TEST(testSphereSphere);
 CPPUNIT_TEST(testSpherePlane);
 CPPUNIT_TEST(testSphereHalfSpace);
 
@@ -30,6 +31,7 @@ public:
        void testSimpleRayBox();
        void testRayBox();
        void testBoxBox();
+       void testSphereSphere();
        void testSpherePlane();
        void testSphereHalfSpace();