From 042760eba8ebc0011262ab22b7a805ba50236418 Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Wed, 21 Feb 2024 01:57:19 -0800 Subject: [PATCH] Add compiler settings to mjmModel. PiperOrigin-RevId: 608908314 Change-Id: Id3b0d8c62ca710b5b6d6e423abbbddcb7e7079a1 --- src/user/user_api.h | 34 +++++++++++++++++++++-- src/user/user_flexcomp.cc | 10 +++---- src/user/user_init.cc | 22 +++++++++++++++ src/user/user_mesh.cc | 4 +-- src/user/user_model.cc | 54 +++++++++++++++--------------------- src/user/user_model.h | 48 ++++++++++++++------------------ src/user/user_objects.cc | 8 +++--- src/xml/xml.cc | 6 ++-- src/xml/xml_native_reader.cc | 17 ++++++++---- src/xml/xml_native_reader.h | 2 +- src/xml/xml_native_writer.cc | 8 +++--- src/xml/xml_urdf.cc | 8 +++--- 12 files changed, 130 insertions(+), 91 deletions(-) diff --git a/src/user/user_api.h b/src/user/user_api.h index 9d0f869f..bed0b699 100644 --- a/src/user/user_api.h +++ b/src/user/user_api.h @@ -69,11 +69,39 @@ typedef enum _mjtLimited { // type of limit specification } mjtLimited; +typedef enum _mjtInertiaFromGeom { + mjINERTIAFROMGEOM_FALSE = 0, // do not use; inertial element required + mjINERTIAFROMGEOM_TRUE, // always use; overwrite inertial element + mjINERTIAFROMGEOM_AUTO // use only if inertial element is missing +} mjtInertiaFromGeom; + + //---------------------------------- attribute structs (mjm) --------------------------------------- typedef struct _mjmModel { // model specification mjElement element; // internal, do not modify mjStatistic stat; // statistics override (if defined) + + //------------------------ compiler settings + mjtByte autolimits; // infer "limited" attribute based on range + double boundmass; // enforce minimum body mass + double boundinertia; // enforce minimum body diagonal inertia + double settotalmass; // rescale masses and inertias; <=0: ignore + mjtByte balanceinertia; // automatically impose A + B >= C rule + mjtByte strippath; // automatically strip paths from mesh files + mjtByte fitaabb; // meshfit to aabb instead of inertia box + mjtByte degree; // angles in radians or degrees + char euler[3]; // sequence for euler rotations + mjString meshdir; // mesh and hfield directory + mjString texturedir; // texture directory + mjtByte discardvisual; // discard visual geoms in parser + mjtByte convexhull; // compute mesh convex hulls + mjtByte usethread; // use multiple threads to speed up compiler + mjtByte fusestatic; // fuse static bodies with parent + int inertiafromgeom; // use geom inertias (mjtInertiaFromGeom) + int inertiagrouprange[2]; // range of geom groups used to compute inertia + mjtByte exactmeshinertia; // if false, use old formula + mjLROpt LRopt; // options for lengthrange computation } mjmModel; typedef struct _mjmOrientation { // alternative orientation specifiers @@ -320,8 +348,8 @@ typedef struct _mjmFlex { // other properties int dim; // element dimensionality double radius; // radius around primitive element - bool internal; // enable internal collisions - bool flatskin; // render flex skin with flat shading + mjtByte internal; // enable internal collisions + mjtByte flatskin; // render flex skin with flat shading int selfcollide; // mode for flex self colllision int activelayers; // number of active element layers in 3D int group; // group for visualizatioh @@ -442,7 +470,7 @@ typedef struct _mjmMaterial { // material specification mjString name; // name mjString classname; // class name mjString texture; // name of texture (empty: none) - bool texuniform; // make texture cube uniform + mjtByte texuniform; // make texture cube uniform float texrepeat[2]; // texture repetition for 2D mapping float emission; // emission float specular; // specular diff --git a/src/user/user_flexcomp.cc b/src/user/user_flexcomp.cc index 4c880f58..47f3e952 100644 --- a/src/user/user_flexcomp.cc +++ b/src/user/user_flexcomp.cc @@ -124,7 +124,7 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz } // compute orientation - const char* alterr = alt.Set(quat, model->degree, model->euler); + const char* alterr = alt.Set(quat, model->spec.degree, model->spec.euler); if (alterr) { return comperr(error, alterr, error_sz); } @@ -814,7 +814,7 @@ template static T* VecToArray(std::vector& vector, bool clear = // make mesh bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) { // strip path - if (!file.empty() && model->strippath) { + if (!file.empty() && model->spec.strippath) { file = mjuu_strippath(file); } @@ -837,7 +837,7 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) { } // load resource - string filename = mjuu_makefullname(model->modelfiledir, model->meshdir, file); + string filename = mjuu_makefullname(model->modelfiledir, mjm_getString(model->spec.meshdir), file); mjResource* resource = nullptr; try { @@ -933,7 +933,7 @@ static int findstring(const char* buffer, int buffer_sz, const char* str) { // load points and elements from GMSH file bool mjCFlexcomp::MakeGMSH(mjCModel* model, char* error, int error_sz) { // strip path - if (!file.empty() && model->strippath) { + if (!file.empty() && model->spec.strippath) { file = mjuu_strippath(file); } @@ -943,7 +943,7 @@ bool mjCFlexcomp::MakeGMSH(mjCModel* model, char* error, int error_sz) { } // open resource - string filename = mjuu_makefullname(model->modelfiledir, model->meshdir, file); + string filename = mjuu_makefullname(model->modelfiledir, mjm_getString(model->spec.meshdir), file); mjResource* resource = nullptr; try { diff --git a/src/user/user_init.cc b/src/user/user_init.cc index c0e84918..212944c4 100644 --- a/src/user/user_init.cc +++ b/src/user/user_init.cc @@ -31,6 +31,28 @@ void mjm_defaultModel(mjmModel& model) { model.stat.meansize = mjNAN; model.stat.extent = mjNAN; model.stat.center[0] = mjNAN; + + // compiler settings + model.autolimits = true; + model.boundmass = 0; + model.boundinertia = 0; + model.settotalmass = -1; + model.balanceinertia = false; + model.strippath = false; + model.fitaabb = false; + model.degree = true; + model.euler[0] = 'x'; + model.euler[1] = 'y'; + model.euler[2] = 'z'; + model.discardvisual = false; + model.convexhull = true; + model.usethread = true; + model.fusestatic = false; + model.inertiafromgeom = mjINERTIAFROMGEOM_AUTO; + model.inertiagrouprange[0] = 0; + model.inertiagrouprange[1] = mjNGROUP-1; + model.exactmeshinertia = false; + mj_defaultLROpt(&model.LRopt); } diff --git a/src/user/user_mesh.cc b/src/user/user_mesh.cc index 0b88c27d..ee1323fd 100644 --- a/src/user/user_mesh.cc +++ b/src/user/user_mesh.cc @@ -347,7 +347,7 @@ void mjCMesh::Compile(const mjVFS* vfs) { throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str()); } - string filename = mjuu_makefullname(model->modelfiledir, model->meshdir, file_); + string filename = mjuu_makefullname(model->modelfiledir, model->meshdir_, file_); mjResource* resource = LoadResource(filename, vfs); try { @@ -1950,7 +1950,7 @@ void mjCSkin::Compile(const mjVFS* vfs) { throw mjCError(this, "Unknown skin file type: %s", file_.c_str()); } - string filename = mjuu_makefullname(model->modelfiledir, model->meshdir, file_); + string filename = mjuu_makefullname(model->modelfiledir, model->meshdir_, file_); mjResource* resource = LoadResource(filename, vfs); try { diff --git a/src/user/user_model.cc b/src/user/user_model.cc index b0b21831..2dc399c6 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -86,30 +86,8 @@ mjCModel::mjCModel() { mjm_defaultModel(spec); comment.clear(); modelfiledir.clear(); - - //------------------------ compiler settings - autolimits = true; - boundmass = 0; - boundinertia = 0; - settotalmass = -1; - balanceinertia = false; - strippath = false; - fitaabb = false; - degree = true; - euler[0] = 'x'; - euler[1] = 'y'; - euler[2] = 'z'; - meshdir.clear(); - texturedir.clear(); - discardvisual = false; - convexhull = true; - usethread = true; - fusestatic = false; - inertiafromgeom = mjINERTIAFROMGEOM_AUTO; - inertiagrouprange[0] = 0; - inertiagrouprange[1] = mjNGROUP-1; - exactmeshinertia = false; - mj_defaultLROpt(&LRopt); + spec_meshdir_.clear(); + spec_texturedir_.clear(); //------------------------ auto-computed statistics #ifndef MEMORY_SANITIZER @@ -211,13 +189,25 @@ mjCModel::mjCModel() { // point to model from spec + PointToLocal(); +} + + + +void mjCModel::PointToLocal() { spec.element = (mjElement)this; + spec.meshdir = (mjString)&spec_meshdir_; + spec.texturedir = (mjString)&spec_texturedir_; } void mjCModel::CopyFromSpec() { *static_cast(this) = spec; + meshdir_ = spec_meshdir_; + texturedir_ = spec_texturedir_; + meshdir = (mjString)&meshdir_; + texturedir = (mjString)&texturedir_; } @@ -2828,16 +2818,16 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) { } // append directory separator - if (!meshdir.empty()) { - int n = meshdir.length(); - if (meshdir[n-1]!='/' && meshdir[n-1]!='\\') { - meshdir += '/'; + if (!meshdir_.empty()) { + int n = meshdir_.length(); + if (meshdir_[n-1]!='/' && meshdir_[n-1]!='\\') { + meshdir_ += '/'; } } - if (!texturedir.empty()) { - int n = texturedir.length(); - if (texturedir[n-1]!='/' && texturedir[n-1]!='\\') { - texturedir += '/'; + if (!texturedir_.empty()) { + int n = texturedir_.length(); + if (texturedir_[n-1]!='/' && texturedir_[n-1]!='\\') { + texturedir_ += '/'; } } diff --git a/src/user/user_model.h b/src/user/user_model.h index ff3ec5fa..93b18cc8 100644 --- a/src/user/user_model.h +++ b/src/user/user_model.h @@ -25,15 +25,10 @@ #include #include #include +#include #include "user/user_api.h" #include "user/user_objects.h" -typedef enum _mjtInertiaFromGeom { - mjINERTIAFROMGEOM_FALSE = 0, // do not use; inertial element required - mjINERTIAFROMGEOM_TRUE, // always use; overwrite inertial element - mjINERTIAFROMGEOM_AUTO // use only if inertial element is missing -} mjtInertiaFromGeom; - typedef std::map > mjKeyMap; typedef std::array mjListKeyMap; @@ -49,10 +44,19 @@ typedef std::array mjListKeyMap; class mjCModel : private mjmModel { friend class mjCBody; + friend class mjCCamera; friend class mjCGeom; friend class mjCFlex; + friend class mjCHField; + friend class mjCFrame; + friend class mjCJoint; friend class mjCEquality; + friend class mjCMesh; + friend class mjCSkin; + friend class mjCSite; friend class mjCTendon; + friend class mjCTexture; + friend class mjCActuator; friend class mjXReader; friend class mjXWriter; @@ -60,6 +64,7 @@ class mjCModel : private mjmModel { mjCModel(); // constructor ~mjCModel(); // destructor void CopyFromSpec(); // copy spec to private attributes + void PointToLocal(); mjmModel spec; @@ -110,6 +115,10 @@ class mjCModel : private mjmModel { mjCBase* FindObject(mjtObj type, std::string name); // find object given type and name bool IsNullPose(const mjtNum* pos, const mjtNum* quat); // detect null pose + //------------------------ getters + std::string get_meshdir(void) const { return meshdir_; } + std::string get_texturedir(void) const { return texturedir_; } + //------------------------ API for plugins void ResolvePlugin(mjCBase* obj, // resolve plugin instance, create a new one if needed const std::string& plugin_name, @@ -122,27 +131,6 @@ class mjCModel : private mjmModel { std::string modelfiledir; // path to model file std::vector defaults; // settings for each defaults class - //------------------------ compiler settings - bool autolimits; // infer "limited" attribute based on range - double boundmass; // enforce minimum body mass - double boundinertia; // enforce minimum body diagonal inertia - double settotalmass; // rescale masses and inertias; <=0: ignore - bool balanceinertia; // automatically impose A + B >= C rule - bool strippath; // automatically strip paths from mesh files - bool fitaabb; // meshfit to aabb instead of inertia box - bool degree; // angles in radians or degrees - char euler[3]; // sequence for euler rotations - std::string meshdir; // mesh and hfield directory - std::string texturedir; // texture directory - bool discardvisual; // discard visual geoms in parser - bool convexhull; // compute mesh convex hulls - bool usethread; // use multiple threads to speed up compiler - bool fusestatic; // fuse static bodies with parent - int inertiafromgeom; // use geom inertias (mjtInertiaFromGeom) - int inertiagrouprange[2]; // range of geom groups used to compute inertia - bool exactmeshinertia; // if false, use old formula - mjLROpt LRopt; // options for lengthrange computation - //------------------------ engine data std::string modelname; // model name mjOption option; // options @@ -307,5 +295,11 @@ class mjCModel : private mjmModel { mjCError errInfo; // last error info int fixCount; // how many bodies have been fixed std::vector qpos0; // save qpos0, to recognize changed key_qpos in write + + // variable-size attributes + std::string meshdir_; + std::string texturedir_; + std::string spec_meshdir_; + std::string spec_texturedir_; }; #endif // MUJOCO_SRC_USER_USER_MODEL_H_ diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index 6e55fcbe..2fcd2fcd 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -1246,7 +1246,7 @@ void mjCFrame::Compile() { } CopyFromSpec(); - const char* err = alt_.Set(quat, model->degree, model->euler); + const char* err = alt_.Set(quat, model->spec.degree, model->spec.euler); if (err) { throw mjCError(this, "orientation specification error '%s' in site %d", err, id); } @@ -2599,7 +2599,7 @@ void mjCHField::Compile(const mjVFS* vfs) { throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str()); } - string filename = mjuu_makefullname(model->modelfiledir, model->meshdir, file_); + string filename = mjuu_makefullname(model->modelfiledir, model->meshdir_, file_); mjResource* resource = LoadResource(filename, vfs); try { @@ -3218,7 +3218,7 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) { } // make filename - string filename = mjuu_makefullname(model->modelfiledir, model->texturedir, cubefiles_[i]); + string filename = mjuu_makefullname(model->modelfiledir, model->texturedir_, cubefiles_[i]); // load PNG or custom unsigned int w, h; @@ -3318,7 +3318,7 @@ void mjCTexture::Compile(const mjVFS* vfs) { } // make filename - string filename = mjuu_makefullname(model->modelfiledir, model->texturedir, file_); + string filename = mjuu_makefullname(model->modelfiledir, model->texturedir_, file_); // dispatch if (type==mjTEXTURE_2D) { diff --git a/src/xml/xml.cc b/src/xml/xml.cc index a8f29685..95e169ee 100644 --- a/src/xml/xml.cc +++ b/src/xml/xml.cc @@ -376,9 +376,9 @@ mjCModel* mjParseXML(const char* filename, const mjVFS* vfs, // set reasonable default for parsing a URDF // this is separate from the Parser to allow multiple URDFs to be loaded. - model->strippath = true; - model->fusestatic = true; - model->discardvisual = true; + model->spec.strippath = true; + model->spec.fusestatic = true; + model->spec.discardvisual = true; parser.SetModel(model); parser.Parse(root); diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 9449878c..37776f2d 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -818,7 +818,7 @@ void mjXReader::Parse(XMLElement* root) { for (XMLElement* section = FirstChildElement(root, "compiler"); section; section = NextSiblingElement(section, "compiler")) { - Compiler(section, model); + Compiler(section, &model->spec); } for (XMLElement* section = FirstChildElement(root, "option"); section; @@ -909,7 +909,7 @@ void mjXReader::Parse(XMLElement* root) { // compiler section parser -void mjXReader::Compiler(XMLElement* section, mjCModel* mod) { +void mjXReader::Compiler(XMLElement* section, mjmModel* mod) { string text; int n; @@ -945,12 +945,17 @@ void mjXReader::Compiler(XMLElement* section, mjCModel* mod) { memcpy(mod->euler, text.c_str(), 3); } if (ReadAttrTxt(section, "assetdir", text)) { - mod->meshdir = text; - mod->texturedir = text; + mjm_setString(mod->meshdir, text.c_str()); + mjm_setString(mod->texturedir, text.c_str()); } // meshdir and texturedir take precedence over assetdir - ReadAttrTxt(section, "meshdir", mod->meshdir); - ReadAttrTxt(section, "texturedir", mod->texturedir); + std::string meshdir, texturedir; + if (ReadAttrTxt(section, "meshdir", meshdir)) { + mjm_setString(mod->meshdir, meshdir.c_str()); + }; + if (ReadAttrTxt(section, "texturedir", texturedir)) { + mjm_setString(mod->texturedir, texturedir.c_str()); + } if (MapValue(section, "discardvisual", &n, bool_map, 2)) { mod->discardvisual = (n==1); } diff --git a/src/xml/xml_native_reader.h b/src/xml/xml_native_reader.h index 289a5370..51a3bb8f 100644 --- a/src/xml/xml_native_reader.h +++ b/src/xml/xml_native_reader.h @@ -43,7 +43,7 @@ class mjXReader : public mjXBase { void SetTextureDir(std::string texturedir); // XML sections embedded in all formats - static void Compiler(tinyxml2::XMLElement* section, mjCModel* mod); // compiler section + static void Compiler(tinyxml2::XMLElement* section, mjmModel* mod); // compiler section static void Option(tinyxml2::XMLElement* section, mjOption* opt); // option section static void Size(tinyxml2::XMLElement* section, mjCModel* mod); // size section diff --git a/src/xml/xml_native_writer.cc b/src/xml/xml_native_writer.cc index 1aa48403..43efe352 100644 --- a/src/xml/xml_native_writer.cc +++ b/src/xml/xml_native_writer.cc @@ -821,11 +821,11 @@ void mjXWriter::Compiler(XMLElement* root) { WriteAttrTxt(section, "convexhull", FindValue(bool_map, 2, model->convexhull)); } WriteAttrTxt(section, "angle", "radian"); - if (!model->meshdir.empty()) { - WriteAttrTxt(section, "meshdir", model->meshdir); + if (!model->get_meshdir().empty()) { + WriteAttrTxt(section, "meshdir", model->get_meshdir()); } - if (!model->texturedir.empty()) { - WriteAttrTxt(section, "texturedir", model->texturedir); + if (!model->get_texturedir().empty()) { + WriteAttrTxt(section, "texturedir", model->get_texturedir()); } if (!model->usethread) { WriteAttrTxt(section, "usethread", "false"); diff --git a/src/xml/xml_urdf.cc b/src/xml/xml_urdf.cc index 3f57bc20..fc31f5c5 100644 --- a/src/xml/xml_urdf.cc +++ b/src/xml/xml_urdf.cc @@ -93,7 +93,7 @@ void mjXURDF::Parse( if (mjc) { XMLElement *section; if ((section = FindSubElem(mjc, "compiler"))) { - mjXReader::Compiler(section, model); + mjXReader::Compiler(section, &model->spec); } if ((section = FindSubElem(mjc, "option"))) { @@ -106,7 +106,7 @@ void mjXURDF::Parse( } // enforce required compiler defaults for URDF - model->degree = false; + model->spec.degree = false; // get model name ReadAttrTxt(root, "name", model->modelname); @@ -310,7 +310,7 @@ void mjXURDF::Body(XMLElement* body_elem) { } } // create geom if not discarded - if (!model->discardvisual) { + if (!model->spec.discardvisual) { pgeom = Geom(elem, pbody, false); // save color @@ -563,7 +563,7 @@ mjmGeom* mjXURDF::Geom(XMLElement* geom_elem, mjmBody* pbody, bool collision) { .value_or(default_meshscale); // strip file name if necessary - if (model->strippath) { + if (model->spec.strippath) { meshfile = mjuu_strippath(meshfile); }