|
|
|
|
@ -16,7 +16,7 @@
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/** @file
|
|
|
|
|
* @brief Class Magnum::Physics::ShapeGroup |
|
|
|
|
* @brief Class Magnum::Physics::ShapeGroup, typedef Magnum::Physics::ShapeGroup2D, Magnum::Physics::ShapeGroup3D |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include "AbstractShape.h" |
|
|
|
|
@ -27,8 +27,25 @@
|
|
|
|
|
namespace Magnum { namespace Physics { |
|
|
|
|
|
|
|
|
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
|
|
|
|
#define enableIfIsBaseType typename std::enable_if<std::is_base_of<AbstractShape, T>::value, ShapeGroup>::type |
|
|
|
|
#define enableIfAreBaseType typename std::enable_if<std::is_base_of<AbstractShape, T>::value && std::is_base_of<AbstractShape, U>::value, ShapeGroup>::type |
|
|
|
|
namespace Implementation { |
|
|
|
|
enum GroupOperation { |
|
|
|
|
RefA = 0x01, |
|
|
|
|
RefB = 0x02, |
|
|
|
|
RefAB = 0x03, |
|
|
|
|
// Complement = 1 << 2,
|
|
|
|
|
// Union = 2 << 2,
|
|
|
|
|
// Intersection = 3 << 2,
|
|
|
|
|
// Difference = 4 << 2,
|
|
|
|
|
// Xor = 5 << 2,
|
|
|
|
|
And = 6 << 2, |
|
|
|
|
Or = 7 << 2, |
|
|
|
|
Not = 8 << 2, |
|
|
|
|
FirstObjectOnly = 9 << 2, |
|
|
|
|
AlwaysFalse = 10 << 2 |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
#define enableIfIsBaseType typename std::enable_if<std::is_base_of<AbstractShape<T::Dimensions>, T>::value, ShapeGroup<T::Dimensions>>::type |
|
|
|
|
#define enableIfAreBaseType typename std::enable_if<T::Dimensions == U::Dimensions && std::is_base_of<AbstractShape<T::Dimensions>, T>::value && std::is_base_of<AbstractShape<T::Dimensions>, U>::value, ShapeGroup<T::Dimensions>>::type |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -36,26 +53,27 @@ namespace Magnum { namespace Physics {
|
|
|
|
|
|
|
|
|
|
Result of logical operations on shapes. |
|
|
|
|
See @ref collision-detection for brief introduction. |
|
|
|
|
@see ShapeGroup2D, ShapeGroup3D |
|
|
|
|
*/ |
|
|
|
|
class PHYSICS_EXPORT ShapeGroup: public AbstractShape { |
|
|
|
|
template<size_t dimensions> class PHYSICS_EXPORT ShapeGroup: public AbstractShape<dimensions> { |
|
|
|
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
|
|
|
|
// template<class T> friend constexpr enableIfIsBaseType operator~(const T& a);
|
|
|
|
|
// template<class T> friend constexpr enableIfIsBaseType operator~(T&& a);
|
|
|
|
|
// template<class T> friend constexpr enableIfIsBaseType operator~(T& a);
|
|
|
|
|
template<class T> friend constexpr enableIfIsBaseType operator!(const T& a); |
|
|
|
|
template<class T> friend constexpr enableIfIsBaseType operator!(T&& a); |
|
|
|
|
template<class T> friend constexpr enableIfIsBaseType operator!(T& a); |
|
|
|
|
// template<class T> friend constexpr operator~(const T& a) -> enableIfIsBaseType;
|
|
|
|
|
// template<class T> friend constexpr operator~(T&& a) -> enableIfIsBaseType;
|
|
|
|
|
// template<class T> friend constexpr operator~(T& a) -> enableIfIsBaseType;
|
|
|
|
|
template<class T> friend constexpr auto operator!(const T& a) -> enableIfIsBaseType; |
|
|
|
|
template<class T> friend constexpr auto operator!(T&& a) -> enableIfIsBaseType; |
|
|
|
|
template<class T> friend constexpr auto operator!(T& a) -> enableIfIsBaseType; |
|
|
|
|
|
|
|
|
|
#define friendOp(char) \ |
|
|
|
|
template<class T, class U> friend constexpr enableIfAreBaseType operator char(const T& a, const U& b); \
|
|
|
|
|
template<class T, class U> friend constexpr enableIfAreBaseType operator char(const T& a, U&& b); \
|
|
|
|
|
template<class T, class U> friend constexpr enableIfAreBaseType operator char(T&& a, const U& b); \
|
|
|
|
|
template<class T, class U> friend constexpr enableIfAreBaseType operator char(T&& a, U&& b); \
|
|
|
|
|
template<class T, class U> friend constexpr enableIfAreBaseType operator char(const T& a, std::reference_wrapper<U> b); \
|
|
|
|
|
template<class T, class U> friend constexpr enableIfAreBaseType operator char(T&& a, std::reference_wrapper<U> b); \
|
|
|
|
|
template<class T, class U> friend constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, const U& b); \
|
|
|
|
|
template<class T, class U> friend constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, U&& b); \
|
|
|
|
|
template<class T, class U> friend constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, std::reference_wrapper<U> b); |
|
|
|
|
template<class T, class U> friend constexpr auto operator char(const T& a, const U& b) -> enableIfAreBaseType; \
|
|
|
|
|
template<class T, class U> friend constexpr auto operator char(const T& a, U&& b) -> enableIfAreBaseType; \
|
|
|
|
|
template<class T, class U> friend constexpr auto operator char(T&& a, const U& b) -> enableIfAreBaseType; \
|
|
|
|
|
template<class T, class U> friend constexpr auto operator char(T&& a, U&& b) -> enableIfAreBaseType; \
|
|
|
|
|
template<class T, class U> friend constexpr auto operator char(const T& a, std::reference_wrapper<U> b) -> enableIfAreBaseType; \
|
|
|
|
|
template<class T, class U> friend constexpr auto operator char(T&& a, std::reference_wrapper<U> b) -> enableIfAreBaseType; \
|
|
|
|
|
template<class T, class U> friend constexpr auto operator char(std::reference_wrapper<T> a, const U& b) -> enableIfAreBaseType; \
|
|
|
|
|
template<class T, class U> friend constexpr auto operator char(std::reference_wrapper<T> a, U&& b) -> enableIfAreBaseType; \
|
|
|
|
|
template<class T, class U> friend constexpr auto operator char(std::reference_wrapper<T> a, std::reference_wrapper<U> b) -> enableIfAreBaseType; |
|
|
|
|
// friendOp(|)
|
|
|
|
|
// friendOp(&)
|
|
|
|
|
// friendOp(-)
|
|
|
|
|
@ -68,26 +86,9 @@ class PHYSICS_EXPORT ShapeGroup: public AbstractShape {
|
|
|
|
|
ShapeGroup(const ShapeGroup& other) = delete; |
|
|
|
|
ShapeGroup& operator=(const ShapeGroup& other) = delete; |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
enum Operation { |
|
|
|
|
RefA = 0x01, |
|
|
|
|
RefB = 0x02, |
|
|
|
|
RefAB = 0x03, |
|
|
|
|
// Complement = 1 << 2,
|
|
|
|
|
// Union = 2 << 2,
|
|
|
|
|
// Intersection = 3 << 2,
|
|
|
|
|
// Difference = 4 << 2,
|
|
|
|
|
// Xor = 5 << 2,
|
|
|
|
|
And = 6 << 2, |
|
|
|
|
Or = 7 << 2, |
|
|
|
|
Not = 8 << 2, |
|
|
|
|
FirstObjectOnly = 9 << 2, |
|
|
|
|
AlwaysFalse = 10 << 2 |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
/** @brief Default constructor */ |
|
|
|
|
inline ShapeGroup(): operation(AlwaysFalse), a(nullptr), b(nullptr) {} |
|
|
|
|
inline ShapeGroup(): operation(Implementation::GroupOperation::AlwaysFalse), a(nullptr), b(nullptr) {} |
|
|
|
|
|
|
|
|
|
/** @brief Move constructor */ |
|
|
|
|
ShapeGroup(ShapeGroup&& other); |
|
|
|
|
@ -98,21 +99,36 @@ class PHYSICS_EXPORT ShapeGroup: public AbstractShape {
|
|
|
|
|
/** @brief Move assignment */ |
|
|
|
|
ShapeGroup& operator=(ShapeGroup&& other); |
|
|
|
|
|
|
|
|
|
void applyTransformation(const Matrix4& transformation); |
|
|
|
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
|
|
|
|
void applyTransformation(const typename AbstractShape<dimensions>::MatrixType& transformation); |
|
|
|
|
#else |
|
|
|
|
void applyTransformation(const MatrixType& transformation); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
bool collides(const AbstractShape* other) const; |
|
|
|
|
bool collides(const AbstractShape<dimensions>* other) const; |
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
virtual Type type() const { return Type::ShapeGroup; } |
|
|
|
|
virtual typename AbstractShape<dimensions>::Type type() const { return AbstractShape<dimensions>::Type::ShapeGroup; } |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
inline ShapeGroup(int operation, AbstractShape* a, AbstractShape* b): operation(operation), a(a), b(b) {} |
|
|
|
|
inline ShapeGroup(int operation, AbstractShape<dimensions>* a, AbstractShape<dimensions>* b): operation(operation), a(a), b(b) {} |
|
|
|
|
|
|
|
|
|
int operation; |
|
|
|
|
AbstractShape* a; |
|
|
|
|
AbstractShape* b; |
|
|
|
|
AbstractShape<dimensions>* a; |
|
|
|
|
AbstractShape<dimensions>* b; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
|
|
|
|
extern template class PHYSICS_EXPORT ShapeGroup<2>; |
|
|
|
|
extern template class PHYSICS_EXPORT ShapeGroup<3>; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/** @brief Two-dimensional shape group */ |
|
|
|
|
typedef ShapeGroup<2> ShapeGroup2D; |
|
|
|
|
|
|
|
|
|
/** @brief Three-dimensional shape group */ |
|
|
|
|
typedef ShapeGroup<3> ShapeGroup3D; |
|
|
|
|
|
|
|
|
|
// /* @brief Complement of shape */
|
|
|
|
|
// template<class T> inline constexpr enableIfIsBaseType operator~(const T& a) {
|
|
|
|
|
// return ShapeGroup(ShapeGroup::Complement, new T(a), nullptr);
|
|
|
|
|
@ -129,15 +145,15 @@ class PHYSICS_EXPORT ShapeGroup: public AbstractShape {
|
|
|
|
|
/** @relates ShapeGroup
|
|
|
|
|
@brief Logical NOT of shape |
|
|
|
|
*/ |
|
|
|
|
template<class T> inline constexpr enableIfIsBaseType operator!(const T& a) { |
|
|
|
|
return ShapeGroup(ShapeGroup::Not, new T(a), nullptr); |
|
|
|
|
template<class T> inline constexpr auto operator!(const T& a) -> enableIfIsBaseType { |
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::Not, new T(a), nullptr); |
|
|
|
|
} |
|
|
|
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
|
|
|
|
template<class T> inline constexpr enableIfIsBaseType operator!(T&& a) { |
|
|
|
|
return ShapeGroup(ShapeGroup::Not, new T(std::forward<T>(a)), nullptr); |
|
|
|
|
template<class T> inline constexpr auto operator!(T&& a) -> enableIfIsBaseType { |
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::Not, new T(std::forward<T>(a)), nullptr); |
|
|
|
|
} |
|
|
|
|
template<class T> inline constexpr enableIfIsBaseType operator!(T& a) { |
|
|
|
|
return ShapeGroup(ShapeGroup::Not|ShapeGroup::RefA, &a.get(), nullptr); |
|
|
|
|
template<class T> inline constexpr auto operator!(T& a) -> enableIfIsBaseType { |
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::Not|Implementation::GroupOperation::RefA, &a.get(), nullptr); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
@ -161,7 +177,7 @@ is used here, so this operation can be used for providing simplified shape
|
|
|
|
|
version, because collision with @p b is computed only if @p a collides. |
|
|
|
|
See @ref collision-detection-shape-simplification for an example. |
|
|
|
|
*/ |
|
|
|
|
template<class T, class U> inline constexpr ShapeGroup operator&&(T a, U b); |
|
|
|
|
template<size_t dimensions, class T, class U> inline constexpr ShapeGroup<dimensions> operator&&(T a, U b); |
|
|
|
|
|
|
|
|
|
/** @relates ShapeGroup
|
|
|
|
|
@brief Logical OR of two shapes |
|
|
|
|
@ -170,35 +186,35 @@ template<class T, class U> inline constexpr ShapeGroup operator&&(T a, U b);
|
|
|
|
|
is used, so if collision with @p a is detected, collision with @p b is not |
|
|
|
|
computed. |
|
|
|
|
*/ |
|
|
|
|
template<class T, class U> inline constexpr ShapeGroup operator||(T a, U b); |
|
|
|
|
template<size_t dimensions, class T, class U> inline constexpr ShapeGroup<dimensions> operator||(T a, U b); |
|
|
|
|
#else |
|
|
|
|
#define op(type, char) \ |
|
|
|
|
template<class T, class U> inline constexpr enableIfAreBaseType operator char(const T& a, const U& b) { \
|
|
|
|
|
return ShapeGroup(ShapeGroup::type, new T(a), new U(b)); \
|
|
|
|
|
template<class T, class U> inline constexpr auto operator char(const T& a, const U& b) -> enableIfAreBaseType { \
|
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::type, new T(a), new U(b)); \
|
|
|
|
|
} \
|
|
|
|
|
template<class T, class U> inline constexpr enableIfAreBaseType operator char(const T& a, U&& b) { \
|
|
|
|
|
return ShapeGroup(ShapeGroup::type, new T(a), new U(std::forward<U>(b))); \
|
|
|
|
|
template<class T, class U> inline constexpr auto operator char(const T& a, U&& b) -> enableIfAreBaseType { \
|
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::type, new T(a), new U(std::forward<U>(b))); \
|
|
|
|
|
} \
|
|
|
|
|
template<class T, class U> inline constexpr enableIfAreBaseType operator char(T&& a, const U& b) { \
|
|
|
|
|
return ShapeGroup(ShapeGroup::type, new T(std::forward<T>(a)), new U(b)); \
|
|
|
|
|
template<class T, class U> inline constexpr auto operator char(T&& a, const U& b) -> enableIfAreBaseType { \
|
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::type, new T(std::forward<T>(a)), new U(b)); \
|
|
|
|
|
} \
|
|
|
|
|
template<class T, class U> inline constexpr enableIfAreBaseType operator char(T&& a, U&& b) { \
|
|
|
|
|
return ShapeGroup(ShapeGroup::type, new T(std::forward<T>(a)), new U(std::forward<U>(b))); \
|
|
|
|
|
template<class T, class U> inline constexpr auto operator char(T&& a, U&& b) -> enableIfAreBaseType { \
|
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::type, new T(std::forward<T>(a)), new U(std::forward<U>(b))); \
|
|
|
|
|
} \
|
|
|
|
|
template<class T, class U> inline constexpr enableIfAreBaseType operator char(const T& a, std::reference_wrapper<U> b) { \
|
|
|
|
|
return ShapeGroup(ShapeGroup::type|ShapeGroup::RefB, new T(a), &b.get()); \
|
|
|
|
|
template<class T, class U> inline constexpr auto operator char(const T& a, std::reference_wrapper<U> b) -> enableIfAreBaseType { \
|
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::type|Implementation::GroupOperation::RefB, new T(a), &b.get()); \
|
|
|
|
|
} \
|
|
|
|
|
template<class T, class U> inline constexpr enableIfAreBaseType operator char(T&& a, std::reference_wrapper<U> b) { \
|
|
|
|
|
return ShapeGroup(ShapeGroup::type|ShapeGroup::RefB, new T(std::forward<T>(a)), &b.get()); \
|
|
|
|
|
template<class T, class U> inline constexpr auto operator char(T&& a, std::reference_wrapper<U> b) -> enableIfAreBaseType { \
|
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::type|Implementation::GroupOperation::RefB, new T(std::forward<T>(a)), &b.get()); \
|
|
|
|
|
} \
|
|
|
|
|
template<class T, class U> inline constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, const U& b) { \
|
|
|
|
|
return ShapeGroup(ShapeGroup::type|ShapeGroup::RefA, &a.get(), new U(b)); \
|
|
|
|
|
template<class T, class U> inline constexpr auto operator char(std::reference_wrapper<T> a, const U& b) -> enableIfAreBaseType { \
|
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::type|Implementation::GroupOperation::RefA, &a.get(), new U(b)); \
|
|
|
|
|
} \
|
|
|
|
|
template<class T, class U> inline constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, U&& b) { \
|
|
|
|
|
return ShapeGroup(ShapeGroup::type|ShapeGroup::RefA, &a.get(), new U(std::forward<U>(b))); \
|
|
|
|
|
template<class T, class U> inline constexpr auto operator char(std::reference_wrapper<T> a, U&& b) -> enableIfAreBaseType { \
|
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::type|Implementation::GroupOperation::RefA, &a.get(), new U(std::forward<U>(b))); \
|
|
|
|
|
} \
|
|
|
|
|
template<class T, class U> inline constexpr enableIfAreBaseType operator char(std::reference_wrapper<T> a, std::reference_wrapper<U> b) { \
|
|
|
|
|
return ShapeGroup(ShapeGroup::type|ShapeGroup::RefAB, &a.get(), &b.get()); \
|
|
|
|
|
template<class T, class U> inline constexpr auto operator char(std::reference_wrapper<T> a, std::reference_wrapper<U> b) -> enableIfAreBaseType { \
|
|
|
|
|
return ShapeGroup<T::Dimensions>(Implementation::GroupOperation::type|Implementation::GroupOperation::RefAB, &a.get(), &b.get()); \
|
|
|
|
|
} |
|
|
|
|
// op(Union, |)
|
|
|
|
|
// op(Intersection, &)
|
|
|
|
|
|