Do not copy the spec during attach.

Use a reference count for managing the memory.

PiperOrigin-RevId: 716169486
Change-Id: Id270c4858c17b9250115e9544d5ea143584e2d5f
This commit is contained in:
Alessio Quaglino
2025-01-16 03:52:31 -08:00
committed by Copybara-Service
parent 6436055c6c
commit c2138c3fb0
19 changed files with 505 additions and 173 deletions
+9
View File
@@ -1510,6 +1510,15 @@ Free memory allocation in mjSpec.
Activate plugin. Returns 0 on success.
.. _mjs_setDeepCopy:
`mjs_setDeepCopy <#mjs_setDeepCopy>`__
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. mujoco-include:: mjs_setDeepCopy
Turn deep copy on or off attach. Returns 0 on success.
.. _Errorandmemory:
Error and memory
+7 -2
View File
@@ -2,8 +2,13 @@
Changelog
=========
Version 3.2.7 (Jan 14, 2025)
----------------------------
Upcoming version (not yet released)
-----------------------------------
- Added ``mjs_setDeepCopy`` API function. When the deep copy flag is 0, attaching a model will not copy it to the
parent, so the original references to the child allow to modify the parent as well. The default behavior is to perform
such a shallow copy. The old behavioud of creating a deep copy of the child model while attaching can be restored by
setting the deep copy flag to 1.
Python bindings
^^^^^^^^^^^^^^^
+1
View File
@@ -3181,6 +3181,7 @@ mjSpec* mj_makeSpec(void);
mjSpec* mj_copySpec(const mjSpec* s);
void mj_deleteSpec(mjSpec* s);
int mjs_activatePlugin(mjSpec* s, const char* name);
int mjs_setDeepCopy(mjSpec* s, int deepcopy);
void mj_printFormattedModel(const mjModel* m, const char* filename, const char* float_format);
void mj_printModel(const mjModel* m, const char* filename);
void mj_printFormattedData(const mjModel* m, mjData* d, const char* filename,
+17 -7
View File
@@ -106,12 +106,14 @@ procedurally, default classes are passed in explicitly to element constructors.
Attachment
^^^^^^^^^^
This framework introduces a powerful new feature: attaching and detaching model subtrees. Attachment allows the user
copy a subtree from one model into another, while also copying related referenced assets and referencing elements from
outside the kinematic tree (e.g., actuators and sensors). Similarly, detaching a subtree will remove all associated
elements from the model. This feature is already used to power the :ref:`attach<body-attach>` and
:ref:`replicate<replicate>` meta-elements in MJCF. It is possible to :ref:`attach a body to a frame<mjs_attachBody>` and
to :ref:`attach a body to a site<mjs_attachToSite>`:
This framework introduces a powerful new feature: attaching and detaching model subtrees. This feature is already used
to power the :ref:`attach<body-attach>` an :ref:`replicate<replicate>` meta-elements in MJCF. Attachment allows the user
to move or copy a subtree from one model into another, while also copying or moving related referenced assets and
referencing elements from outside the kinematic tree (e.g., actuators and sensors). Similarly, detaching a subtree will
remove all associated elements from the model. The default behavior is to move during attach. The user can select to
instead copy by passing the corresponding flag to ``mjs_setDeepCopy``. This flag is temporary set to true while parsing
XMLs. It is possible to :ref:`attach a body to a frame<mjs_attachBody>`:
.. code-block:: C
@@ -120,9 +122,17 @@ to :ref:`attach a body to a site<mjs_attachToSite>`:
parent->compiler.degree = 0;
child->compiler.degree = 1;
mjsFrame* frame = mjs_addFrame(mjs_findBody(parent, "world"), NULL);
mjsSite* site = mjs_addSite(mjs_findBody(parent, "world"), NULL);
mjsBody* body = mjs_addBody(mjs_findBody(child, "world"), NULL);
mjsBody* attached_body_1 = mjs_attachBody(frame, body, "attached-", "-1");
or :ref:`attach a body to a site<mjs_attachToSite>`:
.. code-block:: C
mjSpec* parent = mj_makeSpec();
mjSpec* child = mj_makeSpec();
mjsSite* site = mjs_addSite(mjs_findBody(parent, "world"), NULL);
mjsBody* body = mjs_addBody(mjs_findBody(child, "world"), NULL);
mjsBody* attached_body_2 = mjs_attachToSite(site, body, "attached-", "-2");
or :ref:`attach a frame to a body<mjs_attachFrame>`:
+7 -3
View File
@@ -531,15 +531,19 @@ Attachment
It is possible to combine multiple specs by using attachments. The following options are possible:
- Attach a body from the child spec to a frame in the parent spec: ``body.attach_body(body, prefix, suffix)``, returns
the newly createdbody in the parent spec.
the reference to the attached body, which should be identical to the body used as input.
- Attach a frame from the child spec to a body in the parent spec: ``body.attach_frame(frame, prefix, suffix)``,
returns the newly created frame in the parent spec.
returns the reference to the attached frame, which should be identical to the frame used as input.
- Attach a body from the child spec to a site in the parent spec: ``site.attach(body, prefix, suffix)``, returns the
newly created body in the parent spec.
reference to the attached body, which should be identical to the body used as input.
- Attach the worldbody from the child spec to a frame in the parent spec and transform it to a frame:
``body.attach(spec, prefix, suffix)``, returns the newly created frame that the child worldbody was transformed
into.
Attaching does not copy, so all the child reference are still valid in the parent and therefore modifying the child will
modify the parent. This is not true for the attach :ref:`attach<body-attach>` an :ref:`replicate<replicate>`
meta-elements in MJCF, which create deep copies while attaching.
.. code-block:: python
import mujoco