@@ -1308,11 +1308,32 @@ TYPED_TEST(SimulationFeaturesTestBasic, ShapeBoundingBox)
13081308 }
13091309}
13101310
1311- TYPED_TEST (SimulationFeaturesTestBasic, CollideBitmasks)
1311+ using FeaturesCollisionContacts= gz::physics::FeatureList<
1312+ gz::physics::sdf::ConstructSdfModel,
1313+ gz::physics::sdf::ConstructSdfWorld,
1314+ gz::physics::GetModelFromWorld,
1315+ gz::physics::GetLinkFromModel,
1316+ gz::physics::GetShapeFromLink,
1317+ gz::physics::ForwardStep,
1318+ gz::physics::GetContactsFromLastStepFeature
1319+ >;
1320+
1321+ using SimulationFeaturesCollisionContacts =
1322+ SimulationFeaturesTest<FeaturesCollisionContacts>;
1323+
1324+ using FeaturesCollisionFilter = gz::physics::FeatureList<
1325+ FeaturesCollisionContacts,
1326+ gz::physics::CollisionFilterMaskFeature
1327+ >;
1328+
1329+ using SimulationFeaturesCollisionFilter =
1330+ SimulationFeaturesTest<FeaturesCollisionFilter>;
1331+
1332+ TEST_F (SimulationFeaturesCollisionFilter, CollideBitmasks)
13121333{
13131334 for (const std::string &name : this ->pluginNames )
13141335 {
1315- auto world = LoadPluginAndWorld<Features >(
1336+ auto world = LoadPluginAndWorld<FeaturesCollisionFilter >(
13161337 this ->loader ,
13171338 name,
13181339 common_test::worlds::kShapesBitmaskWorld );
@@ -1321,7 +1342,7 @@ TYPED_TEST(SimulationFeaturesTestBasic, CollideBitmasks)
13211342 auto filteredBox = world->GetModel (" box_filtered" );
13221343 auto collidingBox = world->GetModel (" box_colliding" );
13231344
1324- auto checkedOutput = StepWorld<Features >(world, true ).first ;
1345+ auto checkedOutput = StepWorld<FeaturesCollisionFilter >(world, true ).first ;
13251346 EXPECT_TRUE (checkedOutput);
13261347 auto contacts = world->GetContactsFromLastStep ();
13271348 // Only box_colliding should collide with box_base
@@ -1334,7 +1355,7 @@ TYPED_TEST(SimulationFeaturesTestBasic, CollideBitmasks)
13341355 // Also test the getter
13351356 EXPECT_EQ (0xF0 , collidingShape->GetCollisionFilterMask ());
13361357 // Step and make sure there are no collisions
1337- checkedOutput = StepWorld<Features >(world, false ).first ;
1358+ checkedOutput = StepWorld<FeaturesCollisionFilter >(world, false ).first ;
13381359 EXPECT_FALSE (checkedOutput);
13391360 contacts = world->GetContactsFromLastStep ();
13401361 EXPECT_EQ (0u , contacts.size ());
@@ -1343,7 +1364,7 @@ TYPED_TEST(SimulationFeaturesTestBasic, CollideBitmasks)
13431364 // Equivalent to 0xFF
13441365 collidingShape->RemoveCollisionFilterMask ();
13451366 filteredShape->RemoveCollisionFilterMask ();
1346- checkedOutput = StepWorld<Features >(world, false ).first ;
1367+ checkedOutput = StepWorld<FeaturesCollisionFilter >(world, false ).first ;
13471368 EXPECT_FALSE (checkedOutput);
13481369 // Expect box_filtered and box_colliding to collide with box_base
13491370 contacts = world->GetContactsFromLastStep ();
@@ -1532,6 +1553,101 @@ TYPED_TEST(SimulationFeaturesTestBasic, RetrieveContacts)
15321553 }
15331554}
15341555
1556+ TEST_F (SimulationFeaturesCollisionContacts,
1557+ ContactsForLinkWithMultipleCollisions)
1558+ {
1559+ // This test verifies that the collision entities in contact points
1560+ // are correct. Thest test world consists of a box model with a single
1561+ // link containining multiple collisions over a ground plane. Verify
1562+ // that only the bottom collision in the box model should collide with
1563+ // the ground plane.
1564+
1565+ auto getModelStr = [](const std::string &_name,
1566+ const gz::math::Pose3d &_pose)
1567+ {
1568+ std::stringstream modelStaticStr;
1569+ modelStaticStr << R"(
1570+ <sdf version="1.11">
1571+ <model name=")" ;
1572+ modelStaticStr << _name << R"( ">
1573+ <pose>)" ;
1574+ modelStaticStr << _pose;
1575+ modelStaticStr << R"( </pose>
1576+ <link name="body">
1577+ <collision name="box_collision_mid">
1578+ <pose>0 0 1.0 0 0 0</pose>
1579+ <geometry>
1580+ <box><size>1 1 1</size></box>
1581+ </geometry>
1582+ </collision>
1583+ <collision name="box_collision_bottom">
1584+ <geometry>
1585+ <box><size>1 1 1</size></box>
1586+ </geometry>
1587+ </collision>
1588+ <collision name="box_collision_top">
1589+ <pose>0 0 2.0 0 0 0</pose>
1590+ <geometry>
1591+ <box><size>1 1 1</size></box>
1592+ </geometry>
1593+ </collision>
1594+ </link>
1595+ <static>false</static>
1596+ </model>
1597+ </sdf>)" ;
1598+ return modelStaticStr.str ();
1599+ };
1600+
1601+ for (const std::string &name : this ->pluginNames )
1602+ {
1603+ // TPE does not support collision checking with plane shapes.
1604+ if (this ->PhysicsEngineName (name) == " tpe" ) continue ;
1605+
1606+ auto world =
1607+ LoadPluginAndWorld<FeaturesCollisionContacts>(
1608+ this ->loader ,
1609+ name,
1610+ common_test::worlds::kGroundSdf );
1611+ ASSERT_NE (nullptr , world);
1612+
1613+ sdf::Root root;
1614+ sdf::Errors errors = root.LoadSdfString (getModelStr (
1615+ " boxes" , gz::math::Pose3d (0 , 0 , 0.5 , 0 , 0 , 0 )));
1616+ ASSERT_TRUE (errors.empty ()) << errors.front ();
1617+ ASSERT_NE (nullptr , root.Model ());
1618+ world->ConstructModel (*root.Model ());
1619+
1620+ gz::physics::ForwardStep::Output output;
1621+ gz::physics::ForwardStep::State state;
1622+ gz::physics::ForwardStep::Input input;
1623+ for (std::size_t i = 0 ; i < 10 ; ++i)
1624+ {
1625+ world->Step (output, state, input);
1626+ }
1627+
1628+ // box lands on ground plane
1629+ // verify contacts
1630+ auto contacts = world->GetContactsFromLastStep ();
1631+ EXPECT_LT (0u , contacts.size ());
1632+
1633+ for (auto contact : contacts)
1634+ {
1635+ const auto &contactPoint = contact.template Get <
1636+ gz::physics::World3d<FeaturesCollisionContacts>::ContactPoint>();
1637+ ASSERT_TRUE (contactPoint.collision1 );
1638+ ASSERT_TRUE (contactPoint.collision2 );
1639+ EXPECT_NE (contactPoint.collision1 , contactPoint.collision2 );
1640+
1641+ auto c1 = contactPoint.collision1 ;
1642+ auto c2 = contactPoint.collision2 ;
1643+ // Contacts should be between ground plane model's 'collision'
1644+ // and box model's 'box_collision_bottom' collision
1645+ EXPECT_TRUE (c1->GetName () == " collision" ||
1646+ c1->GetName () == " box_collision_bottom" );
1647+ }
1648+ }
1649+ }
1650+
15351651struct FeaturesContactPropertiesCallback : gz::physics::FeatureList<
15361652 gz::physics::ConstructEmptyWorldFeature,
15371653
0 commit comments