Add body.find_all() to Python bindings.

This enables to generate a list of all body children of a given type.

Also, add recursive option to mjs_firstChild and mjs_nextChild. Fixes #2112.

PiperOrigin-RevId: 681039348
Change-Id: Iebbb26fd5ec314150206edfdddd88633baa0bec6
This commit is contained in:
Alessio Quaglino
2024-10-01 08:56:03 -07:00
committed by Copybara-Service
parent 8a825e6050
commit 89aea5e217
11 changed files with 150 additions and 46 deletions
+14 -4
View File
@@ -655,17 +655,27 @@ void mjs_setDefault(mjsElement* element, mjsDefault* defspec) {
// return first child of selected type
mjsElement* mjs_firstChild(mjsBody* body, mjtObj type) {
mjsElement* mjs_firstChild(mjsBody* body, mjtObj type, int recurse) {
mjCBody* bodyC = static_cast<mjCBody*>(body->element);
return bodyC->NextChild(NULL, type);
try {
return bodyC->NextChild(NULL, type, recurse);
} catch (mjCError& e) {
bodyC->model->SetError(e);
return nullptr;
}
}
// return body's next child; return NULL if child is last
mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child) {
mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child, int recurse) {
mjCBody* bodyC = static_cast<mjCBody*>(body->element);
return bodyC->NextChild(child);
try {
return bodyC->NextChild(child, child->elemtype, recurse);
} catch(mjCError& e) {
bodyC->model->SetError(e);
return nullptr;
}
}
+4 -3
View File
@@ -218,11 +218,12 @@ MJAPI int mjs_getId(mjsElement* element);
//---------------------------------- Tree traversal ------------------------------------------------
// Return body's first child of given type.
MJAPI mjsElement* mjs_firstChild(mjsBody* body, mjtObj type);
// Return body's first child of given type. If recurse is nonzero, also search the body's subtree.
MJAPI mjsElement* mjs_firstChild(mjsBody* body, mjtObj type, int recurse);
// Return body's next child of the same type; return NULL if child is last.
MJAPI mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child);
// If recurse is nonzero, also search the body's subtree.
MJAPI mjsElement* mjs_nextChild(mjsBody* body, mjsElement* child, int recurse);
// Return spec's first element of selected type.
MJAPI mjsElement* mjs_firstElement(mjSpec* s, mjtObj type);
+7
View File
@@ -921,6 +921,13 @@ mjsElement* mjCModel::NextObject(mjsElement* object, mjtObj type) {
switch (type) {
case mjOBJ_BODY:
if (!object) {
return bodies_[0]->spec.element;
} else if (object == bodies_[0]->spec.element) {
return bodies_[0]->NextChild(NULL, type, /*recursive=*/true);
} else {
return bodies_[0]->NextChild(object, type, /*recursive=*/true);
}
case mjOBJ_SITE:
case mjOBJ_GEOM:
case mjOBJ_JOINT:
+3
View File
@@ -1338,6 +1338,9 @@ mjsElement* mjCBody::NextChild(mjsElement* child, mjtObj type, bool recursive) {
candidate = GetNext(frames, child, recursive);
break;
default:
throw mjCError(this,
"Body.NextChild supports the types: body, frame, geom, "
"site, light, camera");
break;
}