Add support for querying of MjsTendon path from Python.

Fixes #2670

PiperOrigin-RevId: 822215254
Change-Id: Ice5a264e54f963776093511c6e4ac830aae6d4f8
This commit is contained in:
Sam Haves
2025-10-21 11:50:24 -07:00
committed by Copybara-Service
parent 2f65e23779
commit ac2cd5dfd6
9 changed files with 411 additions and 11 deletions
+81
View File
@@ -1338,6 +1338,76 @@ mjsElement* mjs_nextElement(mjSpec* s, mjsElement* element) {
mjsElement* mjs_getWrapTarget(mjsWrap* wrap) {
mjCWrap* cwrap = static_cast<mjCWrap*>(wrap->element);
mjtObj type = mjOBJ_UNKNOWN;
switch (cwrap->Type()) {
case mjWRAP_SPHERE:
case mjWRAP_CYLINDER:
type = mjOBJ_GEOM;
break;
case mjWRAP_SITE:
type = mjOBJ_SITE;
break;
case mjWRAP_JOINT:
type = mjOBJ_JOINT;
break;
case mjWRAP_PULLEY:
// Pulleys have no target.
return nullptr;
default:
return nullptr;
}
mjSpec* spec = mjs_getSpec(wrap->element);
mjsElement* target = mjs_findElement(spec, type, cwrap->name.c_str());
return target;
}
mjsSite* mjs_getWrapSideSite(mjsWrap* wrap) {
mjCWrap* cwrap = static_cast<mjCWrap*>(wrap->element);
// only sphere and cylinder (geoms) have side sites
if ((cwrap->Type() != mjWRAP_SPHERE &&
cwrap->Type() != mjWRAP_CYLINDER) ||
cwrap->sidesite.empty()) {
return nullptr;
}
mjSpec* spec = mjs_getSpec(wrap->element);
mjsElement* site = mjs_findElement(spec, mjOBJ_SITE, cwrap->sidesite.c_str());
if (site == nullptr) {
mju_warning("Could not find side site %s for wrap %s in spec",
cwrap->sidesite.c_str(), cwrap->name.c_str());
return nullptr;
}
return mjs_asSite(site);
}
double mjs_getWrapDivisor(mjsWrap* wrap) {
mjCWrap* cwrap = static_cast<mjCWrap*>(wrap->element);
if (cwrap->Type() != mjWRAP_PULLEY) {
mju_warning("Querying divisor attribute of non-pulley wrap: %s", cwrap->name.c_str());
return 1.0;
}
return cwrap->prm;
}
double mjs_getWrapCoef(mjsWrap* wrap) {
mjCWrap* cwrap = static_cast<mjCWrap*>(wrap->element);
if (cwrap->Type() != mjWRAP_JOINT) {
mju_warning("Querying coef attribute of non-joint wrap: %s", cwrap->name.c_str());
return 1.0;
}
return cwrap->prm;
}
// return body given mjsElement
mjsBody* mjs_asBody(mjsElement* element) {
if (element && element->elemtype == mjOBJ_BODY) {
@@ -1712,7 +1782,18 @@ const double* mjs_getDouble(const mjDoubleVec* source, int* size) {
return source->data();
}
int mjs_getWrapNum(const mjsTendon* tendonspec) {
mjCTendon* tendon = static_cast<mjCTendon*>(tendonspec->element);
return tendon->NumWraps();
}
mjsWrap* mjs_getWrap(const mjsTendon* tendonspec, int i) {
mjCTendon* tendon = static_cast<mjCTendon*>(tendonspec->element);
if (i < 0 || i >= tendon->NumWraps()) {
mju_error("Wrap index out of range (0, %d)", tendon->NumWraps());
}
return &const_cast<mjCWrap*>(tendon->GetWrap(i))->spec;
}
// set plugin attributes
void mjs_setPluginAttributes(mjsPlugin* plugin, void* attributes) {
+17
View File
@@ -266,6 +266,18 @@ MJAPI mjsElement* mjs_firstElement(mjSpec* s, mjtObj type);
// Return spec's next element; return NULL if element is last.
MJAPI mjsElement* mjs_nextElement(mjSpec* s, mjsElement* element);
// Get wrapped element in tendon path.
MJAPI mjsElement* mjs_getWrapTarget(mjsWrap* wrap);
// Get wrapped element in tendon path.
MJAPI mjsSite* mjs_getWrapSideSite(mjsWrap* wrap);
// Get divisor of mjsWrap wrapping a puller.
MJAPI double mjs_getWrapDivisor(mjsWrap* wrap);
// Get coefficient of mjsWrap wrapping a joint.
MJAPI double mjs_getWrapCoef(mjsWrap* wrap);
// Safely cast an element as mjsBody, or return NULL if the element is not an mjsBody.
MJAPI mjsBody* mjs_asBody(mjsElement* element);
@@ -389,6 +401,11 @@ MJAPI const char* mjs_getString(const mjString* source);
// Get double array contents and optionally its size.
MJAPI const double* mjs_getDouble(const mjDoubleVec* source, int* size);
// Get number of elements a tendon wraps.
MJAPI int mjs_getWrapNum(const mjsTendon* tendonspec);
MJAPI mjsWrap* mjs_getWrap(const mjsTendon* tendonspec, int i);
// Get plugin attributes.
MJAPI const void* mjs_getPluginAttributes(const mjsPlugin* plugin);