Add mjmDef to C API.

PiperOrigin-RevId: 607310534
Change-Id: I530f32c8fd4340dc1006585259a5e05cb4aa62b8
This commit is contained in:
Alessio Quaglino
2024-02-15 06:16:56 -08:00
committed by Copybara-Service
parent 6f958bc404
commit 414a67640a
10 changed files with 405 additions and 263 deletions
+43 -29
View File
@@ -48,8 +48,8 @@ MJAPI void mjm_finalize(mjElement object) {
// add child body to body, return child spec
mjmBody* mjm_addBody(mjmBody* bodyspec, void* defspec) {
mjCDef* def = static_cast<mjCDef*>(defspec);
mjmBody* mjm_addBody(mjmBody* bodyspec, mjmDefault* defspec) {
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCBody* body = reinterpret_cast<mjCBody*>(bodyspec->element)->AddBody(def);
return &body->spec;
}
@@ -57,8 +57,8 @@ mjmBody* mjm_addBody(mjmBody* bodyspec, void* defspec) {
// add site to body, return site spec
mjmSite* mjm_addSite(mjmBody* bodyspec, void* defspec) {
mjCDef* def = static_cast<mjCDef*>(defspec);
mjmSite* mjm_addSite(mjmBody* bodyspec, mjmDefault* defspec) {
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCBody* body = reinterpret_cast<mjCBody*>(bodyspec->element);
mjCSite* site = body->AddSite(def);
return &site->spec;
@@ -67,8 +67,8 @@ mjmSite* mjm_addSite(mjmBody* bodyspec, void* defspec) {
// add joint to body
mjmJoint* mjm_addJoint(mjmBody* bodyspec, void* defspec) {
mjCDef* def = static_cast<mjCDef*>(defspec);
mjmJoint* mjm_addJoint(mjmBody* bodyspec, mjmDefault* defspec) {
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCBody* body = reinterpret_cast<mjCBody*>(bodyspec->element);
mjCJoint* joint = body->AddJoint(def);
return &joint->spec;
@@ -86,8 +86,8 @@ mjmJoint* mjm_addFreeJoint(mjmBody* bodyspec) {
// add geom to body
mjmGeom* mjm_addGeom(mjmBody* bodyspec, void* defspec) {
mjCDef* def = static_cast<mjCDef*>(defspec);
mjmGeom* mjm_addGeom(mjmBody* bodyspec, mjmDefault* defspec) {
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCBody* body = reinterpret_cast<mjCBody*>(bodyspec->element);
mjCGeom* geom = body->AddGeom(def);
return &geom->spec;
@@ -96,8 +96,8 @@ mjmGeom* mjm_addGeom(mjmBody* bodyspec, void* defspec) {
// add camera to body
mjmCamera* mjm_addCamera(mjmBody* bodyspec, void* defspec) {
mjCDef* def = static_cast<mjCDef*>(defspec);
mjmCamera* mjm_addCamera(mjmBody* bodyspec, mjmDefault* defspec) {
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCBody* body = reinterpret_cast<mjCBody*>(bodyspec->element);
mjCCamera* camera = body->AddCamera(def);
return &camera->spec;
@@ -106,8 +106,8 @@ mjmCamera* mjm_addCamera(mjmBody* bodyspec, void* defspec) {
// add light to body
mjmLight* mjm_addLight(mjmBody* bodyspec, void* defspec) {
mjCDef* def = static_cast<mjCDef*>(defspec);
mjmLight* mjm_addLight(mjmBody* bodyspec, mjmDefault* defspec) {
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCBody* body = reinterpret_cast<mjCBody*>(bodyspec->element);
mjCLight* light = body->AddLight(def);
return &light->spec;
@@ -138,8 +138,8 @@ mjmFrame* mjm_addFrame(mjmBody* bodyspec, mjmFrame* parentframe) {
// add mesh to model
mjmMesh* mjm_addMesh(void* model, void* defspec) {
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec) : 0;
mjmMesh* mjm_addMesh(void* model, mjmDefault* defspec) {
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCModel* modelC = static_cast<mjCModel*>(model);
mjCMesh* mesh = modelC->AddMesh(def);
return &mesh->spec;
@@ -175,9 +175,9 @@ mjmTexture* mjm_addTexture(void* model) {
// add material to model
mjmMaterial* mjm_addMaterial(void* model, void* defspec) {
mjmMaterial* mjm_addMaterial(void* model, mjmDefault* defspec) {
mjCModel* modelC = static_cast<mjCModel*>(model);
mjCDef* def = static_cast<mjCDef*>(defspec);
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCMaterial* material = modelC->AddMaterial(def);
return &material->spec;
}
@@ -185,9 +185,9 @@ mjmMaterial* mjm_addMaterial(void* model, void* defspec) {
// add pair to model
mjmPair* mjm_addPair(void* model, void* defspec) {
mjmPair* mjm_addPair(void* model, mjmDefault* defspec) {
mjCModel* modelC = static_cast<mjCModel*>(model);
mjCDef* def = static_cast<mjCDef*>(defspec);
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCPair* pair = modelC->AddPair(def);
return &pair->spec;
}
@@ -204,9 +204,9 @@ mjmExclude* mjm_addExclude(void* model) {
// add equality to model
mjmEquality* mjm_addEquality(void* model, void* defspec) {
mjmEquality* mjm_addEquality(void* model, mjmDefault* defspec) {
mjCModel* modelC = static_cast<mjCModel*>(model);
mjCDef* def = static_cast<mjCDef*>(defspec);
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCEquality* equality = modelC->AddEquality(def);
return &equality->spec;
}
@@ -214,9 +214,9 @@ mjmEquality* mjm_addEquality(void* model, void* defspec) {
// add tendon to model
mjmTendon* mjm_addTendon(void* model, void* defspec) {
mjmTendon* mjm_addTendon(void* model, mjmDefault* defspec) {
mjCModel* modelC = static_cast<mjCModel*>(model);
mjCDef* def = static_cast<mjCDef*>(defspec);
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCTendon* tendon = modelC->AddTendon(def);
return &tendon->spec;
}
@@ -260,9 +260,9 @@ mjmWrap* mjm_wrapPulley(mjmTendon* tendonspec, double divisor) {
// add actuator to model
mjmActuator* mjm_addActuator(void* model, void* defspec) {
mjmActuator* mjm_addActuator(void* model, mjmDefault* defspec) {
mjCModel* modelC = static_cast<mjCModel*>(model);
mjCDef* def = static_cast<mjCDef*>(defspec);
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec->element) : 0;
mjCActuator* actuator = modelC->AddActuator(def);
return &actuator->spec;
}
@@ -314,7 +314,7 @@ mjmKey* mjm_addKey(void* model) {
// Add plugin to model.
// add plugin to model
mjElement mjm_addPlugin(void* model) {
mjCModel* modelC = static_cast<mjCModel*>(model);
mjCPlugin* plugin = modelC->AddPlugin();
@@ -323,6 +323,19 @@ mjElement mjm_addPlugin(void* model) {
// add default to model
mjmDefault* mjm_addDefault(void* model, const char* classname, int parentid) {
mjCModel* modelC = static_cast<mjCModel*>(model);
mjCDef* def = modelC->AddDef(classname, parentid);
if (def) {
return &def->spec;
} else {
return nullptr;
}
}
// get objects
void* mjm_getModel(mjmBody* bodyspec) {
return reinterpret_cast<mjCBody*>(bodyspec->element)->model;
@@ -331,8 +344,8 @@ void* mjm_getModel(mjmBody* bodyspec) {
// get default
void* mjm_getDefault(mjElement element) {
return reinterpret_cast<mjCBase*>(element)->def;
mjmDefault* mjm_getDefault(mjElement element) {
return &(reinterpret_cast<mjCBase*>(element)->def->spec);
}
@@ -381,9 +394,10 @@ int mjm_getId(mjElement element) {
// set default
void mjm_setDefault(mjElement element, void* defspec) {
void mjm_setDefault(mjElement element, mjmDefault* defspec) {
mjCBase* baseC = reinterpret_cast<mjCBase*>(element);
baseC->def = static_cast<mjCDef*>(defspec);
baseC->def = reinterpret_cast<mjCDef*>(defspec->element);
baseC->def->PointToLocal();
}
+35 -14
View File
@@ -641,6 +641,24 @@ typedef struct _mjmKey { // keyframe specification
} mjmKey;
typedef struct _mjmDefault { // default specification
mjString name; // name
mjElement element; // internal, do not modify
mjmJoint* joint; // joint defaults
mjmGeom* geom; // geom defaults
mjmSite* site; // site defaults
mjmCamera* camera; // camera defaults
mjmLight* light; // light defaults
mjmFlex* flex; // flex defaults
mjmMesh* mesh; // mesh defaults
mjmMaterial* material; // material defaults
mjmPair* pair; // pair defaults
mjmEquality* equality; // equality defaults
mjmTendon* tendon; // tendon defaults
mjmActuator* actuator; // actuator defaults
} mjmDefault;
//---------------------------------- API functions -------------------------------------------------
// Create model.
@@ -653,25 +671,25 @@ MJAPI void mjm_deleteModel(void* modelspec);
MJAPI void mjm_finalize(mjElement object);
// Add child body to body, return child spec.
MJAPI mjmBody* mjm_addBody(mjmBody* body, void* defspec);
MJAPI mjmBody* mjm_addBody(mjmBody* body, mjmDefault* def);
// Add site to body, return site spec.
MJAPI mjmSite* mjm_addSite(mjmBody* body, void* defspec);
MJAPI mjmSite* mjm_addSite(mjmBody* body, mjmDefault* def);
// Add joint to body.
MJAPI mjmJoint* mjm_addJoint(mjmBody* body, void* defspec);
MJAPI mjmJoint* mjm_addJoint(mjmBody* body, mjmDefault* def);
// Add freejoint to body.
MJAPI mjmJoint* mjm_addFreeJoint(mjmBody* body);
// Add geom to body.
MJAPI mjmGeom* mjm_addGeom(mjmBody* body, void* defspec);
MJAPI mjmGeom* mjm_addGeom(mjmBody* body, mjmDefault* def);
// Add camera to body.
MJAPI mjmCamera* mjm_addCamera(mjmBody* body, void* defspec);
MJAPI mjmCamera* mjm_addCamera(mjmBody* body, mjmDefault* def);
// Add light to body.
MJAPI mjmLight* mjm_addLight(mjmBody* body, void* defspec);
MJAPI mjmLight* mjm_addLight(mjmBody* body, mjmDefault* def);
// Add frame to body.
MJAPI mjmFrame* mjm_addFrame(mjmBody* body, mjmFrame* parentframe);
@@ -680,7 +698,7 @@ MJAPI mjmFrame* mjm_addFrame(mjmBody* body, mjmFrame* parentframe);
MJAPI mjmFlex* mjm_addFlex(void* model);
// Add mesh to model.
MJAPI mjmMesh* mjm_addMesh(void* model, void* defspec);
MJAPI mjmMesh* mjm_addMesh(void* model, mjmDefault* def);
// Add height field to model.
MJAPI mjmHField* mjm_addHField(void* model);
@@ -692,19 +710,19 @@ MJAPI mjmSkin* mjm_addSkin(void* model);
MJAPI mjmTexture* mjm_addTexture(void* model);
// Add material to model.
MJAPI mjmMaterial* mjm_addMaterial(void* model, void* defspec);
MJAPI mjmMaterial* mjm_addMaterial(void* model, mjmDefault* def);
// Add pair to model.
MJAPI mjmPair* mjm_addPair(void* model, void* defspec);
MJAPI mjmPair* mjm_addPair(void* model, mjmDefault* def);
// Add excluded body pair to model.
MJAPI mjmExclude* mjm_addExclude(void *model);
// Add equality to model.
MJAPI mjmEquality* mjm_addEquality(void* model, void* defspec);
MJAPI mjmEquality* mjm_addEquality(void* model, mjmDefault* def);
// Add tendon to model.
MJAPI mjmTendon* mjm_addTendon(void* model, void* defspec);
MJAPI mjmTendon* mjm_addTendon(void* model, mjmDefault* def);
// Wrap site using tendon.
MJAPI mjmWrap* mjm_wrapSite(mjmTendon* tendon, const char* name);
@@ -719,7 +737,7 @@ MJAPI mjmWrap* mjm_wrapJoint(mjmTendon* tendon, const char* name, double coef);
MJAPI mjmWrap* mjm_wrapPulley(mjmTendon* tendon, double divisor);
// Add actuator to model.
MJAPI mjmActuator* mjm_addActuator(void* model, void* defspec);
MJAPI mjmActuator* mjm_addActuator(void* model, mjmDefault* def);
// Add sensor to model.
MJAPI mjmSensor* mjm_addSensor(void* model);
@@ -739,11 +757,14 @@ MJAPI mjmKey* mjm_addKey(void* model);
// Add plugin to model.
MJAPI mjElement mjm_addPlugin(void* model);
// Add default to model.
MJAPI mjmDefault* mjm_addDefault(void* model, const char* classname, int parentid);
// Get model from body.
MJAPI void* mjm_getModel(mjmBody* body);
// Get default corresponding to an mjElement.
MJAPI void* mjm_getDefault(mjElement element);
MJAPI mjmDefault* mjm_getDefault(mjElement element);
// Find body in model by name.
MJAPI mjmBody* mjm_findBody(void* modelspec, const char* name);
@@ -788,7 +809,7 @@ MJAPI const char* mjm_getString(mjString source);
MJAPI const double* mjm_getDouble(mjDoubleVec source, int* size);
// Set default.
MJAPI void mjm_setDefault(mjElement element, void* defspec);
MJAPI void mjm_setDefault(mjElement element, mjmDefault* def);
// Set frame.
MJAPI void mjm_setFrame(mjElement dest, mjmFrame* frame);
+77 -70
View File
@@ -116,9 +116,16 @@ bool mjCComposite::AddDefaultJoint(char* error, int error_sz) {
return false;
} else {
mjCDef jnt;
jnt.joint.spec.group = 3;
jnt.spec.joint->group = 3;
defjoint[(mjtCompKind)i].push_back(jnt);
}
// TODO: push_back might invoke a copy constructor, we undo its effect on pointers here
for (int i=0; i<mjNCOMPKINDS; i++) {
for (int j=0; j<defjoint[(mjtCompKind)i].size(); j++) {
defjoint[(mjtCompKind)i][j].PointToLocal();
}
}
}
return true;
}
@@ -137,9 +144,9 @@ void mjCComposite::SetDefault(void) {
// set all deafult groups to 3
for (int i=0; i<mjNCOMPKINDS; i++) {
def[i].geom.spec.group = 3;
def[i].site.spec.group = 3;
def[i].tendon.spec.group = 3;
def[i].spec.geom->group = 3;
def[i].spec.site->group = 3;
def[i].spec.tendon->group = 3;
}
// set default joint
@@ -153,8 +160,8 @@ void mjCComposite::SetDefault(void) {
type==mjCOMPTYPE_CABLE ||
(type==mjCOMPTYPE_GRID && tmpdim==1)) {
for (int i=0; i<mjNCOMPKINDS; i++) {
def[i].geom.spec.group = 0;
def[i].tendon.spec.group = 0;
def[i].spec.geom->group = 0;
def[i].spec.tendon->group = 0;
}
}
@@ -163,15 +170,15 @@ void mjCComposite::SetDefault(void) {
case mjCOMPTYPE_PARTICLE: // particle
// no friction with anything
def[0].geom.spec.condim = 1;
def[0].geom.spec.priority = 1;
def[0].spec.geom->condim = 1;
def[0].spec.geom->priority = 1;
break;
case mjCOMPTYPE_GRID: // grid
// hard main tendon fix
AdjustSoft(def[mjCOMPKIND_TENDON].equality.spec.solref,
def[mjCOMPKIND_TENDON].equality.spec.solimp, 0);
AdjustSoft(def[mjCOMPKIND_TENDON].spec.equality->solref,
def[mjCOMPKIND_TENDON].spec.equality->solimp, 0);
break;
@@ -193,19 +200,19 @@ void mjCComposite::SetDefault(void) {
case mjCOMPTYPE_ELLIPSOID:
// no self-collisions
def[0].geom.spec.contype = 0;
def[0].spec.geom->contype = 0;
// soft smoothing
AdjustSoft(solrefsmooth, solimpsmooth, 1);
// soft fix everywhere
for (int i=0; i<mjNCOMPKINDS; i++) {
AdjustSoft(def[i].equality.spec.solref, def[i].equality.spec.solimp, 1);
AdjustSoft(def[i].spec.equality->solref, def[i].spec.equality->solimp, 1);
}
// hard main tendon fix
AdjustSoft(def[mjCOMPKIND_TENDON].equality.spec.solref,
def[mjCOMPKIND_TENDON].equality.spec.solimp, 0);
AdjustSoft(def[mjCOMPKIND_TENDON].spec.equality->solref,
def[mjCOMPKIND_TENDON].spec.equality->solimp, 0);
break;
default:
// SHOULD NOT OCCUR
@@ -219,9 +226,9 @@ void mjCComposite::SetDefault(void) {
// make composite object
bool mjCComposite::Make(mjCModel* model, mjmBody* body, char* error, int error_sz) {
// check geom type
if ((def[0].geom.spec.type!=mjGEOM_SPHERE &&
def[0].geom.spec.type!=mjGEOM_CAPSULE &&
def[0].geom.spec.type!=mjGEOM_ELLIPSOID) &&
if ((def[0].spec.geom->type!=mjGEOM_SPHERE &&
def[0].spec.geom->type!=mjGEOM_CAPSULE &&
def[0].spec.geom->type!=mjGEOM_ELLIPSOID) &&
type!=mjCOMPTYPE_PARTICLE && type!=mjCOMPTYPE_CABLE) {
return comperr(error, "Composite geom type must be sphere, capsule or ellipsoid", error_sz);
}
@@ -240,8 +247,8 @@ bool mjCComposite::Make(mjCModel* model, mjmBody* body, char* error, int error_s
// check spacing
if (type==mjCOMPTYPE_GRID || (type==mjCOMPTYPE_PARTICLE && uservert.empty())) {
if (spacing < mju_max(def[0].geom.spec.size[0],
mju_max(def[0].geom.spec.size[1], def[0].geom.spec.size[2]))) {
if (spacing < mju_max(def[0].spec.geom->size[0],
mju_max(def[0].spec.geom->size[1], def[0].spec.geom->size[2]))) {
return comperr(error, "Spacing must be larger than geometry size",
error_sz);
}
@@ -342,8 +349,8 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjmBody* body, char* error, int
// populate vertices and names
if (uservert.empty()) {
if (spacing < mju_max(def[0].geom.spec.size[0],
mju_max(def[0].geom.spec.size[1], def[0].geom.spec.size[2])))
if (spacing < mju_max(def[0].spec.geom->size[0],
mju_max(def[0].spec.geom->size[1], def[0].spec.geom->size[2])))
return comperr(error, "Spacing must be larger than geometry size", error_sz);
for (int ix=0; ix<count[0]; ix++) {
@@ -466,7 +473,7 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjmBody* body, char* error, int
// add slider joints if none defined
if (!add[mjCOMPKIND_PARTICLE]) {
for (int i=0; i<3; i++) {
mjmJoint* jnt = mjm_addJoint(b, &defjoint[mjCOMPKIND_JOINT][0]);
mjmJoint* jnt = mjm_addJoint(b, &defjoint[mjCOMPKIND_JOINT][0].spec);
mjm_setDefault(jnt->element, mjm_getDefault(body->element));
jnt->type = mjJNT_SLIDE;
mjuu_setvec(jnt->pos, 0, 0, 0);
@@ -478,17 +485,17 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjmBody* body, char* error, int
// add user-specified joints
else {
for (auto defjnt : defjoint[mjCOMPKIND_PARTICLE]) {
mjmJoint* jnt = mjm_addJoint(b, &defjnt);
mjmJoint* jnt = mjm_addJoint(b, &defjnt.spec);
mjm_setDefault(jnt->element, mjm_getDefault(body->element));
}
}
// add geom
mjmGeom* g = mjm_addGeom(b, def);
mjmGeom* g = mjm_addGeom(b, &def[0].spec);
mjm_setDefault(g->element, mjm_getDefault(body->element));
// add site
mjmSite* s = mjm_addSite(b, def);
mjmSite* s = mjm_addSite(b, &def[0].spec);
mjm_setDefault(s->element, mjm_getDefault(body->element));
s->type = mjGEOM_SPHERE;
mju::sprintf_arr(txt, "%sS%d", prefix.c_str(), i);
@@ -544,16 +551,16 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjmBody* body, char* error, int
mju::sprintf_arr(txt2, "%sS%d", prefix.c_str(), v1);
// create tendon
mjmTendon* ten = mjm_addTendon(model, def + mjCOMPKIND_TENDON);
mjm_setDefault(ten->element, model->defaults[0]);
mjmTendon* ten = mjm_addTendon(model, &def[mjCOMPKIND_TENDON].spec);
mjm_setDefault(ten->element, &model->defaults[0]->spec);
mjm_setString(ten->name, txt0);
ten->group = 4;
mjm_wrapSite(ten, txt1);
mjm_wrapSite(ten, txt2);
// add equality constraint
mjmEquality* eq = mjm_addEquality(model, def + mjCOMPKIND_TENDON);
mjm_setDefault(eq->element, model->defaults[0]);
mjmEquality* eq = mjm_addEquality(model, &def[mjCOMPKIND_TENDON].spec);
mjm_setDefault(eq->element, &model->defaults[0]->spec);
eq->type = mjEQ_TENDON;
mjm_setString(eq->name1, mjm_getString(ten->name));
}
@@ -609,14 +616,14 @@ bool mjCComposite::MakeGrid(mjCModel* model, mjmBody* body, char* error, int err
b->pos[2] = offset[2];
// add geom
mjmGeom* g = mjm_addGeom(b, def);
mjmGeom* g = mjm_addGeom(b, &def[0].spec);
mjm_setDefault(g->element, mjm_getDefault(body->element));
g->type = mjGEOM_SPHERE;
mju::sprintf_arr(txt, "%sG%d_%d", prefix.c_str(), ix, iy);
mjm_setString(g->name, txt);
// add site
mjmSite* s = mjm_addSite(b, def);
mjmSite* s = mjm_addSite(b, &def[0].spec);
mjm_setDefault(s->element, mjm_getDefault(body->element));
s->type = mjGEOM_SPHERE;
mju::sprintf_arr(txt, "%sS%d_%d", prefix.c_str(), ix, iy);
@@ -637,7 +644,7 @@ bool mjCComposite::MakeGrid(mjCModel* model, mjmBody* body, char* error, int err
// add slider joint
mjmJoint* jnt[3];
for (int i=0; i<3; i++) {
jnt[i] = mjm_addJoint(b, &defjoint[mjCOMPKIND_JOINT][0]);
jnt[i] = mjm_addJoint(b, &defjoint[mjCOMPKIND_JOINT][0].spec);
mjm_setDefault(jnt[i]->element, mjm_getDefault(body->element));
mju::sprintf_arr(txt, "%sJ%d_%d_%d", prefix.c_str(), i, ix, iy);
mjm_setString(jnt[i]->name, txt);
@@ -666,8 +673,8 @@ bool mjCComposite::MakeGrid(mjCModel* model, mjmBody* body, char* error, int err
ten->WrapSite(txt2);
// add equality constraint
mjmEquality* eq = mjm_addEquality(model, def + mjCOMPKIND_TENDON);
mjm_setDefault(eq->element, model->defaults[0]);
mjmEquality* eq = mjm_addEquality(model, &def[mjCOMPKIND_TENDON].spec);
mjm_setDefault(eq->element, &model->defaults[0]->spec);
eq->type = mjEQ_TENDON;
mjm_setString(eq->name1, ten->name.c_str());
}
@@ -700,9 +707,9 @@ bool mjCComposite::MakeCable(mjCModel* model, mjmBody* body, char* error, int er
}
// check geom type
if (def[0].geom.spec.type!=mjGEOM_CYLINDER &&
def[0].geom.spec.type!=mjGEOM_CAPSULE &&
def[0].geom.spec.type!=mjGEOM_BOX) {
if (def[0].spec.geom->type!=mjGEOM_CYLINDER &&
def[0].spec.geom->type!=mjGEOM_CAPSULE &&
def[0].spec.geom->type!=mjGEOM_BOX) {
return comperr(error, "Cable geom type must be sphere, capsule or box", error_sz);
}
@@ -748,14 +755,14 @@ bool mjCComposite::MakeCable(mjCModel* model, mjmBody* body, char* error, int er
}
// add skin
if (def[0].geom.spec.type==mjGEOM_BOX) {
if (def[0].spec.geom->type==mjGEOM_BOX) {
if (skinsubgrid>0) {
count[1]+=2;
MakeSkin2Subgrid(model, 2*def[0].geom.spec.size[2]);
MakeSkin2Subgrid(model, 2*def[0].spec.geom->size[2]);
count[1]-=2;
} else {
count[1]++;
MakeSkin2(model, 2*def[0].geom.spec.size[2]);
MakeSkin2(model, 2*def[0].spec.geom->size[2]);
count[1]--;
}
}
@@ -835,14 +842,14 @@ mjmBody* mjCComposite::AddCableBody(mjCModel* model, mjmBody* body, int ix, mjtN
}
// add geom
mjmGeom* geom = mjm_addGeom(body, def);
mjmGeom* geom = mjm_addGeom(body, &def[0].spec);
mjm_setDefault(geom->element, mjm_getDefault(body->element));
mjm_setString(geom->name, txt_geom);
if (def[0].geom.spec.type==mjGEOM_CYLINDER ||
def[0].geom.spec.type==mjGEOM_CAPSULE) {
if (def[0].spec.geom->type==mjGEOM_CYLINDER ||
def[0].spec.geom->type==mjGEOM_CAPSULE) {
mjuu_zerovec(geom->fromto, 6);
geom->fromto[3] = length;
} else if (def[0].geom.spec.type==mjGEOM_BOX) {
} else if (def[0].spec.geom->type==mjGEOM_BOX) {
mjuu_zerovec(geom->pos, 3);
geom->pos[0] = length/2;
geom->size[0] = length/2;
@@ -862,7 +869,7 @@ mjmBody* mjCComposite::AddCableBody(mjCModel* model, mjmBody* body, int ix, mjtN
// add curvature joint
if (!first || strcmp(initial.c_str(), "none")) {
mjmJoint* jnt = mjm_addJoint(body, &defjoint[mjCOMPKIND_JOINT][0]);
mjmJoint* jnt = mjm_addJoint(body, &defjoint[mjCOMPKIND_JOINT][0].spec);
mjm_setDefault(jnt->element, mjm_getDefault(body->element));
jnt->type = (first && strcmp(initial.c_str(), "free")==0) ? mjJNT_FREE : mjJNT_BALL;
jnt->damping = jnt->type==mjJNT_FREE ? 0 : jnt->damping;
@@ -880,7 +887,7 @@ mjmBody* mjCComposite::AddCableBody(mjCModel* model, mjmBody* body, int ix, mjtN
// add site at the boundary
if (last || first) {
mjmSite* site = mjm_addSite(body, def);
mjmSite* site = mjm_addSite(body, &def[0].spec);
mjm_setDefault(site->element, mjm_getDefault(body->element));
mjm_setString(site->name, txt_site);
mjuu_setvec(site->pos, last ? length : 0, 0, 0);
@@ -991,7 +998,7 @@ mjmBody* mjCComposite::AddRopeBody(mjCModel* model, mjmBody* body, int ix, int i
}
// add geom
mjmGeom* geom = mjm_addGeom(body, def);
mjmGeom* geom = mjm_addGeom(body, &def[0].spec);
mjm_setDefault(geom->element, mjm_getDefault(body->element));
mju::sprintf_arr(txt, "%sG%d", prefix.c_str(), ix1);
mjm_setString(geom->name, txt);
@@ -1006,7 +1013,7 @@ mjmBody* mjCComposite::AddRopeBody(mjCModel* model, mjmBody* body, int ix, int i
// add main joint
for (int i=0; i<2; i++) {
// add joint
mjmJoint* jnt = mjm_addJoint(body, &defjoint[mjCOMPKIND_JOINT][0]);
mjmJoint* jnt = mjm_addJoint(body, &defjoint[mjCOMPKIND_JOINT][0].spec);
mjm_setDefault(jnt->element, mjm_getDefault(body->element));
mju::sprintf_arr(txt, "%sJ%d_%d", prefix.c_str(), i, ix1);
mjm_setString(jnt->name, txt);
@@ -1019,7 +1026,7 @@ mjmBody* mjCComposite::AddRopeBody(mjCModel* model, mjmBody* body, int ix, int i
// add twist joint
if (add[mjCOMPKIND_TWIST]) {
// add joint
mjmJoint* jnt = mjm_addJoint(body, &defjoint[mjCOMPKIND_TWIST][0]);
mjmJoint* jnt = mjm_addJoint(body, &defjoint[mjCOMPKIND_TWIST][0].spec);
mjm_setDefault(jnt->element, mjm_getDefault(body->element));
mju::sprintf_arr(txt, "%sJT%d", prefix.c_str(), ix1);
mjm_setString(jnt->name, txt);
@@ -1028,8 +1035,8 @@ mjmBody* mjCComposite::AddRopeBody(mjCModel* model, mjmBody* body, int ix, int i
mjuu_setvec(jnt->axis, 1, 0, 0);
// add constraint
mjmEquality* eq = mjm_addEquality(model, def + mjCOMPKIND_TWIST);
mjm_setDefault(eq->element, model->defaults[0]);
mjmEquality* eq = mjm_addEquality(model, &def[mjCOMPKIND_TWIST].spec);
mjm_setDefault(eq->element, &model->defaults[0]->spec);
eq->type = mjEQ_JOINT;
mjm_setString(eq->name1, mjm_getString(jnt->name));
}
@@ -1037,7 +1044,7 @@ mjmBody* mjCComposite::AddRopeBody(mjCModel* model, mjmBody* body, int ix, int i
// add stretch joint
if (add[mjCOMPKIND_STRETCH]) {
// add joint
mjmJoint* jnt = mjm_addJoint(body, &defjoint[mjCOMPKIND_STRETCH][0]);
mjmJoint* jnt = mjm_addJoint(body, &defjoint[mjCOMPKIND_STRETCH][0].spec);
mjm_setDefault(jnt->element, mjm_getDefault(body->element));
mju::sprintf_arr(txt, "%sJS%d", prefix.c_str(), ix1);
mjm_setString(jnt->name, txt);
@@ -1046,8 +1053,8 @@ mjmBody* mjCComposite::AddRopeBody(mjCModel* model, mjmBody* body, int ix, int i
mjuu_setvec(jnt->axis, 1, 0, 0);
// add constraint
mjmEquality* eq = mjm_addEquality(model, def + mjCOMPKIND_STRETCH);
mjm_setDefault(eq->element, model->defaults[0]);
mjmEquality* eq = mjm_addEquality(model, &def[mjCOMPKIND_STRETCH].spec);
mjm_setDefault(eq->element, &model->defaults[0]->spec);
eq->type = mjEQ_JOINT;
mjm_setString(eq->name1, mjm_getString(jnt->name));
}
@@ -1103,7 +1110,7 @@ bool mjCComposite::MakeBox(mjCModel* model, mjmBody* body, char* error, int erro
}
// center geom: two times bigger
mjmGeom* geom = mjm_addGeom(body, def);
mjmGeom* geom = mjm_addGeom(body, &def[0].spec);
mjm_setDefault(geom->element, mjm_getDefault(body->element));
geom->type = mjGEOM_SPHERE;
mju::sprintf_arr(txt, "%sGcenter", prefix.c_str());
@@ -1144,7 +1151,7 @@ bool mjCComposite::MakeBox(mjCModel* model, mjmBody* body, char* error, int erro
mjuu_normvec(b->alt.zaxis, 3);
// add geom
mjmGeom* g = mjm_addGeom(b, def);
mjmGeom* g = mjm_addGeom(b, &def[0].spec);
mjm_setDefault(g->element, mjm_getDefault(body->element));
mju::sprintf_arr(txt, "%sG%d_%d_%d", prefix.c_str(), ix, iy, iz);
mjm_setString(g->name, txt);
@@ -1158,7 +1165,7 @@ bool mjCComposite::MakeBox(mjCModel* model, mjmBody* body, char* error, int erro
}
// add slider joint
mjmJoint* jnt = mjm_addJoint(b, &defjoint[mjCOMPKIND_JOINT][0]);
mjmJoint* jnt = mjm_addJoint(b, &defjoint[mjCOMPKIND_JOINT][0].spec);
mjm_setDefault(jnt->element, mjm_getDefault(body->element));
mju::sprintf_arr(txt, "%sJ%d_%d_%d", prefix.c_str(), ix, iy, iz);
mjm_setString(jnt->name, txt);
@@ -1167,8 +1174,8 @@ bool mjCComposite::MakeBox(mjCModel* model, mjmBody* body, char* error, int erro
mjuu_setvec(jnt->axis, 0, 0, 1);
// add fix constraint
mjmEquality* eq = mjm_addEquality(model, def + mjCOMPKIND_JOINT);
mjm_setDefault(eq->element, model->defaults[0]);
mjmEquality* eq = mjm_addEquality(model, &def[mjCOMPKIND_JOINT].spec);
mjm_setDefault(eq->element, &model->defaults[0]->spec);
eq->type = mjEQ_JOINT;
mjm_setString(eq->name1, mjm_getString(jnt->name));
@@ -1201,8 +1208,8 @@ bool mjCComposite::MakeBox(mjCModel* model, mjmBody* body, char* error, int erro
}
// finalize fixed tendon
mjmEquality* eqt = mjm_addEquality(model, def + mjCOMPKIND_TENDON);
mjm_setDefault(eqt->element, model->defaults[0]);
mjmEquality* eqt = mjm_addEquality(model, &def[mjCOMPKIND_TENDON].spec);
mjm_setDefault(eqt->element, &model->defaults[0]->spec);
eqt->type = mjEQ_TENDON;
mjm_setString(eqt->name1, ten->name.c_str());
@@ -1237,8 +1244,8 @@ void mjCComposite::MakeShear(mjCModel* model) {
ten->name = txt;
// equality constraint
mjmEquality* eq = mjm_addEquality(model, def + mjCOMPKIND_SHEAR);
mjm_setDefault(eq->element, model->defaults[0]);
mjmEquality* eq = mjm_addEquality(model, &def[mjCOMPKIND_SHEAR].spec);
mjm_setDefault(eq->element, &model->defaults[0]->spec);
eq->type = mjEQ_TENDON;
mjm_setString(eq->name1, txt);
}
@@ -1495,15 +1502,15 @@ void mjCComposite::MakeCableBones(mjCModel* model, mjmSkin* skin) {
// bind pose
if (iy==0) {
mjm_appendString(skin->bodyname, this_body);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
bindpos.push_back(-def[0].geom.spec.size[1]);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].spec.geom->size[0] : 0);
bindpos.push_back(-def[0].spec.geom->size[1]);
bindpos.push_back(0);
bindquat.push_back(1); bindquat.push_back(0);
bindquat.push_back(0); bindquat.push_back(0);
} else {
mjm_appendString(skin->bodyname, this_body);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
bindpos.push_back(def[0].geom.spec.size[1]);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].spec.geom->size[0] : 0);
bindpos.push_back(def[0].spec.geom->size[1]);
bindpos.push_back(0);
bindquat.push_back(1); bindquat.push_back(0);
bindquat.push_back(0); bindquat.push_back(0);
@@ -1535,15 +1542,15 @@ void mjCComposite::MakeCableBonesSubgrid(mjCModel* model, mjmSkin* skin) {
// bind pose
if (iy==0) {
bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].spec.geom->size[0] : 0);
bindpos.push_back(-def[0].geom.spec.size[1]);
bindpos.push_back(0);
} else if (iy==2) {
bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].spec.geom->size[0] : 0);
bindpos.push_back(def[0].geom.spec.size[1]);
bindpos.push_back(0);
} else {
bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].spec.geom->size[0] : 0);
bindpos.push_back(0);
bindpos.push_back(0);
}
+12 -13
View File
@@ -78,8 +78,7 @@ mjCFlexcomp::mjCFlexcomp(void) {
// make flexcomp object
bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz) {
def.flex.CopyFromSpec();
mjmFlex* dflex = def.spec.flex;
bool radial = (type==mjFCOMPTYPE_BOX ||
type==mjFCOMPTYPE_CYLINDER ||
type==mjFCOMPTYPE_ELLIPSOID);
@@ -100,7 +99,7 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz
}
// check spacing
double minspace = 2*def.flex.spec.radius + def.flex.spec.margin;
double minspace = 2*dflex->radius + dflex->margin;
if (!direct) {
if (spacing[0]<minspace ||
spacing[1]<minspace ||
@@ -158,7 +157,7 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz
}
// get dim and check
int dim = def.flex.spec.dim;
int dim = dflex->dim;
if (dim<1 || dim>3) {
return comperr(error, "Invalid dim, must be between 1 and 3", error_sz);
}
@@ -166,7 +165,7 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz
// force flatskin shading for box, cylinder and 3D grid
if (type==mjFCOMPTYPE_BOX || type==mjFCOMPTYPE_CYLINDER ||
(type==mjFCOMPTYPE_GRID && dim==3)) {
def.flex.spec.flatskin = true;
dflex->flatskin = true;
}
// check pin sizes
@@ -485,8 +484,8 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz
// create edge equality constraint
if (equality) {
mjmEquality* pe = mjm_addEquality(model, &def);
mjm_setDefault(pe->element, model->defaults[0]);
mjmEquality* pe = mjm_addEquality(model, &def.spec);
mjm_setDefault(pe->element, &model->defaults[0]->spec);
pe->type = mjEQ_FLEX;
pe->active = true;
mjm_setString(pe->name1, name.c_str());
@@ -690,7 +689,7 @@ bool mjCFlexcomp::MakeBox(char* error, int error_sz) {
double pos[3];
// set 3D
def.flex.spec.dim = 3;
def.spec.flex->dim = 3;
// add center point
point.push_back(0);
@@ -822,7 +821,7 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) {
}
// check dim
if (def.flex.spec.dim!=2) {
if (def.spec.flex->dim!=2) {
return comperr(error, "Flex dim must be 2 in for mesh", error_sz);
}
@@ -1034,7 +1033,7 @@ void mjCFlexcomp::LoadGMSH(mjCModel* model, mjResource* resource) {
if (entityDim<1 || entityDim>3) {
throw mjCError(NULL, "Entity must be 1D, 2D or 3D");
}
def.flex.spec.dim = entityDim;
def.spec.flex->dim = entityDim;
// read and discard node tags; require range from minNodeTag to maxNodeTag
for (size_t i=0; i<numNodes; i++) {
@@ -1086,7 +1085,7 @@ void mjCFlexcomp::LoadGMSH(mjCModel* model, mjResource* resource) {
if (entityDim<1 || entityDim>3) {
throw mjCError(NULL, "Entity must be 1D, 2D or 3D");
}
def.flex.spec.dim = entityDim;
def.spec.flex->dim = entityDim;
// check section byte size
if (nodeend-nodebegin < 52+numNodes*4*8) {
@@ -1134,7 +1133,7 @@ void mjCFlexcomp::LoadGMSH(mjCModel* model, mjResource* resource) {
}
// dimensionality must be same as nodes
if (entityDim!=def.flex.spec.dim) {
if (entityDim!=def.spec.flex->dim) {
throw mjCError(NULL, "Inconsistent dimensionality in Elements");
}
@@ -1183,7 +1182,7 @@ void mjCFlexcomp::LoadGMSH(mjCModel* model, mjResource* resource) {
}
// dimensionality must be same as nodes
if (entityDim!=def.flex.spec.dim) {
if (entityDim!=def.spec.flex->dim) {
throw mjCError(NULL, "Inconsistent dimensionality in Elements");
}
+44 -13
View File
@@ -471,6 +471,19 @@ mjCDef::mjCDef(void) {
name.clear();
parentid = -1;
childid.clear();
mjm_defaultJoint(joint.spec);
mjm_defaultGeom(geom.spec);
mjm_defaultSite(site.spec);
mjm_defaultCamera(camera.spec);
mjm_defaultLight(light.spec);
mjm_defaultFlex(flex.spec);
mjm_defaultMesh(mesh.spec);
mjm_defaultMaterial(material.spec);
mjm_defaultPair(pair.spec);
mjm_defaultEquality(equality.spec);
mjm_defaultTendon(tendon.spec);
mjm_defaultActuator(actuator.spec);
PointToLocal();
}
@@ -494,6 +507,28 @@ void mjCDef::PointToLocal() {
geom.PointToLocal();
site.PointToLocal();
camera.PointToLocal();
light.PointToLocal();
flex.PointToLocal();
mesh.PointToLocal();
material.PointToLocal();
pair.PointToLocal();
equality.PointToLocal();
tendon.PointToLocal();
actuator.PointToLocal();
spec.element = (mjElement)this;
spec.name = (mjString)&name;
spec.joint = &joint.spec;
spec.geom = &geom.spec;
spec.site = &site.spec;
spec.camera = &camera.spec;
spec.light = &light.spec;
spec.flex = &flex.spec;
spec.mesh = &mesh.spec;
spec.material = &material.spec;
spec.pair = &pair.spec;
spec.equality = &equality.spec;
spec.tendon = &tendon.spec;
spec.actuator = &actuator.spec;
}
@@ -1248,7 +1283,6 @@ mjCJoint::mjCJoint(mjCModel* _model, mjCDef* _def) {
// reset to default if given
if (_def) {
_def->joint.CopyFromSpec();
*this = _def->joint;
}
@@ -1442,7 +1476,6 @@ mjCGeom::mjCGeom(mjCModel* _model, mjCDef* _def) {
// reset to default if given
if (_def) {
_def->geom.CopyFromSpec();
*this = _def->geom;
}
@@ -2043,7 +2076,6 @@ mjCSite::mjCSite(mjCModel* _model, mjCDef* _def) {
// reset to default if given
if (_def) {
_def->site.CopyFromSpec();
*this = _def->site;
}
@@ -2185,7 +2217,6 @@ mjCCamera::mjCCamera(mjCModel* _model, mjCDef* _def) {
// reset to default if given
if (_def) {
_def->camera.CopyFromSpec();
*this = _def->camera;
}
@@ -2322,7 +2353,6 @@ mjCLight::mjCLight(mjCModel* _model, mjCDef* _def) {
// reset to default if given
if (_def) {
_def->light.CopyFromSpec();
*this = _def->light;
}
@@ -2330,14 +2360,18 @@ mjCLight::mjCLight(mjCModel* _model, mjCDef* _def) {
model = _model;
def = (_def ? _def : (_model ? _model->defaults[0] : 0));
// point to local
PointToLocal();
CopyFromSpec();
}
void mjCLight::PointToLocal() {
spec.element = (mjElement)this;
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.targetbody = (mjString)&spec_targetbody_;
spec.info = (mjString)&info;
CopyFromSpec();
}
@@ -3350,7 +3384,6 @@ mjCMaterial::mjCMaterial(mjCModel* _model, mjCDef* _def) {
// reset to default if given
if (_def) {
_def->material.CopyFromSpec();
*this = _def->material;
}
@@ -3409,7 +3442,6 @@ mjCPair::mjCPair(mjCModel* _model, mjCDef* _def) {
// reset to default if given
if (_def) {
_def->pair.CopyFromSpec();
*this = _def->pair;
}
@@ -3669,7 +3701,6 @@ mjCEquality::mjCEquality(mjCModel* _model, mjCDef* _def) {
// reset to default if given
if (_def) {
_def->equality.CopyFromSpec();
*this = _def->equality;
}
@@ -4185,7 +4216,7 @@ mjCActuator::mjCActuator(mjCModel* _model, mjCDef* _def) {
CopyFromSpec();
// point to local (needs to be after defaults)
MakePointerLocal();
PointToLocal();
}
@@ -4196,7 +4227,7 @@ bool mjCActuator::is_actlimited() const { return islimited(actlimited, actrange)
void mjCActuator::MakePointerLocal() {
void mjCActuator::PointToLocal() {
spec.element = (mjElement)this;
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
+7 -2
View File
@@ -534,6 +534,7 @@ class mjCLight : public mjCBase, private mjmLight {
mjCLight(mjCModel* = 0, mjCDef* = 0); // constructor
void Compile(void); // compiler
void CopyFromSpec(void);
void PointToLocal(void);
mjCBody* body; // light's body
int targetbodyid; // id of target body; -1: none
@@ -1203,7 +1204,7 @@ class mjCActuator : public mjCBase, private mjmActuator {
mjCActuator(mjCModel* = 0, mjCDef* = 0); // constructor
void Compile(void); // compiler
void CopyFromSpec();
void MakePointerLocal();
void PointToLocal();
int trnid[2]; // id of transmission target
@@ -1385,6 +1386,8 @@ class mjCKey : public mjCBase, private mjmKey {
// Describes one set of defaults
class mjCDef {
friend class mjXWriter;
public:
mjCDef(void); // constructor
void Compile(const mjCModel* model); // compiler
@@ -1395,7 +1398,9 @@ class mjCDef {
int parentid; // id of parent class
std::vector<int> childid; // ids of child classes
// default objects
mjmDefault spec;
// default objects (TODO: they should become private)
mjCJoint joint;
mjCGeom geom;
mjCSite site;
+127 -119
View File
@@ -1665,7 +1665,7 @@ void mjXReader::OneGeom(XMLElement* elem, mjmGeom* pgeom) {
// site element parser
void mjXReader::OneSite(XMLElement* elem, mjmSite& site) {
void mjXReader::OneSite(XMLElement* elem, mjmSite* site) {
int n;
string text, name, classname;
std::vector<double> userdata;
@@ -1673,30 +1673,30 @@ void mjXReader::OneSite(XMLElement* elem, mjmSite& site) {
// read attributes
if (ReadAttrTxt(elem, "name", name)) {
mjm_setString(site.name, name.c_str());
mjm_setString(site->name, name.c_str());
}
if (ReadAttrTxt(elem, "class", classname)) {
mjm_setString(site.classname, classname.c_str());
mjm_setString(site->classname, classname.c_str());
}
if (MapValue(elem, "type", &n, geom_map, mjNGEOMTYPES)) {
site.type = (mjtGeom)n;
site->type = (mjtGeom)n;
}
ReadAttr(elem, "size", 3, site.size, text, false, false);
ReadAttrInt(elem, "group", &site.group);
ReadAttr(elem, "pos", 3, site.pos, text);
ReadQuat(elem, "quat", site.quat, text);
ReadAttr(elem, "size", 3, site->size, text, false, false);
ReadAttrInt(elem, "group", &site->group);
ReadAttr(elem, "pos", 3, site->pos, text);
ReadQuat(elem, "quat", site->quat, text);
if (ReadAttrTxt(elem, "material", material)) {
mjm_setString(site.material, material.c_str());
mjm_setString(site->material, material.c_str());
}
ReadAttr(elem, "rgba", 4, site.rgba, text);
ReadAttr(elem, "fromto", 6, site.fromto, text);
ReadAlternative(elem, site.alt);
ReadAttr(elem, "rgba", 4, site->rgba, text);
ReadAttr(elem, "fromto", 6, site->fromto, text);
ReadAlternative(elem, site->alt);
if (ReadVector(elem, "user", userdata, text)) {
mjm_setDouble(site.userdata, userdata.data(), userdata.size());
mjm_setDouble(site->userdata, userdata.data(), userdata.size());
}
// write error info
mjm_setString(site.info,
mjm_setString(site->info,
std::string("line = " + std::to_string(elem->GetLineNum()) + ", column = -1").c_str());
}
@@ -2240,7 +2240,7 @@ void mjXReader::OneActuator(XMLElement* elem, mjmActuator* pact) {
// make composite
void mjXReader::OneComposite(XMLElement* elem, mjmBody* pbody, mjCDef* def) {
void mjXReader::OneComposite(XMLElement* elem, mjmBody* pbody, mjmDefault* def) {
string text;
int n;
@@ -2326,7 +2326,7 @@ void mjXReader::OneComposite(XMLElement* elem, mjmBody* pbody, mjCDef* def) {
XMLElement* egeom = FirstChildElement(elem, "geom");
if (egeom) {
std::string material;
mjmGeom& dgeom = comp.def[0].geom.spec;
mjmGeom& dgeom = *comp.def[0].spec.geom;
if (MapValue(egeom, "type", &n, geom_map, mjNGEOMTYPES)) {
dgeom.type = (mjtGeom)n;
}
@@ -2354,7 +2354,7 @@ void mjXReader::OneComposite(XMLElement* elem, mjmBody* pbody, mjCDef* def) {
XMLElement* esite = FirstChildElement(elem, "site");
if (esite) {
std::string material;
mjmSite& dsite = comp.def[0].site.spec;
mjmSite& dsite = *comp.def[0].spec.site;
ReadAttr(esite, "size", 3, dsite.size, text, false, false);
ReadAttrInt(esite, "group", &dsite.group);
ReadAttrTxt(esite, "material", material);
@@ -2379,33 +2379,35 @@ void mjXReader::OneComposite(XMLElement* elem, mjmBody* pbody, mjCDef* def) {
comp.add[kind] = true;
// get element
mjCDef *el = &comp.defjoint[(mjtCompKind)kind].back();
mjmDefault* dspec = &comp.defjoint[(mjtCompKind)kind].back().spec;
mjmJoint& djoint = *dspec->joint;
mjmEquality& dequality = *dspec->equality;
// particle joint
if (MapValue(ejnt, "type", &n, joint_map, joint_sz)) {
el->joint.spec.type = (mjtJoint)n;
djoint.type = (mjtJoint)n;
}
ReadAttr(ejnt, "axis", 3, el->joint.spec.axis, text);
ReadAttr(ejnt, "axis", 3, djoint.axis, text);
// solreffix, solimpfix
ReadAttr(ejnt, "solreffix", mjNREF, el->equality.spec.solref, text, false, false);
ReadAttr(ejnt, "solimpfix", mjNIMP, el->equality.spec.solimp, text, false, false);
ReadAttr(ejnt, "solreffix", mjNREF, dequality.solref, text, false, false);
ReadAttr(ejnt, "solimpfix", mjNIMP, dequality.solimp, text, false, false);
// joint attributes
MapValue(elem, "limited", &el->joint.spec.limited, TFAuto_map, 3);
ReadAttrInt(ejnt, "group", &el->joint.spec.group);
ReadAttr(ejnt, "solreflimit", mjNREF, el->joint.spec.solref_limit, text, false, false);
ReadAttr(ejnt, "solimplimit", mjNIMP, el->joint.spec.solimp_limit, text, false, false);
MapValue(elem, "limited", &djoint.limited, TFAuto_map, 3);
ReadAttrInt(ejnt, "group", &djoint.group);
ReadAttr(ejnt, "solreflimit", mjNREF, djoint.solref_limit, text, false, false);
ReadAttr(ejnt, "solimplimit", mjNIMP, djoint.solimp_limit, text, false, false);
ReadAttr(ejnt,
"solreffriction", mjNREF, el->joint.spec.solref_friction, text, false, false);
"solreffriction", mjNREF, djoint.solref_friction, text, false, false);
ReadAttr(ejnt,
"solimpfriction", mjNIMP, el->joint.spec.solimp_friction, text, false, false);
ReadAttr(ejnt, "stiffness", 1, &el->joint.spec.stiffness, text);
ReadAttr(ejnt, "range", 2, el->joint.spec.range, text);
ReadAttr(ejnt, "margin", 1, &el->joint.spec.margin, text);
ReadAttr(ejnt, "armature", 1, &el->joint.spec.armature, text);
ReadAttr(ejnt, "damping", 1, &el->joint.spec.damping, text);
ReadAttr(ejnt, "frictionloss", 1, &el->joint.spec.frictionloss, text);
"solimpfriction", mjNIMP, djoint.solimp_friction, text, false, false);
ReadAttr(ejnt, "stiffness", 1, &djoint.stiffness, text);
ReadAttr(ejnt, "range", 2, djoint.range, text);
ReadAttr(ejnt, "margin", 1, &djoint.margin, text);
ReadAttr(ejnt, "armature", 1, &djoint.armature, text);
ReadAttr(ejnt, "damping", 1, &djoint.damping, text);
ReadAttr(ejnt, "frictionloss", 1, &djoint.frictionloss, text);
// advance
ejnt = NextSiblingElement(ejnt, "joint");
@@ -2419,29 +2421,33 @@ void mjXReader::OneComposite(XMLElement* elem, mjmBody* pbody, mjCDef* def) {
MapValue(eten, "kind", &kind, tkind_map, 2, true);
comp.add[kind] = true;
// get default structs
mjmTendon& dtendon = *comp.def[kind].spec.tendon;
mjmEquality& dequality = *comp.def[kind].spec.equality;
// solreffix, solimpfix
ReadAttr(eten, "solreffix", mjNREF, comp.def[kind].equality.spec.solref, text, false, false);
ReadAttr(eten, "solimpfix", mjNIMP, comp.def[kind].equality.spec.solimp, text, false, false);
ReadAttr(eten, "solreffix", mjNREF, dequality.solref, text, false, false);
ReadAttr(eten, "solimpfix", mjNIMP, dequality.solimp, text, false, false);
// tendon attributes
std::string material;
MapValue(elem, "limited", &comp.def[kind].tendon.spec.limited, TFAuto_map, 3);
ReadAttrInt(eten, "group", &comp.def[kind].tendon.spec.group);
ReadAttr(eten, "solreflimit", mjNREF, comp.def[kind].tendon.spec.solref_limit, text, false, false);
ReadAttr(eten, "solimplimit", mjNIMP, comp.def[kind].tendon.spec.solimp_limit, text, false, false);
MapValue(elem, "limited", &dtendon.limited, TFAuto_map, 3);
ReadAttrInt(eten, "group", &dtendon.group);
ReadAttr(eten, "solreflimit", mjNREF, dtendon.solref_limit, text, false, false);
ReadAttr(eten, "solimplimit", mjNIMP, dtendon.solimp_limit, text, false, false);
ReadAttr(eten,
"solreffriction", mjNREF, comp.def[kind].tendon.spec.solref_friction, text, false, false);
"solreffriction", mjNREF, dtendon.solref_friction, text, false, false);
ReadAttr(eten,
"solimpfriction", mjNIMP, comp.def[kind].tendon.spec.solimp_friction, text, false, false);
ReadAttr(eten, "range", 2, comp.def[kind].tendon.spec.range, text);
ReadAttr(eten, "margin", 1, &comp.def[kind].tendon.spec.margin, text);
ReadAttr(eten, "stiffness", 1, &comp.def[kind].tendon.spec.stiffness, text);
ReadAttr(eten, "damping", 1, &comp.def[kind].tendon.spec.damping, text);
ReadAttr(eten, "frictionloss", 1, &comp.def[kind].tendon.spec.frictionloss, text);
"solimpfriction", mjNIMP, dtendon.solimp_friction, text, false, false);
ReadAttr(eten, "range", 2, dtendon.range, text);
ReadAttr(eten, "margin", 1, &dtendon.margin, text);
ReadAttr(eten, "stiffness", 1, &dtendon.stiffness, text);
ReadAttr(eten, "damping", 1, &dtendon.damping, text);
ReadAttr(eten, "frictionloss", 1, &dtendon.frictionloss, text);
ReadAttrTxt(eten, "material", material);
mjm_setString(comp.def[kind].tendon.spec.material, material.c_str());
ReadAttr(eten, "rgba", 4, comp.def[kind].tendon.spec.rgba, text);
ReadAttr(eten, "width", 1, &comp.def[kind].tendon.spec.width, text);
mjm_setString(dtendon.material, material.c_str());
ReadAttr(eten, "rgba", 4, dtendon.rgba, text);
ReadAttr(eten, "width", 1, &dtendon.width, text);
// advance
eten = NextSiblingElement(eten, "tendon");
@@ -2481,6 +2487,7 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjmBody* pbody) {
// create out-of-DOM element
mjCFlexcomp fcomp;
mjmFlex& dflex = *fcomp.def.spec.flex;
// common properties
ReadAttrTxt(elem, "name", fcomp.name, true);
@@ -2494,15 +2501,15 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjmBody* pbody) {
ReadAttr(elem, "inertiabox", 1, &fcomp.inertiabox, text);
ReadAttrTxt(elem, "file", fcomp.file);
if (ReadAttrTxt(elem, "material", material)) {
mjm_setString(fcomp.def.flex.spec.material, material.c_str());
mjm_setString(dflex.material, material.c_str());
}
ReadAttr(elem, "rgba", 4, fcomp.def.flex.spec.rgba, text);
ReadAttr(elem, "rgba", 4, dflex.rgba, text);
if (MapValue(elem, "flatskin", &n, bool_map, 2)) {
fcomp.def.flex.spec.flatskin = (n==1);
dflex.flatskin = (n==1);
}
ReadAttrInt(elem, "dim", &fcomp.def.flex.spec.dim);
ReadAttr(elem, "radius", 1, &fcomp.def.flex.spec.radius, text);
ReadAttrInt(elem, "group", &fcomp.def.flex.spec.group);
ReadAttrInt(elem, "dim", &dflex.dim);
ReadAttr(elem, "radius", 1, &dflex.radius, text);
ReadAttrInt(elem, "group", &dflex.group);
// pose
ReadAttr(elem, "pos", 3, fcomp.pos, text);
@@ -2529,30 +2536,30 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjmBody* pbody) {
if (MapValue(edge, "equality", &n, bool_map, 2)) {
fcomp.equality = (n==1);
}
ReadAttr(edge, "solref", mjNREF, fcomp.def.equality.spec.solref, text, false, false);
ReadAttr(edge, "solimp", mjNIMP, fcomp.def.equality.spec.solimp, text, false, false);
ReadAttr(edge, "stiffness", 1, &fcomp.def.flex.spec.edgestiffness, text);
ReadAttr(edge, "damping", 1, &fcomp.def.flex.spec.edgedamping, text);
ReadAttr(edge, "solref", mjNREF, fcomp.def.spec.equality->solref, text, false, false);
ReadAttr(edge, "solimp", mjNIMP, fcomp.def.spec.equality->solimp, text, false, false);
ReadAttr(edge, "stiffness", 1, &dflex.edgestiffness, text);
ReadAttr(edge, "damping", 1, &dflex.edgedamping, text);
}
// contact
XMLElement* cont = FirstChildElement(elem, "contact");
if (cont) {
ReadAttrInt(cont, "contype", &fcomp.def.flex.spec.contype);
ReadAttrInt(cont, "conaffinity", &fcomp.def.flex.spec.conaffinity);
ReadAttrInt(cont, "condim", &fcomp.def.flex.spec.condim);
ReadAttrInt(cont, "priority", &fcomp.def.flex.spec.priority);
ReadAttr(cont, "friction", 3, fcomp.def.flex.spec.friction, text, false, false);
ReadAttr(cont, "solmix", 1, &fcomp.def.flex.spec.solmix, text);
ReadAttr(cont, "solref", mjNREF, fcomp.def.flex.spec.solref, text, false, false);
ReadAttr(cont, "solimp", mjNIMP, fcomp.def.flex.spec.solimp, text, false, false);
ReadAttr(cont, "margin", 1, &fcomp.def.flex.spec.margin, text);
ReadAttr(cont, "gap", 1, &fcomp.def.flex.spec.gap, text);
ReadAttrInt(cont, "contype", &dflex.contype);
ReadAttrInt(cont, "conaffinity", &dflex.conaffinity);
ReadAttrInt(cont, "condim", &dflex.condim);
ReadAttrInt(cont, "priority", &dflex.priority);
ReadAttr(cont, "friction", 3, dflex.friction, text, false, false);
ReadAttr(cont, "solmix", 1, &dflex.solmix, text);
ReadAttr(cont, "solref", mjNREF, dflex.solref, text, false, false);
ReadAttr(cont, "solimp", mjNIMP, dflex.solimp, text, false, false);
ReadAttr(cont, "margin", 1, &dflex.margin, text);
ReadAttr(cont, "gap", 1, &dflex.gap, text);
if (MapValue(cont, "internal", &n, bool_map, 2)) {
fcomp.def.flex.spec.internal = (n==1);
dflex.internal = (n==1);
}
MapValue(cont, "selfcollide", &fcomp.def.flex.spec.selfcollide, flexself_map, 5);
ReadAttrInt(cont, "activelayers", &fcomp.def.flex.spec.activelayers);
MapValue(cont, "selfcollide", &dflex.selfcollide, flexself_map, 5);
ReadAttrInt(cont, "activelayers", &dflex.activelayers);
}
// pin
@@ -2633,7 +2640,7 @@ void mjXReader::OnePlugin(XMLElement* elem, mjmPlugin* plugin) {
void mjXReader::Default(XMLElement* section, int parentid) {
XMLElement* elem;
string text, name;
mjCDef* def;
mjmDefault* def;
int thisid;
// create new default, except at top level (already added in mjCModel ctor)
@@ -2648,14 +2655,14 @@ void mjXReader::Default(XMLElement* section, int parentid) {
}
if (parentid>=0) {
thisid = (int)model->defaults.size();
def = model->AddDef(text, parentid);
def = mjm_addDefault(model, text.c_str(), parentid);
if (!def) {
throw mjXError(section, "repeated default class name");
}
} else {
thisid = 0;
def = model->defaults[0];
def->name = text;
def = &model->defaults[0]->spec;
mjm_setString(def->name, text.c_str());
}
// iterate over elements other than nested defaults
@@ -2665,34 +2672,34 @@ void mjXReader::Default(XMLElement* section, int parentid) {
name = elem->Value();
// read mesh
if (name=="mesh") OneMesh(elem, &def->mesh.spec);
if (name=="mesh") OneMesh(elem, def->mesh);
// read material
else if (name=="material") OneMaterial(elem, &def->material.spec);
else if (name=="material") OneMaterial(elem, def->material);
// read joint
else if (name=="joint") OneJoint(elem, &def->joint.spec);
else if (name=="joint") OneJoint(elem, def->joint);
// read geom
else if (name=="geom") OneGeom(elem, &def->geom.spec);
else if (name=="geom") OneGeom(elem, def->geom);
// read site
else if (name=="site") OneSite(elem, def->site.spec);
else if (name=="site") OneSite(elem, def->site);
// read camera
else if (name=="camera") OneCamera(elem, &def->camera.spec);
else if (name=="camera") OneCamera(elem, def->camera);
// read light
else if (name=="light") OneLight(elem, &def->light.spec);
else if (name=="light") OneLight(elem, def->light);
// read pair
else if (name=="pair") OnePair(elem, &def->pair.spec);
else if (name=="pair") OnePair(elem, def->pair);
// read equality
else if (name=="equality") OneEquality(elem, &def->equality.spec);
else if (name=="equality") OneEquality(elem, def->equality);
// read tendon
else if (name=="tendon") OneTendon(elem, &def->tendon.spec);
else if (name=="tendon") OneTendon(elem, def->tendon);
// read actuator
else if (name=="general" ||
@@ -2704,21 +2711,22 @@ void mjXReader::Default(XMLElement* section, int parentid) {
name=="cylinder" ||
name=="muscle" ||
name=="adhesion") {
OneActuator(elem, &def->actuator.spec);
OneActuator(elem, def->actuator);
}
// copy into private attributes
mjm_finalize(def->geom.spec.element);
mjm_finalize(def->joint.spec.element);
mjm_finalize(def->site.spec.element);
mjm_finalize(def->camera.spec.element);
mjm_finalize(def->light.spec.element);
mjm_finalize(def->actuator.spec.element);
mjm_finalize(def->material.spec.element);
mjm_finalize(def->equality.spec.element);
mjm_finalize(def->tendon.spec.element);
mjm_finalize(def->flex.spec.element);
mjm_finalize(def->pair.spec.element);
mjm_finalize(def->joint->element);
mjm_finalize(def->geom->element);
mjm_finalize(def->site->element);
mjm_finalize(def->camera->element);
mjm_finalize(def->light->element);
mjm_finalize(def->flex->element);
mjm_finalize(def->mesh->element);
mjm_finalize(def->material->element);
mjm_finalize(def->pair->element);
mjm_finalize(def->equality->element);
mjm_finalize(def->tendon->element);
mjm_finalize(def->actuator->element);
// advance
elem = NextSiblingElement(elem);
@@ -3066,9 +3074,9 @@ void mjXReader::Asset(XMLElement* section) {
name = elem->Value();
// get class if specified, otherwise use default0
mjCDef* def = GetClass(elem);
mjmDefault* def = GetClass(elem);
if (!def) {
def = model->defaults[0];
def = &model->defaults[0]->spec;
}
// texture sub-element
@@ -3248,9 +3256,9 @@ void mjXReader::Body(XMLElement* section, mjmBody* pbody, mjmFrame* frame) {
name = elem->Value();
// get class if specified, otherwise use body
mjCDef* def = GetClass(elem);
mjmDefault* def = GetClass(elem);
if (!def) {
def = (mjCDef*)mjm_getDefault(pbody->element);
def = (mjmDefault*)mjm_getDefault(pbody->element);
}
// inertial sub-element
@@ -3318,7 +3326,7 @@ void mjXReader::Body(XMLElement* section, mjmBody* pbody, mjmFrame* frame) {
else if (name=="site") {
// create site and parse
mjmSite* site = mjm_addSite(pbody, def);
OneSite(elem, *site);
OneSite(elem, site);
mjm_setFrame(site->element, frame);
}
@@ -3370,9 +3378,9 @@ void mjXReader::Body(XMLElement* section, mjmBody* pbody, mjmFrame* frame) {
// body sub-element
else if (name=="body") {
// read childdef
mjCDef* childdef = 0;
mjmDefault* childdef = 0;
if (ReadAttrTxt(elem, "childclass", text)) {
childdef = model->FindDef(text);
childdef = &model->FindDef(text)->spec;
if (!childdef) {
throw mjXError(elem, "unknown default childclass");
}
@@ -3437,9 +3445,9 @@ void mjXReader::Contact(XMLElement* section) {
name = elem->Value();
// get class if specified, otherwise use default0
mjCDef* def = GetClass(elem);
mjmDefault* def = GetClass(elem);
if (!def) {
def = model->defaults[0];
def = &model->defaults[0]->spec;
}
// geom pair to include
@@ -3482,9 +3490,9 @@ void mjXReader::Equality(XMLElement* section) {
elem = FirstChildElement(section);
while (elem) {
// get class if specified, otherwise use default0
mjCDef* def = GetClass(elem);
mjmDefault* def = GetClass(elem);
if (!def) {
def = model->defaults[0];
def = &model->defaults[0]->spec;
}
// create equality constraint and parse
@@ -3510,9 +3518,9 @@ void mjXReader::Deformable(XMLElement* section) {
name = elem->Value();
// get class if specified, otherwise use default0
mjCDef* def = GetClass(elem);
mjmDefault* def = GetClass(elem);
if (!def) {
def = model->defaults[0];
def = &model->defaults[0]->spec;
}
// flex sub-element
@@ -3546,9 +3554,9 @@ void mjXReader::Tendon(XMLElement* section) {
elem = FirstChildElement(section);
while (elem) {
// get class if specified, otherwise use default0
mjCDef* def = GetClass(elem);
mjmDefault* def = GetClass(elem);
if (!def) {
def = model->defaults[0];
def = &model->defaults[0]->spec;
}
// create equality constraint and parse
@@ -3612,9 +3620,9 @@ void mjXReader::Actuator(XMLElement* section) {
elem = FirstChildElement(section);
while (elem) {
// get class if specified, otherwise use default0
mjCDef* def = GetClass(elem);
mjmDefault* def = GetClass(elem);
if (!def) {
def = model->defaults[0];
def = &model->defaults[0]->spec;
}
// create actuator and parse
@@ -4003,12 +4011,12 @@ void mjXReader::Keyframe(XMLElement* section) {
// get defaults class
mjCDef* mjXReader::GetClass(XMLElement* section) {
mjmDefault* mjXReader::GetClass(XMLElement* section) {
string text;
mjCDef* def = 0;
mjmDefault* def = 0;
if (ReadAttrTxt(section, "class", text)) {
def = model->FindDef(text);
def = &model->FindDef(text)->spec;
if (!def) {
throw mjXError(section, "unknown default class");
}
+3 -3
View File
@@ -64,19 +64,19 @@ class mjXReader : public mjXBase {
void OneMaterial(tinyxml2::XMLElement* elem, mjmMaterial* pmaterial);
void OneJoint(tinyxml2::XMLElement* elem, mjmJoint* pjoint);
void OneGeom(tinyxml2::XMLElement* elem, mjmGeom* pgeom);
void OneSite(tinyxml2::XMLElement* elem, mjmSite& site);
void OneSite(tinyxml2::XMLElement* elem, mjmSite* site);
void OneCamera(tinyxml2::XMLElement* elem, mjmCamera* pcamera);
void OneLight(tinyxml2::XMLElement* elem, mjmLight* plight);
void OnePair(tinyxml2::XMLElement* elem, mjmPair* ppair);
void OneEquality(tinyxml2::XMLElement* elem, mjmEquality* pequality);
void OneTendon(tinyxml2::XMLElement* elem, mjmTendon* ptendon);
void OneActuator(tinyxml2::XMLElement* elem, mjmActuator* pactuator);
void OneComposite(tinyxml2::XMLElement* elem, mjmBody* pbody, mjCDef* def);
void OneComposite(tinyxml2::XMLElement* elem, mjmBody* pbody, mjmDefault* def);
void OneFlexcomp(tinyxml2::XMLElement* elem, mjmBody* pbody);
void OnePlugin(tinyxml2::XMLElement* elem, mjmPlugin* plugin);
mjXSchema schema; // schema used for validation
mjCDef* GetClass(tinyxml2::XMLElement* section); // get default class name
mjmDefault* GetClass(tinyxml2::XMLElement* section); // get default class name
static void GetXMLPos(tinyxml2::XMLElement* elem, mjCBase* obj); // get xml position
bool readingdefaults; // true while reading defaults
+25
View File
@@ -437,6 +437,31 @@ TEST_F(XMLReaderTest, InvalidDoubleOrientation) {
}
}
}
TEST_F(XMLReaderTest, RepeatedDefaultName) {
static constexpr char xml[] = R"(
<mujoco>
<default>
<default class="sphere">
<geom type="sphere" size="1"/>
</default>
<default class="sphere">
<geom type="capsule" size="1 1"/>
</default>
</default>
<worldbody>
<body>
<geom class="sphere"/>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, IsNull()) << error.data();
EXPECT_THAT(error.data(), HasSubstr("repeated default class name"));
}
// ------------------------ test including -------------------------------------
TEST_F(XMLReaderTest, IncludeTest) {
+32
View File
@@ -694,6 +694,38 @@ TEST_F(XMLWriterTest, WritesDefaults) {
mj_deleteModel(model);
}
TEST_F(XMLWriterTest, WritesActuatorDefaults) {
static constexpr char xml[] = R"(
<mujoco>
<default>
<default class="position">
<position kp="3" kv="4" />
</default>
<default class="intvelocity">
<intvelocity kp="5" kv="6" />
</default>
</default>
<worldbody>
<body>
<geom size="1"/>
<joint name="jnt" type="slide" axis="1 0 0" range="0 2"/>
</body>
</worldbody>
<actuator>
<position joint="jnt" class="position"/>
<intvelocity joint="jnt" actrange="-1 1"/>
</actuator>
</mujoco>
)";
mjModel* model = LoadModelFromString(xml);
ASSERT_THAT(model, NotNull());
std::string saved_xml = SaveAndReadXml(model);
EXPECT_THAT(saved_xml, Not(HasSubstr("mass")));
EXPECT_THAT(saved_xml, HasSubstr(
"<general biastype=\"affine\" gainprm=\"3 0 0 0 0 0 0 0 0 0\""));
mj_deleteModel(model);
}
TEST_F(XMLWriterTest, WritesDensity) {
static constexpr char xml[] = R"(
<mujoco>