diff --git a/Doxyfile b/Doxyfile
index 18a8b85e8..90af7401d 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -204,6 +204,7 @@ ALIASES = \
"configurationvalueref{1}=@see @ref configurationvalues \"Corrade::Utility::ConfigurationValue<\1>\"" \
"configurationvalue{1}=@brief %Configuration value parser and writer @xrefitem configurationvalues \"Configuration value parser and writer\" \"Configuration value parsers and writers for custom types\" Allows parsing and writing \1 from and to Corrade::Utility::Configuration." \
"collisionoccurenceoperator{2}=@relates \1\n@brief %Collision occurence of %\1 and %\2\n@see \2::operator%(const \1&) const" \
+ "collisionoperator{2}=@relates \1\n@brief %Collision of %\1 and %\2\n@see \2::operator/(const \1&) const" \
"todoc=@xrefitem todoc \"Documentation todo\" \"Documentation-related todo list\"" \
"fn_gl{1}=gl\1()" \
"fn_gl_extension{3}=gl\1\2()" \
diff --git a/doc/coding-style.dox b/doc/coding-style.dox
index d520b14cf..b20bab75d 100644
--- a/doc/coding-style.dox
+++ b/doc/coding-style.dox
@@ -102,11 +102,15 @@ Additionally to @c \@todoc, @c \@debugoperator @c \@configurationvalue and
@subsubsection documentation-commands-collisionoperator Shape collision operators
-Out-of-class operators for collision occurence in Shapes namespace should be
-marked with @c \@collisionoccurenceoperator, e.g.:
+Out-of-class operators for collision and collision occurence in Shapes
+namespace should be marked with @c \@collisionoperator and @c \@collisionoccurenceoperator,
+e.g.:
@code
// @collisionoccurenceoperator{Point,Sphere}
inline bool operator%(const Point& a, const Sphere& b) { return b % a; }
+
+// @collisionoperator{Point,Sphere}
+inline Collision operator/(const Point& a, const Sphere& b) { return (b/a).reverted(); }
@endcode
They will appear as related functions within documentation of class for which
the operator is implemented (not of class in which the operator is
diff --git a/src/Shapes/CMakeLists.txt b/src/Shapes/CMakeLists.txt
index de98a9474..72f85a6ea 100644
--- a/src/Shapes/CMakeLists.txt
+++ b/src/Shapes/CMakeLists.txt
@@ -46,6 +46,7 @@ set(MagnumShapes_HEADERS
Box.h
Capsule.h
Cylinder.h
+ Collision.h
Composition.h
Line.h
LineSegment.h
diff --git a/src/Shapes/Collision.h b/src/Shapes/Collision.h
new file mode 100644
index 000000000..c1f3731ce
--- /dev/null
+++ b/src/Shapes/Collision.h
@@ -0,0 +1,131 @@
+#ifndef Magnum_Shapes_Collision_h
+#define Magnum_Shapes_Collision_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 @ref Magnum::Shapes::Collision
+ */
+
+#include "Math/Vector2.h"
+#include "Math/Vector3.h"
+#include "DimensionTraits.h"
+
+namespace Magnum { namespace Shapes {
+
+/**
+@brief %Collision data
+
+Contains information about collision between objects A and B, described by
+contact position, separation normal and separation distance.
+
+If the collision occured, contact position is on object B surface, separation
+normal is *normalized* vector in which direction should object A be moved to
+separate the bodies, separation distance is positive and describes minimal
+movement of object A in direction of separation normal after which the contact
+position will no longer be colliding with object A.
+
+If the collision not occured, contact position and separation normal is
+undefined (i.e., *not* normalized) and separation distance is negative or zero.
+@see @ref Collision2D, @ref Collision3D
+*/
+template class Collision {
+ public:
+ /**
+ * @brief Default constructor
+ *
+ * Sets position, normal and separation distance to zero, as if no
+ * collision happened.
+ */
+ /*implicit*/ Collision(): _separationDistance(0.0f) {}
+
+ /**
+ * @brief Constructor
+ *
+ * If separation distance is positive, the separation normal is
+ * expected to be normalized.
+ */
+ explicit Collision(typename DimensionTraits::VectorType position, typename DimensionTraits::VectorType separationNormal, Float separationDistance) noexcept: _position(position), _separationNormal(separationNormal), _separationDistance(separationDistance) {
+ CORRADE_ASSERT(_separationDistance < Math::TypeTraits::epsilon() || separationNormal.isNormalized(), "Shapes::Collision::Collision: separation normal is not normalized", );
+ }
+
+ /**
+ * @brief Whether the collision happened
+ *
+ * Negative or zero separation distance means that no collision
+ * happened.
+ * @see @ref separationDistance()
+ */
+ operator bool() const { return _separationDistance > 0.0f; }
+
+ /** @brief %Collision position */
+ typename DimensionTraits::VectorType position() const {
+ return _position;
+ }
+
+ /**
+ * @brief Separation normal
+ *
+ * @see @ref separationDistance(), @ref flipped()
+ */
+ typename DimensionTraits::VectorType separationNormal() const {
+ return _separationNormal;
+ }
+
+ /**
+ * @brief Separation distance
+ *
+ * @see @ref separationNormal(), operator bool()
+ */
+ Float separationDistance() const {
+ return _separationDistance;
+ }
+
+ /**
+ * @brief Flipped collision
+ *
+ * Returns new collision object as if the collision occured between
+ * flipped pair of objects, i.e. with flipped separation normal and
+ * contact position on surface of object A.
+ * @see @ref position(), @ref separationNormal()
+ */
+ Collision flipped() const {
+ return Collision(_position - _separationDistance*_separationNormal, -_separationNormal, _separationDistance);
+ }
+
+ private:
+ typename DimensionTraits::VectorType _position;
+ typename DimensionTraits::VectorType _separationNormal;
+ Float _separationDistance;
+};
+
+/** @brief Two-dimensional collision data */
+typedef Collision<2> Collision2D;
+
+/** @brief Three-dimensional collision data */
+typedef Collision<3> Collision3D;
+
+}}
+
+#endif
diff --git a/src/Shapes/Shapes.h b/src/Shapes/Shapes.h
index dc292db2e..2bda9882c 100644
--- a/src/Shapes/Shapes.h
+++ b/src/Shapes/Shapes.h
@@ -48,6 +48,10 @@ template class Capsule;
typedef Capsule<2> Capsule2D;
typedef Capsule<3> Capsule3D;
+template class Collision;
+typedef Collision<2> Collision2D;
+typedef Collision<3> Collision3D;
+
template class Composition;
typedef Composition<2> Composition2D;
typedef Composition<3> Composition3D;
diff --git a/src/Shapes/Test/CMakeLists.txt b/src/Shapes/Test/CMakeLists.txt
index b08d2ec0a..83cf11eaa 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(ShapesCollisionTest CollisionTest.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)
diff --git a/src/Shapes/Test/CollisionTest.cpp b/src/Shapes/Test/CollisionTest.cpp
new file mode 100644
index 000000000..545d13f35
--- /dev/null
+++ b/src/Shapes/Test/CollisionTest.cpp
@@ -0,0 +1,61 @@
+/*
+ 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
+
+#include "Shapes/Collision.h"
+#include "Magnum.h"
+
+namespace Magnum { namespace Shapes { namespace Test {
+
+class CollisionTest: public TestSuite::Tester {
+ public:
+ explicit CollisionTest();
+
+ void boolConversion();
+ void flipped();
+};
+
+CollisionTest::CollisionTest() {
+ addTests({&CollisionTest::boolConversion,
+ &CollisionTest::flipped});
+}
+
+void CollisionTest::boolConversion() {
+ CORRADE_VERIFY(!Collision3D());
+ CORRADE_VERIFY(!Collision3D({}, {2.0f, 0.0f, 0.0f}, 0.0f));
+ CORRADE_VERIFY(!Collision3D({}, {0.0f, 0.0f, 2.0f}, -0.1f));
+ CORRADE_VERIFY(Collision3D({}, {0.0f, 1.0f, 0.0f}, 0.1f));
+}
+
+void CollisionTest::flipped() {
+ const auto flipped = Collision3D({-1.0f, 0.5f, 3.0f}, {1.0f, 0.0f, 0.0f}, 0.5f).flipped();
+ CORRADE_COMPARE(flipped.position(), Vector3(-1.5f, 0.5f, 3.0f));
+ CORRADE_COMPARE(flipped.separationNormal(), Vector3(-1.0f, 0.0f, 0.0f));
+ CORRADE_COMPARE(flipped.separationDistance(), 0.5f);
+}
+
+}}}
+
+CORRADE_TEST_MAIN(Magnum::Shapes::Test::CollisionTest)