Add asset argument to MjSpec constructors.

PiperOrigin-RevId: 720628689
Change-Id: I189aa34973e58b9fb87951e34cb923d94e081a55
This commit is contained in:
Alessio Quaglino
2025-01-28 10:38:38 -08:00
committed by Copybara-Service
parent 5b330ca19c
commit 0643017346
2 changed files with 53 additions and 11 deletions
+37 -11
View File
@@ -71,17 +71,25 @@ using MjDoubleRefVec = Eigen::Ref<const Eigen::VectorXd>;
struct MjSpec { struct MjSpec {
MjSpec() : ptr(mj_makeSpec()) {} MjSpec() : ptr(mj_makeSpec()) {}
MjSpec(raw::MjSpec* ptr) : ptr(ptr) {} MjSpec(raw::MjSpec* ptr, const py::dict& assets_ = {}) : ptr(ptr) {
for (const auto [key, value] : assets_) {
assets[key] = value;
}
}
// copy constructor and assignment // copy constructor and assignment
MjSpec(const MjSpec& other) : ptr(mj_copySpec(other.ptr)) { MjSpec(const MjSpec& other) : ptr(mj_copySpec(other.ptr)) {
override_assets = other.override_assets; override_assets = other.override_assets;
assets = other.assets; for (const auto [key, value] : other.assets) {
assets[key] = value;
}
} }
MjSpec& operator=(const MjSpec& other) { MjSpec& operator=(const MjSpec& other) {
override_assets = other.override_assets; override_assets = other.override_assets;
ptr = mj_copySpec(other.ptr); ptr = mj_copySpec(other.ptr);
assets = other.assets; for (const auto [key, value] : other.assets) {
assets[key] = value;
}
return *this; return *this;
} }
@@ -89,14 +97,18 @@ struct MjSpec {
MjSpec(MjSpec&& other) : ptr(other.ptr) { MjSpec(MjSpec&& other) : ptr(other.ptr) {
override_assets = other.override_assets; override_assets = other.override_assets;
other.ptr = nullptr; other.ptr = nullptr;
assets = other.assets; for (const auto [key, value] : other.assets) {
assets[key] = value;
}
other.assets.clear(); other.assets.clear();
} }
MjSpec& operator=(MjSpec&& other) { MjSpec& operator=(MjSpec&& other) {
override_assets = other.override_assets; override_assets = other.override_assets;
ptr = other.ptr; ptr = other.ptr;
other.ptr = nullptr; other.ptr = nullptr;
assets = other.assets; for (const auto [key, value] : other.assets) {
assets[key] = value;
}
other.assets.clear(); other.assets.clear();
return *this; return *this;
} }
@@ -263,8 +275,8 @@ PYBIND11_MODULE(_specs, m) {
mjSpec.def_static( mjSpec.def_static(
"from_file", "from_file",
[](std::string& filename, [](std::string& filename,
std::optional<std::unordered_map<std::string, py::bytes>>& include) std::optional<std::unordered_map<std::string, py::bytes>>& include,
-> MjSpec { std::optional<py::dict>& assets) -> MjSpec {
const auto files = _impl::ConvertAssetsDict(include); const auto files = _impl::ConvertAssetsDict(include);
raw::MjSpec* spec; raw::MjSpec* spec;
{ {
@@ -280,9 +292,13 @@ PYBIND11_MODULE(_specs, m) {
throw py::value_error(error); throw py::value_error(error);
} }
} }
if (assets.has_value()) {
return MjSpec(spec, assets.value());
}
return MjSpec(spec); return MjSpec(spec);
}, },
py::arg("filename"), py::arg("include") = py::none(), R"mydelimiter( py::arg("filename"), py::arg("include") = py::none(),
py::arg("assets") = py::none(), R"mydelimiter(
Creates a spec from an XML file. Creates a spec from an XML file.
Parameters Parameters
@@ -292,13 +308,16 @@ PYBIND11_MODULE(_specs, m) {
include : dict, optional include : dict, optional
A dictionary of xml files included by the model. The keys are file names A dictionary of xml files included by the model. The keys are file names
and the values are file contents. and the values are file contents.
assets : dict, optional
A dictionary of assets to be used by the spec. The keys are asset names
and the values are asset contents.
)mydelimiter", )mydelimiter",
py::return_value_policy::move); py::return_value_policy::move);
mjSpec.def_static( mjSpec.def_static(
"from_string", "from_string",
[](std::string& xml, [](std::string& xml,
std::optional<std::unordered_map<std::string, py::bytes>>& include) std::optional<std::unordered_map<std::string, py::bytes>>& include,
-> MjSpec { std::optional<py::dict>& assets) -> MjSpec {
auto files = _impl::ConvertAssetsDict(include); auto files = _impl::ConvertAssetsDict(include);
raw::MjSpec* spec; raw::MjSpec* spec;
{ {
@@ -324,9 +343,13 @@ PYBIND11_MODULE(_specs, m) {
throw py::value_error(error); throw py::value_error(error);
} }
} }
if (assets.has_value()) {
return MjSpec(spec, assets.value());
}
return MjSpec(spec); return MjSpec(spec);
}, },
py::arg("xml"), py::arg("include") = py::none(), R"mydelimiter( py::arg("xml"), py::arg("include") = py::none(),
py::arg("assets") = py::none(), R"mydelimiter(
Creates a spec from an XML string. Creates a spec from an XML string.
Parameters Parameters
@@ -336,6 +359,9 @@ PYBIND11_MODULE(_specs, m) {
include : dict, optional include : dict, optional
A dictionary of xml files included by the model. The keys are file names A dictionary of xml files included by the model. The keys are file names
and the values are file contents. and the values are file contents.
assets : dict, optional
A dictionary of assets to be used by the spec. The keys are asset names
and the values are asset contents.
)mydelimiter", )mydelimiter",
py::return_value_policy::move); py::return_value_policy::move);
mjSpec.def("recompile", [mjmodel_mjdata_from_spec_ptr]( mjSpec.def("recompile", [mjmodel_mjdata_from_spec_ptr](
+16
View File
@@ -749,6 +749,22 @@ class SpecsTest(absltest.TestCase):
self.assertEqual(model.nmeshvert, 8) self.assertEqual(model.nmeshvert, 8)
self.assertEqual(spec.assets['cube.obj'], cube) self.assertEqual(spec.assets['cube.obj'], cube)
xml = """
<mujoco model="test">
<asset>
<mesh name="cube" file="cube.obj"/>
</asset>
<worldbody>
<geom mesh="cube"/>
</worldbody>
</mujoco>
"""
assets = {'cube.obj': cube}
spec = mujoco.MjSpec.from_string(xml, assets=assets)
model = spec.compile()
self.assertEqual(model.nmeshvert, 8)
self.assertEqual(spec.assets['cube.obj'], cube)
def test_include(self): def test_include(self):
included_xml = """ included_xml = """
<mujoco> <mujoco>