Skip to content

Commit a02a27d

Browse files
quaglacopybara-github
authored andcommitted
Combine all mjs_attach functions into one.
PiperOrigin-RevId: 742702092 Change-Id: I89e35c59ada017cd061e2031584eeea71776743d
1 parent 08d22ba commit a02a27d

File tree

13 files changed

+201
-318
lines changed

13 files changed

+201
-318
lines changed

doc/APIreference/functions.rst

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3808,41 +3808,14 @@ Free all pointers with ``mju_free()``.
38083808

38093809
Attachment
38103810
^^^^^^^^^^
3811-
.. _mjs_attachBody:
3811+
.. _mjs_attach:
38123812

3813-
`mjs_attachBody <#mjs_attachBody>`__
3814-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3815-
3816-
.. mujoco-include:: mjs_attachBody
3817-
3818-
Attach child body to a parent frame, return the attached body if success or NULL otherwise.
3819-
3820-
.. _mjs_attachFrame:
3821-
3822-
`mjs_attachFrame <#mjs_attachFrame>`__
3823-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3824-
3825-
.. mujoco-include:: mjs_attachFrame
3826-
3827-
Attach child frame to a parent body, return the attached frame if success or NULL otherwise.
3828-
3829-
.. _mjs_attachToSite:
3830-
3831-
`mjs_attachToSite <#mjs_attachToSite>`__
3832-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3833-
3834-
.. mujoco-include:: mjs_attachToSite
3835-
3836-
Attach child body to a parent site, return the attached body if success or NULL otherwise.
3837-
3838-
.. _mjs_attachFrameToSite:
3839-
3840-
`mjs_attachFrameToSite <#mjs_attachFrameToSite>`__
3841-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3813+
`mjs_attach <#mjs_attach>`__
3814+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
38423815

3843-
.. mujoco-include:: mjs_attachFrameToSite
3816+
.. mujoco-include:: mjs_attach
38443817

3845-
Attach child frame to a parent site, return the attached frame if success or NULL otherwise.
3818+
Attach child to a parent, return the attached element if success or NULL otherwise.
38463819

38473820
.. _mjs_detachBody:
38483821

doc/XMLreference.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,10 @@ replicating 200 times, suffixes will be ``000, 001, ...`` etc). All referencing
175175
and namespaced appropriately. Detailed examples of models using replicate can be found in the
176176
`model/replicate/ <https://github.com/google-deepmind/mujoco/tree/main/model/replicate>`__ directory.
177177

178-
There is a caveat concerning :ref:`keyframes<keyframe>` when using replicate. Since :ref:`mjs_attachFrame` is used to
178+
There is a caveat concerning :ref:`keyframes<keyframe>` when using replicate. Since :ref:`mjs_attach` is used to
179179
self-attach multiple times the enclosed kinematic tree, if this tree contains further :ref:`attach<body-attach>`
180180
elements, keyframes will not be replicated nor namespaced by :ref:`replicate<replicate>`, but they will be attached and
181-
namespaced once by the innermost call of :ref:`mjs_attachFrame` or :ref:`mjs_attachBody`. See the limitations discussed
182-
in :ref:`attach<body-attach>`.
181+
namespaced once by the innermost call of :ref:`mjs_attach`. See the limitations discussed in :ref:`attach<body-attach>`.
183182

184183
.. _replicate-count:
185184

doc/changelog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Upcoming version (not yet released)
1010

1111
- The default value of the flag for toggling :ref:`internal flex contacts<flex-contact-internal>` was changed from
1212
"true" to "false". This feature has proven to be counterintuitive for users.
13+
- All of the attach functions (``mjs_attachBody``, ``mjs_attachFrame``, ``mjs_attachToSite``,
14+
``mjs_attachFrameToSite``) have been removed and replaced by a single function :ref:`mjs_attach`.
1315

1416
General
1517
^^^^^^^

