40
40
#include < pxr/usd/usdPhysics/driveAPI.h>
41
41
#include < pxr/usd/usdPhysics/fixedJoint.h>
42
42
#include < pxr/usd/usdPhysics/joint.h>
43
+ #include < pxr/usd/usdPhysics/prismaticJoint.h>
43
44
#include < pxr/usd/usdPhysics/revoluteJoint.h>
45
+ #include < pxr/usd/usdPhysics/sphericalJoint.h>
44
46
#pragma pop_macro ("__DEPRECATED")
45
47
46
48
#include " sdf/Joint.hh"
55
57
// Fixture that creates a USD stage for each test case.
56
58
class UsdJointStageFixture : public: :testing::Test
57
59
{
58
- public: UsdJointStageFixture() = default ;
60
+ public: UsdJointStageFixture() :
61
+ worldPath (" /world" )
62
+ {
63
+ }
59
64
60
65
protected: void SetUp () override
61
66
{
62
67
this ->stage = pxr::UsdStage::CreateInMemory ();
63
68
ASSERT_TRUE (this ->stage );
64
69
}
65
70
71
+ // / \brief Parse the contents of a SDF file and convert to USD
72
+ // / \param[in] _sdfFile The full path to the SDF file to parse
73
+ public: void GenerateUSD (const std::string &_sdfFile)
74
+ {
75
+ // load the world in the SDF file
76
+ ASSERT_TRUE (sdf::testing::LoadSdfFile (_sdfFile, this ->root ));
77
+ this ->model = const_cast <sdf::Model *>(this ->root .Model ());
78
+ ASSERT_NE (nullptr , this ->model );
79
+
80
+ this ->modelPath =
81
+ std::string (this ->worldPath .GetString () + " /" + this ->model ->Name ());
82
+ const auto errors = sdf::usd::ParseSdfModel (*(this ->model ), this ->stage ,
83
+ this ->modelPath , this ->worldPath );
84
+ EXPECT_TRUE (errors.empty ());
85
+
86
+ // save the model's USD joint paths so that they can be verified
87
+ for (uint64_t i = 0 ; i < this ->model ->JointCount (); ++i)
88
+ {
89
+ const auto joint = this ->model ->JointByIndex (i);
90
+ const auto jointPath = this ->modelPath + " /" + joint->Name ();
91
+ this ->jointPathToSdf [jointPath] = joint;
92
+ }
93
+ EXPECT_EQ (this ->model ->JointCount (), this ->jointPathToSdf .size ());
94
+ }
95
+
66
96
// / \brief Verify that a USD joint is pointing to the correct parent link.
67
97
// / \param[in] _usdJoint The USD joint
68
98
// / \param[in] _parentLinkPath The parent link path that _usdJoint should
@@ -194,39 +224,32 @@ class UsdJointStageFixture : public::testing::Test
194
224
EXPECT_FLOAT_EQ (usdUpperLimit, _targetUpper);
195
225
}
196
226
227
+ // / \brief The USD stage
197
228
public: pxr::UsdStageRefPtr stage;
229
+
230
+ // / \brief The SDF model with joints to be parsed to USD
231
+ public: sdf::Model *model{nullptr };
232
+
233
+ // / \brief The USD path of the SDF world
234
+ public: const pxr::SdfPath worldPath;
235
+
236
+ // / \brief The string representation of this->model's USD path
237
+ public: std::string modelPath;
238
+
239
+ // / \brief Mapping of a joint's USD path to the corresponding SDF joint
240
+ public: std::unordered_map<std::string, const sdf::Joint *> jointPathToSdf;
241
+
242
+ // / \brief The root object of the SDF file that has been loaded. A reference
243
+ // / to the root must be kept so that pointer objects extracted from the root
244
+ // / (sdf::Model and sdf::Joint, for example) remain valid throughout the test
245
+ // / (destroying the sdf::Root object early invalidates referenced pointers)
246
+ private: sdf::Root root;
198
247
};
199
248
200
249
// ///////////////////////////////////////////////
201
250
TEST_F (UsdJointStageFixture, RevoluteJoints)
202
251
{
203
- const auto path = sdf::testing::TestFile (" sdf" , " double_pendulum.sdf" );
204
- sdf::Root root;
205
-
206
- // load the world in the SDF file
207
- ASSERT_TRUE (sdf::testing::LoadSdfFile (path, root));
208
- const auto model = root.Model ();
209
- ASSERT_NE (nullptr , model);
210
-
211
- // create a dummy world path so that we can call the sdf::usd::ParseSdfModel
212
- // API
213
- const auto worldPath = pxr::SdfPath (" /world" );
214
-
215
- const auto modelPath =
216
- std::string (worldPath.GetString () + " /" + model->Name ());
217
- const auto errors =
218
- sdf::usd::ParseSdfModel (*model, this ->stage , modelPath, worldPath);
219
- EXPECT_TRUE (errors.empty ());
220
-
221
- // save the model's USD joint paths so that they can be verified
222
- std::unordered_map<std::string, const sdf::Joint *> jointPathToSdf;
223
- for (uint64_t i = 0 ; i < model->JointCount (); ++i)
224
- {
225
- const auto joint = model->JointByIndex (i);
226
- const auto jointPath = modelPath + " /" + joint->Name ();
227
- jointPathToSdf[jointPath] = joint;
228
- }
229
- EXPECT_EQ (model->JointCount (), jointPathToSdf.size ());
252
+ this ->GenerateUSD (sdf::testing::TestFile (" sdf" , " double_pendulum.sdf" ));
230
253
231
254
// validate USD joints
232
255
int checkedJoints = 0 ;
@@ -235,8 +258,8 @@ TEST_F(UsdJointStageFixture, RevoluteJoints)
235
258
if (!prim.IsA <pxr::UsdPhysicsJoint>())
236
259
continue ;
237
260
238
- auto iter = jointPathToSdf.find (prim.GetPath ().GetString ());
239
- ASSERT_NE (jointPathToSdf.end (), iter);
261
+ auto iter = this -> jointPathToSdf .find (prim.GetPath ().GetString ());
262
+ ASSERT_NE (this -> jointPathToSdf .end (), iter);
240
263
const auto sdfJoint = iter->second ;
241
264
242
265
// the double pendulum model only has revolute joints
@@ -247,9 +270,9 @@ TEST_F(UsdJointStageFixture, RevoluteJoints)
247
270
248
271
// make sure joint is pointing to the proper parent/child links
249
272
this ->CheckParentLinkPath (&usdRevoluteJoint,
250
- modelPath + " /" + sdfJoint->ParentLinkName ());
273
+ this -> modelPath + " /" + sdfJoint->ParentLinkName ());
251
274
this ->CheckChildLinkPath (&usdRevoluteJoint,
252
- modelPath + " /" + sdfJoint->ChildLinkName ());
275
+ this -> modelPath + " /" + sdfJoint->ChildLinkName ());
253
276
254
277
// check joint's pose w.r.t. parent and child links
255
278
ignition::math::Pose3d parentToJointPose;
@@ -315,33 +338,7 @@ TEST_F(UsdJointStageFixture, RevoluteJoints)
315
338
// ///////////////////////////////////////////////
316
339
TEST_F (UsdJointStageFixture, JointParentIsWorld)
317
340
{
318
- const auto path = sdf::testing::TestFile (" sdf" , " joint_parent_world.sdf" );
319
- sdf::Root root;
320
-
321
- // load the world in the SDF file
322
- ASSERT_TRUE (sdf::testing::LoadSdfFile (path, root));
323
- const auto model = root.Model ();
324
- ASSERT_NE (nullptr , model);
325
-
326
- // create a dummy world path so that we can call the sdf::usd::ParseSdfModel
327
- // API
328
- const auto worldPath = pxr::SdfPath (" /world" );
329
-
330
- const auto modelPath =
331
- std::string (worldPath.GetString () + " /" + model->Name ());
332
- const auto errors =
333
- sdf::usd::ParseSdfModel (*model, this ->stage , modelPath, worldPath);
334
- EXPECT_TRUE (errors.empty ());
335
-
336
- // save the model's USD joint paths so that they can be verified
337
- std::unordered_map<std::string, const sdf::Joint *> jointPathToSdf;
338
- for (uint64_t i = 0 ; i < model->JointCount (); ++i)
339
- {
340
- const auto joint = model->JointByIndex (i);
341
- const auto jointPath = modelPath + " /" + joint->Name ();
342
- jointPathToSdf[jointPath] = joint;
343
- }
344
- EXPECT_EQ (model->JointCount (), jointPathToSdf.size ());
341
+ this ->GenerateUSD (sdf::testing::TestFile (" sdf" , " joint_parent_world.sdf" ));
345
342
346
343
// validate USD joints
347
344
int checkedJoints = 0 ;
@@ -350,8 +347,8 @@ TEST_F(UsdJointStageFixture, JointParentIsWorld)
350
347
if (!prim.IsA <pxr::UsdPhysicsJoint>())
351
348
continue ;
352
349
353
- auto iter = jointPathToSdf.find (prim.GetPath ().GetString ());
354
- ASSERT_NE (jointPathToSdf.end (), iter);
350
+ auto iter = this -> jointPathToSdf .find (prim.GetPath ().GetString ());
351
+ ASSERT_NE (this -> jointPathToSdf .end (), iter);
355
352
const auto sdfJoint = iter->second ;
356
353
357
354
// the only joint type in this test file is a fixed joint
@@ -362,9 +359,9 @@ TEST_F(UsdJointStageFixture, JointParentIsWorld)
362
359
363
360
// make sure joint is pointing to the proper parent/child links.
364
361
// The parent in this test should be the world
365
- this ->CheckParentLinkPath (&usdFixedJoint, worldPath.GetString ());
362
+ this ->CheckParentLinkPath (&usdFixedJoint, this -> worldPath .GetString ());
366
363
this ->CheckChildLinkPath (&usdFixedJoint,
367
- modelPath + " /" + sdfJoint->ChildLinkName ());
364
+ this -> modelPath + " /" + sdfJoint->ChildLinkName ());
368
365
369
366
// check joint's pose w.r.t. parent and child links. For this test case,
370
367
// we need to get the joint pose w.r.t. the world
@@ -373,7 +370,7 @@ TEST_F(UsdJointStageFixture, JointParentIsWorld)
373
370
EXPECT_TRUE (poseErrors.empty ());
374
371
poseErrors.clear ();
375
372
ignition::math::Pose3d worldToModelPose;
376
- poseErrors = model->SemanticPose ().Resolve (worldToModelPose);
373
+ poseErrors = this -> model ->SemanticPose ().Resolve (worldToModelPose);
377
374
const auto worldToJointPose = worldToModelPose * modelToJointPose;
378
375
EXPECT_TRUE (poseErrors.empty ());
379
376
poseErrors.clear ();
@@ -389,11 +386,76 @@ TEST_F(UsdJointStageFixture, JointParentIsWorld)
389
386
EXPECT_EQ (checkedJoints, 1 );
390
387
}
391
388
392
- // TODO(adlarkin) Add the following test cases:
393
- // 1. prismatic
394
- // - prismatic joints share a few things with revolute joints that need to
395
- // be checked: axisAttr, jointLimits
396
- // - parent/child link reference paths and pose w.r.t. parent/child links
397
- // 2. Revolute joint with the axis being "y"
398
- // - this is a special case; see the sdf::usd::SetUSDJointPose method in
399
- // usd/src/sdf_parser/Joint.cc for how this is handled
389
+ // ///////////////////////////////////////////////
390
+ TEST_F (UsdJointStageFixture, BallPrismaticJoint)
391
+ {
392
+ this ->GenerateUSD (sdf::testing::TestFile (" sdf" , " ball_prismatic_joint.sdf" ));
393
+
394
+ // validate USD joints
395
+ int checkedBallJoints = 0 ;
396
+ int checkedPrismaticJoints = 0 ;
397
+ for (const auto & prim : this ->stage ->Traverse ())
398
+ {
399
+ if (!prim.IsA <pxr::UsdPhysicsJoint>())
400
+ continue ;
401
+
402
+ auto iter = this ->jointPathToSdf .find (prim.GetPath ().GetString ());
403
+ ASSERT_NE (this ->jointPathToSdf .end (), iter);
404
+ const auto sdfJoint = iter->second ;
405
+
406
+ if (prim.IsA <pxr::UsdPhysicsSphericalJoint>())
407
+ {
408
+ checkedBallJoints++;
409
+ }
410
+ else if (prim.IsA <pxr::UsdPhysicsPrismaticJoint>())
411
+ {
412
+ checkedPrismaticJoints++;
413
+
414
+ const auto usdPrismaticJoint =
415
+ pxr::UsdPhysicsPrismaticJoint::Get (this ->stage , prim.GetPath ());
416
+ ASSERT_TRUE (usdPrismaticJoint);
417
+
418
+ // check the joint's axis
419
+ this ->VerifyJointAxis (usdPrismaticJoint, " Z" );
420
+
421
+ // check the joint limits
422
+ this ->VerifyJointLimits (usdPrismaticJoint,
423
+ static_cast <float >(sdfJoint->Axis ()->Lower ()),
424
+ static_cast <float >(sdfJoint->Axis ()->Upper ()),
425
+ false );
426
+ }
427
+ else
428
+ {
429
+ continue ;
430
+ }
431
+
432
+ const auto usdJoint =
433
+ pxr::UsdPhysicsJoint::Get (this ->stage , prim.GetPath ());
434
+ ASSERT_TRUE (usdJoint);
435
+
436
+ // make sure joint is pointing to the proper parent/child links
437
+ this ->CheckParentLinkPath (&usdJoint,
438
+ this ->modelPath + " /" + sdfJoint->ParentLinkName ());
439
+ this ->CheckChildLinkPath (&usdJoint,
440
+ this ->modelPath + " /" + sdfJoint->ChildLinkName ());
441
+
442
+ // check joint's pose w.r.t. parent and child links
443
+ ignition::math::Pose3d parentToJointPose;
444
+ auto poseErrors = sdfJoint->SemanticPose ().Resolve (parentToJointPose,
445
+ sdfJoint->ParentLinkName ());
446
+ EXPECT_TRUE (poseErrors.empty ());
447
+ poseErrors.clear ();
448
+ ignition::math::Pose3d childToJointPose;
449
+ poseErrors = sdfJoint->SemanticPose ().Resolve (childToJointPose,
450
+ sdfJoint->ChildLinkName ());
451
+ EXPECT_TRUE (poseErrors.empty ());
452
+ this ->CheckRelativeLinkPoses (&usdJoint, parentToJointPose,
453
+ childToJointPose);
454
+ }
455
+ EXPECT_EQ (checkedBallJoints, 1 );
456
+ EXPECT_EQ (checkedPrismaticJoints, 1 );
457
+ }
458
+
459
+ // TODO(adlarkin) Add a test case for a revolute joint with the axis being "y".
460
+ // This is a special case; see the sdf::usd::SetUSDJointPose method in
461
+ // usd/src/sdf_parser/Joint.cc for how this is handled
0 commit comments