Skip to content

Commit eff4dda

Browse files
quaglacopybara-github
authored andcommitted
Suffix asset names when attaching specs.
PiperOrigin-RevId: 794717786 Change-Id: I02abe06ca3c43138e91e61f4acf87a26b3faf7fc
1 parent dcdf0a9 commit eff4dda

File tree

2 files changed

+49
-11
lines changed

2 files changed

+49
-11
lines changed

python/mujoco/specs.cc

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,22 @@ py::list FindAllImpl(raw::MjsBody& body, mjtObj objtype, bool recursive) {
176176
return list; // list of pointers, so they can be copied
177177
}
178178

179+
static std::string addSuffixBeforeExtension(const std::string& original_path,
180+
const std::string& suffix_to_add) {
181+
// Find the position of the last dot
182+
size_t dot_pos = original_path.rfind('.');
183+
184+
// Check if a dot was found
185+
if (dot_pos != std::string::npos) {
186+
std::string new_path = original_path;
187+
new_path.insert(dot_pos, suffix_to_add);
188+
return new_path;
189+
} else {
190+
// No extension found, just append
191+
return original_path + suffix_to_add;
192+
}
193+
}
194+
179195
PYBIND11_MODULE(_specs, m) {
180196
auto structs_m = py::module::import("mujoco._structs");
181197
py::function mjmodel_from_raw_ptr =
@@ -471,13 +487,35 @@ PYBIND11_MODULE(_specs, m) {
471487
throw pybind11::value_error(mjs_getError(self.ptr));
472488
}
473489
}
490+
// append the assets adding the suffix to their path
491+
std::string suff(s);
474492
for (const auto& asset : child.assets) {
475-
if (self.assets.contains(asset.first) && !self.override_assets) {
493+
std::string asset_name =
494+
addSuffixBeforeExtension(asset.first.cast<std::string>(), suff);
495+
if (self.assets.contains(asset_name) && !self.override_assets) {
476496
throw pybind11::value_error("Asset " +
477497
asset.first.cast<std::string>() +
478498
" already exists in parent spec.");
479499
}
480-
self.assets[asset.first] = asset.second;
500+
self.assets[py::str(asset_name)] = asset.second;
501+
}
502+
raw::MjsElement* mesh = mjs_firstElement(child.ptr, mjOBJ_MESH);
503+
while (mesh) {
504+
std::string file = mjs_getString(mjs_asMesh(mesh)->file);
505+
if (!file.empty()) {
506+
std::string mesh_file = addSuffixBeforeExtension(file, suff);
507+
mjs_setString(mjs_asMesh(mesh)->file, mesh_file.c_str());
508+
}
509+
mesh = mjs_nextElement(child.ptr, mesh);
510+
}
511+
raw::MjsElement* tex = mjs_firstElement(child.ptr, mjOBJ_TEXTURE);
512+
while (tex) {
513+
std::string file = mjs_getString(mjs_asTexture(tex)->file);
514+
if (!file.empty()) {
515+
std::string tex_file = addSuffixBeforeExtension(file, suff);
516+
mjs_setString(mjs_asTexture(tex)->file, tex_file.c_str());
517+
}
518+
tex = mjs_nextElement(child.ptr, tex);
481519
}
482520
child.parent = &self;
483521
return mjs_asFrame(attached_frame);

python/mujoco/specs_test.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ def test_attach_to_site(self):
10691069
child2 = mujoco.MjSpec()
10701070
child2.assets = {'cube2.obj': 'cube2_content'}
10711071
body2 = child2.worldbody.add_body(name='body')
1072-
self.assertIsNotNone(parent.attach(child2, site=site, prefix='child2-'))
1072+
self.assertIsNotNone(parent.attach(child2, site=site, suffix='-child2'))
10731073
self.assertIsNotNone(child2.worldbody)
10741074
self.assertEqual(child2.parent, parent)
10751075
body2.pos = [-1, -1, -1]
@@ -1081,13 +1081,13 @@ def test_attach_to_site(self):
10811081
np.testing.assert_array_equal(model2.body_quat[1], [0, 0, 0, 1])
10821082
np.testing.assert_array_equal(model2.body_quat[2], [0, 0, 0, 1])
10831083
self.assertEqual(parent.assets['cube.obj'], 'cube_content')
1084-
self.assertEqual(parent.assets['cube2.obj'], 'cube2_content')
1084+
self.assertEqual(parent.assets['cube2-child2.obj'], 'cube2_content')
10851085

10861086
# Attach another spec to site (referenced by name) and compile again.
10871087
child3 = mujoco.MjSpec()
10881088
child3.assets = {'cube3.obj': 'cube3_content'}
10891089
body3 = child3.worldbody.add_body(name='body')
1090-
self.assertIsNotNone(parent.attach(child3, site='site', prefix='child3-'))
1090+
self.assertIsNotNone(parent.attach(child3, site='site', suffix='-child3'))
10911091
self.assertIsNotNone(child3.worldbody)
10921092
self.assertEqual(child3.parent, parent)
10931093
body3.pos = [-2, -2, -2]
@@ -1101,8 +1101,8 @@ def test_attach_to_site(self):
11011101
np.testing.assert_array_equal(model3.body_quat[2], [0, 0, 0, 1])
11021102
np.testing.assert_array_equal(model3.body_quat[3], [0, 0, 0, 1])
11031103
self.assertEqual(parent.assets['cube.obj'], 'cube_content')
1104-
self.assertEqual(parent.assets['cube2.obj'], 'cube2_content')
1105-
self.assertEqual(parent.assets['cube3.obj'], 'cube3_content')
1104+
self.assertEqual(parent.assets['cube2-child2.obj'], 'cube2_content')
1105+
self.assertEqual(parent.assets['cube3-child3.obj'], 'cube3_content')
11061106

11071107
# Fail to attach to a site that does not exist.
11081108
child4 = mujoco.MjSpec()
@@ -1150,7 +1150,7 @@ def test_attach_to_frame(self):
11501150
child2.assets = {'cube2.obj': 'cube2_content'}
11511151
body2 = child2.worldbody.add_body(name='body')
11521152
body2.set_frame(child2.worldbody.add_frame(pos=[-1, -1, 1]))
1153-
self.assertIsNotNone(parent.attach(child2, frame=frame, prefix='child-'))
1153+
self.assertIsNotNone(parent.attach(child2, frame=frame, suffix='-child'))
11541154
self.assertIsNotNone(child2.worldbody)
11551155
self.assertEqual(child2.parent, parent)
11561156
body2.pos = [-1, -1, -1]
@@ -1162,14 +1162,14 @@ def test_attach_to_frame(self):
11621162
np.testing.assert_array_equal(model2.body_quat[1], [0, 0, 0, 1])
11631163
np.testing.assert_array_equal(model2.body_quat[2], [0, 0, 0, 1])
11641164
self.assertEqual(parent.assets['cube.obj'], 'cube_content')
1165-
self.assertEqual(parent.assets['cube2.obj'], 'cube2_content')
1165+
self.assertEqual(parent.assets['cube2-child.obj'], 'cube2_content')
11661166

11671167
# Attach another spec to frame (referenced by name) and compile again.
11681168
child3 = mujoco.MjSpec()
11691169
child3.assets = {'cube2.obj': 'new_cube2_content'}
11701170
body3 = child3.worldbody.add_body(name='body')
11711171
body3.set_frame(child3.worldbody.add_frame(pos=[-1, -1, 1]))
1172-
self.assertIsNotNone(parent.attach(child3, frame='frame', prefix='child3-'))
1172+
self.assertIsNotNone(parent.attach(child3, frame='frame', suffix='-child3'))
11731173
self.assertIsNotNone(child3.worldbody)
11741174
self.assertEqual(child3.parent, parent)
11751175
body3.pos = [-2, -2, -2]
@@ -1183,7 +1183,7 @@ def test_attach_to_frame(self):
11831183
np.testing.assert_array_equal(model3.body_quat[2], [0, 0, 0, 1])
11841184
np.testing.assert_array_equal(model3.body_quat[3], [0, 0, 0, 1])
11851185
self.assertEqual(parent.assets['cube.obj'], 'cube_content')
1186-
self.assertEqual(parent.assets['cube2.obj'], 'new_cube2_content')
1186+
self.assertEqual(parent.assets['cube2-child3.obj'], 'new_cube2_content')
11871187

11881188
# Fail to attach to a frame that does not exist.
11891189
child4 = mujoco.MjSpec()

0 commit comments

Comments
 (0)