doc/includes/references.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3613,14 +3613,8 @@ void mju_threadPoolEnqueue(mjThreadPool* thread_pool, mjTask* task);
36133613
void mju_threadPoolDestroy(mjThreadPool* thread_pool);
36143614
void mju_defaultTask(mjTask* task);
36153615
void mju_taskJoin(mjTask* task);
3616-
mjsBody* mjs_attachBody(mjsFrame* parent, const mjsBody* child,
3617-
const char* prefix, const char* suffix);
3618-
mjsFrame* mjs_attachFrame(mjsBody* parent, const mjsFrame* child,
3619-
const char* prefix, const char* suffix);
3620-
mjsBody* mjs_attachToSite(mjsSite* parent, const mjsBody* child,
3621-
const char* prefix, const char* suffix);
3622-
mjsFrame* mjs_attachFrameToSite(mjsSite* parent, const mjsFrame* child,
3623-
const char* prefix, const char* suffix);
3616+
mjsElement* mjs_attach(mjsElement* parent, const mjsElement* child,
3617+
const char* prefix, const char* suffix);
36243618
int mjs_detachBody(mjSpec* s, mjsBody* b);
36253619
int mjs_detachDefault(mjSpec* s, mjsDefault* d);
36263620
mjsBody* mjs_addBody(mjsBody* body, const mjsDefault* def);

doc/programming/modeledit.rst

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,39 +111,40 @@ This framework introduces a powerful new feature: attaching and detaching model
111111
to power the :ref:`attach<body-attach>` an :ref:`replicate<replicate>` meta-elements in MJCF. Attachment allows the user
112112
to move or copy a subtree from one model into another, while also copying or moving related referenced assets and
113113
referencing elements from outside the kinematic tree (e.g., actuators and sensors). Similarly, detaching a subtree will
114-
remove all associated elements from the model. The default behavior is to move during attach. The user can select to
115-
instead copy by passing the corresponding flag to ``mjs_setDeepCopy``. This flag is temporary set to true while parsing
116-
XMLs. It is possible to :ref:`attach a body to a frame<mjs_attachBody>`:
114+
remove all associated elements from the model. The default behavior is to move the child into the parent while
115+
attaching, so subsequent changes to the child will also change the parent. Alternatively, the user can choose to make an
116+
entirely new copy during attach using :ref:`mjs_setDeepCopy`. This flag is temporarily set to true while parsing XMLs.
117+
It is possible to :ref:`attach a body to a frame<mjs_attach>`:
117118

118119
.. code-block:: C
119120
120121
mjSpec* parent = mj_makeSpec();
121122
mjSpec* child = mj_makeSpec();
122123
parent->compiler.degree = 0;
123124
child->compiler.degree = 1;
124-
mjsFrame* frame = mjs_addFrame(mjs_findBody(parent, "world"), NULL);
125-
mjsBody* body = mjs_addBody(mjs_findBody(child, "world"), NULL);
126-
mjsBody* attached_body_1 = mjs_attachBody(frame, body, "attached-", "-1");
125+
mjsElement* frame = mjs_addFrame(mjs_findBody(parent, "world"), NULL)->element;
126+
mjsElement* body = mjs_addBody(mjs_findBody(child, "world"), NULL)->element;
127+
mjsBody* attached_body_1 = mjs_asBody(mjs_attach(frame, body, "attached-", "-1"));
127128
128-
or :ref:`attach a body to a site<mjs_attachToSite>`:
129+
or :ref:`attach a body to a site<mjs_attach>`:
129130

130131
.. code-block:: C
131132
132133
mjSpec* parent = mj_makeSpec();
133134
mjSpec* child = mj_makeSpec();
134-
mjsSite* site = mjs_addSite(mjs_findBody(parent, "world"), NULL);
135-
mjsBody* body = mjs_addBody(mjs_findBody(child, "world"), NULL);
136-
mjsBody* attached_body_2 = mjs_attachToSite(site, body, "attached-", "-2");
135+
mjsElement* site = mjs_addSite(mjs_findBody(parent, "world"), NULL)->element;
136+
mjsElement* body = mjs_addBody(mjs_findBody(child, "world"), NULL)->element;
137+
mjsBody* attached_body_2 = mjs_asBody(mjs_attach(site, body, "attached-", "-2"));
137138
138-
or :ref:`attach a frame to a body<mjs_attachFrame>`:
139+
or :ref:`attach a frame to a body<mjs_attach>`:
139140

