diff --git a/Library/include/playrho/Contact.hpp b/Library/include/playrho/Contact.hpp
index a8691aa9d1..bffc6d1cee 100644
--- a/Library/include/playrho/Contact.hpp
+++ b/Library/include/playrho/Contact.hpp
@@ -67,6 +67,9 @@ struct ToiConf;
class Contact
{
public:
+ /// @brief Default contactable value.
+ static constexpr auto DefaultContactable = Contactable{InvalidBodyID, InvalidShapeID, 0};
+
/// @brief Substep type.
using substep_type = TimestepIters;
@@ -74,7 +77,11 @@ class Contact
constexpr Contact() noexcept = default;
/// @brief Initializing constructor.
- /// @note This need never be called directly by a user.
+ /// @param a The "a" contactable value.
+ /// @param b The "b" contactable value.
+ /// @post If either @p a or @p b is not the value of @c DefaultContactable then:
+ /// IsEnabled()
and NeedsUpdating()
return true,
+ /// else they return false.
constexpr Contact(const Contactable& a, const Contactable& b) noexcept;
/// @brief Is this contact touching?
@@ -290,10 +297,10 @@ class Contact
};
/// @brief Identifying info for the A-side of the 2-bodied contact.
- Contactable m_contactableA{InvalidBodyID, InvalidShapeID, 0};
+ Contactable m_contactableA = DefaultContactable;
/// @brief Identifying info for the B-side of the 2-bodied contact.
- Contactable m_contactableB{InvalidBodyID, InvalidShapeID, 0};
+ Contactable m_contactableB = DefaultContactable;
// initialized on construction (construction-time depedent)
@@ -322,7 +329,8 @@ class Contact
constexpr Contact::Contact(const Contactable& a, const Contactable& b) noexcept
: m_contactableA{a},
m_contactableB{b},
- m_flags{e_enabledFlag | e_dirtyFlag}
+ m_flags{((a != DefaultContactable) || (b != DefaultContactable))
+ ? FlagsType(e_enabledFlag | e_dirtyFlag): FlagsType{}}
{
}
@@ -516,7 +524,8 @@ constexpr void Contact::IncrementToiCount() noexcept
/// @relatedalso Contact
constexpr bool operator==(const Contact& lhs, const Contact& rhs) noexcept
{
- return lhs.GetContactableA() == rhs.GetContactableB() && //
+ return lhs.GetContactableA() == rhs.GetContactableA() && //
+ lhs.GetContactableB() == rhs.GetContactableB() && //
lhs.GetFriction() == rhs.GetFriction() && //
lhs.GetRestitution() == rhs.GetRestitution() && //
lhs.GetTangentSpeed() == rhs.GetTangentSpeed() && //
diff --git a/UnitTests/Contact.cpp b/UnitTests/Contact.cpp
index 666604e293..703be650c1 100644
--- a/UnitTests/Contact.cpp
+++ b/UnitTests/Contact.cpp
@@ -25,29 +25,6 @@
using namespace playrho;
using namespace playrho::d2;
-TEST(Contact, ByteSize)
-{
- // Check size at test runtime instead of compile-time via static_assert to avoid stopping
- // builds and to report actual size rather than just reporting that expected size is wrong.
- switch (sizeof(Real))
- {
- case 4:
- EXPECT_EQ(alignof(Contact), 4u);
- EXPECT_EQ(sizeof(Contact), std::size_t(36));
- break;
- case 8:
- EXPECT_EQ(alignof(Contact), 8u);
- EXPECT_EQ(sizeof(Contact), std::size_t(56));
- break;
- case 16:
- EXPECT_EQ(sizeof(Contact), std::size_t(96));
- break;
- default:
- FAIL();
- break;
- }
-}
-
TEST(Contact, Enabled)
{
const auto bA = BodyID(0u);
@@ -63,6 +40,11 @@ TEST(Contact, Enabled)
TEST(Contact, DefaultConstruction)
{
+ {
+ const auto c = Contact();
+ EXPECT_EQ(c.GetContactableA(), Contact::DefaultContactable);
+ EXPECT_EQ(c.GetContactableB(), Contact::DefaultContactable);
+ }
EXPECT_EQ(GetBodyA(Contact()), InvalidBodyID);
EXPECT_EQ(GetBodyB(Contact()), InvalidBodyID);
EXPECT_EQ(GetShapeA(Contact()), InvalidShapeID);
@@ -218,3 +200,78 @@ TEST(Contact, GetOtherBody)
EXPECT_EQ(GetOtherBody(contact, bodyIdA), bodyIdB);
EXPECT_EQ(GetOtherBody(contact, bodyIdB), bodyIdA);
}
+
+TEST(Contact, Equality)
+{
+ EXPECT_TRUE(Contact() == Contact());
+ EXPECT_TRUE(Contact() == Contact(Contact::DefaultContactable, Contact::DefaultContactable));
+ {
+ auto c = Contact();
+ c.SetTouching();
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.SetEnabled();
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.SetFriction(NonNegative(2));
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.SetRestitution(Real(42));
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.SetTangentSpeed(42_mps);
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.SetToiCount(42u);
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.SetToi(std::optional>(0.5));
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.FlagForFiltering();
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.FlagForUpdating();
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.SetSensor();
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.SetImpenetrable();
+ EXPECT_FALSE(Contact() == c);
+ }
+ {
+ auto c = Contact();
+ c.SetIsActive();
+ EXPECT_FALSE(Contact() == c);
+ }
+ EXPECT_FALSE(Contact() ==
+ Contact(Contactable{BodyID(1u), ShapeID(0u), ChildCounter(0u)},
+ Contact::DefaultContactable));
+ EXPECT_FALSE(Contact() ==
+ Contact(Contactable{BodyID(0u), ShapeID(1u), ChildCounter(0u)},
+ Contact::DefaultContactable));
+ EXPECT_FALSE(Contact() ==
+ Contact(Contactable{BodyID(0u), ShapeID(0u), ChildCounter(1u)},
+ Contact::DefaultContactable));
+}