Add mjs_getOriginSpec to retrieve the original spec of an element.
The new function mjs_getOriginSpec returns the mjSpec that was used to define a given mjsElement. Unlike mjs_getSpec, this value remains constant even after the element has been attached to a different model. PiperOrigin-RevId: 911930951 Change-Id: Ia9cd79d9dfabc513d6121eadcffc5d41075224c9
This commit is contained in:
committed by
Copybara-Service
parent
8b06fe4c16
commit
ec50260e26
@@ -4783,6 +4783,16 @@ Find and get utilities
|
|||||||
|
|
||||||
Get spec from body.
|
Get spec from body.
|
||||||
|
|
||||||
|
.. _mjs_getOriginSpec:
|
||||||
|
|
||||||
|
`mjs_getOriginSpec <#mjs_getOriginSpec>`__
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. mujoco-include:: mjs_getOriginSpec
|
||||||
|
|
||||||
|
get spec that originally defined an element
|
||||||
|
contrary to mjs_getSpec, this does not change after attachment
|
||||||
|
|
||||||
.. _mjs_getCompiler:
|
.. _mjs_getCompiler:
|
||||||
|
|
||||||
`mjs_getCompiler <#mjs_getCompiler>`__
|
`mjs_getCompiler <#mjs_getCompiler>`__
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ General
|
|||||||
energy gain in the presence of contacts and in fluid media.
|
energy gain in the presence of contacts and in fluid media.
|
||||||
- Added :ref:`mju_sym2dense`, converting a lower-triangular, implicitly symmetric CSR matrix to a dense
|
- Added :ref:`mju_sym2dense`, converting a lower-triangular, implicitly symmetric CSR matrix to a dense
|
||||||
symmetric matrix. The inertia matrix ``mjData.M`` is an example of such a matrix.
|
symmetric matrix. The inertia matrix ``mjData.M`` is an example of such a matrix.
|
||||||
|
- Added :ref:`mjs_getOriginSpec`, returning the spec that originally defined an element, prior to attachment. This is in
|
||||||
|
contrast to :ref:`mjs_getSpec` which returns the spec currently owning the element. If the element is not the result
|
||||||
|
of an attach operation, the functions are identical.
|
||||||
|
|
||||||
.. admonition:: Future breaking API changes
|
.. admonition:: Future breaking API changes
|
||||||
:class: warning
|
:class: warning
|
||||||
|
|||||||
@@ -3687,6 +3687,7 @@ mjsTexture* mjs_addTexture(mjSpec* s);
|
|||||||
mjsMaterial* mjs_addMaterial(mjSpec* s, const mjsDefault* def);
|
mjsMaterial* mjs_addMaterial(mjSpec* s, const mjsDefault* def);
|
||||||
int mjs_makeMesh(mjsMesh* mesh, mjtMeshBuiltin builtin, double* params, int nparams);
|
int mjs_makeMesh(mjsMesh* mesh, mjtMeshBuiltin builtin, double* params, int nparams);
|
||||||
mjSpec* mjs_getSpec(const mjsElement* element);
|
mjSpec* mjs_getSpec(const mjsElement* element);
|
||||||
|
mjSpec* mjs_getOriginSpec(const mjsElement* element);
|
||||||
mjsCompiler* mjs_getCompiler(const mjsElement* element);
|
mjsCompiler* mjs_getCompiler(const mjsElement* element);
|
||||||
mjSpec* mjs_findSpec(const mjSpec* spec, const char* name);
|
mjSpec* mjs_findSpec(const mjSpec* spec, const char* name);
|
||||||
mjsBody* mjs_findBody(const mjSpec* s, const char* name);
|
mjsBody* mjs_findBody(const mjSpec* s, const char* name);
|
||||||
|
|||||||
@@ -1776,6 +1776,10 @@ MJAPI int mjs_makeMesh(mjsMesh* mesh, mjtMeshBuiltin builtin, double* params, in
|
|||||||
// Get spec from body.
|
// Get spec from body.
|
||||||
MJAPI mjSpec* mjs_getSpec(const mjsElement* element);
|
MJAPI mjSpec* mjs_getSpec(const mjsElement* element);
|
||||||
|
|
||||||
|
// get spec that originally defined an element
|
||||||
|
// contrary to mjs_getSpec, this does not change after attachment
|
||||||
|
MJAPI mjSpec* mjs_getOriginSpec(const mjsElement* element);
|
||||||
|
|
||||||
// Get compiler associated with element's origin spec.
|
// Get compiler associated with element's origin spec.
|
||||||
MJAPI mjsCompiler* mjs_getCompiler(const mjsElement* element);
|
MJAPI mjsCompiler* mjs_getCompiler(const mjsElement* element);
|
||||||
|
|
||||||
|
|||||||
@@ -11126,6 +11126,22 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
|
|||||||
),
|
),
|
||||||
doc='Get spec from body.',
|
doc='Get spec from body.',
|
||||||
)),
|
)),
|
||||||
|
('mjs_getOriginSpec',
|
||||||
|
FunctionDecl(
|
||||||
|
name='mjs_getOriginSpec',
|
||||||
|
return_type=PointerType(
|
||||||
|
inner_type=ValueType(name='mjSpec'),
|
||||||
|
),
|
||||||
|
parameters=(
|
||||||
|
FunctionParameterDecl(
|
||||||
|
name='element',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='mjsElement', is_const=True),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
doc='get spec that originally defined an element contrary to mjs_getSpec, this does not change after attachment', # pylint: disable=line-too-long
|
||||||
|
)),
|
||||||
('mjs_getCompiler',
|
('mjs_getCompiler',
|
||||||
FunctionDecl(
|
FunctionDecl(
|
||||||
name='mjs_getCompiler',
|
name='mjs_getCompiler',
|
||||||
|
|||||||
@@ -1308,6 +1308,16 @@ mjSpec* mjs_getSpec(const mjsElement* element) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// get spec that originally defined an element
|
||||||
|
// contrary to mjs_getSpec, this does not change after attachment
|
||||||
|
mjSpec* mjs_getOriginSpec(const mjsElement* element) {
|
||||||
|
const mjCModel* model = static_cast<const mjCBase*>(element)->model;
|
||||||
|
const mjsCompiler* compiler = static_cast<const mjCBase*>(element)->compiler;
|
||||||
|
return model->FindSpec(compiler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mjsCompiler* mjs_getCompiler(const mjsElement* element) {
|
mjsCompiler* mjs_getCompiler(const mjsElement* element) {
|
||||||
return static_cast<const mjCBase*>(element)->compiler;
|
return static_cast<const mjCBase*>(element)->compiler;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,6 +224,10 @@ MJAPI int mjs_makeMesh(mjsMesh* mesh, mjtMeshBuiltin builtin, double* params, in
|
|||||||
// Get spec from body.
|
// Get spec from body.
|
||||||
MJAPI mjSpec* mjs_getSpec(const mjsElement* element);
|
MJAPI mjSpec* mjs_getSpec(const mjsElement* element);
|
||||||
|
|
||||||
|
// get spec that originally defined an element
|
||||||
|
// contrary to mjs_getSpec, this does not change after attachment
|
||||||
|
MJAPI mjSpec* mjs_getOriginSpec(const mjsElement* element);
|
||||||
|
|
||||||
// Find spec (model asset) by name.
|
// Find spec (model asset) by name.
|
||||||
MJAPI mjSpec* mjs_findSpec(const mjSpec* spec, const char* name);
|
MJAPI mjSpec* mjs_findSpec(const mjSpec* spec, const char* name);
|
||||||
|
|
||||||
|
|||||||
@@ -205,6 +205,39 @@ TEST_F(MujocoTest, AttachAndChildDeletion) {
|
|||||||
mj_deleteSpec(parent_spec);
|
mj_deleteSpec(parent_spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(MujocoTest, OriginSpecInvariantToAttachment) {
|
||||||
|
mjSpec* child_spec = mj_makeSpec();
|
||||||
|
mjsBody* child_world = mjs_findBody(child_spec, "world");
|
||||||
|
mjsBody* child_body = mjs_addBody(child_world, 0);
|
||||||
|
mjsJoint* freejoint = mjs_addJoint(child_body, 0);
|
||||||
|
freejoint->type = mjJNT_FREE;
|
||||||
|
mjs_setName(freejoint->element, "child_freejoint");
|
||||||
|
|
||||||
|
mjSpec* parent_spec = mj_makeSpec();
|
||||||
|
mjsBody* parent_world = mjs_findBody(parent_spec, "world");
|
||||||
|
mjsBody* parent_body = mjs_addBody(parent_world, 0);
|
||||||
|
mjs_setName(parent_body->element, "parent_body");
|
||||||
|
|
||||||
|
// Attach child spec to parent_body
|
||||||
|
mjsElement* attached =
|
||||||
|
mjs_attach(parent_body->element, child_spec->element, "pre_", "");
|
||||||
|
ASSERT_THAT(attached, NotNull());
|
||||||
|
|
||||||
|
// The freejoint should still be in parent_spec because deletion failed
|
||||||
|
mjsElement* child_spec_joint =
|
||||||
|
mjs_findElement(parent_spec, mjOBJ_JOINT, "pre_child_freejoint");
|
||||||
|
EXPECT_EQ(mjs_getSpec(child_spec_joint), parent_spec);
|
||||||
|
EXPECT_EQ(mjs_getOriginSpec(child_spec_joint), child_spec);
|
||||||
|
|
||||||
|
mjsElement* parent_spec_body =
|
||||||
|
mjs_findElement(parent_spec, mjOBJ_BODY, "parent_body");
|
||||||
|
EXPECT_EQ(mjs_getOriginSpec(parent_spec_body), parent_spec);
|
||||||
|
|
||||||
|
|
||||||
|
mj_deleteSpec(child_spec);
|
||||||
|
mj_deleteSpec(parent_spec);
|
||||||
|
}
|
||||||
|
|
||||||
int open_mock(mjResource* resource) {
|
int open_mock(mjResource* resource) {
|
||||||
static const char parent_xml[] = R"(
|
static const char parent_xml[] = R"(
|
||||||
<mujoco>
|
<mujoco>
|
||||||
|
|||||||
@@ -9793,6 +9793,14 @@ std::string mjs_getName_wrapper(MjsElement& element) {
|
|||||||
return *mjs_getName(element.get());
|
return *mjs_getName(element.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<MjSpec> mjs_getOriginSpec_wrapper(const MjsElement& element) {
|
||||||
|
mjSpec* result = mjs_getOriginSpec(element.get());
|
||||||
|
if (result == nullptr) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return MjSpec(result);
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<MjsBody> mjs_getParent_wrapper(const MjsElement& element) {
|
std::optional<MjsBody> mjs_getParent_wrapper(const MjsElement& element) {
|
||||||
mjsBody* result = mjs_getParent(element.get());
|
mjsBody* result = mjs_getParent(element.get());
|
||||||
if (result == nullptr) {
|
if (result == nullptr) {
|
||||||
@@ -13343,6 +13351,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
|||||||
function("mjs_getFrame", &mjs_getFrame_wrapper);
|
function("mjs_getFrame", &mjs_getFrame_wrapper);
|
||||||
function("mjs_getId", &mjs_getId_wrapper);
|
function("mjs_getId", &mjs_getId_wrapper);
|
||||||
function("mjs_getName", &mjs_getName_wrapper);
|
function("mjs_getName", &mjs_getName_wrapper);
|
||||||
|
function("mjs_getOriginSpec", &mjs_getOriginSpec_wrapper);
|
||||||
function("mjs_getParent", &mjs_getParent_wrapper);
|
function("mjs_getParent", &mjs_getParent_wrapper);
|
||||||
function("mjs_getSpec", &mjs_getSpec_wrapper);
|
function("mjs_getSpec", &mjs_getSpec_wrapper);
|
||||||
function("mjs_getSpecDefault", &mjs_getSpecDefault_wrapper);
|
function("mjs_getSpecDefault", &mjs_getSpecDefault_wrapper);
|
||||||
|
|||||||
Reference in New Issue
Block a user