140141
.. code-block:: C
141142
142143
mjSpec* parent = mj_makeSpec();
143144
mjSpec* child = mj_makeSpec();
144-
mjsBody* body = mjs_addBody(mjs_findBody(parent, "world"), NULL);
145-
mjsFrame* frame = mjs_addFrame(mjs_findBody(child, "world"), NULL);
146-
mjsFrame* attached_frame = mjs_attachFrame(body, frame, "attached-", "-1");
145+
mjsElement* body = mjs_addBody(mjs_findBody(parent, "world"), NULL)->element;
146+
mjsElement* frame = mjs_addFrame(mjs_findBody(child, "world"), NULL)->element;
147+
mjsFrame* attached_frame = mjs_asFrame(mjs_attach(body, frame, "attached-", "-1"));
147148
148149
Note that in the above examples, the parent and child models have different values for ``compiler.degree``,
149150
corresponding to the :ref:`compiler/angle<compiler-angle>` attribute, specifying the units in which angles are

include/mujoco/mujoco.h

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,21 +1414,9 @@ MJAPI void mju_taskJoin(mjTask* task);
14141414

14151415
//---------------------------------- Attachment ----------------------------------------------------
14161416

1417-
// Attach child body to a parent frame, return the attached body if success or NULL otherwise.
1418-
MJAPI mjsBody* mjs_attachBody(mjsFrame* parent, const mjsBody* child,
1419-
const char* prefix, const char* suffix);
1420-
1421-
// Attach child frame to a parent body, return the attached frame if success or NULL otherwise.
1422-
MJAPI mjsFrame* mjs_attachFrame(mjsBody* parent, const mjsFrame* child,
1423-
const char* prefix, const char* suffix);
1424-
1425-
// Attach child body to a parent site, return the attached body if success or NULL otherwise.
1426-
MJAPI mjsBody* mjs_attachToSite(mjsSite* parent, const mjsBody* child,
1427-
const char* prefix, const char* suffix);
1428-
1429-
// Attach child frame to a parent site, return the attached frame if success or NULL otherwise.
1430-
MJAPI mjsFrame* mjs_attachFrameToSite(mjsSite* parent, const mjsFrame* child,
1431-
const char* prefix, const char* suffix);
1417+
// Attach child to a parent, return the attached element if success or NULL otherwise.
1418+
MJAPI mjsElement* mjs_attach(mjsElement* parent, const mjsElement* child,
1419+
const char* prefix, const char* suffix);
14321420

14331421
// Delete body and descendants from mjSpec, remove all references, return 0 on success.
14341422
MJAPI int mjs_detachBody(mjSpec* s, mjsBody* b);

python/mujoco/introspect/functions.py

