@@ -45,6 +45,22 @@ using namespace collision;
4545using namespace dynamics ;
4646using namespace dart ::test;
4747
48+ namespace {
49+
50+ class DummyCollisionObject : public collision ::CollisionObject
51+ {
52+ public:
53+ DummyCollisionObject (
54+ collision::CollisionDetector* detector, const dynamics::ShapeFrame* frame)
55+ : CollisionObject(detector, frame)
56+ {
57+ }
58+
59+ void updateEngineData () override {}
60+ };
61+
62+ } // namespace
63+
4864// ==============================================================================
4965TEST (Raycast, RayHitDefaultConstructor)
5066{
@@ -62,6 +78,45 @@ TEST(Raycast, RaycastResultDefaultConstructor)
6278 EXPECT_TRUE (result.mRayHits .empty ());
6379}
6480
81+ // ==============================================================================
82+ TEST (Raycast, RaycastOptionPassesFilterWhenUnset)
83+ {
84+ auto detector = DARTCollisionDetector::create ();
85+
86+ auto frame = SimpleFrame::createShared (Frame::World ());
87+ frame->setShape (std::make_shared<SphereShape>(0.1 ));
88+ DummyCollisionObject object (detector.get (), frame.get ());
89+
90+ RaycastOption option;
91+
92+ EXPECT_FALSE (option.mEnableAllHits );
93+ EXPECT_FALSE (option.mSortByClosest );
94+ EXPECT_TRUE (option.passesFilter (&object));
95+ }
96+
97+ // ==============================================================================
98+ TEST (Raycast, RaycastOptionHonorsPredicate)
99+ {
100+ auto detector = DARTCollisionDetector::create ();
101+
102+ auto firstFrame = SimpleFrame::createShared (Frame::World ());
103+ firstFrame->setShape (std::make_shared<SphereShape>(0.1 ));
104+ auto secondFrame = SimpleFrame::createShared (Frame::World ());
105+ secondFrame->setShape (std::make_shared<SphereShape>(0.1 ));
106+
107+ DummyCollisionObject first (detector.get (), firstFrame.get ());
108+ DummyCollisionObject second (detector.get (), secondFrame.get ());
109+
110+ RaycastOption option (true , true , [&](const collision::CollisionObject* obj) {
111+ return obj == &first;
112+ });
113+
114+ EXPECT_TRUE (option.mEnableAllHits );
115+ EXPECT_TRUE (option.mSortByClosest );
116+ EXPECT_TRUE (option.passesFilter (&first));
117+ EXPECT_FALSE (option.passesFilter (&second));
118+ }
119+
65120// ==============================================================================
66121void testBasicInterface (const std::shared_ptr<CollisionDetector>& cd)
67122{
@@ -242,3 +297,90 @@ TEST(Raycast, testOptions)
242297 auto dart = DARTCollisionDetector::create ();
243298 testOptions (dart);
244299}
300+
301+ // ==============================================================================
302+ void testFilters (const std::shared_ptr<CollisionDetector>& cd)
303+ {
304+ if (cd->getType () != " bullet" ) {
305+ DART_WARN (
306+ " Aborting test: distance check is not supported by {}." , cd->getType ());
307+ return ;
308+ }
309+
310+ auto simpleFrame1 = SimpleFrame::createShared (Frame::World ());
311+ auto simpleFrame2 = SimpleFrame::createShared (Frame::World ());
312+
313+ auto sphere = std::make_shared<SphereShape>(1.0 );
314+ simpleFrame1->setShape (sphere);
315+ simpleFrame2->setShape (sphere);
316+
317+ auto group = cd->createCollisionGroup (simpleFrame1.get (), simpleFrame2.get ());
318+
319+ collision::RaycastOption option;
320+ collision::RaycastResult result;
321+
322+ simpleFrame1->setTranslation (Eigen::Vector3d (-2 , 0 , 0 ));
323+ simpleFrame2->setTranslation (Eigen::Vector3d (2 , 0 , 0 ));
324+
325+ option.mEnableAllHits = false ;
326+ option.mSortByClosest = false ;
327+ option.mFilter = [&](const collision::CollisionObject* obj) {
328+ return obj->getShapeFrame () == simpleFrame2.get ();
329+ };
330+
331+ result.clear ();
332+ cd->raycast (
333+ group.get (),
334+ Eigen::Vector3d (-5 , 0 , 0 ),
335+ Eigen::Vector3d (5 , 0 , 0 ),
336+ option,
337+ &result);
338+ ASSERT_TRUE (result.hasHit ());
339+ ASSERT_EQ (result.mRayHits .size (), 1u );
340+ auto rayHit = result.mRayHits [0 ];
341+ EXPECT_TRUE (equals (rayHit.mPoint , Eigen::Vector3d (1 , 0 , 0 )));
342+ EXPECT_TRUE (equals (rayHit.mNormal , Eigen::Vector3d (-1 , 0 , 0 )));
343+ EXPECT_NEAR (rayHit.mFraction , 0.6 , 1e-5 );
344+
345+ option.mEnableAllHits = true ;
346+ option.mFilter = [&](const collision::CollisionObject* obj) {
347+ return obj->getShapeFrame () == simpleFrame1.get ();
348+ };
349+ result.clear ();
350+ cd->raycast (
351+ group.get (),
352+ Eigen::Vector3d (-5 , 0 , 0 ),
353+ Eigen::Vector3d (5 , 0 , 0 ),
354+ option,
355+ &result);
356+ ASSERT_TRUE (result.hasHit ());
357+ ASSERT_EQ (result.mRayHits .size (), 1u );
358+ rayHit = result.mRayHits [0 ];
359+ EXPECT_TRUE (equals (rayHit.mPoint , Eigen::Vector3d (-3 , 0 , 0 )));
360+ EXPECT_TRUE (equals (rayHit.mNormal , Eigen::Vector3d (-1 , 0 , 0 )));
361+ EXPECT_NEAR (rayHit.mFraction , 0.2 , 1e-5 );
362+
363+ option.mFilter = [&](const collision::CollisionObject*) {
364+ return false ;
365+ };
366+ result.clear ();
367+ cd->raycast (
368+ group.get (),
369+ Eigen::Vector3d (-5 , 0 , 0 ),
370+ Eigen::Vector3d (5 , 0 , 0 ),
371+ option,
372+ &result);
373+ EXPECT_FALSE (result.hasHit ());
374+ EXPECT_TRUE (result.mRayHits .empty ());
375+ }
376+
377+ // ==============================================================================
378+ TEST (Raycast, testFilters)
379+ {
380+ #if HAVE_BULLET
381+ auto bullet = BulletCollisionDetector::create ();
382+ testFilters (bullet);
383+ #else
384+ GTEST_SKIP () << " Bullet collision detector not available." ;
385+ #endif
386+ }
0 commit comments