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