diff --git a/src/user/user_api.cc b/src/user/user_api.cc index 74ec08f0..05f03cc6 100644 --- a/src/user/user_api.cc +++ b/src/user/user_api.cc @@ -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(defspec); +mjmBody* mjm_addBody(mjmBody* bodyspec, mjmDefault* defspec) { + mjCDef* def = defspec ? reinterpret_cast(defspec->element) : 0; mjCBody* body = reinterpret_cast(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(defspec); +mjmSite* mjm_addSite(mjmBody* bodyspec, mjmDefault* defspec) { + mjCDef* def = defspec ? reinterpret_cast(defspec->element) : 0; mjCBody* body = reinterpret_cast(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(defspec); +mjmJoint* mjm_addJoint(mjmBody* bodyspec, mjmDefault* defspec) { + mjCDef* def = defspec ? reinterpret_cast(defspec->element) : 0; mjCBody* body = reinterpret_cast(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(defspec); +mjmGeom* mjm_addGeom(mjmBody* bodyspec, mjmDefault* defspec) { + mjCDef* def = defspec ? reinterpret_cast(defspec->element) : 0; mjCBody* body = reinterpret_cast(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(defspec); +mjmCamera* mjm_addCamera(mjmBody* bodyspec, mjmDefault* defspec) { + mjCDef* def = defspec ? reinterpret_cast(defspec->element) : 0; mjCBody* body = reinterpret_cast(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(defspec); +mjmLight* mjm_addLight(mjmBody* bodyspec, mjmDefault* defspec) { + mjCDef* def = defspec ? reinterpret_cast(defspec->element) : 0; mjCBody* body = reinterpret_cast(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(defspec) : 0; +mjmMesh* mjm_addMesh(void* model, mjmDefault* defspec) { + mjCDef* def = defspec ? reinterpret_cast(defspec->element) : 0; mjCModel* modelC = static_cast(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(model); - mjCDef* def = static_cast(defspec); + mjCDef* def = defspec ? reinterpret_cast(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(model); - mjCDef* def = static_cast(defspec); + mjCDef* def = defspec ? reinterpret_cast(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(model); - mjCDef* def = static_cast(defspec); + mjCDef* def = defspec ? reinterpret_cast(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(model); - mjCDef* def = static_cast(defspec); + mjCDef* def = defspec ? reinterpret_cast(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(model); - mjCDef* def = static_cast(defspec); + mjCDef* def = defspec ? reinterpret_cast(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(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(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(bodyspec->element)->model; @@ -331,8 +344,8 @@ void* mjm_getModel(mjmBody* bodyspec) { // get default -void* mjm_getDefault(mjElement element) { - return reinterpret_cast(element)->def; +mjmDefault* mjm_getDefault(mjElement element) { + return &(reinterpret_cast(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(element); - baseC->def = static_cast(defspec); + baseC->def = reinterpret_cast(defspec->element); + baseC->def->PointToLocal(); } diff --git a/src/user/user_api.h b/src/user/user_api.h index fb9be03f..05ca79d2 100644 --- a/src/user/user_api.h +++ b/src/user/user_api.h @@ -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); diff --git a/src/user/user_composite.cc b/src/user/user_composite.cc index ddb7e88a..f30e9fd9 100644 --- a/src/user/user_composite.cc +++ b/src/user/user_composite.cc @@ -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; igroup = 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; igroup = 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; isolref, 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; ixelement, 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); } diff --git a/src/user/user_flexcomp.cc b/src/user/user_flexcomp.cc index 06bda286..ef298c05 100644 --- a/src/user/user_flexcomp.cc +++ b/src/user/user_flexcomp.cc @@ -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]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; i3) { 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"); } diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index cf19599d..f017995c 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -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; diff --git a/src/user/user_objects.h b/src/user/user_objects.h index feaec000..804ec564 100644 --- a/src/user/user_objects.h +++ b/src/user/user_objects.h @@ -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 childid; // ids of child classes - // default objects + mjmDefault spec; + + // default objects (TODO: they should become private) mjCJoint joint; mjCGeom geom; mjCSite site; diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 3557a295..13834b72 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -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 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"); } diff --git a/src/xml/xml_native_reader.h b/src/xml/xml_native_reader.h index f9bf0fde..cd8d8208 100644 --- a/src/xml/xml_native_reader.h +++ b/src/xml/xml_native_reader.h @@ -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 diff --git a/test/xml/xml_native_reader_test.cc b/test/xml/xml_native_reader_test.cc index b85aa8db..8be293fb 100644 --- a/test/xml/xml_native_reader_test.cc +++ b/test/xml/xml_native_reader_test.cc @@ -437,6 +437,31 @@ TEST_F(XMLReaderTest, InvalidDoubleOrientation) { } } } + +TEST_F(XMLReaderTest, RepeatedDefaultName) { + static constexpr char xml[] = R"( + + + + + + + + + + + + + + + + )"; + std::array 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) { diff --git a/test/xml/xml_native_writer_test.cc b/test/xml/xml_native_writer_test.cc index d3e000cd..53147f0f 100644 --- a/test/xml/xml_native_writer_test.cc +++ b/test/xml/xml_native_writer_test.cc @@ -694,6 +694,38 @@ TEST_F(XMLWriterTest, WritesDefaults) { mj_deleteModel(model); } +TEST_F(XMLWriterTest, WritesActuatorDefaults) { + static constexpr char xml[] = R"( + + + + + + + + + + + + + + + + + + + + + )"; + 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( + "