From f7d38dac621cf098622fefcca762c4eccf2f3cbc Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Thu, 9 Jan 2025 04:55:19 -0800 Subject: [PATCH] Add recursive call to FindSpec for handling nested attachments. PiperOrigin-RevId: 713629578 Change-Id: I23efa5a86bac187fc42eb955d29cc03cbacfd9e0 --- src/user/user_mesh.cc | 3 +++ src/user/user_model.cc | 12 ++++++++---- test/user/user_api_test.cc | 31 ++++++++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/user/user_mesh.cc b/src/user/user_mesh.cc index f92f8c66..4de4e2e3 100644 --- a/src/user/user_mesh.cc +++ b/src/user/user_mesh.cc @@ -151,6 +151,7 @@ mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) { // set model, def model = _model; + if (_model) compiler = &_model->spec.compiler; classname = (_def ? _def->name : (_model ? "main" : "")); // in case this body is not compiled @@ -1981,6 +1982,7 @@ mjCSkin::mjCSkin(mjCModel* _model) { // set model pointer model = _model; + if (model) compiler = &model->spec.compiler; // clear data spec_file_.clear(); @@ -2638,6 +2640,7 @@ mjCFlex::mjCFlex(mjCModel* _model) { // set model model = _model; + if (_model) compiler = &_model->spec.compiler; // clear internal variables nvert = 0; diff --git a/src/user/user_model.cc b/src/user/user_model.cc index 57b6a7da..55fcb0d8 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -236,7 +236,7 @@ void mjCModel::CopyList(std::vector& dest, } // copy the element from the other model to this model source[i]->ForgetKeyframes(); - mjSpec* origin = FindSpec(mjs_getString(source[i]->model->spec.modelname)); + mjSpec* origin = FindSpec(source[i]->compiler); dest.push_back(candidate); dest.back()->model = this; dest.back()->compiler = origin ? &origin->compiler : &spec.compiler; @@ -1228,9 +1228,13 @@ mjSpec* mjCModel::FindSpec(std::string name) const { // find spec by mjsCompiler pointer mjSpec* mjCModel::FindSpec(const mjsCompiler* compiler_) const { - for (auto spec : specs_) { - if (&(static_cast(spec->element)->GetSourceSpec()->compiler) == compiler_) { - return spec; + if (&GetSourceSpec()->compiler == compiler_) { + return (mjSpec*)&spec; + } + for (auto s : specs_) { + mjSpec* source = static_cast(s->element)->FindSpec(compiler_); + if (source) { + return source; } } return nullptr; diff --git a/test/user/user_api_test.cc b/test/user/user_api_test.cc index 9a81a9b9..7394c7f1 100644 --- a/test/user/user_api_test.cc +++ b/test/user/user_api_test.cc @@ -2033,6 +2033,19 @@ TEST_F(MujocoTest, ResizeParentKeyframe) { } TEST_F(MujocoTest, DifferentUnitsAllowed) { + static constexpr char gchild_xml[] = R"( + + + + + + + + + + + )"; + static constexpr char child_xml[] = R"( @@ -2041,6 +2054,7 @@ TEST_F(MujocoTest, DifferentUnitsAllowed) { + @@ -2059,19 +2073,27 @@ TEST_F(MujocoTest, DifferentUnitsAllowed) { )"; std::array error; + mjSpec* gchild = + mj_parseXMLString(gchild_xml, 0, error.data(), error.size()); mjSpec* child = mj_parseXMLString(child_xml, 0, error.data(), error.size()); mjSpec* spec = mj_parseXMLString(parent_xml, 0, error.data(), error.size()); ASSERT_THAT(spec, NotNull()) << error.data(); - mjs_attachBody(mjs_findFrame(spec, "frame"), mjs_findBody(child, "child"), + mjs_attachBody(mjs_findFrame(child, "frame"), + mjs_findBody(gchild, "gchild"), + "gchild_", ""); + mjs_attachBody(mjs_findFrame(spec, "frame"), + mjs_findBody(child, "child"), "child_", ""); mjModel* model = mj_compile(spec, 0); EXPECT_THAT(model, NotNull()); - EXPECT_THAT(model->njnt, 2); + EXPECT_THAT(model->njnt, 3); EXPECT_NEAR(model->jnt_range[0], -mjPI, 1e-6); EXPECT_NEAR(model->jnt_range[1], mjPI, 1e-6); EXPECT_NEAR(model->jnt_range[2], -mjPI, 1e-6); EXPECT_NEAR(model->jnt_range[3], mjPI, 1e-6); + EXPECT_NEAR(model->jnt_range[4], -mjPI, 1e-6); + EXPECT_NEAR(model->jnt_range[5], mjPI, 1e-6); EXPECT_NEAR(model->body_quat[4], 1, 1e-12); EXPECT_NEAR(model->body_quat[5], 0, 1e-12); EXPECT_NEAR(model->body_quat[6], 0, 1e-12); @@ -2079,6 +2101,7 @@ TEST_F(MujocoTest, DifferentUnitsAllowed) { mjSpec* copied_spec = mj_copySpec(spec); ASSERT_THAT(copied_spec, NotNull()); + mj_deleteSpec(gchild); mj_deleteSpec(child); mj_deleteSpec(spec); mj_deleteModel(model); @@ -2086,11 +2109,13 @@ TEST_F(MujocoTest, DifferentUnitsAllowed) { // check that deleting `parent` or `child` does not invalidate the copy mjModel* copied_model = mj_compile(copied_spec, 0); EXPECT_THAT(copied_model, NotNull()); - EXPECT_THAT(copied_model->njnt, 2); + EXPECT_THAT(copied_model->njnt, 3); EXPECT_NEAR(copied_model->jnt_range[0], -mjPI, 1e-6); EXPECT_NEAR(copied_model->jnt_range[1], mjPI, 1e-6); EXPECT_NEAR(copied_model->jnt_range[2], -mjPI, 1e-6); EXPECT_NEAR(copied_model->jnt_range[3], mjPI, 1e-6); + EXPECT_NEAR(copied_model->jnt_range[4], -mjPI, 1e-6); + EXPECT_NEAR(copied_model->jnt_range[5], mjPI, 1e-6); EXPECT_NEAR(copied_model->body_quat[4], 1, 1e-12); EXPECT_NEAR(copied_model->body_quat[5], 0, 1e-12); EXPECT_NEAR(copied_model->body_quat[6], 0, 1e-12);