diff --git a/doc/shapes.dox b/doc/shapes.dox index cb99d5454..1e5772d56 100644 --- a/doc/shapes.dox +++ b/doc/shapes.dox @@ -51,6 +51,7 @@ line and point. Collision of two lines can be detected only in 2D. @subsection shapes-3D Three-dimensional shapes - @ref Shapes::Sphere "Shapes::Sphere*D" -- @copybrief Shapes::Sphere +- @ref Shapes::Cylinder "Shapes::Cylinder*D" -- @copybrief Shapes::Cylinder - @ref Shapes::Capsule "Shapes::Capsule*D" -- @copybrief Shapes::Capsule - @ref Shapes::AxisAlignedBox "Shapes::AxisAlignedBox*D" -- @copybrief Shapes::AxisAlignedBox - @ref Shapes::Box "Shapes::Box*D" -- @copybrief Shapes::Box diff --git a/src/Shapes/CMakeLists.txt b/src/Shapes/CMakeLists.txt index 2f23c8abb..de98a9474 100644 --- a/src/Shapes/CMakeLists.txt +++ b/src/Shapes/CMakeLists.txt @@ -27,6 +27,7 @@ set(MagnumShapes_SRCS AxisAlignedBox.cpp Box.cpp Capsule.cpp + Cylinder.cpp Composition.cpp Line.cpp Plane.cpp @@ -44,6 +45,7 @@ set(MagnumShapes_HEADERS AxisAlignedBox.h Box.h Capsule.h + Cylinder.h Composition.h Line.h LineSegment.h diff --git a/src/Shapes/Capsule.h b/src/Shapes/Capsule.h index bceb0876c..c0f0d4bbc 100644 --- a/src/Shapes/Capsule.h +++ b/src/Shapes/Capsule.h @@ -40,7 +40,7 @@ namespace Magnum { namespace Shapes { Unlike other elements the capsule expects uniform scaling. See @ref shapes for brief introduction. -@see Capsule2D, Capsule3D +@see Capsule2D, Capsule3D, Cylinder @todo Store the radius as squared value to avoid sqrt/pow? Will complicate collision detection with sphere. */ diff --git a/src/Shapes/Composition.h b/src/Shapes/Composition.h index 5552352cc..1783ee593 100644 --- a/src/Shapes/Composition.h +++ b/src/Shapes/Composition.h @@ -79,6 +79,7 @@ template class MAGNUM_SHAPES_EXPORT Composition { Line, /**< Line */ LineSegment, /**< @ref LineSegment "Line segment" */ Sphere, /**< Sphere */ + Cylinder, /**< @ref Cylinder */ Capsule, /**< Capsule */ AxisAlignedBox, /**< @ref AxisAlignedBox "Axis aligned box" */ Box, /**< Box */ diff --git a/src/Shapes/Cylinder.cpp b/src/Shapes/Cylinder.cpp new file mode 100644 index 000000000..b24cc43f0 --- /dev/null +++ b/src/Shapes/Cylinder.cpp @@ -0,0 +1,58 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Cylinder.h" + +#include "Math/Functions.h" +#include "Math/Matrix3.h" +#include "Math/Matrix4.h" +#include "Math/Geometry/Distance.h" +#include "Magnum.h" +#include "Shapes/Point.h" +#include "Shapes/Sphere.h" + +using namespace Magnum::Math::Geometry; + +namespace Magnum { namespace Shapes { + +template Cylinder Cylinder::transformed(const typename DimensionTraits::MatrixType& matrix) const { + return Cylinder(matrix.transformPoint(_a), matrix.transformPoint(_b), matrix.uniformScaling()*_radius); +} + +template bool Cylinder::operator%(const Point& other) const { + return Distance::linePointSquared(_a, _b, other.position()) < + Math::pow<2>(_radius); +} + +template bool Cylinder::operator%(const Sphere& other) const { + return Distance::linePointSquared(_a, _b, other.position()) < + Math::pow<2>(_radius+other.radius()); +} + +#ifndef DOXYGEN_GENERATING_OUTPUT +template class MAGNUM_SHAPES_EXPORT Cylinder<2>; +template class MAGNUM_SHAPES_EXPORT Cylinder<3>; +#endif + +}} diff --git a/src/Shapes/Cylinder.h b/src/Shapes/Cylinder.h new file mode 100644 index 000000000..e9a04d33b --- /dev/null +++ b/src/Shapes/Cylinder.h @@ -0,0 +1,117 @@ +#ifndef Magnum_Shapes_Cylinder_h +#define Magnum_Shapes_Cylinder_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Shapes::Cylinder, typedef Magnum::Shapes::Cylinder2D, Magnum::Shapes::Cylinder3D + */ + +#include "Math/Vector3.h" +#include "DimensionTraits.h" +#include "Shapes/Shapes.h" +#include "Shapes/magnumShapesVisibility.h" + +namespace Magnum { namespace Shapes { + +/** +@brief Infinite cylinder defined by line and radius + +Unlike other elements the cylinder expects uniform scaling. See @ref shapes for +brief introduction. +@see @ref Cylinder2D, @ref Cylinder3D, @ref Capsule +@todo Store the radius as squared value to avoid sqrt/pow? Will complicate + collision detection with sphere. +*/ +template class MAGNUM_SHAPES_EXPORT Cylinder { + public: + enum: UnsignedInt { + Dimensions = dimensions /**< Dimension count */ + }; + + /** + * @brief Constructor + * + * Creates zero-sized cylinder at origin. + */ + constexpr /*implicit*/ Cylinder(): _radius(0.0f) {} + + /** @brief Constructor */ + constexpr /*implicit*/ Cylinder(const typename DimensionTraits::VectorType& a, const typename DimensionTraits::VectorType& b, Float radius): _a(a), _b(b), _radius(radius) {} + + /** @brief Transformed shape */ + Cylinder transformed(const typename DimensionTraits::MatrixType& matrix) const; + + /** @brief First point */ + constexpr typename DimensionTraits::VectorType a() const { + return _a; + } + + /** @brief Set first point */ + void setA(const typename DimensionTraits::VectorType& a) { + _a = a; + } + + /** @brief Second point */ + constexpr typename DimensionTraits::VectorType b() const { + return _b; + } + + /** @brief Set second point */ + void setB(const typename DimensionTraits::VectorType& b) { + _b = b; + } + + /** @brief Radius */ + constexpr Float radius() const { return _radius; } + + /** @brief Set radius */ + void setRadius(Float radius) { _radius = radius; } + + /** @brief Collision with point */ + bool operator%(const Point& other) const; + + /** @brief Collision with sphere */ + bool operator%(const Sphere& other) const; + + private: + typename DimensionTraits::VectorType _a, _b; + Float _radius; +}; + +/** @brief Infinite two-dimensional cylinder */ +typedef Cylinder<2> Cylinder2D; + +/** @brief Infinite three-dimensional cylinder */ +typedef Cylinder<3> Cylinder3D; + +/** @collisionoperator{Point,Cylinder} */ +template inline bool operator%(const Point& a, const Cylinder& b) { return b % a; } + +/** @collisionoperator{Sphere,Cylinder} */ +template inline bool operator%(const Sphere& a, const Cylinder& b) { return b % a; } + +}} + +#endif diff --git a/src/Shapes/Implementation/CollisionDispatch.cpp b/src/Shapes/Implementation/CollisionDispatch.cpp index d4c0e8602..d5943d612 100644 --- a/src/Shapes/Implementation/CollisionDispatch.cpp +++ b/src/Shapes/Implementation/CollisionDispatch.cpp @@ -27,6 +27,7 @@ #include "Shapes/AxisAlignedBox.h" #include "Shapes/Box.h" #include "Shapes/Capsule.h" +#include "Shapes/Cylinder.h" #include "Shapes/LineSegment.h" #include "Shapes/Plane.h" #include "Shapes/Point.h" @@ -47,6 +48,9 @@ template<> bool collides(const AbstractShape<2>& a, const AbstractShape<2>& b) { _c(Sphere, Sphere2D, LineSegment, LineSegment2D) _c(Sphere, Sphere2D, Sphere, Sphere2D) + _c(Cylinder, Cylinder2D, Point, Point2D) + _c(Cylinder, Cylinder2D, Sphere, Sphere2D) + _c(Capsule, Capsule2D, Point, Point2D) _c(Capsule, Capsule2D, Sphere, Sphere2D) @@ -69,6 +73,9 @@ template<> bool collides(const AbstractShape<3>& a, const AbstractShape<3>& b) { _c(Sphere, Sphere3D, LineSegment, LineSegment3D) _c(Sphere, Sphere3D, Sphere, Sphere3D) + _c(Cylinder, Cylinder3D, Point, Point3D) + _c(Cylinder, Cylinder3D, Sphere, Sphere3D) + _c(Capsule, Capsule3D, Point, Point3D) _c(Capsule, Capsule3D, Sphere, Sphere3D) diff --git a/src/Shapes/Shapes.h b/src/Shapes/Shapes.h index dfc0d0fd7..057cb7e90 100644 --- a/src/Shapes/Shapes.h +++ b/src/Shapes/Shapes.h @@ -54,6 +54,10 @@ template class Composition; typedef Composition<2> Composition2D; typedef Composition<3> Composition3D; +template class Cylinder; +typedef Cylinder<2> Cylinder2D; +typedef Cylinder<3> Cylinder3D; + template class Line; typedef Line<2> Line2D; typedef Line<3> Line3D; diff --git a/src/Shapes/Test/CMakeLists.txt b/src/Shapes/Test/CMakeLists.txt index 2615b6d99..b08d2ec0a 100644 --- a/src/Shapes/Test/CMakeLists.txt +++ b/src/Shapes/Test/CMakeLists.txt @@ -26,6 +26,7 @@ corrade_add_test(ShapesShapeImplementationTest ShapeImplementationTest.cpp LIBRA corrade_add_test(ShapesAxisAlignedBoxTest AxisAlignedBoxTest.cpp LIBRARIES MagnumShapes) corrade_add_test(ShapesBoxTest BoxTest.cpp LIBRARIES MagnumShapes) corrade_add_test(ShapesCapsuleTest CapsuleTest.cpp LIBRARIES MagnumShapes) +corrade_add_test(ShapesCylinderTest CylinderTest.cpp LIBRARIES MagnumShapes) corrade_add_test(ShapesLineTest LineTest.cpp LIBRARIES MagnumShapes) corrade_add_test(ShapesPlaneTest PlaneTest.cpp LIBRARIES MagnumShapes) corrade_add_test(ShapesPointTest PointTest.cpp LIBRARIES MagnumShapes) diff --git a/src/Shapes/Test/CylinderTest.cpp b/src/Shapes/Test/CylinderTest.cpp new file mode 100644 index 000000000..013f16da9 --- /dev/null +++ b/src/Shapes/Test/CylinderTest.cpp @@ -0,0 +1,85 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Math/Matrix3.h" +#include "Math/Matrix4.h" +#include "Magnum.h" +#include "Shapes/Cylinder.h" +#include "Shapes/Point.h" +#include "Shapes/Sphere.h" + +#include "ShapeTestBase.h" + +namespace Magnum { namespace Shapes { namespace Test { + +class CylinderTest: public TestSuite::Tester { + public: + CylinderTest(); + + void transformed(); + void transformedAverageScaling(); + void collisionPoint(); + void collisionSphere(); +}; + +CylinderTest::CylinderTest() { + addTests({&CylinderTest::transformed, + &CylinderTest::collisionPoint, + &CylinderTest::collisionSphere}); +} + +void CylinderTest::transformed() { + const Shapes::Cylinder3D cylinder({1.0f, 2.0f, 3.0f}, {-1.0f, -2.0f, -3.0f}, 7.0f); + + const auto transformed = cylinder.transformed(Matrix4::scaling(Vector3(2.0f))*Matrix4::rotation(Deg(90.0f), Vector3::zAxis())); + CORRADE_COMPARE(transformed.a(), Vector3(-4.0f, 2.0f, 6.0f)); + CORRADE_COMPARE(transformed.b(), Vector3(4.0f, -2.0f, -6.0f)); + CORRADE_COMPARE(transformed.radius(), 14.0f); +} + +void CylinderTest::collisionPoint() { + Shapes::Cylinder3D cylinder({-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}, 2.0f); + Shapes::Point3D point({2.0f, 0.0f, 0.0f}); + Shapes::Point3D point1({1.0f, 3.1f, 0.0f}); + Shapes::Point3D point2({2.9f, -1.0f, 0.0f}); + + VERIFY_COLLIDES(cylinder, point); + VERIFY_COLLIDES(cylinder, point1); + VERIFY_NOT_COLLIDES(cylinder, point2); +} + +void CylinderTest::collisionSphere() { + Shapes::Cylinder3D cylinder({-1.0f, -1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}, 2.0f); + Shapes::Sphere3D sphere({3.0f, 0.0f, 0.0f}, 0.9f); + Shapes::Sphere3D sphere1({1.0f, 4.1f, 0.0f}, 1.0f); + Shapes::Sphere3D sphere2({3.5f, -1.0f, 0.0f}, 0.6f); + + VERIFY_COLLIDES(cylinder, sphere); + VERIFY_COLLIDES(cylinder, sphere1); + VERIFY_NOT_COLLIDES(cylinder, sphere2); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Shapes::Test::CylinderTest) diff --git a/src/Shapes/shapeImplementation.cpp b/src/Shapes/shapeImplementation.cpp index 1b3b57973..9a9ab4a4f 100644 --- a/src/Shapes/shapeImplementation.cpp +++ b/src/Shapes/shapeImplementation.cpp @@ -36,6 +36,7 @@ Debug operator<<(Debug debug, ShapeDimensionTraits<2>::Type value) { _val(LineSegment) _val(Sphere) _val(Capsule) + _val(Cylinder) _val(AxisAlignedBox) _val(Box) _val(Composition) @@ -53,6 +54,7 @@ Debug operator<<(Debug debug, ShapeDimensionTraits<3>::Type value) { _val(LineSegment) _val(Sphere) _val(Capsule) + _val(Cylinder) _val(AxisAlignedBox) _val(Box) _val(Plane) diff --git a/src/Shapes/shapeImplementation.h b/src/Shapes/shapeImplementation.h index ecf028570..8b2a16597 100644 --- a/src/Shapes/shapeImplementation.h +++ b/src/Shapes/shapeImplementation.h @@ -44,10 +44,11 @@ template<> struct ShapeDimensionTraits<2> { Line = 2, LineSegment = 3, Sphere = 5, - Capsule = 7, - AxisAlignedBox = 11, - Box = 13, - Composition = 17 + Cylinder = 7, + Capsule = 11, + AxisAlignedBox = 13, + Box = 17, + Composition = 19 }; }; @@ -57,11 +58,12 @@ template<> struct ShapeDimensionTraits<3> { Line = 2, LineSegment = 3, Sphere = 5, - Capsule = 7, - AxisAlignedBox = 11, - Box = 13, - Plane = 17, - Composition = 19 + Cylinder = 7, + Capsule = 11, + AxisAlignedBox = 13, + Box = 17, + Plane = 19, + Composition = 23 }; }; @@ -92,6 +94,11 @@ template struct TypeOf> { return ShapeDimensionTraits::Type::Sphere; } }; +template struct TypeOf> { + constexpr static typename ShapeDimensionTraits::Type type() { + return ShapeDimensionTraits::Type::Cylinder; + } +}; template struct TypeOf> { constexpr static typename ShapeDimensionTraits::Type type() { return ShapeDimensionTraits::Type::Capsule;