Lines changed: 6 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -9000,125 +9000,23 @@
90009000
),
90019001
doc='Wait for a task to complete.',
90029002
)),
9003-
('mjs_attachBody',
9003+
('mjs_attach',
90049004
FunctionDecl(
9005-
name='mjs_attachBody',
9005+
name='mjs_attach',
90069006
return_type=PointerType(
9007-
inner_type=ValueType(name='mjsBody'),
9008-
),
9009-
parameters=(
9010-
FunctionParameterDecl(
9011-
name='parent',
9012-
type=PointerType(
9013-
inner_type=ValueType(name='mjsFrame'),
9014-
),
9015-
),
9016-
FunctionParameterDecl(
9017-
name='child',
9018-
type=PointerType(
9019-
inner_type=ValueType(name='mjsBody', is_const=True),
9020-
),
9021-
),
9022-
FunctionParameterDecl(
9023-
name='prefix',
9024-
type=PointerType(
9025-
inner_type=ValueType(name='char', is_const=True),
9026-
),
9027-
),
9028-
FunctionParameterDecl(
9029-
name='suffix',
9030-
type=PointerType(
9031-
inner_type=ValueType(name='char', is_const=True),
9032-
),
9033-
),
9034-
),
9035-
doc='Attach child body to a parent frame, return the attached body if success or NULL otherwise.', # pylint: disable=line-too-long
9036-
)),
9037-
('mjs_attachFrame',
9038-
FunctionDecl(
9039-
name='mjs_attachFrame',
9040-
return_type=PointerType(
9041-
inner_type=ValueType(name='mjsFrame'),
9042-
),
9043-
parameters=(
9044-
FunctionParameterDecl(
9045-
name='parent',
9046-
type=PointerType(
9047-
inner_type=ValueType(name='mjsBody'),
9048-
),
9049-
),
9050-
FunctionParameterDecl(
9051-
name='child',
9052-
type=PointerType(
9053-
inner_type=ValueType(name='mjsFrame', is_const=True),
9054-
),
9055-
),
9056-
FunctionParameterDecl(
9057-
name='prefix',
9058-
type=PointerType(
9059-
inner_type=ValueType(name='char', is_const=True),
9060-
),
9061-
),
9062-
FunctionParameterDecl(
9063-
name='suffix',
9064-
type=PointerType(
9065-
inner_type=ValueType(name='char', is_const=True),
9066-
),
9067-
),
9068-
),
9069-
doc='Attach child frame to a parent body, return the attached frame if success or NULL otherwise.', # pylint: disable=line-too-long
9070-
)),
9071-
('mjs_attachToSite',
9072-
FunctionDecl(
9073-
name='mjs_attachToSite',
9074-
return_type=PointerType(
9075-
inner_type=ValueType(name='mjsBody'),
9076-
),
9077-
parameters=(
9078-
FunctionParameterDecl(
9079-
name='parent',
9080-
type=PointerType(
9081-
inner_type=ValueType(name='mjsSite'),
9082-
),
9083-
),
9084-
FunctionParameterDecl(
9085-
name='child',
9086-
type=PointerType(
9087-
inner_type=ValueType(name='mjsBody', is_const=True),
9088-
),
9089-
),
9090-
FunctionParameterDecl(
9091-
name='prefix',
9092-
type=PointerType(
9093-
inner_type=ValueType(name='char', is_const=True),
9094-
),
9095-
),
9096-
FunctionParameterDecl(
9097-
name='suffix',
9098-
type=PointerType(
9099-
inner_type=ValueType(name='char', is_const=True),
9100-
),
9101-
),
9102-
),
9103-
doc='Attach child body to a parent site, return the attached body if success or NULL otherwise.', # pylint: disable=line-too-long
9104-
)),
9105-
('mjs_attachFrameToSite',
9106-
FunctionDecl(
9107-
name='mjs_attachFrameToSite',
9108-
return_type=PointerType(
9109-
inner_type=ValueType(name='mjsFrame'),
9007+
inner_type=ValueType(name='mjsElement'),
91109008
),
91119009
parameters=(
91129010
FunctionParameterDecl(
91139011
name='parent',
91149012
type=PointerType(
9115-
inner_type=ValueType(name='mjsSite'),
9013+
inner_type=ValueType(name='mjsElement'),
91169014
),
91179015
),
91189016
FunctionParameterDecl(
91199017
name='child',
91209018
type=PointerType(
9121-
inner_type=ValueType(name='mjsFrame', is_const=True),
9019+
inner_type=ValueType(name='mjsElement', is_const=True),
91229020
),
91239021
),
91249022
FunctionParameterDecl(
@@ -9134,7 +9032,7 @@
91349032
),
91359033
),
91369034
),
9137-
doc='Attach child frame to a parent site, return the attached frame if success or NULL otherwise.', # pylint: disable=line-too-long
9035+
doc='Attach child to a parent, return the attached element if success or NULL otherwise.', # pylint: disable=line-too-long
91389036
)),
91399037
('mjs_detachBody',
91409038
FunctionDecl(

python/mujoco/specs.cc

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ PYBIND11_MODULE(_specs, m) {
540540
SetFrame(worldbody, mjOBJ_CAMERA, worldframe);
541541
const char* p = prefix.has_value() ? prefix.value().c_str() : "";
542542
const char* s = suffix.has_value() ? suffix.value().c_str() : "";
543-
raw::MjsFrame* attached_frame = nullptr;
543+
raw::MjsElement* attached_frame = nullptr;
544544
if (frame.has_value()) {
545545
raw::MjsFrame* frame_ptr = nullptr;
546546
try {
@@ -560,11 +560,12 @@ PYBIND11_MODULE(_specs, m) {
560560
if (!parent_body) {
561561
throw pybind11::value_error("Frame does not have a parent body.");
562562
}
563-
attached_frame = mjs_attachFrame(parent_body, worldframe, p, s);
563+
attached_frame =
564+
mjs_attach(parent_body->element, worldframe->element, p, s);
564565
if (!attached_frame) {
565566
throw pybind11::value_error(mjs_getError(self.ptr));
566567
}
567-
if (mjs_setFrame(attached_frame->element, frame_ptr) != 0) {
568+
if (mjs_setFrame(attached_frame, frame_ptr) != 0) {
568569
throw pybind11::value_error(mjs_getError(self.ptr));
569570
}
570571
}
@@ -583,7 +584,8 @@ PYBIND11_MODULE(_specs, m) {
583584
throw pybind11::value_error(
584585
"Site spec does not match parent spec.");
585586
}
586-
attached_frame = mjs_attachFrameToSite(site_ptr, worldframe, p, s);
587+
attached_frame =
588+
mjs_attach(site_ptr->element, worldframe->element, p, s);
587589
if (!attached_frame) {
588590
throw pybind11::value_error(mjs_getError(self.ptr));
589591
}
@@ -597,7 +599,7 @@ PYBIND11_MODULE(_specs, m) {
597599
self.assets[asset.first] = asset.second;
598600
}
599601
child.parent = &self;
600-
return attached_frame;
602+
return mjs_asFrame(attached_frame);
601603
},
602604
py::arg("child"), py::arg("prefix") = py::none(),
603605
py::arg("suffix") = py::none(), py::arg("site") = py::none(),
@@ -829,11 +831,11 @@ PYBIND11_MODULE(_specs, m) {
829831
std::optional<std::string>& suffix) -> raw::MjsFrame* {
830832
const char* p = prefix.has_value() ? prefix.value().c_str() : "";
831833
const char* s = suffix.has_value() ? suffix.value().c_str() : "";
832-
auto new_frame = mjs_attachFrame(&self, &frame, p, s);
834+
auto new_frame = mjs_attach(self.element, frame.element, p, s);
833835
if (!new_frame) {
834836
throw pybind11::value_error(mjs_getError(mjs_getSpec(self.element)));
835837
}
836-
return new_frame;
838+
return mjs_asFrame(new_frame);
837839
},
838840
py::arg("frame"), py::arg("prefix") = py::none(),
839841
py::arg("suffix") = py::none(),
@@ -870,12 +872,12 @@ PYBIND11_MODULE(_specs, m) {
870872
std::optional<std::string>& suffix) -> raw::MjsBody* {
871873
const char* p = prefix.has_value() ? prefix.value().c_str() : "";
872874
const char* s = suffix.has_value() ? suffix.value().c_str() : "";
873-
auto new_body = mjs_attachBody(&self, &body, p, s);
875+
auto new_body = mjs_attach(self.element, body.element, p, s);
874876
if (!new_body) {
875877
throw pybind11::value_error(
876878
mjs_getError(mjs_getSpec(self.element)));
877879
}
878-
return new_body;
880+
return mjs_asBody(new_body);
879881
},
880882
py::arg("body"), py::arg("prefix") = py::none(),
881883
py::arg("suffix") = py::none(),
@@ -953,12 +955,12 @@ PYBIND11_MODULE(_specs, m) {
953955
std::optional<std::string>& suffix) -> raw::MjsBody* {
954956
const char* p = prefix.has_value() ? prefix.value().c_str() : "";
955957
const char* s = suffix.has_value() ? suffix.value().c_str() : "";
956-
auto new_body = mjs_attachToSite(&self, &body, p, s);
958+
auto new_body = mjs_attach(self.element, body.element, p, s);
957959
if (!new_body) {
958960
throw pybind11::value_error(
959961
mjs_getError(mjs_getSpec(self.element)));
960962
}
961-
return new_body;
963+
return mjs_asBody(new_body);
962964
},
963965
py::arg("body"), py::arg("prefix") = py::none(),
964966
py::arg("suffix") = py::none(),

0 commit comments

Comments
 (0)