Expose function for determining if tendons should be drawn using a catenary.

PiperOrigin-RevId: 931170146
Change-Id: Ia3352a3e2bdc5e4df932e9d476e1e34200b62df1
This commit is contained in:
Haroon Qureshi
2026-06-12 08:44:48 -07:00
committed by Copybara-Service
parent 4bb02e299d
commit 0ea9c7cb3a
2 changed files with 61 additions and 47 deletions
+33 -23
View File
@@ -1083,21 +1083,7 @@ static void addSiteGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
} }
static void addSpatialTendonGeoms(const mjModel* m, mjData* d, const mjvOption* vopt, int catmask, int mjv_isCatenary(const mjModel* m, const mjData* d, int i, mjtNum* length) {
mjvScene* scn) {
const int category = mjCAT_DYNAMIC;
if (!(category & catmask)) {
return;
}
if (!vopt->flags[mjVIS_TENDON]) {
return;
}
for (int i=0; i < m->ntendon; i++) {
if (!vopt->tendongroup[mjMAX(0, mjMIN(mjNGROUP-1, m->tendon_group[i]))]) {
continue;
}
int has_stiffness = m->tendon_stiffness[i] || int has_stiffness = m->tendon_stiffness[i] ||
!mju_isZero(m->tendon_stiffnesspoly+mjNPOLY*i, mjNPOLY); !mju_isZero(m->tendon_stiffnesspoly+mjNPOLY*i, mjNPOLY);
@@ -1138,6 +1124,38 @@ static void addSpatialTendonGeoms(const mjModel* m, mjData* d, const mjvOption*
} }
} }
if (draw_catenary) {
// length of the tendon
if (limitedconstraint) {
*length = m->tendon_range[2*i+1];
} else {
*length = m->tendon_lengthspring[2*i+1];
}
}
return draw_catenary;
}
static void addSpatialTendonGeoms(const mjModel* m, mjData* d, const mjvOption* vopt, int catmask,
mjvScene* scn) {
const int category = mjCAT_DYNAMIC;
if (!(category & catmask)) {
return;
}
if (!vopt->flags[mjVIS_TENDON]) {
return;
}
for (int i=0; i < m->ntendon; i++) {
if (!vopt->tendongroup[mjMAX(0, mjMIN(mjNGROUP-1, m->tendon_group[i]))]) {
continue;
}
mjtNum length;
int draw_catenary = mjv_isCatenary(m, d, i, &length);
// conditions not met: draw straight lines // conditions not met: draw straight lines
if (!draw_catenary) { if (!draw_catenary) {
for (int j=d->ten_wrapadr[i]; j < d->ten_wrapadr[i]+d->ten_wrapnum[i]-1; j++) { for (int j=d->ten_wrapadr[i]; j < d->ten_wrapadr[i]+d->ten_wrapnum[i]-1; j++) {
@@ -1213,14 +1231,6 @@ static void addSpatialTendonGeoms(const mjModel* m, mjData* d, const mjvOption*
mju_copy3(x0, d->wrap_xpos + 3*d->ten_wrapadr[i]); mju_copy3(x0, d->wrap_xpos + 3*d->ten_wrapadr[i]);
mju_copy3(x1, d->wrap_xpos + 3*d->ten_wrapadr[i] + 3); mju_copy3(x1, d->wrap_xpos + 3*d->ten_wrapadr[i] + 3);
// length of the tendon
mjtNum length;
if (limitedconstraint) {
length = m->tendon_range[2*i+1];
} else {
length = m->tendon_lengthspring[2*i+1];
}
// get number of points along catenary path (capped at 100) // get number of points along catenary path (capped at 100)
int ncatenary = mjMIN(m->vis.quality.numslices + 1, 100); int ncatenary = mjMIN(m->vis.quality.numslices + 1, 100);
mjtNum catenary[300]; mjtNum catenary[300];
+4
View File
@@ -65,6 +65,10 @@ MJAPI void mjv_cameraFrame(mjtNum headpos[3], mjtNum forward[3], mjtNum up[3], m
MJAPI void mjv_cameraFrustum(float zver[2], float zhor[2], float zclip[2], const mjModel* m, MJAPI void mjv_cameraFrustum(float zver[2], float zhor[2], float zclip[2], const mjModel* m,
const mjvCamera* cam); const mjvCamera* cam);
// determines if tendon should be rendered as a catenary curve and, if so, computes its length
MJAPI int mjv_isCatenary(const mjModel* m, const mjData* d, int i, mjtNum* length);
// computes points along a catenary curve
int mjv_catenary(const mjtNum x0[3], const mjtNum x1[3], const mjtNum gravity[3], mjtNum length, int mjv_catenary(const mjtNum x0[3], const mjtNum x1[3], const mjtNum gravity[3], mjtNum length,
mjtNum* catenary, int ncatenary); mjtNum* catenary, int ncatenary);