From b679804776e72bc4c9db63481db8144ebf23b93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Br=C3=A9mond?= Date: Thu, 18 Jul 2019 00:51:59 -0700 Subject: [PATCH 1/2] [feature] Add geometry queries --- README.md | 35 +- .../Geometry/3D/Objects/Line.cpp | 8 +- .../Geometry/3D/Objects/Plane.cpp | 25 +- .../Geometry/3D/Objects/Ray.cpp | 7 +- .../Geometry/3D/Objects/Segment.cpp | 8 +- .../Mathematics/Geometry/3D/Objects/Line.hpp | 32 +- .../Mathematics/Geometry/3D/Objects/Plane.hpp | 164 ++++++++- .../Mathematics/Geometry/3D/Objects/Ray.hpp | 45 ++- .../Geometry/3D/Objects/Segment.hpp | 32 +- .../Mathematics/Geometry/3D/Intersection.cpp | 20 +- .../Mathematics/Geometry/3D/Object.cpp | 142 +++++++- .../Mathematics/Geometry/3D/Objects/Line.cpp | 81 ++++- .../Mathematics/Geometry/3D/Objects/Plane.cpp | 152 +++++++- .../Mathematics/Geometry/3D/Objects/Ray.cpp | 61 +++- .../Geometry/3D/Objects/Segment.cpp | 94 ++++- .../Geometry/3D/Objects/Line.test.cpp | 146 +++++++- .../Geometry/3D/Objects/Plane.test.cpp | 343 ++++++++++++++---- .../Geometry/3D/Objects/Ray.test.cpp | 162 ++++++++- .../Geometry/3D/Objects/Segment.test.cpp | 220 +++++++---- 19 files changed, 1547 insertions(+), 230 deletions(-) diff --git a/README.md b/README.md index a476cc8b..8f8c14a3 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,15 @@ The **Mathematics** library exhibits the following structure: │ │ │ ├── Line │ │ │ ├── Ray │ │ │ ├── Segment -│ │ │ ├── Rectangle +│ │ │ ├── Line String +│ │ │ ├── Polygon │ │ │ ├── Plane +│ │ │ ├── Cuboid │ │ │ ├── Sphere │ │ │ ├── Ellipsoid │ │ │ ├── Cone -│ │ │ └── Pyramid +│ │ │ ├── Pyramid +│ │ │ └── Composite │ │ ├── Intersection │ │ └── Transformations │ │ ├── Identity @@ -109,6 +112,32 @@ Various tutorials are available here: - [C++](./tutorials/cpp) - [Python](./tutorials/python) +## Features + +### Geometry Queries + +- `?`: query only +- `x`: query and intersection + +#### 3D + +| Intersection | Point | Point Set | Line | Ray | Segment | Line String | Polygon | Plane | Cuboid | Sphere | Ellipsoid | Cone | Pyramid | Composite | +|--------------|-------|-----------|------|-----|---------|-------------|---------|-------|--------|--------|-----------|------|---------|-----------| +| Point | | | | | | | | | | | | | | | +| Point Set | | | | | | | | | | | | | | | +| Line | ? | | | | | | | x | | ? | ? | | | | +| Ray | ? | | | | | | | x | | ? | x | | | | +| Segment | | | | | | | | x | | ? | ? | | | | +| Line String | | | | | | | | | | | | | | | +| Polygon | | | | | | | | | | | | | | | +| Plane | x | x | x | x | x | | | | | | | | | | +| Cuboid | ? | ? | ? | | | | | | | | | | | | +| Sphere | ? | ? | ? | ? | ? | | | ? | | | | | ? | | +| Ellipsoid | ? | ? | x | x | x | | | ? | | | | | x | | +| Cone | | | | | | | | | | | x | | | | +| Pyramid | | | | | | | | | | | x | | | | +| Composite | | | | | | | | | | | | | | | + ## Setup ### Development @@ -182,4 +211,4 @@ Please read our [contributing guide](CONTRIBUTING.md) to learn about our develop ## License -Apache License 2.0 \ No newline at end of file +Apache License 2.0 diff --git a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Line.cpp b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Line.cpp index b81a42cf..1ba895e6 100755 --- a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Line.cpp +++ b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Line.cpp @@ -20,8 +20,10 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Line ( using library::math::geom::d3::Object ; using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Line ; + using library::math::geom::d3::objects::Plane ; using library::math::geom::d3::objects::Sphere ; using library::math::geom::d3::objects::Ellipsoid ; + using library::math::geom::d3::Intersection ; scope in_Line = class_>("Line", init()) @@ -33,18 +35,20 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Line ( .def("isDefined", &Line::isDefined) .def("intersectsPoint", +[] (const Line& aLine, const Point& aPoint) -> bool { return aLine.intersects(aPoint) ; }) + .def("intersectsPlane", +[] (const Line& aLine, const Plane& aPlane) -> bool { return aLine.intersects(aPlane) ; }) .def("intersectsSphere", +[] (const Line& aLine, const Sphere& aSphere) -> bool { return aLine.intersects(aSphere) ; }) .def("intersectsEllipsoid", +[] (const Line& aLine, const Ellipsoid& anEllipsoid) -> bool { return aLine.intersects(anEllipsoid) ; }) .def("containsPoint", +[] (const Line& aLine, const Point& aPoint) -> bool { return aLine.contains(aPoint) ; }) .def("getOrigin", &Line::getOrigin) .def("getDirection", &Line::getDirection) + .def("intersectionWithPlane", +[] (const Line& aLine, const Plane& aPlane) -> Intersection { return aLine.intersectionWith(aPlane) ; }) .def("applyTransformation", &Line::applyTransformation) - + .def("Undefined", &Line::Undefined).staticmethod("Undefined") ; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Plane.cpp b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Plane.cpp index 89a306d8..d0741dd5 100755 --- a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Plane.cpp +++ b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Plane.cpp @@ -19,7 +19,12 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Plane ( using library::math::obj::Vector3d ; using library::math::geom::d3::Object ; using library::math::geom::d3::objects::Point ; + using library::math::geom::d3::objects::PointSet ; using library::math::geom::d3::objects::Plane ; + using library::math::geom::d3::objects::Line ; + using library::math::geom::d3::objects::Ray ; + using library::math::geom::d3::objects::Segment ; + using library::math::geom::d3::Intersection ; scope in_Plane = class_>("Plane", init()) @@ -28,18 +33,32 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Plane ( .def(self_ns::str(self_ns::self)) .def(self_ns::repr(self_ns::self)) - + .def("isDefined", &Plane::isDefined) + .def("intersectsPoint", +[] (const Plane& aPlane, const Point& aPoint) -> bool { return aPlane.intersects(aPoint) ; }) + .def("intersectsPointSet", +[] (const Plane& aPlane, const PointSet& aPointSet) -> bool { return aPlane.intersects(aPointSet) ; }) + .def("intersectsLine", +[] (const Plane& aPlane, const Line& aLine) -> bool { return aPlane.intersects(aLine) ; }) + .def("intersectsRay", +[] (const Plane& aPlane, const Ray& aRay) -> bool { return aPlane.intersects(aRay) ; }) + .def("intersectsSegment", +[] (const Plane& aPlane, const Segment& aSegment) -> bool { return aPlane.intersects(aSegment) ; }) .def("containsPoint", +[] (const Plane& aPlane, const Point& aPoint) -> bool { return aPlane.contains(aPoint) ; }) + .def("containsPointSet", +[] (const Plane& aPlane, const PointSet& aPointSet) -> bool { return aPlane.contains(aPointSet) ; }) + .def("containsLine", +[] (const Plane& aPlane, const Line& aLine) -> bool { return aPlane.contains(aLine) ; }) + .def("containsRay", +[] (const Plane& aPlane, const Ray& aRay) -> bool { return aPlane.contains(aRay) ; }) + .def("containsSegment", +[] (const Plane& aPlane, const Segment& aSegment) -> bool { return aPlane.contains(aSegment) ; }) .def("getPoint", &Plane::getPoint) .def("getNormalVector", &Plane::getNormalVector) + .def("intersectionWithPoint", +[] (const Plane& aPlane, const Point& aPoint) -> Intersection { return aPlane.intersectionWith(aPoint) ; }) + .def("intersectionWithPointSet", +[] (const Plane& aPlane, const PointSet& aPointSet) -> Intersection { return aPlane.intersectionWith(aPointSet) ; }) + .def("intersectionWithLine", +[] (const Plane& aPlane, const Line& aLine) -> Intersection { return aPlane.intersectionWith(aLine) ; }) + .def("intersectionWithRay", +[] (const Plane& aPlane, const Ray& aRay) -> Intersection { return aPlane.intersectionWith(aRay) ; }) + .def("intersectionWithSegment", +[] (const Plane& aPlane, const Segment& aSegment) -> Intersection { return aPlane.intersectionWith(aSegment) ; }) .def("applyTransformation", &Plane::applyTransformation) - + .def("Undefined", &Plane::Undefined).staticmethod("Undefined") ; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Ray.cpp b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Ray.cpp index d0a652f4..90978038 100755 --- a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Ray.cpp +++ b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Ray.cpp @@ -19,6 +19,7 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Ray ( ) using library::math::obj::Vector3d ; using library::math::geom::d3::Object ; using library::math::geom::d3::objects::Point ; + using library::math::geom::d3::objects::PointSet ; using library::math::geom::d3::objects::Ray ; using library::math::geom::d3::objects::Plane ; using library::math::geom::d3::objects::Sphere ; @@ -35,20 +36,22 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Ray ( ) .def("isDefined", &Ray::isDefined) .def("intersectsPoint", +[] (const Ray& aRay, const Point& aPoint) -> bool { return aRay.intersects(aPoint) ; }) + .def("intersectsPlane", +[] (const Ray& aRay, const Plane& aPlane) -> bool { return aRay.intersects(aPlane) ; }) .def("intersectsSphere", +[] (const Ray& aRay, const Sphere& aSphere) -> bool { return aRay.intersects(aSphere) ; }) .def("intersectsEllipsoid", +[] (const Ray& aRay, const Ellipsoid& anEllipsoid) -> bool { return aRay.intersects(anEllipsoid) ; }) .def("containsPoint", +[] (const Ray& aRay, const Point& aPoint) -> bool { return aRay.contains(aPoint) ; }) + .def("containsPointSet", +[] (const Ray& aRay, const PointSet& aPointSet) -> bool { return aRay.contains(aPointSet) ; }) .def("getOrigin", &Ray::getOrigin) .def("getDirection", &Ray::getDirection) .def("intersectionWithPlane", +[] (const Ray& aRay, const Plane& aPlane) -> Intersection { return aRay.intersectionWith(aPlane) ; }) .def("intersectionWithEllipsoid", +[] (const Ray& aRay, const Ellipsoid& anEllipsoid) -> Intersection { return aRay.intersectionWith(anEllipsoid) ; }) .def("applyTransformation", &Ray::applyTransformation) - + .def("Undefined", &Ray::Undefined).staticmethod("Undefined") ; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Segment.cpp b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Segment.cpp index 0b7e3a78..8159941c 100755 --- a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Segment.cpp +++ b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Segment.cpp @@ -19,8 +19,10 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Segment using library::math::geom::d3::Object ; using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Segment ; + using library::math::geom::d3::objects::Plane ; using library::math::geom::d3::objects::Sphere ; using library::math::geom::d3::objects::Ellipsoid ; + using library::math::geom::d3::Intersection ; scope in_Segment = class_>("Segment", init()) @@ -32,6 +34,7 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Segment .def("isDefined", &Segment::isDefined) .def("isDegenerate", &Segment::isDegenerate) + .def("intersectsPlane", +[] (const Segment& aSegment, const Plane& aPlane) -> bool { return aSegment.intersects(aPlane) ; }) .def("intersectsSphere", +[] (const Segment& aSegment, const Sphere& aSphere) -> bool { return aSegment.intersects(aSphere) ; }) .def("intersectsEllipsoid", +[] (const Segment& aSegment, const Ellipsoid& anEllipsoid) -> bool { return aSegment.intersects(anEllipsoid) ; }) .def("containsPoint", +[] (const Segment& aSegment, const Point& aPoint) -> bool { return aSegment.contains(aPoint) ; }) @@ -41,12 +44,13 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Segment .def("getCenter", &Segment::getCenter) .def("getDirection", &Segment::getDirection) .def("getLength", &Segment::getLength) + .def("intersectionWithPlane", +[] (const Segment& aSegment, const Plane& aPlane) -> Intersection { return aSegment.intersectionWith(aPlane) ; }) .def("applyTransformation", &Segment::applyTransformation) - + .def("Undefined", &Segment::Undefined).staticmethod("Undefined") ; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/Library/Mathematics/Geometry/3D/Objects/Line.hpp b/include/Library/Mathematics/Geometry/3D/Objects/Line.hpp index 6be62c2c..d5079d66 100755 --- a/include/Library/Mathematics/Geometry/3D/Objects/Line.hpp +++ b/include/Library/Mathematics/Geometry/3D/Objects/Line.hpp @@ -38,6 +38,8 @@ using library::math::geom::d3::objects::Point ; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class PointSet ; +class Plane ; class Sphere ; class Ellipsoid ; @@ -110,11 +112,24 @@ class Line : public Object /// line.intersects(point) ; /// @endcode /// - /// @param [in] anPoint An point + /// @param [in] anPoint A point /// @return True if line intersects point - + bool intersects ( const Point& aPoint ) const ; + /// @brief Check if line intersects plane + /// + /// @code + /// Line line = ... ; + /// Plane plane = ... ; + /// line.intersects(plane) ; + /// @endcode + /// + /// @param [in] aPlane A plane + /// @return True if line intersects plane + + bool intersects ( const Plane& aPlane ) const ; + /// @brief Check if line intersects sphere /// /// @code @@ -125,7 +140,7 @@ class Line : public Object /// /// @param [in] aSphere A sphere /// @return True if line intersects sphere - + bool intersects ( const Sphere& aSphere ) const ; /// @brief Check if line intersects ellipsoid @@ -138,7 +153,7 @@ class Line : public Object /// /// @param [in] anEllipsoid An ellipsoid /// @return True if line intersects ellipsoid - + bool intersects ( const Ellipsoid& anEllipsoid ) const ; /// @brief Check if line contains point @@ -174,6 +189,13 @@ class Line : public Object Vector3d getDirection ( ) const ; + /// @brief Compute intersection of line with plane + /// + /// @param [in] aPlane A plane + /// @return Intersection of line with plane + + Intersection intersectionWith ( const Plane& aPlane ) const ; + /// @brief Print line /// /// @param [in] anOutputStream An output stream @@ -217,4 +239,4 @@ class Line : public Object #endif -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/Library/Mathematics/Geometry/3D/Objects/Plane.hpp b/include/Library/Mathematics/Geometry/3D/Objects/Plane.hpp index bee336a5..8f93b666 100755 --- a/include/Library/Mathematics/Geometry/3D/Objects/Plane.hpp +++ b/include/Library/Mathematics/Geometry/3D/Objects/Plane.hpp @@ -10,6 +10,10 @@ #ifndef __Library_Mathematics_Geometry_3D_Objects_Plane__ #define __Library_Mathematics_Geometry_3D_Objects_Plane__ +#include +#include +#include +#include #include #include #include @@ -32,6 +36,10 @@ namespace objects using library::math::obj::Vector3d ; using library::math::geom::d3::Object ; using library::math::geom::d3::objects::Point ; +using library::math::geom::d3::objects::PointSet ; +using library::math::geom::d3::objects::Line ; +using library::math::geom::d3::objects::Ray ; +using library::math::geom::d3::objects::Segment ; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -96,10 +104,75 @@ class Plane : public Object virtual bool isDefined ( ) const override ; + /// @brief Check if plane intersects point + /// + /// @code + /// Plane plane = ... ; + /// Point point = ... ; + /// plane.intersects(point) ; + /// @endcode + /// + /// @param [in] aPoint A point + /// @return True if plane intersects point + + bool intersects ( const Point& aPoint ) const ; + + /// @brief Check if plane intersects point set + /// + /// @code + /// Plane plane = ... ; + /// PointSet pointSet = ... ; + /// plane.intersects(pointSet) ; + /// @endcode + /// + /// @param [in] aPointSet A point set + /// @return True if plane intersects point set + + bool intersects ( const PointSet& aPointSet ) const ; + + /// @brief Check if plane intersects line + /// + /// @code + /// Plane plane = ... ; + /// Line line = ... ; + /// plane.intersects(line) ; + /// @endcode + /// + /// @param [in] aLine A line + /// @return True if plane intersects line + + bool intersects ( const Line& aLine ) const ; + + /// @brief Check if plane intersects ray + /// + /// @code + /// Plane plane = ... ; + /// Ray ray = ... ; + /// plane.intersects(ray) ; + /// @endcode + /// + /// @param [in] aRay A ray + /// @return True if plane intersects ray + + bool intersects ( const Ray& aRay ) const ; + + /// @brief Check if plane intersects segment + /// + /// @code + /// Plane plane = ... ; + /// Segment segment = ... ; + /// plane.intersects(segment) ; + /// @endcode + /// + /// @param [in] aSegment A segment + /// @return True if plane intersects segment + + bool intersects ( const Segment& aSegment ) const ; + /// @brief Check if plane contains point /// /// @code - /// Point plane = ... ; + /// Plane plane = ... ; /// Point point = ... ; /// plane.contains(point) ; /// @endcode @@ -109,6 +182,58 @@ class Plane : public Object bool contains ( const Point& aPoint ) const ; + /// @brief Check if plane contains point set + /// + /// @code + /// Point plane = ... ; + /// PointSet pointSet = ... ; + /// plane.contains(pointSet) ; + /// @endcode + /// + /// @param [in] aPointSet A point set + /// @return True if plane contains point set + + bool contains ( const PointSet& aPointSet ) const ; + + /// @brief Check if plane contains line + /// + /// @code + /// Point plane = ... ; + /// Line line = ... ; + /// plane.contains(line) ; + /// @endcode + /// + /// @param [in] aLine A line + /// @return True if plane contains line + + bool contains ( const Line& aLine ) const ; + + /// @brief Check if plane contains ray + /// + /// @code + /// Point plane = ... ; + /// Ray ray = ... ; + /// plane.contains(ray) ; + /// @endcode + /// + /// @param [in] aRay A ray + /// @return True if plane contains ray + + bool contains ( const Ray& aRay ) const ; + + /// @brief Check if plane contains segment + /// + /// @code + /// Point plane = ... ; + /// Segment segment = ... ; + /// plane.contains(segment) ; + /// @endcode + /// + /// @param [in] aSegment A segment + /// @return True if plane contains segment + + bool contains ( const Segment& aSegment ) const ; + /// @brief Get plane point /// /// @code @@ -129,6 +254,41 @@ class Plane : public Object Vector3d getNormalVector ( ) const ; + /// @brief Compute intersection of plane with point + /// + /// @param [in] aPoint A point + /// @return Intersection of plane with point + + Intersection intersectionWith ( const Point& aPoint ) const ; + + /// @brief Compute intersection of plane with point set + /// + /// @param [in] aPointSet A point set + /// @return Intersection of plane with point set + + Intersection intersectionWith ( const PointSet& aPointSet ) const ; + + /// @brief Compute intersection of plane with line + /// + /// @param [in] aLine A line + /// @return Intersection of plane with line + + Intersection intersectionWith ( const Line& aLine ) const ; + + /// @brief Compute intersection of plane with ray + /// + /// @param [in] aRay A ray + /// @return Intersection of plane with ray + + Intersection intersectionWith ( const Ray& aRay ) const ; + + /// @brief Compute intersection of plane with segment + /// + /// @param [in] aSegment A segment + /// @return Intersection of plane with segment + + Intersection intersectionWith ( const Segment& aSegment ) const ; + /// @brief Print plane /// /// @param [in] anOutputStream An output stream @@ -172,4 +332,4 @@ class Plane : public Object #endif -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/Library/Mathematics/Geometry/3D/Objects/Ray.hpp b/include/Library/Mathematics/Geometry/3D/Objects/Ray.hpp index 37da50e6..cbf0d962 100755 --- a/include/Library/Mathematics/Geometry/3D/Objects/Ray.hpp +++ b/include/Library/Mathematics/Geometry/3D/Objects/Ray.hpp @@ -38,6 +38,7 @@ using library::math::geom::d3::objects::Point ; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class PointSet ; class Line ; class Segment ; class Plane ; @@ -115,11 +116,24 @@ class Ray : public Object /// ray.intersects(point) ; /// @endcode /// - /// @param [in] anPoint An point + /// @param [in] anPoint A point /// @return True if ray intersects point - + bool intersects ( const Point& aPoint ) const ; + /// @brief Check if ray intersects plane + /// + /// @code + /// Ray ray = ... ; + /// Plane plane = ... ; + /// ray.intersects(plane) ; + /// @endcode + /// + /// @param [in] aPlane A plane + /// @return True if ray intersects plane + + bool intersects ( const Plane& aPlane ) const ; + /// @brief Check if ray intersects sphere /// /// @code @@ -130,9 +144,9 @@ class Ray : public Object /// /// @param [in] anSphere A sphere /// @return True if ray intersects sphere - + bool intersects ( const Sphere& aSphere ) const ; - + /// @brief Check if ray intersects ellipsoid /// /// @code @@ -143,22 +157,35 @@ class Ray : public Object /// /// @param [in] anEllipsoid An ellipsoid /// @return True if ray intersects ellipsoid - + bool intersects ( const Ellipsoid& anEllipsoid ) const ; /// @brief Check if ray contains point /// /// @code /// Ray ray = ... ; - /// Ellipsoid ellipsoid = ... ; - /// ray.contains(ellipsoid) ; + /// Point point = ... ; + /// ray.contains(point) ; /// @endcode /// - /// @param [in] anEllipsoid An ellipsoid + /// @param [in] aPoint A point /// @return True if ray contains point bool contains ( const Point& aPoint ) const ; + /// @brief Check if ray contains point set + /// + /// @code + /// Ray ray = ... ; + /// PointSet pointSet = ... ; + /// ray.contains(pointSet) ; + /// @endcode + /// + /// @param [in] aPointSet A point set + /// @return True if ray contains point set + + bool contains ( const PointSet& aPointSet ) const ; + /// @brief Get ray origin /// /// @code @@ -247,4 +274,4 @@ class Ray : public Object #endif -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/Library/Mathematics/Geometry/3D/Objects/Segment.hpp b/include/Library/Mathematics/Geometry/3D/Objects/Segment.hpp index ab71cbc8..9c2554e0 100755 --- a/include/Library/Mathematics/Geometry/3D/Objects/Segment.hpp +++ b/include/Library/Mathematics/Geometry/3D/Objects/Segment.hpp @@ -37,6 +37,8 @@ using library::math::geom::d3::objects::Point ; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class PointSet ; +class Plane ; class Sphere ; class Ellipsoid ; @@ -114,6 +116,19 @@ class Segment : public Object bool isDegenerate ( ) const ; + /// @brief Check if segment intersects plane + /// + /// @code + /// Segment segment = ... ; + /// Plane plane = ... ; + /// segment.intersects(plane) ; + /// @endcode + /// + /// @param [in] aPlane A plane + /// @return True if segment intersects plane + + bool intersects ( const Plane& aPlane ) const ; + /// @brief Check if segment intersects sphere /// /// @code @@ -124,7 +139,7 @@ class Segment : public Object /// /// @param [in] aSphere A sphere /// @return True if segment intersects sphere - + bool intersects ( const Sphere& aSphere ) const ; /// @brief Check if segment intersects ellipsoid @@ -137,7 +152,7 @@ class Segment : public Object /// /// @param [in] anEllipsoid An ellipsoid /// @return True if segment intersects ellipsoid - + bool intersects ( const Ellipsoid& anEllipsoid ) const ; /// @brief Check if segment contains point @@ -148,7 +163,7 @@ class Segment : public Object /// segment.contains(point) ; /// @endcode /// - /// @param [in] aPoint An point + /// @param [in] aPoint A point /// @return True if segment contains point bool contains ( const Point& aPoint ) const ; @@ -170,7 +185,7 @@ class Segment : public Object /// @endcode /// /// @return Segment second point - + Point getSecondPoint ( ) const ; /// @brief Get segment center @@ -203,6 +218,13 @@ class Segment : public Object Real getLength ( ) const ; + /// @brief Compute intersection of segment with plane + /// + /// @param [in] aPlane A plane + /// @return Intersection of segment with plane + + Intersection intersectionWith ( const Plane& aPlane ) const ; + /// @brief Print segment /// /// @param [in] anOutputStream An output stream @@ -246,4 +268,4 @@ class Segment : public Object #endif -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/Library/Mathematics/Geometry/3D/Intersection.cpp b/src/Library/Mathematics/Geometry/3D/Intersection.cpp index 94c71396..cf27764d 100644 --- a/src/Library/Mathematics/Geometry/3D/Intersection.cpp +++ b/src/Library/Mathematics/Geometry/3D/Intersection.cpp @@ -89,7 +89,7 @@ Intersection Intersection::operator + ( intersection.composite_ = composite_ + anIntersection.composite_ ; intersection.type_ = Intersection::TypeFromObjects(intersection.composite_.accessObjects()) ; - + return intersection ; } @@ -105,7 +105,7 @@ Intersection& Intersection::operator += ( composite_ += anIntersection.composite_ ; type_ = Intersection::TypeFromObjects(composite_.accessObjects()) ; - + return *this ; } @@ -117,7 +117,7 @@ std::ostream& operator << ( library::core::utils::Print::Header(anOutputStream, "Intersection") ; library::core::utils::Print::Line(anOutputStream) << "Type:" << Intersection::StringFromType(anIntersection.type_) ; - + library::core::utils::Print::Line(anOutputStream) << "Composite:" ; anIntersection.composite_.print(anOutputStream, false) ; @@ -130,7 +130,7 @@ std::ostream& operator << ( bool Intersection::isDefined ( ) const { - return (type_ != Intersection::Type::Undefined) && composite_.isDefined() ; + return type_ != Intersection::Type::Undefined ; } bool Intersection::isEmpty ( ) const @@ -150,7 +150,7 @@ const Composite& Intersection::accessComposite ( ) { throw library::core::error::runtime::Undefined("Intersection") ; } - + return composite_ ; } @@ -162,14 +162,14 @@ Intersection::Type Intersection::getType ( ) { throw library::core::error::runtime::Undefined("Intersection") ; } - + return type_ ; } Intersection Intersection::Undefined ( ) { - + Intersection intersection ; intersection.type_ = Intersection::Type::Undefined ; @@ -202,7 +202,7 @@ Intersection Intersection::PointSet ( Intersection intersection ; intersection.type_ = Intersection::Type::PointSet ; - + intersection.composite_ = Composite { aPointSet } ; return intersection ; @@ -215,7 +215,7 @@ Intersection Intersection::LineString ( Intersection intersection ; intersection.type_ = Intersection::Type::LineString ; - + intersection.composite_ = Composite { aLineString } ; return intersection ; @@ -430,4 +430,4 @@ Intersection::Type Intersection::TypeFromObject ( } } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/Library/Mathematics/Geometry/3D/Object.cpp b/src/Library/Mathematics/Geometry/3D/Object.cpp index 4921c292..44f6e663 100644 --- a/src/Library/Mathematics/Geometry/3D/Object.cpp +++ b/src/Library/Mathematics/Geometry/3D/Object.cpp @@ -293,10 +293,12 @@ bool Object::intersects ( if (const Line* objectPtr = dynamic_cast(this)) { - // if (const Line* otherObjectPtr = dynamic_cast(&anObject)) - // { - // return objectPtr->intersects(*otherObjectPtr) ; - // } + // Plane + + if (const Plane* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->intersects(*otherObjectPtr) ; + } // Sphere @@ -319,10 +321,12 @@ bool Object::intersects ( if (const Ray* objectPtr = dynamic_cast(this)) { - // if (const Ray* otherObjectPtr = dynamic_cast(&anObject)) - // { - // return objectPtr->intersects(*otherObjectPtr) ; - // } + // Plane + + if (const Plane* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->intersects(*otherObjectPtr) ; + } // Sphere @@ -345,10 +349,12 @@ bool Object::intersects ( if (const Segment* objectPtr = dynamic_cast(this)) { - // if (const Segment* otherObjectPtr = dynamic_cast(&anObject)) - // { - // return objectPtr->intersects(*otherObjectPtr) ; - // } + // Plane + + if (const Plane* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->intersects(*otherObjectPtr) ; + } // Sphere @@ -366,6 +372,48 @@ bool Object::intersects ( } + // Plane + + if (const Plane* objectPtr = dynamic_cast(this)) + { + + // Point + + if (const Point* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->intersects(*otherObjectPtr) ; + } + + // PointSet + + if (const PointSet* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->intersects(*otherObjectPtr) ; + } + + // Line + + if (const Line* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->intersects(*otherObjectPtr) ; + } + + // Ray + + if (const Ray* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->intersects(*otherObjectPtr) ; + } + + // Segment + + if (const Segment* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->intersects(*otherObjectPtr) ; + } + + } + // Sphere if (const Sphere* objectPtr = dynamic_cast(this)) @@ -552,6 +600,48 @@ bool Object::contains ( // } + // Plane + + if (const Plane* objectPtr = dynamic_cast(this)) + { + + // Point + + if (const Point* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->contains(*otherObjectPtr) ; + } + + // PointSet + + if (const PointSet* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->contains(*otherObjectPtr) ; + } + + // Line + + if (const Line* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->contains(*otherObjectPtr) ; + } + + // Ray + + if (const Ray* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->contains(*otherObjectPtr) ; + } + + // Segment + + if (const Segment* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->contains(*otherObjectPtr) ; + } + + } + // Ellipsoid if (const Ellipsoid* objectPtr = dynamic_cast(this)) @@ -623,6 +713,20 @@ Intersection Object::intersectionWith ( throw library::core::error::runtime::Undefined("Object") ; } + // Line + + if (const Line* objectPtr = dynamic_cast(this)) + { + + // Plane + + if (const Plane* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->intersectionWith(*otherObjectPtr) ; + } + + } + // Ray if (const Ray* objectPtr = dynamic_cast(this)) @@ -644,6 +748,20 @@ Intersection Object::intersectionWith ( } + // Segment + + if (const Segment* objectPtr = dynamic_cast(this)) + { + + // Plane + + if (const Plane* otherObjectPtr = dynamic_cast(&anObject)) + { + return objectPtr->intersectionWith(*otherObjectPtr) ; + } + + } + // Sphere if (const Sphere* objectPtr = dynamic_cast(this)) diff --git a/src/Library/Mathematics/Geometry/3D/Objects/Line.cpp b/src/Library/Mathematics/Geometry/3D/Objects/Line.cpp index 6a349a4a..4335e1ac 100644 --- a/src/Library/Mathematics/Geometry/3D/Objects/Line.cpp +++ b/src/Library/Mathematics/Geometry/3D/Objects/Line.cpp @@ -7,9 +7,11 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include #include #include #include +#include #include #include @@ -44,7 +46,7 @@ namespace objects { throw library::core::error::runtime::Wrong("Direction") ; } - + direction_ = direction_.normalized() ; } @@ -90,9 +92,39 @@ bool Line::intersects ( // bool Line::intersects ( const Line& aLine ) const // { - + // } +bool Line::intersects ( const Plane& aPlane ) const +{ + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Line") ; + } + + if (!aPlane.isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + const Vector3d n = aPlane.getNormalVector() ; + const Vector3d v = direction_ ; + + const Vector3d Q_0 = aPlane.getPoint().asVector() ; + const Vector3d P_0 = origin_.asVector() ; + + const double nDotV = n.dot(v) ; + + if (nDotV == 0.0) // Line and plane are parallel + { + return n.dot(Q_0 - P_0) == 0.0 ; // Line is in plane + } + + return true ; + +} + bool Line::intersects ( const Sphere& aSphere ) const { return aSphere.intersects(*this) ; @@ -132,7 +164,7 @@ Point Line::getOrigin ( ) { throw library::core::error::runtime::Undefined("Line") ; } - + return origin_ ; } @@ -144,11 +176,50 @@ Vector3d Line::getDirection ( ) con { throw library::core::error::runtime::Undefined("Line") ; } - + return direction_ ; } +Intersection Line::intersectionWith ( const Plane& aPlane ) const +{ + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Line") ; + } + + if (!aPlane.isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + const Vector3d n = aPlane.getNormalVector() ; + const Vector3d v = direction_ ; + + const Vector3d Q_0 = aPlane.getPoint().asVector() ; + const Vector3d P_0 = origin_.asVector() ; + + const double nDotV = n.dot(v) ; + + if (nDotV == 0.0) // Line and plane are parallel + { + + if (n.dot(Q_0 - P_0) == 0.0) // Line is in plane + { + return Intersection::Line(*this) ; + } + + return Intersection::Empty() ; + + } + + const double t = n.dot(Q_0 - P_0) / nDotV ; + + return Intersection::Point(Point::Vector(P_0 + t * v)) ; + +} + void Line::print ( std::ostream& anOutputStream, bool displayDecorators ) const { @@ -193,4 +264,4 @@ Line Line::Undefined ( ) } } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/Library/Mathematics/Geometry/3D/Objects/Plane.cpp b/src/Library/Mathematics/Geometry/3D/Objects/Plane.cpp index c3b2b90e..7be35c34 100644 --- a/src/Library/Mathematics/Geometry/3D/Objects/Plane.cpp +++ b/src/Library/Mathematics/Geometry/3D/Objects/Plane.cpp @@ -7,6 +7,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include #include #include @@ -69,9 +70,51 @@ bool Plane::isDefined ( ) return point_.isDefined() && normal_.isDefined() ; } +bool Plane::intersects ( const Point& aPoint ) const +{ + return this->contains(aPoint) ; +} + +bool Plane::intersects ( const PointSet& aPointSet ) const +{ + + if (!aPointSet.isDefined()) + { + throw library::core::error::runtime::Undefined("Point Set") ; + } + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + return (!aPointSet.isEmpty()) && std::any_of(aPointSet.begin(), aPointSet.end(), [this] (const Point& aPoint) -> bool { return this->contains(aPoint) ; }) ; + +} + +bool Plane::intersects ( const Line& aLine ) const +{ + return aLine.intersects(*this) ; +} + +bool Plane::intersects ( const Ray& aRay ) const +{ + return aRay.intersects(*this) ; +} + +bool Plane::intersects ( const Segment& aSegment ) const +{ + return aSegment.intersects(*this) ; +} + bool Plane::contains ( const Point& aPoint ) const { + if (!aPoint.isDefined()) + { + throw library::core::error::runtime::Undefined("Point") ; + } + if (!this->isDefined()) { throw library::core::error::runtime::Undefined("Plane") ; @@ -81,6 +124,74 @@ bool Plane::contains ( } +bool Plane::contains ( const PointSet& aPointSet ) const +{ + + if (!aPointSet.isDefined()) + { + throw library::core::error::runtime::Undefined("Point Set") ; + } + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + return (!aPointSet.isEmpty()) && std::all_of(aPointSet.begin(), aPointSet.end(), [this] (const Point& aPoint) -> bool { return this->contains(aPoint) ; }) ; + +} + +bool Plane::contains ( const Line& aLine ) const +{ + + if (!aLine.isDefined()) + { + throw library::core::error::runtime::Undefined("Line") ; + } + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + return this->contains(aLine.getOrigin()) && (normal_.dot(aLine.getDirection()) == 0.0) ; + +} + +bool Plane::contains ( const Ray& aRay ) const +{ + + if (!aRay.isDefined()) + { + throw library::core::error::runtime::Undefined("Ray") ; + } + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + return this->contains(aRay.getOrigin()) && (normal_.dot(aRay.getDirection()) == 0.0) ; + +} + +bool Plane::contains ( const Segment& aSegment ) const +{ + + if (!aSegment.isDefined()) + { + throw library::core::error::runtime::Undefined("Segment") ; + } + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + return this->contains(aSegment.getFirstPoint()) && this->contains(aSegment.getSecondPoint()) ; + +} + Point Plane::getPoint ( ) const { @@ -105,6 +216,45 @@ Vector3d Plane::getNormalVector ( ) } +Intersection Plane::intersectionWith ( const Point& aPoint ) const +{ + return this->contains(aPoint) ? Intersection::Point(aPoint) : Intersection::Empty() ; +} + +Intersection Plane::intersectionWith ( const PointSet& aPointSet ) const +{ + + Array points = Array::Empty() ; + + for (const auto& point : aPointSet) + { + + if (this->contains(point)) + { + points.add(point) ; + } + + } + + return (!points.isEmpty()) ? Intersection::PointSet({ points }) : Intersection::Empty() ; + +} + +Intersection Plane::intersectionWith ( const Line& aLine ) const +{ + return aLine.intersectionWith(*this) ; +} + +Intersection Plane::intersectionWith ( const Ray& aRay ) const +{ + return aRay.intersectionWith(*this) ; +} + +Intersection Plane::intersectionWith ( const Segment& aSegment ) const +{ + return aSegment.intersectionWith(*this) ; +} + void Plane::print ( std::ostream& anOutputStream, bool displayDecorators ) const { @@ -149,4 +299,4 @@ Plane Plane::Undefined ( ) } } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/Library/Mathematics/Geometry/3D/Objects/Ray.cpp b/src/Library/Mathematics/Geometry/3D/Objects/Ray.cpp index 7e7cd445..1c83676d 100644 --- a/src/Library/Mathematics/Geometry/3D/Objects/Ray.cpp +++ b/src/Library/Mathematics/Geometry/3D/Objects/Ray.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -45,7 +46,7 @@ namespace objects { throw library::core::error::runtime::Wrong("Direction") ; } - + direction_ = direction_.normalized() ; } @@ -86,9 +87,41 @@ bool Ray::intersects ( // bool Ray::intersects ( const Ray& aRay ) const // { - + // } +bool Ray::intersects ( const Plane& aPlane ) const +{ + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Ray") ; + } + + if (!aPlane.isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + const Vector3d n = aPlane.getNormalVector() ; + const Vector3d v = direction_ ; + + const Vector3d Q_0 = aPlane.getPoint().asVector() ; + const Vector3d P_0 = origin_.asVector() ; + + const double nDotV = n.dot(v) ; + + if (nDotV == 0.0) // Ray and plane are parallel + { + return n.dot(Q_0 - P_0) == 0.0 ; // Ray is in plane + } + + const double t = n.dot(Q_0 - P_0) / nDotV ; + + return t >= 0.0 ; + +} + bool Ray::intersects ( const Sphere& aSphere ) const { return aSphere.intersects(*this) ; @@ -118,10 +151,22 @@ bool Ray::contains ( } -// bool Ray::contains ( const PointSet& aPointSet ) const -// { +bool Ray::contains ( const PointSet& aPointSet ) const +{ -// } + if (!aPointSet.isDefined()) + { + throw library::core::error::runtime::Undefined("Point Set") ; + } + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Ray") ; + } + + return (!aPointSet.isEmpty()) && std::all_of(aPointSet.begin(), aPointSet.end(), [this] (const Point& aPoint) -> bool { return this->contains(aPoint) ; }) ; + +} Point Ray::getOrigin ( ) const { @@ -130,7 +175,7 @@ Point Ray::getOrigin ( ) { throw library::core::error::runtime::Undefined("Ray") ; } - + return origin_ ; } @@ -142,7 +187,7 @@ Vector3d Ray::getDirection ( ) { throw library::core::error::runtime::Undefined("Ray") ; } - + return direction_ ; } @@ -247,4 +292,4 @@ Ray Ray::Undefined ( ) } } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/Library/Mathematics/Geometry/3D/Objects/Segment.cpp b/src/Library/Mathematics/Geometry/3D/Objects/Segment.cpp index 0c64efb5..a264456e 100644 --- a/src/Library/Mathematics/Geometry/3D/Objects/Segment.cpp +++ b/src/Library/Mathematics/Geometry/3D/Objects/Segment.cpp @@ -7,9 +7,11 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include #include #include #include +#include #include #include @@ -74,16 +76,50 @@ bool Segment::isDegenerate ( ) { throw library::core::error::runtime::Undefined("Segment") ; } - + return firstPoint_ == secondPoint_ ; } // bool Segment::intersects ( const Segment& aSegment ) const // { - + // } +bool Segment::intersects ( const Plane& aPlane ) const +{ + + // http://geomalgorithms.com/a05-_intersect-1.html + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Segment") ; + } + + if (!aPlane.isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + const Vector3d n = aPlane.getNormalVector() ; + const Vector3d v = secondPoint_ - firstPoint_ ; + + const Vector3d Q_0 = aPlane.getPoint().asVector() ; + const Vector3d P_0 = firstPoint_.asVector() ; + + const double nDotV = n.dot(v) ; + + if (nDotV == 0.0) // Segment and plane are parallel + { + return n.dot(Q_0 - P_0) == 0.0 ; // Segment is in plane + } + + const double t = n.dot(Q_0 - P_0) / nDotV ; + + return ((t >= 0.0) && (t <= 1.0)) ; + +} + bool Segment::intersects ( const Sphere& aSphere ) const { return aSphere.intersects(*this) ; @@ -165,7 +201,7 @@ Point Segment::getCenter ( ) { throw library::core::error::runtime::Undefined("Segment") ; } - + return firstPoint_ + (secondPoint_ - firstPoint_) / 2.0 ; } @@ -182,7 +218,7 @@ Vector3d Segment::getDirection ( ) { throw library::core::error::RuntimeError("Segment is degenerate.") ; } - + return (secondPoint_ - firstPoint_).normalized() ; } @@ -194,11 +230,57 @@ Real Segment::getLength ( ) { throw library::core::error::runtime::Undefined("Segment") ; } - + return (secondPoint_ - firstPoint_).norm() ; } +Intersection Segment::intersectionWith ( const Plane& aPlane ) const +{ + + // http://geomalgorithms.com/a05-_intersect-1.html + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Segment") ; + } + + if (!aPlane.isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + const Vector3d n = aPlane.getNormalVector() ; + const Vector3d v = secondPoint_ - firstPoint_ ; + + const Vector3d Q_0 = aPlane.getPoint().asVector() ; + const Vector3d P_0 = firstPoint_.asVector() ; + + const double nDotV = n.dot(v) ; + + if (nDotV == 0.0) // Segment and plane are parallel + { + + if (n.dot(Q_0 - P_0) == 0.0) // Segment is in plane + { + return Intersection::Segment(*this) ; + } + + return Intersection::Empty() ; + + } + + const double t = n.dot(Q_0 - P_0) / nDotV ; + + if ((t < 0.0) || (t > 1.0)) + { + return Intersection::Empty() ; + } + + return Intersection::Point(Point::Vector(P_0 + t * v)) ; + +} + void Segment::print ( std::ostream& anOutputStream, bool displayDecorators ) const { @@ -243,4 +325,4 @@ Segment Segment::Undefined ( ) } } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/Library/Mathematics/Geometry/3D/Objects/Line.test.cpp b/test/Library/Mathematics/Geometry/3D/Objects/Line.test.cpp index 0610cd73..99a043b9 100644 --- a/test/Library/Mathematics/Geometry/3D/Objects/Line.test.cpp +++ b/test/Library/Mathematics/Geometry/3D/Objects/Line.test.cpp @@ -7,6 +7,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include #include #include #include @@ -47,7 +48,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Line, EqualToOperator) { using library::math::geom::d3::objects::Line ; - + { EXPECT_TRUE(Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }) == Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, +1.0 })) ; @@ -115,7 +116,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Line, StreamOperator) { using library::math::geom::d3::objects::Line ; - + { testing::internal::CaptureStdout() ; @@ -132,7 +133,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Line, IsDefined) { using library::math::geom::d3::objects::Line ; - + { EXPECT_TRUE(Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).isDefined()) ; @@ -156,7 +157,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Line, Intersects_Point) { EXPECT_TRUE(Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(0.0, 0.0, 0.0))) ; - + EXPECT_TRUE(Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(0.0, 0.0, -1.0))) ; EXPECT_TRUE(Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(0.0, 0.0, +1.0))) ; @@ -183,6 +184,46 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Line, Intersects_Point) } +TEST (Library_Mathematics_Geometry_3D_Objects_Line, Intersects_Plane) +{ + + using library::math::geom::d3::objects::Line ; + using library::math::geom::d3::objects::Plane ; + + { + + EXPECT_TRUE(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_TRUE(Line({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Line({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 1.0, 2.0, 3.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Line({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 1.0, 2.0, 3.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_TRUE(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ +1.0, +2.0, +3.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ -1.0, -2.0, -3.0 }, { 1.0, 0.0, 0.0 }))) ; + + } + + { + + EXPECT_FALSE(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ +1.0, +2.0, +3.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_FALSE(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ +1.0, +2.0, +3.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_FALSE(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ -1.0, -2.0, -3.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_FALSE(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ -1.0, -2.0, -3.0 }, { 0.0, 0.0, 1.0 }))) ; + + } + + { + + EXPECT_ANY_THROW(Line::Undefined().intersects(Plane::Undefined())) ; + EXPECT_ANY_THROW(Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Plane::Undefined())) ; + + } + +} + TEST (Library_Mathematics_Geometry_3D_Objects_Line, Intersects_Sphere) { @@ -268,12 +309,12 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Line, GetOrigin) using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Line ; - + { EXPECT_EQ(Point(0.0, 0.0, 0.0), Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).getOrigin()) ; EXPECT_EQ(Point(0.0, 0.0, 1.0), Line({ 0.0, 0.0, 1.0 }, { 0.0, 0.0, 2.0 }).getOrigin()) ; - + EXPECT_EQ(Point(0.0, 0.0, -1.0), Line({ 0.0, 0.0, -1.0 }, { 0.0, 0.0, +1.0 }).getOrigin()) ; } @@ -292,7 +333,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Line, GetDirection) using library::math::obj::Vector3d ; using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Line ; - + { EXPECT_EQ(Vector3d(0.0, 0.0, +1.0), Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, +2.0 }).getDirection()) ; @@ -308,6 +349,93 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Line, GetDirection) } +TEST (Library_Mathematics_Geometry_3D_Objects_Line, IntersectionWith_Plane) +{ + + using library::core::types::Real ; + + using library::math::geom::d3::objects::Point ; + using library::math::geom::d3::objects::Line ; + using library::math::geom::d3::objects::Plane ; + using library::math::geom::d3::Intersection ; + + const auto expectLineIntersection = + [] (const Line& aLine, const Plane& aPlane, const Line& anIntersectionLine) -> void + { + + const Intersection intersection = aLine.intersectionWith(aPlane) ; + + EXPECT_TRUE(intersection.isDefined()) ; + + ASSERT_TRUE(intersection.accessComposite().is()) ; + + const Line line = intersection.accessComposite().as() ; + + EXPECT_EQ(anIntersectionLine, line) ; + + } ; + + const auto expectPointIntersection = + [] (const Line& aLine, const Plane& aPlane, const Point& anIntersectionPoint) -> void + { + + const Intersection intersection = aLine.intersectionWith(aPlane) ; + + EXPECT_TRUE(intersection.isDefined()) ; + + ASSERT_TRUE(intersection.accessComposite().is()) ; + + const Point point = intersection.accessComposite().as() ; + + EXPECT_TRUE(point.isNear(anIntersectionPoint, Real::Epsilon())) ; + + } ; + + const auto expectEmptyIntersection = + [] (const Line& aLine, const Plane& aPlane) -> void + { + + const Intersection intersection = aLine.intersectionWith(aPlane) ; + + EXPECT_TRUE(intersection.isDefined()) ; + EXPECT_TRUE(intersection.isEmpty()) ; + + } ; + + { + + expectPointIntersection(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Point(0.0, 0.0, 0.0)) ; + expectLineIntersection(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }), Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 })) ; + expectLineIntersection(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 })) ; + + expectPointIntersection(Line({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }), Plane({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }), Point(1.0, 2.0, 3.0)) ; + expectLineIntersection(Line({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }), Plane({ 1.0, 2.0, 3.0 }, { 0.0, 1.0, 0.0 }), Line({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 })) ; + expectLineIntersection(Line({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }), Plane({ 1.0, 2.0, 3.0 }, { 0.0, 0.0, 1.0 }), Line({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 })) ; + + expectPointIntersection(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ +1.0, +2.0, +3.0 }, { 1.0, 0.0, 0.0 }), Point(+1.0, 0.0, 0.0)) ; + expectPointIntersection(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ -1.0, -2.0, -3.0 }, { 1.0, 0.0, 0.0 }), Point(-1.0, 0.0, 0.0)) ; + + } + + { + + expectEmptyIntersection(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ +1.0, +2.0, +3.0 }, { 0.0, 1.0, 0.0 })) ; + expectEmptyIntersection(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ +1.0, +2.0, +3.0 }, { 0.0, 0.0, 1.0 })) ; + + expectEmptyIntersection(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ -1.0, -2.0, -3.0 }, { 0.0, 1.0, 0.0 })) ; + expectEmptyIntersection(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ -1.0, -2.0, -3.0 }, { 0.0, 0.0, 1.0 })) ; + + } + + { + + EXPECT_ANY_THROW(Line::Undefined().intersectionWith(Plane::Undefined())) ; + EXPECT_ANY_THROW(Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersectionWith(Plane::Undefined())) ; + + } + +} + TEST (Library_Mathematics_Geometry_3D_Objects_Line, ApplyTransformation) { @@ -360,7 +488,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Line, Undefined) { using library::math::geom::d3::objects::Line ; - + { EXPECT_NO_THROW(Line::Undefined()) ; @@ -370,4 +498,4 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Line, Undefined) } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/Library/Mathematics/Geometry/3D/Objects/Plane.test.cpp b/test/Library/Mathematics/Geometry/3D/Objects/Plane.test.cpp index 7607455e..ccabbbd9 100644 --- a/test/Library/Mathematics/Geometry/3D/Objects/Plane.test.cpp +++ b/test/Library/Mathematics/Geometry/3D/Objects/Plane.test.cpp @@ -7,6 +7,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include #include #include #include @@ -45,7 +46,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, EqualToOperator) { using library::math::geom::d3::objects::Plane ; - + { EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }) == Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 })) ; @@ -107,7 +108,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, StreamOperator) { using library::math::geom::d3::objects::Plane ; - + { testing::internal::CaptureStdout() ; @@ -124,7 +125,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IsDefined) { using library::math::geom::d3::objects::Plane ; - + { EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).isDefined()) ; @@ -140,137 +141,233 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IsDefined) } -// TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Intersects) -// { +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Intersects_Point) +{ + + using library::math::geom::d3::objects::Point ; + using library::math::geom::d3::objects::Plane ; + + { + + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(0.0, 0.0, 0.0))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(1.0, 0.0, 0.0))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(0.0, 1.0, 0.0))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(1.0, 1.0, 0.0))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 2.0 }).intersects(Point(0.0, 0.0, 0.0))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(0.0, 0.0, 1.0))) ; + EXPECT_TRUE(Plane({ 1.0, 1.0, 1.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(0.0, 0.0, 1.0))) ; + + } + + { + + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(0.0, 0.0, 0.1))) ; + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(0.0, 0.0, 1.0))) ; + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point(0.0, 0.0, -1.0))) ; + + } + + { + + EXPECT_ANY_THROW(Plane::Undefined().intersects(Point::Undefined())) ; + EXPECT_ANY_THROW(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Point::Undefined())) ; + EXPECT_ANY_THROW(Plane::Undefined().intersects(Point(0.0, 0.0, 0.0))) ; + + } + +} + +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Intersects_PointSet) +{ + + using library::math::geom::d3::objects::PointSet ; + using library::math::geom::d3::objects::Plane ; + + { + + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(PointSet({{ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }}))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(PointSet({{ 1.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }}))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(PointSet({{ 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0 }}))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(PointSet({{ 1.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0 }}))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 2.0 }).intersects(PointSet({{ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }}))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0 }).intersects(PointSet({{ 0.0, 0.0, 1.0 }, { 1.0, 0.0, 1.0 }}))) ; + EXPECT_TRUE(Plane({ 1.0, 1.0, 1.0 }, { 0.0, 0.0, 1.0 }).intersects(PointSet({{ 0.0, 0.0, 1.0 }, { 0.0, 1.0, 1.0 }}))) ; + + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(PointSet({{ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.1 }}))) ; + + } -// using library::math::geom::d3::objects::Plane ; -// using library::math::geom::d3::objects::Ellipsoid ; + { -// // Point + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(PointSet({{ 0.0, 0.0, 0.1 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, -1.0 }}))) ; -// { + } -// // [TBI] + { -// } + EXPECT_ANY_THROW(Plane::Undefined().intersects(PointSet::Empty())) ; + EXPECT_ANY_THROW(Plane::Undefined().intersects(PointSet({{ 0.0, 0.0, 0.0 }}))) ; -// // PointSet + } -// { +} -// // [TBI] +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Intersects_Line) +{ -// } + using library::math::geom::d3::objects::Line ; + using library::math::geom::d3::objects::Plane ; -// // Plane + { -// { + // See: Library_Mathematics_Geometry_3D_Objects_Line.Intersects_Plane -// // [TBI] + SUCCEED() ; -// } + } -// // Sphere +} -// { +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Intersects_Ray) +{ -// // [TBI] + using library::math::geom::d3::objects::Ray ; + using library::math::geom::d3::objects::Plane ; -// } + { -// // Ellipsoid + // See: Library_Mathematics_Geometry_3D_Objects_Ray.Intersects_Plane -// { + SUCCEED() ; -// { + } -// // See: Library_Mathematics_Geometry_3D_Objects_Ellipsoid.Intersects +} -// SUCCEED() ; +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Intersects_Segment) +{ -// } + using library::math::geom::d3::objects::Segment ; + using library::math::geom::d3::objects::Plane ; -// { + { -// EXPECT_ANY_THROW(Plane::Undefined().intersects(Ellipsoid::Undefined())) ; -// EXPECT_ANY_THROW(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).intersects(Ellipsoid::Undefined())) ; + // See: Library_Mathematics_Geometry_3D_Objects_Segment.Intersects_Plane -// } + SUCCEED() ; -// } + } -// } +} -TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Contains) +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Contains_Point) { using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Plane ; - // Point + { + + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 0.0))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(1.0, 0.0, 0.0))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 1.0, 0.0))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(1.0, 1.0, 0.0))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 2.0 }).contains(Point(0.0, 0.0, 0.0))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 1.0))) ; + EXPECT_TRUE(Plane({ 1.0, 1.0, 1.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 1.0))) ; + + } { - { + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 0.1))) ; + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 1.0))) ; + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, -1.0))) ; - EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 0.0))) ; - EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(1.0, 0.0, 0.0))) ; - EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 1.0, 0.0))) ; - EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(1.0, 1.0, 0.0))) ; - EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 2.0 }).contains(Point(0.0, 0.0, 0.0))) ; - EXPECT_TRUE(Plane({ 0.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 1.0))) ; - EXPECT_TRUE(Plane({ 1.0, 1.0, 1.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 1.0))) ; + } - } + { - { + EXPECT_ANY_THROW(Plane::Undefined().contains(Point::Undefined())) ; + EXPECT_ANY_THROW(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point::Undefined())) ; + EXPECT_ANY_THROW(Plane::Undefined().contains(Point(0.0, 0.0, 0.0))) ; - EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 0.1))) ; - EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 1.0))) ; - EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, -1.0))) ; + } - } +} - { +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Contains_PointSet) +{ - EXPECT_ANY_THROW(Plane::Undefined().contains(Point::Undefined())) ; - EXPECT_ANY_THROW(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point::Undefined())) ; - EXPECT_ANY_THROW(Plane::Undefined().contains(Point(0.0, 0.0, 0.0))) ; + using library::math::geom::d3::objects::PointSet ; + using library::math::geom::d3::objects::Plane ; + + { - } + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }}))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 1.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }}))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0 }}))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 1.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0 }}))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 2.0 }).contains(PointSet({{ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }}))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 0.0, 1.0 }, { 1.0, 0.0, 1.0 }}))) ; + EXPECT_TRUE(Plane({ 1.0, 1.0, 1.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 0.0, 1.0 }, { 0.0, 1.0, 1.0 }}))) ; } - // PointSet + { + + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 0.0, 0.1 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, -1.0 }}))) ; + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.1 }}))) ; + + } { - // [TBI] - + EXPECT_ANY_THROW(Plane::Undefined().contains(PointSet::Empty())) ; + EXPECT_ANY_THROW(Plane::Undefined().contains(PointSet({{ 0.0, 0.0, 0.0 }}))) ; + } - // Plane +} + +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Contains_Line) +{ + + using library::math::geom::d3::objects::Line ; + using library::math::geom::d3::objects::Plane ; { - // [TBI] - + FAIL() ; + } - // Sphere +} + +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Contains_Ray) +{ + + using library::math::geom::d3::objects::Ray ; + using library::math::geom::d3::objects::Plane ; { - // [TBI] - + FAIL() ; + } - // Ellipsoid +} + +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Contains_Segment) +{ + + using library::math::geom::d3::objects::Segment ; + using library::math::geom::d3::objects::Plane ; { - // [TBI] - + FAIL() ; + } } @@ -280,7 +377,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, GetPoint) using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Plane ; - + { EXPECT_EQ(Point(0.0, 0.0, 0.0), Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).getPoint()) ; @@ -302,7 +399,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, GetNormalVector) using library::math::obj::Vector3d ; using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Plane ; - + { EXPECT_EQ(Vector3d(0.0, 0.0, +1.0), Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, +2.0 }).getNormalVector()) ; @@ -318,9 +415,109 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, GetNormalVector) } +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_Point) +{ + + using library::math::geom::d3::objects::Point ; + using library::math::geom::d3::objects::Plane ; + + { + + FAIL() ; + + } + + { + + EXPECT_ANY_THROW(Plane::Undefined().intersectionWith(Point::Undefined())) ; + + } + +} + +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_PointSet) +{ + + using library::math::geom::d3::objects::PointSet ; + using library::math::geom::d3::objects::Plane ; + + { + + FAIL() ; + + } + + { + + EXPECT_ANY_THROW(Plane::Undefined().intersectionWith(PointSet::Empty())) ; + + } + +} + +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_Line) +{ + + using library::math::geom::d3::objects::Line ; + using library::math::geom::d3::objects::Plane ; + + { + + FAIL() ; + + } + + { + + EXPECT_ANY_THROW(Plane::Undefined().intersectionWith(Line::Undefined())) ; + + } + +} + +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_Ray) +{ + + using library::math::geom::d3::objects::Ray ; + using library::math::geom::d3::objects::Plane ; + + { + + FAIL() ; + + } + + { + + EXPECT_ANY_THROW(Plane::Undefined().intersectionWith(Ray::Undefined())) ; + + } + +} + +TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_Segment) +{ + + using library::math::geom::d3::objects::Segment ; + using library::math::geom::d3::objects::Plane ; + + { + + FAIL() ; + + } + + { + + EXPECT_ANY_THROW(Plane::Undefined().intersectionWith(Segment::Undefined())) ; + + } + +} + TEST (Library_Mathematics_Geometry_3D_Objects_Plane, ApplyTransformation) { - + using library::core::types::Real ; using library::math::obj::Vector3d ; @@ -370,7 +567,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Undefined) { using library::math::geom::d3::objects::Plane ; - + { EXPECT_NO_THROW(Plane::Undefined()) ; @@ -380,4 +577,4 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Undefined) } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/Library/Mathematics/Geometry/3D/Objects/Ray.test.cpp b/test/Library/Mathematics/Geometry/3D/Objects/Ray.test.cpp index 60f2fc58..98a81f4e 100644 --- a/test/Library/Mathematics/Geometry/3D/Objects/Ray.test.cpp +++ b/test/Library/Mathematics/Geometry/3D/Objects/Ray.test.cpp @@ -7,8 +7,8 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#include #include +#include #include #include #include @@ -48,7 +48,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, EqualToOperator) { using library::math::geom::d3::objects::Ray ; - + { EXPECT_TRUE(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }) == Ray({ 0.0, 0.0, +0.0 }, { 0.0, 0.0, +1.0 })) ; @@ -119,7 +119,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, StreamOperator) { using library::math::geom::d3::objects::Ray ; - + { testing::internal::CaptureStdout() ; @@ -136,7 +136,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, IsDefined) { using library::math::geom::d3::objects::Ray ; - + { EXPECT_TRUE(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).isDefined()) ; @@ -184,6 +184,47 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, Intersects_Point) } +TEST (Library_Mathematics_Geometry_3D_Objects_Ray, Intersects_Plane) +{ + + using library::math::geom::d3::objects::Ray ; + using library::math::geom::d3::objects::Plane ; + + { + + EXPECT_TRUE(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_TRUE(Ray({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Ray({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 1.0, 2.0, 3.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Ray({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 1.0, 2.0, 3.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_TRUE(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ +1.0, +2.0, +3.0 }, { 1.0, 0.0, 0.0 }))) ; + + } + + { + + EXPECT_FALSE(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ +1.0, +2.0, +3.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_FALSE(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ +1.0, +2.0, +3.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_FALSE(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ -1.0, -2.0, -3.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_FALSE(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ -1.0, -2.0, -3.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_FALSE(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ -1.0, -2.0, -3.0 }, { 1.0, 0.0, 0.0 }))) ; + + } + + { + + EXPECT_ANY_THROW(Ray::Undefined().intersects(Plane::Undefined())) ; + EXPECT_ANY_THROW(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Plane::Undefined())) ; + + } + +} + TEST (Library_Mathematics_Geometry_3D_Objects_Ray, Intersects_Sphere) { @@ -264,17 +305,48 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, Contains_Point) } +TEST (Library_Mathematics_Geometry_3D_Objects_Ray, Contains_PointSet) +{ + + using library::math::geom::d3::objects::PointSet ; + using library::math::geom::d3::objects::Ray ; + + { + + EXPECT_TRUE(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 0.0, 0.0 }}))) ; + EXPECT_TRUE(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }}))) ; + EXPECT_TRUE(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.5 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, 2.0 }}))) ; + + } + + { + + EXPECT_FALSE(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 0.0, -1.0 }, { 0.0, 0.0, 0.5 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, 2.0 }}))) ; + EXPECT_FALSE(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ 0.0, 0.0, -2.0 }, { 0.0, 0.0, 0.5 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, 2.0 }}))) ; + EXPECT_FALSE(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(PointSet({{ -1.0, 0.0, 0.0 }, { 0.0, 0.0, 0.5 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, 2.0 }}))) ; + + } + + { + + EXPECT_ANY_THROW(Ray::Undefined().contains(PointSet::Empty())) ; + EXPECT_ANY_THROW(Ray::Undefined().contains(PointSet({{ 0.0, 0.0, 0.0 }}))) ; + + } + +} + TEST (Library_Mathematics_Geometry_3D_Objects_Ray, GetOrigin) { using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Ray ; - + { EXPECT_EQ(Point(0.0, 0.0, 0.0), Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).getOrigin()) ; EXPECT_EQ(Point(0.0, 0.0, 1.0), Ray({ 0.0, 0.0, 1.0 }, { 0.0, 0.0, 2.0 }).getOrigin()) ; - + EXPECT_EQ(Point(0.0, 0.0, -1.0), Ray({ 0.0, 0.0, -1.0 }, { 0.0, 0.0, +1.0 }).getOrigin()) ; } @@ -293,7 +365,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, GetDirection) using library::math::obj::Vector3d ; using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Ray ; - + { EXPECT_EQ(Vector3d(0.0, 0.0, +1.0), Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, +2.0 }).getDirection()) ; @@ -312,18 +384,86 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, GetDirection) TEST (Library_Mathematics_Geometry_3D_Objects_Ray, IntersectionWith_Plane) { + using library::core::types::Real ; + + using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Ray ; using library::math::geom::d3::objects::Plane ; + using library::math::geom::d3::Intersection ; + const auto expectRayIntersection = + [] (const Ray& aRay, const Plane& aPlane, const Ray& anIntersectionRay) -> void { - // [TBI] + const Intersection intersection = aRay.intersectionWith(aPlane) ; + + EXPECT_TRUE(intersection.isDefined()) ; + + ASSERT_TRUE(intersection.accessComposite().is()) ; + + const Ray ray = intersection.accessComposite().as() ; + + EXPECT_EQ(anIntersectionRay, ray) ; + + } ; + + const auto expectPointIntersection = + [] (const Ray& aRay, const Plane& aPlane, const Point& anIntersectionPoint) -> void + { + + const Intersection intersection = aRay.intersectionWith(aPlane) ; + + EXPECT_TRUE(intersection.isDefined()) ; + + ASSERT_TRUE(intersection.accessComposite().is()) ; + + const Point point = intersection.accessComposite().as() ; + + EXPECT_TRUE(point.isNear(anIntersectionPoint, Real::Epsilon())) ; + + } ; + + const auto expectEmptyIntersection = + [] (const Ray& aRay, const Plane& aPlane) -> void + { + + const Intersection intersection = aRay.intersectionWith(aPlane) ; + + EXPECT_TRUE(intersection.isDefined()) ; + EXPECT_TRUE(intersection.isEmpty()) ; + + } ; + + { + + expectPointIntersection(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Point(0.0, 0.0, 0.0)) ; + expectRayIntersection(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }), Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 })) ; + expectRayIntersection(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 })) ; + + expectPointIntersection(Ray({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }), Plane({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }), Point(1.0, 2.0, 3.0)) ; + expectRayIntersection(Ray({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }), Plane({ 1.0, 2.0, 3.0 }, { 0.0, 1.0, 0.0 }), Ray({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 })) ; + expectRayIntersection(Ray({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }), Plane({ 1.0, 2.0, 3.0 }, { 0.0, 0.0, 1.0 }), Ray({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 })) ; + + expectPointIntersection(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ +1.0, +2.0, +3.0 }, { 1.0, 0.0, 0.0 }), Point(+1.0, 0.0, 0.0)) ; + + } + + { + + expectEmptyIntersection(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ +1.0, +2.0, +3.0 }, { 0.0, 1.0, 0.0 })) ; + expectEmptyIntersection(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ +1.0, +2.0, +3.0 }, { 0.0, 0.0, 1.0 })) ; + + expectEmptyIntersection(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ -1.0, -2.0, -3.0 }, { 0.0, 1.0, 0.0 })) ; + expectEmptyIntersection(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ -1.0, -2.0, -3.0 }, { 0.0, 0.0, 1.0 })) ; + + expectEmptyIntersection(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ -1.0, -2.0, -3.0 }, { 1.0, 0.0, 0.0 })) ; } { EXPECT_ANY_THROW(Ray::Undefined().intersectionWith(Plane::Undefined())) ; + EXPECT_ANY_THROW(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersectionWith(Plane::Undefined())) ; } @@ -334,7 +474,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, IntersectionWith_Ellipsoid) using library::math::geom::d3::objects::Ray ; using library::math::geom::d3::objects::Ellipsoid ; - + { // See: Library_Mathematics_Geometry_3D_Objects_Ellipsoid.IntersectionWith_Ray @@ -403,7 +543,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, Undefined) { using library::math::geom::d3::objects::Ray ; - + { EXPECT_NO_THROW(Ray::Undefined()) ; @@ -413,4 +553,4 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, Undefined) } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/Library/Mathematics/Geometry/3D/Objects/Segment.test.cpp b/test/Library/Mathematics/Geometry/3D/Objects/Segment.test.cpp index c98776ac..a44547e5 100644 --- a/test/Library/Mathematics/Geometry/3D/Objects/Segment.test.cpp +++ b/test/Library/Mathematics/Geometry/3D/Objects/Segment.test.cpp @@ -7,6 +7,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include #include #include #include @@ -47,7 +48,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, EqualToOperator) { using library::math::geom::d3::objects::Segment ; - + { EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }) == Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 })) ; @@ -103,7 +104,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, StreamOperator) { using library::math::geom::d3::objects::Segment ; - + { testing::internal::CaptureStdout() ; @@ -120,7 +121,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, IsDefined) { using library::math::geom::d3::objects::Segment ; - + { EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).isDefined()) ; @@ -140,7 +141,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, IsDegenerate) { using library::math::geom::d3::objects::Segment ; - + { EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).isDegenerate()) ; @@ -163,6 +164,47 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, IsDegenerate) } +TEST (Library_Mathematics_Geometry_3D_Objects_Segment, Intersects_Plane) +{ + + using library::math::geom::d3::objects::Segment ; + using library::math::geom::d3::objects::Plane ; + + { + + EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_TRUE(Segment({ 1.0, 2.0, 3.0 }, { 2.0, 2.0, 3.0 }).intersects(Plane({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Segment({ 1.0, 2.0, 3.0 }, { 2.0, 2.0, 3.0 }).intersects(Plane({ 1.0, 2.0, 3.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Segment({ 1.0, 2.0, 3.0 }, { 2.0, 2.0, 3.0 }).intersects(Plane({ 1.0, 2.0, 3.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ +1.0, +2.0, +3.0 }, { 1.0, 0.0, 0.0 }))) ; + + } + + { + + EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ +1.0, +2.0, +3.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ +1.0, +2.0, +3.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ -1.0, -2.0, -3.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ -1.0, -2.0, -3.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }).intersects(Plane({ -1.0, -2.0, -3.0 }, { 1.0, 0.0, 0.0 }))) ; + + } + + { + + EXPECT_ANY_THROW(Segment::Undefined().intersects(Plane::Undefined())) ; + EXPECT_ANY_THROW(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersects(Plane::Undefined())) ; + + } + +} + TEST (Library_Mathematics_Geometry_3D_Objects_Segment, Intersects_Sphere) { @@ -209,74 +251,36 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, Intersects_Ellipsoid) } -TEST (Library_Mathematics_Geometry_3D_Objects_Segment, Contains) +TEST (Library_Mathematics_Geometry_3D_Objects_Segment, Contains_Point) { using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Segment ; - // Point - { - { - - EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).contains(Point(0.0, 0.0, 0.0))) ; - EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 0.0))) ; - EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 1.0))) ; - EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 0.5))) ; - - } - - { - - EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).contains(Point(0.0, 0.0, 0.1))) ; - EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 2.0))) ; - EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, -1.0))) ; - EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(1.0, 0.0, 0.0))) ; - - } - - { - - EXPECT_ANY_THROW(Segment::Undefined().contains(Point::Undefined())) ; - EXPECT_ANY_THROW(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).contains(Point::Undefined())) ; - EXPECT_ANY_THROW(Segment::Undefined().contains(Point(0.0, 0.0, 0.0))) ; - - } + EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).contains(Point(0.0, 0.0, 0.0))) ; + EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 0.0))) ; + EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 1.0))) ; + EXPECT_TRUE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 0.5))) ; } - // PointSet - { - // [TBI] - - } - - // Segment + EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).contains(Point(0.0, 0.0, 0.1))) ; + EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, 2.0))) ; + EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(0.0, 0.0, -1.0))) ; + EXPECT_FALSE(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Point(1.0, 0.0, 0.0))) ; - { - - // [TBI] - } - // Sphere - { - // [TBI] - - } - - // Ellipsoid - - { + EXPECT_ANY_THROW(Segment::Undefined().contains(Point::Undefined())) ; + EXPECT_ANY_THROW(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).contains(Point::Undefined())) ; + EXPECT_ANY_THROW(Segment::Undefined().contains(Point(0.0, 0.0, 0.0))) ; - // [TBI] - } } @@ -286,12 +290,12 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, GetCenter) using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Segment ; - + { EXPECT_EQ(Point(0.0, 0.0, 0.0), Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).getCenter()) ; EXPECT_EQ(Point(0.0, 0.0, 1.0), Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 2.0 }).getCenter()) ; - + EXPECT_EQ(Point(0.0, 0.0, 0.0), Segment({ 0.0, 0.0, -1.0 }, { 0.0, 0.0, +1.0 }).getCenter()) ; } @@ -310,7 +314,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, GetDirection) using library::math::obj::Vector3d ; using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Segment ; - + { EXPECT_EQ(Vector3d(0.0, 0.0, +1.0), Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, +2.0 }).getDirection()) ; @@ -334,15 +338,15 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, GetLength) using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Segment ; - + { EXPECT_EQ(0.0, Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }).getLength()) ; EXPECT_EQ(0.0, Segment({ 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }).getLength()) ; - + EXPECT_EQ(1.0, Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).getLength()) ; EXPECT_EQ(2.0, Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 2.0 }).getLength()) ; - + EXPECT_EQ(4.0, Segment({ 0.0, 0.0, -2.0 }, { 0.0, 0.0, +2.0 }).getLength()) ; } @@ -355,6 +359,98 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, GetLength) } +TEST (Library_Mathematics_Geometry_3D_Objects_Segment, IntersectionWith_Plane) +{ + + using library::core::types::Real ; + + using library::math::geom::d3::objects::Point ; + using library::math::geom::d3::objects::Segment ; + using library::math::geom::d3::objects::Plane ; + using library::math::geom::d3::Intersection ; + + const auto expectSegmentIntersection = + [] (const Segment& aSegment, const Plane& aPlane, const Segment& anIntersectionSegment) -> void + { + + const Intersection intersection = aSegment.intersectionWith(aPlane) ; + + EXPECT_TRUE(intersection.isDefined()) ; + + ASSERT_TRUE(intersection.accessComposite().is()) ; + + const Segment segment = intersection.accessComposite().as() ; + + EXPECT_EQ(anIntersectionSegment, segment) ; + + } ; + + const auto expectPointIntersection = + [] (const Segment& aSegment, const Plane& aPlane, const Point& anIntersectionPoint) -> void + { + + const Intersection intersection = aSegment.intersectionWith(aPlane) ; + + EXPECT_TRUE(intersection.isDefined()) ; + + ASSERT_TRUE(intersection.accessComposite().is()) ; + + const Point point = intersection.accessComposite().as() ; + + EXPECT_TRUE(point.isNear(anIntersectionPoint, Real::Epsilon())) ; + + } ; + + const auto expectEmptyIntersection = + [] (const Segment& aSegment, const Plane& aPlane) -> void + { + + const Intersection intersection = aSegment.intersectionWith(aPlane) ; + + EXPECT_TRUE(intersection.isDefined()) ; + EXPECT_TRUE(intersection.isEmpty()) ; + + } ; + + { + + expectPointIntersection(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Point(0.0, 0.0, 0.0)) ; + expectPointIntersection(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Point(1.0, 0.0, 0.0)) ; + + expectSegmentIntersection(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }), Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 })) ; + expectSegmentIntersection(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 })) ; + + expectPointIntersection(Segment({ 1.0, 2.0, 3.0 }, { 2.0, 2.0, 3.0 }), Plane({ 1.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }), Point(1.0, 2.0, 3.0)) ; + expectPointIntersection(Segment({ 1.0, 2.0, 3.0 }, { 2.0, 2.0, 3.0 }), Plane({ 2.0, 2.0, 3.0 }, { 1.0, 0.0, 0.0 }), Point(2.0, 2.0, 3.0)) ; + + expectSegmentIntersection(Segment({ 1.0, 2.0, 3.0 }, { 2.0, 2.0, 3.0 }), Plane({ 1.0, 2.0, 3.0 }, { 0.0, 1.0, 0.0 }), Segment({ 1.0, 2.0, 3.0 }, { 2.0, 2.0, 3.0 })) ; + expectSegmentIntersection(Segment({ 1.0, 2.0, 3.0 }, { 2.0, 2.0, 3.0 }), Plane({ 1.0, 2.0, 3.0 }, { 0.0, 0.0, 1.0 }), Segment({ 1.0, 2.0, 3.0 }, { 2.0, 2.0, 3.0 })) ; + + expectPointIntersection(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ +1.0, +2.0, +3.0 }, { 1.0, 0.0, 0.0 }), Point(+1.0, 0.0, 0.0)) ; + + } + + { + + expectEmptyIntersection(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ +1.0, +2.0, +3.0 }, { 0.0, 1.0, 0.0 })) ; + expectEmptyIntersection(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ +1.0, +2.0, +3.0 }, { 0.0, 0.0, 1.0 })) ; + + expectEmptyIntersection(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ -1.0, -2.0, -3.0 }, { 0.0, 1.0, 0.0 })) ; + expectEmptyIntersection(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ -1.0, -2.0, -3.0 }, { 0.0, 0.0, 1.0 })) ; + + expectEmptyIntersection(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }), Plane({ -1.0, -2.0, -3.0 }, { 1.0, 0.0, 0.0 })) ; + + } + + { + + EXPECT_ANY_THROW(Segment::Undefined().intersectionWith(Plane::Undefined())) ; + EXPECT_ANY_THROW(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersectionWith(Plane::Undefined())) ; + + } + +} + TEST (Library_Mathematics_Geometry_3D_Objects_Segment, ApplyTransformation) { @@ -407,7 +503,7 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, Undefined) { using library::math::geom::d3::objects::Segment ; - + { EXPECT_NO_THROW(Segment::Undefined()) ; @@ -417,4 +513,4 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Segment, Undefined) } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// From 2f2ea6118980bf98209f7decf846b8c494f16212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Br=C3=A9mond?= Date: Thu, 18 Jul 2019 10:52:36 -0700 Subject: [PATCH 2/2] [misc] Add missing tests --- README.md | 55 +++-- .../Mathematics/Geometry/3D/Objects/Plane.cpp | 7 +- .../Geometry/3D/Objects/Plane.test.cpp | 205 +++++++++++++++++- 3 files changed, 240 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 8f8c14a3..149e6748 100644 --- a/README.md +++ b/README.md @@ -116,27 +116,46 @@ Various tutorials are available here: ### Geometry Queries -- `?`: query only -- `x`: query and intersection +- `○`: query only +- `✔`: query / intersection set +- ` `: to be implemented +- `-`: undefined #### 3D -| Intersection | Point | Point Set | Line | Ray | Segment | Line String | Polygon | Plane | Cuboid | Sphere | Ellipsoid | Cone | Pyramid | Composite | -|--------------|-------|-----------|------|-----|---------|-------------|---------|-------|--------|--------|-----------|------|---------|-----------| -| Point | | | | | | | | | | | | | | | -| Point Set | | | | | | | | | | | | | | | -| Line | ? | | | | | | | x | | ? | ? | | | | -| Ray | ? | | | | | | | x | | ? | x | | | | -| Segment | | | | | | | | x | | ? | ? | | | | -| Line String | | | | | | | | | | | | | | | -| Polygon | | | | | | | | | | | | | | | -| Plane | x | x | x | x | x | | | | | | | | | | -| Cuboid | ? | ? | ? | | | | | | | | | | | | -| Sphere | ? | ? | ? | ? | ? | | | ? | | | | | ? | | -| Ellipsoid | ? | ? | x | x | x | | | ? | | | | | x | | -| Cone | | | | | | | | | | | x | | | | -| Pyramid | | | | | | | | | | | x | | | | -| Composite | | | | | | | | | | | | | | | +| Intersect | Point | Point Set | Line | Ray | Segment | Line String | Polygon | Plane | Cuboid | Sphere | Ellipsoid | Cone | Pyramid | Composite | +|------------------|-------|-----------|------|-----|---------|-------------|---------|-------|--------|--------|-----------|------|---------|-----------| +| **Point** | | | ○ | ○ | | | | ✔ | ○ | ○ | ○ | | | | +| **Point Set** | | | | | | | | ✔ | ○ | ○ | ○ | | | | +| **Line** | ○ | | | | | | | ✔ | ○ | ○ | ✔ | | | | +| **Ray** | ○ | | | | | | | ✔ | | ○ | ✔ | | | | +| **Segment** | | | | | | | | ✔ | | ○ | ✔ | | | | +| **Line String** | | | | | | | | | | | | | | | +| **Polygon** | | | | | | | | | | | | | | | +| **Plane** | ✔ | ✔ | ✔ | ✔ | ✔ | | | | | ○ | ○ | | | | +| **Cuboid** | ○ | ○ | ○ | | | | | | | | | | | | +| **Sphere** | ○ | ○ | ○ | ○ | ○ | | | ○ | | | | | ○ | | +| **Ellipsoid** | ○ | ○ | ✔ | ✔ | ✔ | | | ○ | | | | ✔ | ✔ | | +| **Cone** | | | | | | | | | | | ✔ | | | | +| **Pyramid** | | | | | | | | | | ○ | ✔ | | | | +| **Composite** | | | | | | | | | | | | | | | + +| Contain | Point | Point Set | Line | Ray | Segment | Line String | Polygon | Plane | Cuboid | Sphere | Ellipsoid | Cone | Pyramid | Composite | +|------------------|-------|-----------|------|-----|---------|-------------|---------|-------|--------|--------|-----------|------|---------|-----------| +| **Point** | | | - | - | - | - | - | - | - | - | - | - | - | | +| **Point Set** | | | - | - | - | - | - | - | - | - | - | - | - | | +| **Line** | ✔ | | | | | | - | - | - | - | - | - | - | | +| **Ray** | ✔ | ✔ | - | | | | - | - | - | - | - | - | - | | +| **Segment** | ✔ | | - | - | | | - | - | - | - | - | - | - | | +| **Line String** | | | - | - | | | - | - | - | - | - | - | - | | +| **Polygon** | | | - | - | | | | - | - | - | - | - | - | | +| **Plane** | ✔ | ✔ | ✔ | ✔ | ✔ | | | | - | - | - | - | - | | +| **Cuboid** | ✔ | ✔ | - | - | | | | - | | | | | | | +| **Sphere** | ✔ | ✔ | - | - | - | - | - | - | | | | | | | +| **Ellipsoid** | ✔ | ✔ | - | - | - | - | - | - | | | | | | | +| **Cone** | | | | | | - | - | - | | | | | | | +| **Pyramid** | ✔ | | | | | | | - | | | | | | | +| **Composite** | | | | | | | | | | | | | | | ## Setup diff --git a/src/Library/Mathematics/Geometry/3D/Objects/Plane.cpp b/src/Library/Mathematics/Geometry/3D/Objects/Plane.cpp index 7be35c34..d38d2329 100644 --- a/src/Library/Mathematics/Geometry/3D/Objects/Plane.cpp +++ b/src/Library/Mathematics/Geometry/3D/Objects/Plane.cpp @@ -224,6 +224,11 @@ Intersection Plane::intersectionWith ( Intersection Plane::intersectionWith ( const PointSet& aPointSet ) const { + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + Array points = Array::Empty() ; for (const auto& point : aPointSet) @@ -236,7 +241,7 @@ Intersection Plane::intersectionWith ( } - return (!points.isEmpty()) ? Intersection::PointSet({ points }) : Intersection::Empty() ; + return (!points.isEmpty()) ? ((points.getSize() == 1) ? Intersection::Point(points.accessFirst()) : Intersection::PointSet({ points })) : Intersection::Empty() ; } diff --git a/test/Library/Mathematics/Geometry/3D/Objects/Plane.test.cpp b/test/Library/Mathematics/Geometry/3D/Objects/Plane.test.cpp index ccabbbd9..86c37e13 100644 --- a/test/Library/Mathematics/Geometry/3D/Objects/Plane.test.cpp +++ b/test/Library/Mathematics/Geometry/3D/Objects/Plane.test.cpp @@ -338,7 +338,30 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Contains_Line) { - FAIL() ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Line({ 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Line({ 0.0, 0.0, 0.0 }, { 1.0, 1.0, 0.0 }))) ; + + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Line({ 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Line({ 0.0, 1.0, 0.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Line({ 1.0, 1.0, 0.0 }, { 1.0, 1.0, 0.0 }))) ; + + } + + { + + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Line({ 0.0, 0.0, +1.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Line({ 0.0, 0.0, -1.0 }, { 0.0, 1.0, 0.0 }))) ; + + } + + { + + EXPECT_ANY_THROW(Plane::Undefined().contains(Line::Undefined())) ; + EXPECT_ANY_THROW(Plane::Undefined().contains(Line({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }))) ; + EXPECT_ANY_THROW(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Line::Undefined())) ; } @@ -352,7 +375,30 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Contains_Ray) { - FAIL() ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 1.0, 0.0 }))) ; + + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Ray({ 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Ray({ 0.0, 1.0, 0.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Ray({ 1.0, 1.0, 0.0 }, { 1.0, 1.0, 0.0 }))) ; + + } + + { + + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Ray({ 0.0, 0.0, +1.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Ray({ 0.0, 0.0, -1.0 }, { 0.0, 1.0, 0.0 }))) ; + + } + + { + + EXPECT_ANY_THROW(Plane::Undefined().contains(Ray::Undefined())) ; + EXPECT_ANY_THROW(Plane::Undefined().contains(Ray({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }))) ; + EXPECT_ANY_THROW(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Ray::Undefined())) ; } @@ -366,7 +412,31 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, Contains_Segment) { - FAIL() ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 1.0, 0.0 }))) ; + + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment({ 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment({ 0.0, 1.0, 0.0 }, { 0.0, 1.0, 0.0 }))) ; + EXPECT_TRUE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment({ 1.0, 1.0, 0.0 }, { 1.0, 1.0, 0.0 }))) ; + + } + + { + + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }))) ; + + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment({ 0.0, 0.0, +1.0 }, { 1.0, 0.0, +1.0 }))) ; + EXPECT_FALSE(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment({ 0.0, 0.0, -1.0 }, { 0.0, 1.0, -1.0 }))) ; + + } + + { + + EXPECT_ANY_THROW(Plane::Undefined().contains(Segment::Undefined())) ; + EXPECT_ANY_THROW(Plane::Undefined().contains(Segment({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }))) ; + EXPECT_ANY_THROW(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).contains(Segment::Undefined())) ; } @@ -418,18 +488,64 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, GetNormalVector) TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_Point) { + using library::core::types::Real ; + using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Plane ; + using library::math::geom::d3::Intersection ; + + const auto expectPointIntersection = + [] (const Plane& aPlane, const Point& aPoint, const Point& anIntersectionPoint) -> void + { + + const Intersection intersection = aPlane.intersectionWith(aPoint) ; + + EXPECT_TRUE(intersection.isDefined()) ; + + ASSERT_TRUE(intersection.accessComposite().is()) ; + const Point point = intersection.accessComposite().as() ; + + EXPECT_TRUE(point.isNear(anIntersectionPoint, Real::Epsilon())) ; + + } ; + + const auto expectEmptyIntersection = + [] (const Plane& aPlane, const Point& aPoint) -> void { - FAIL() ; + const Intersection intersection = aPlane.intersectionWith(aPoint) ; + + EXPECT_TRUE(intersection.isDefined()) ; + EXPECT_TRUE(intersection.isEmpty()) ; + + } ; + + { + + expectPointIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), Point(0.0, 0.0, 0.0), Point(0.0, 0.0, 0.0)) ; + expectPointIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), Point(1.0, 0.0, 0.0), Point(1.0, 0.0, 0.0)) ; + expectPointIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), Point(0.0, 1.0, 0.0), Point(0.0, 1.0, 0.0)) ; + expectPointIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), Point(1.0, 1.0, 0.0), Point(1.0, 1.0, 0.0)) ; + expectPointIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 2.0 }), Point(0.0, 0.0, 0.0), Point(0.0, 0.0, 0.0)) ; + expectPointIntersection(Plane({ 0.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0 }), Point(0.0, 0.0, 1.0), Point(0.0, 0.0, 1.0)) ; + expectPointIntersection(Plane({ 1.0, 1.0, 1.0 }, { 0.0, 0.0, 1.0 }), Point(0.0, 0.0, 1.0), Point(0.0, 0.0, 1.0)) ; + + } + + { + + expectEmptyIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), Point(0.0, 0.0, 0.1)) ; + expectEmptyIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), Point(0.0, 0.0, 1.0)) ; + expectEmptyIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), Point(0.0, 0.0, -1.0)) ; } { EXPECT_ANY_THROW(Plane::Undefined().intersectionWith(Point::Undefined())) ; + EXPECT_ANY_THROW(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }).intersectionWith(Point::Undefined())) ; + EXPECT_ANY_THROW(Plane::Undefined().intersectionWith(Point(0.0, 0.0, 0.0))) ; } @@ -438,18 +554,85 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_Point) TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_PointSet) { + using library::core::types::Real ; + + using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::PointSet ; using library::math::geom::d3::objects::Plane ; + using library::math::geom::d3::Intersection ; + + const auto expectPointIntersection = + [] (const Plane& aPlane, const PointSet& aPointSet, const Point& anIntersectionPoint) -> void + { + + const Intersection intersection = aPlane.intersectionWith(aPointSet) ; + + EXPECT_TRUE(intersection.isDefined()) ; + + ASSERT_TRUE(intersection.accessComposite().is()) ; + + const Point point = intersection.accessComposite().as() ; + + EXPECT_TRUE(point.isNear(anIntersectionPoint, Real::Epsilon())) ; + + } ; + + const auto expectPointSetIntersection = + [] (const Plane& aPlane, const PointSet& aPointSet, const PointSet& anIntersectionPointSet) -> void + { + + const Intersection intersection = aPlane.intersectionWith(aPointSet) ; + + EXPECT_TRUE(intersection.isDefined()) ; + + ASSERT_TRUE(intersection.accessComposite().is()) ; + + const PointSet pointSet = intersection.accessComposite().as() ; + + EXPECT_TRUE(pointSet.isNear(anIntersectionPointSet, Real::Epsilon())) ; + + } ; + + const auto expectEmptyIntersection = + [] (const Plane& aPlane, const PointSet& aPointSet) -> void + { + + const Intersection intersection = aPlane.intersectionWith(aPointSet) ; + + EXPECT_TRUE(intersection.isDefined()) ; + EXPECT_TRUE(intersection.isEmpty()) ; + + } ; + + { + + expectPointSetIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), PointSet({{ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }}), PointSet({{ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }})) ; + expectPointSetIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), PointSet({{ 1.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }}), PointSet({{ 1.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }})) ; + expectPointSetIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), PointSet({{ 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0 }}), PointSet({{ 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0 }})) ; + expectPointSetIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), PointSet({{ 1.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0 }}), PointSet({{ 1.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0 }})) ; + + expectPointSetIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 2.0 }), PointSet({{ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }}), PointSet({{ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }})) ; + expectPointSetIntersection(Plane({ 0.0, 0.0, 1.0 }, { 0.0, 0.0, 1.0 }), PointSet({{ 0.0, 0.0, 1.0 }, { 1.0, 0.0, 1.0 }}), PointSet({{ 0.0, 0.0, 1.0 }, { 1.0, 0.0, 1.0 }})) ; + expectPointSetIntersection(Plane({ 1.0, 1.0, 1.0 }, { 0.0, 0.0, 1.0 }), PointSet({{ 0.0, 0.0, 1.0 }, { 0.0, 1.0, 1.0 }}), PointSet({{ 0.0, 0.0, 1.0 }, { 0.0, 1.0, 1.0 }})) ; + + } + + { + + expectPointIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), PointSet({{ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.1 }}), Point({ 0.0, 0.0, 0.0 })) ; + + } { - FAIL() ; + expectEmptyIntersection(Plane({ 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0 }), PointSet({{ 0.0, 0.0, 0.1 }, { 0.0, 0.0, 1.0 }, { 0.0, 0.0, -1.0 }})) ; } { EXPECT_ANY_THROW(Plane::Undefined().intersectionWith(PointSet::Empty())) ; + EXPECT_ANY_THROW(Plane::Undefined().intersectionWith(PointSet({{ 0.0, 0.0, 0.0 }}))) ; } @@ -463,7 +646,9 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_Line) { - FAIL() ; + // See: Library_Mathematics_Geometry_3D_Objects_Line.IntersectionWith_Plane + + SUCCEED() ; } @@ -483,7 +668,9 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_Ray) { - FAIL() ; + // See: Library_Mathematics_Geometry_3D_Objects_Ray.IntersectionWith_Plane + + SUCCEED() ; } @@ -503,7 +690,9 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Plane, IntersectionWith_Segment) { - FAIL() ; + // See: Library_Mathematics_Geometry_3D_Objects_Segment.IntersectionWith_Plane + + SUCCEED() ; }