From 259d3876ce6816f8572330118487f5f80c4295fa Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Thu, 2 May 2024 05:26:25 -0700 Subject: [PATCH] Remove C-style vectors from user_mesh. PiperOrigin-RevId: 630031676 Change-Id: I87cba3eb816095657acd886037af2c0f06fe4fdd --- src/user/user_flexcomp.cc | 15 +- src/user/user_mesh.cc | 748 ++++++++++++++++---------------------- src/user/user_objects.h | 51 ++- 3 files changed, 334 insertions(+), 480 deletions(-) diff --git a/src/user/user_flexcomp.cc b/src/user/user_flexcomp.cc index 6e7c08d2..9d8bc0ca 100644 --- a/src/user/user_flexcomp.cc +++ b/src/user/user_flexcomp.cc @@ -935,29 +935,22 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) { // LoadOBJ uses userXXX, extra processing needed if (isobj) { // check sizes - if (mesh.get_uservert().empty() || mesh.get_userface().empty()) { + if (mesh.vert_.empty() || mesh.face_.empty()) { return comperr(error, "Vertex and face data required", error_sz); } - if (mesh.get_uservert().size()%3) { + if (mesh.vert_.size()%3) { return comperr(error, "Vertex data must be multiple of 3", error_sz); } - if (mesh.get_userface().size()%3) { + if (mesh.face_.size()%3) { return comperr(error, "Face data must be multiple of 3", error_sz); } - // copy vectors and clear - mesh.nvert_ = mesh.uservert_.size()/3; - mesh.nface_ = mesh.userface_.size()/3; - mesh.vert_ = VecToArray(mesh.uservert_, true); - mesh.face_ = VecToArray(mesh.userface_, true); - // remove repeated vertices (not called in LoadOBJ) mesh.RemoveRepeated(); } // copy faces - element = vector (mesh.nface()*3); - memcpy(element.data(), mesh.face_, mesh.nface_*3*sizeof(int)); + element = mesh.face_; // copy vertices, convert from float to mjtNum point = vector (mesh.nvert()*3); diff --git a/src/user/user_mesh.cc b/src/user/user_mesh.cc index 00103c73..d7cb49c7 100644 --- a/src/user/user_mesh.cc +++ b/src/user/user_mesh.cc @@ -80,7 +80,7 @@ static mjtNum _triangle(mjtNum* normal, mjtNum* center, const float* v1, const float* v2, const float* v3) { // center if (center) { - for (int i=0; i<3; i++) { + for (int i=0; i < 3; i++) { center[i] = (v1[i] + v2[i] + v3[i])/3; } } @@ -107,21 +107,6 @@ static mjtNum _triangle(mjtNum* normal, mjtNum* center, return len/2; } -template -static T* VecToArray(std::vector& vector, bool clear = true){ - if (vector.empty()) - return nullptr; - else { - int n = (int)vector.size(); - T* cvec = (T*) mju_malloc(n*sizeof(T)); - memcpy(cvec, vector.data(), n*sizeof(T)); - if (clear) { - vector.clear(); - } - return cvec; - } -} - // Read data of type T from a potentially unaligned buffer pointer. template static void ReadFromBuffer(T* dst, const char* src) { @@ -146,18 +131,8 @@ mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) { mjuu_setvec(boxsz_volume_, 0, 0, 0); mjuu_setvec(aamm_, 1e10, 1e10, 1e10); mjuu_setvec(aamm_+3, -1e10, -1e10, -1e10); - nvert_ = 0; - nnormal_ = 0; - ntexcoord_ = 0; - nface_ = 0; szgraph_ = 0; - vert_ = NULL; - normal_ = NULL; center_ = NULL; - texcoord_ = NULL; - face_ = NULL; - facenormal_ = NULL; - facetexcoord_ = NULL; graph_ = NULL; needhull_ = false; invalidorientation_.first = -1; @@ -198,55 +173,13 @@ mjCMesh& mjCMesh::operator=(const mjCMesh& other) { this->spec = other.spec; *static_cast(this) = static_cast(other); *static_cast(this) = static_cast(other); - if (other.vert_) { - size_t nvert = 3*other.nvert_*sizeof(float); - this->vert_ = (float*)mju_malloc(nvert); - memcpy(this->vert_, other.vert_, nvert); - } else { - this->vert_ = NULL; - } - if (other.normal_) { - size_t nnormal = 3*other.nnormal_*sizeof(float); - this->normal_ = (float*)mju_malloc(nnormal); - memcpy(this->normal_, other.normal_, nnormal); - } else { - this->normal_ = NULL; - } if (other.center_) { - size_t ncenter = 3*other.nface_*sizeof(double); + size_t ncenter = 3*other.nface()*sizeof(double); this->center_ = (double*)mju_malloc(ncenter); memcpy(this->center_, other.center_, ncenter); } else { this->center_ = NULL; } - if (other.texcoord_) { - size_t ntexcoord = 2*other.ntexcoord_*sizeof(float); - this->texcoord_ = (float*)mju_malloc(ntexcoord); - memcpy(this->texcoord_, other.texcoord_, ntexcoord); - } else { - this->texcoord_ = NULL; - } - if (other.face_) { - size_t nface = 3*other.nface_*sizeof(int); - this->face_ = (int*)mju_malloc(nface); - memcpy(this->face_, other.face_, nface); - } else { - this->face_ = NULL; - } - if (other.facenormal_) { - size_t nfacenormal = 3*other.nface_*sizeof(int); - this->facenormal_ = (int*)mju_malloc(nfacenormal); - memcpy(this->facenormal_, other.facenormal_, nfacenormal); - } else { - this->facenormal_ = NULL; - } - if (other.facetexcoord_) { - size_t nfacetexcoord = 3*other.nface_*sizeof(int); - this->facetexcoord_ = (int*)mju_malloc(nfacetexcoord); - memcpy(this->facetexcoord_, other.facetexcoord_, nfacetexcoord); - } else { - this->facetexcoord_ = NULL; - } if (other.graph_) { size_t szgraph = szgraph_*sizeof(int); this->graph_ = (int*)mju_malloc(szgraph); @@ -267,10 +200,11 @@ void mjCMesh::PointToLocal() { spec.classname = (mjString)&classname; spec.file = (mjString)&spec_file_; spec.content_type = (mjString)&spec_content_type_; - spec.uservert = (mjFloatVec)&spec_uservert_; - spec.usernormal = (mjFloatVec)&spec_usernormal_; - spec.userface = (mjIntVec)&spec_userface_; - spec.usertexcoord = (mjFloatVec)&spec_usertexcoord_; + spec.uservert = (mjFloatVec)&spec_vert_; + spec.usernormal = (mjFloatVec)&spec_normal_; + spec.userface = (mjIntVec)&spec_face_; + spec.usertexcoord = (mjFloatVec)&spec_texcoord_; + spec.userfacetexcoord = (mjIntVec)&spec_facetexcoord_; spec.plugin.name = (mjString)&plugin_name; spec.plugin.instance_name = (mjString)&plugin_instance_name; spec.info = (mjString)&info; @@ -282,55 +216,35 @@ void mjCMesh::CopyFromSpec() { *static_cast(this) = spec; file_ = spec_file_; content_type_ = spec_content_type_; - uservert_ = spec_uservert_; - usernormal_ = spec_usernormal_; - userface_ = spec_userface_; - usertexcoord_ = spec_usertexcoord_; + vert_ = spec_vert_; + normal_ = spec_normal_; + face_ = spec_face_; + texcoord_ = spec_texcoord_; + facetexcoord_ = spec_facetexcoord_; file = (mjString)&file_; content_type = (mjString)&content_type_; - uservert = (mjFloatVec)&uservert_; - usernormal = (mjFloatVec)&usernormal_; - userface = (mjIntVec)&userface_; - usertexcoord = (mjFloatVec)&usertexcoord_; + uservert = (mjFloatVec)&vert_; + usernormal = (mjFloatVec)&normal_; + userface = (mjIntVec)&face_; + usertexcoord = (mjFloatVec)&texcoord_; + userfacetexcoord = (mjIntVec)&facetexcoord_; plugin.active = spec.plugin.active; plugin.instance = spec.plugin.instance; plugin.name = spec.plugin.name; plugin.instance_name = spec.plugin.instance_name; // clear precompiled asset. TODO: use asset cache - if (vert_) mju_free(vert_); - if (normal_) mju_free(normal_); - if (texcoord_) mju_free(texcoord_); if (center_) mju_free(center_); - if (face_) mju_free(face_); - if (facenormal_) mju_free(facenormal_); - if (facetexcoord_) mju_free(facetexcoord_); if (graph_) mju_free(graph_); - nvert_= 0; - nnormal_ = 0; - ntexcoord_ = 0; - nface_ = 0; szgraph_ = 0; - vert_ = NULL; - normal_ = NULL; center_ = NULL; - texcoord_ = NULL; - face_ = NULL; - facenormal_ = NULL; - facetexcoord_ = NULL; graph_ = NULL; } mjCMesh::~mjCMesh() { - if (vert_) mju_free(vert_); - if (normal_) mju_free(normal_); - if (texcoord_) mju_free(texcoord_); if (center_) mju_free(center_); - if (face_) mju_free(face_); - if (facenormal_) mju_free(facenormal_); - if (facetexcoord_) mju_free(facetexcoord_); if (graph_) mju_free(graph_); } @@ -419,9 +333,9 @@ void mjCMesh::LoadSDF() { userface.push_back(mesh.indices.at(i)); } - uservert_ = std::move(uservert); - usernormal_ = std::move(usernormal); - userface_ = std::move(userface); + vert_ = std::move(uservert); + normal_ = std::move(usernormal); + face_ = std::move(userface); delete[] field; } @@ -431,15 +345,22 @@ void mjCMesh::LoadSDF() { void mjCMesh::Compile(const mjVFS* vfs) { CopyFromSpec(); visual_ = true; + std::string asset_type = GetAssetContentType(file_, content_type_); // load file if (!file_.empty()) { + vert_.clear(); + face_.clear(); + normal_.clear(); + texcoord_.clear(); + facenormal_.clear(); + facetexcoord_.clear(); + // remove path from file if necessary if (model->strippath) { file_ = mjuu_strippath(file_); } - std::string asset_type = GetAssetContentType(file_, content_type_); if (asset_type.empty()) { throw mjCError(this, "unknown mesh content type for file: '%s'", file_.c_str()); } @@ -465,6 +386,38 @@ void mjCMesh::Compile(const mjVFS* vfs) { mju_closeResource(resource); throw err; } + + // check repeated mesh data + if (!vert_.empty() && !spec_vert_.empty()) { + throw mjCError(this, "repeated vertex specification"); + } else if (vert_.empty()) { + vert_ = spec_vert_; + } + if (!normal_.empty() && !spec_normal_.empty()) { + throw mjCError(this, "repeated normal specification"); + } else if (normal_.empty()) { + normal_ = spec_normal_; + } + if (!texcoord_.empty() && !spec_texcoord_.empty()) { + throw mjCError(this, "repeated texcoord specification"); + } else if (texcoord_.empty()) { + texcoord_ = spec_texcoord_; + } + if (!face_.empty() && !spec_face_.empty()) { + throw mjCError(this, "repeated face specification"); + } else if (face_.empty()) { + face_ = spec_face_; + } + if (!facenormal_.empty() && !spec_normal_.empty()) { + throw mjCError(this, "repeated facenormal specification"); + } else if (facenormal_.empty()) { + facenormal_ = spec_facenormal_; + } + if (!facetexcoord_.empty() && !spec_facetexcoord_.empty()) { + throw mjCError(this, "repeated facetexcoord specification"); + } else if (facetexcoord_.empty()) { + facetexcoord_ = spec_facetexcoord_; + } } // create using marching cubes @@ -472,179 +425,98 @@ void mjCMesh::Compile(const mjVFS* vfs) { LoadSDF(); } - // copy user vertex - if (!uservert_.empty()) { - // check repeated - if (vert_) { - throw mjCError(this, "repeated vertex specification"); - } + // check sizes + if (vert_.size()<12) throw mjCError(this, "at least 4 vertices required"); + if (vert_.size()%3) throw mjCError(this, "vertex data must be a multiple of 3"); + if (normal_.size()%3) throw mjCError(this, "normal data must be a multiple of 3"); + if (texcoord_.size()%2) throw mjCError(this, "texcoord must be a multiple of 2"); + if (face_.size()%3) throw mjCError(this, "face data must be a multiple of 3"); - // check size - if (uservert_.size()<12) { - throw mjCError(this, "at least 4 vertices required"); - } - if (uservert_.size()%3) { - throw mjCError(this, "vertex data must be a multiple of 3"); - } - - // copy from user - nvert_ = (int)uservert_.size()/3; - vert_ = VecToArray(uservert_, !file_.empty()); + // check texcoord size if no face texcoord indices are given + if (!texcoord_.empty() && texcoord_.size() != 2 * nvert() && + facetexcoord_.empty() && asset_type != "model/obj") { + throw mjCError(this, + "texcoord must be 2*nv if face texcoord indices are not provided in an OBJ file"); } - // copy user normal - if (!usernormal_.empty()) { - // check repeated - if (normal_) { - throw mjCError(this, "repeated normal specification"); + // check vertices exist + for (int i=0; i < face_.size(); i++) { + if (face_[i] >= nvert() || face_[i] < 0) { + throw mjCError(this, "in face %d, vertex index %d does not exist", + nullptr, i / 3, face_[i]); } - - // check size - if (usernormal_.size()%3) { - throw mjCError(this, "normal data must be a multiple of 3"); - } - - // copy from user - nnormal_ = (int)usernormal_.size()/3; - normal_ = VecToArray(usernormal_, !file_.empty()); } - // copy user texcoord - if (!usertexcoord_.empty()) { - // check repeated - if (texcoord_) { - throw mjCError(this, "repeated texcoord specification"); + // create half-edge structure (if mesh was in XML) + if (halfedge_.empty()) { + for (int i=0; i < face_.size()/3; i++) { + int v0 = face_[3*i+0]; + int v1 = face_[3*i+1]; + int v2 = face_[3*i+2]; + mjtNum normal[3]; + float* vtx = vert_.data(); + if (_triangle(normal, nullptr, vtx+3*v0, vtx+3*v1, vtx+3*v2)>sqrt(mjMINVAL)) { + halfedge_.push_back(std::pair(v0, v1)); + halfedge_.push_back(std::pair(v1, v2)); + halfedge_.push_back(std::pair(v2, v0)); + } else { + // TODO(b/255525326) + } } - - // check size - if (usertexcoord_.size()%2) { - throw mjCError(this, "texcoord must be a multiple of 2"); - } - - // check size if no face texcoord indices are given - if (usertexcoord_.size() != 2*nvert_ && userfacetexcoord_.empty()) { - throw mjCError(this, - "texcoord must be 2*nv if face texcoord indices are not provided in an OBJ file"); - } - - // copy from user - ntexcoord_ = (int)usertexcoord_.size()/2; - texcoord_ = VecToArray(usertexcoord_, !file_.empty()); } - // copy user face - if (!userface_.empty()) { - // check repeated - if (face_) { - throw mjCError(this, "repeated face specification"); - } - - // check size - if (userface_.size()%3) { - throw mjCError(this, "face data must be a multiple of 3"); - } - - // check vertices exist - for (int i=0; i= nvert_ || userface_[i] < 0) { - throw mjCError(this, "in face %d, vertex index %d does not exist", - nullptr, i / 3, userface_[i]); - } - } - - // create half-edge structure (if mesh was in XML) - if (useredge_.empty()) { - for (int i=0; isqrt(mjMINVAL)) { - useredge_.push_back(std::pair(v0, v1)); - useredge_.push_back(std::pair(v1, v2)); - useredge_.push_back(std::pair(v2, v0)); - } else { - // TODO(b/255525326) - } - } - } - - // copy from user - nface_ = (int)userface_.size()/3; - face_ = VecToArray(userface_, !file_.empty()); - - // check vertices exist - for (auto vertex_index : userface_) { - if (vertex_index>=nvert_ || vertex_index < 0) { - throw mjCError(this, "found index in userface that exceeds uservert size."); - } + // check vertices exist + for (auto vertex_index : face_) { + if (vertex_index>=nvert() || vertex_index < 0) { + throw mjCError(this, "found index in userface that exceeds uservert size."); } } // check for inconsistent face orientations - if (!useredge_.empty()) { - std::stable_sort(useredge_.begin(), useredge_.end()); - auto iterator = std::adjacent_find(useredge_.begin(), useredge_.end()); - if (iterator != useredge_.end()) { + if (!halfedge_.empty()) { + std::stable_sort(halfedge_.begin(), halfedge_.end()); + auto iterator = std::adjacent_find(halfedge_.begin(), halfedge_.end()); + if (iterator != halfedge_.end()) { invalidorientation_.first = iterator->first+1; invalidorientation_.second = iterator->second+1; } } // require vertices - if (!vert_) { + if (vert_.empty()) { throw mjCError(this, "no vertices"); } // make graph describing convex hull - if ((model->convexhull && needhull_) || !face_) { + if ((model->convexhull && needhull_) || face_.empty()) { MakeGraph(); } // no faces: copy from convex hull - if (!face_) { + if (face_.empty()) { CopyGraph(); } // no normals: make - if (!normal_) { + if (normal_.empty()) { MakeNormal(); } - // copy user normal indices - if (!userfacenormal_.empty()) { - // check repeated - if (facenormal_) { - throw mjCError(this, "repeated facenormal specification"); - } - - if (userfacenormal_.size()!=3*nface_) { - throw mjCError(this, "face data must have the same size as face normal data"); - } - - facenormal_ = VecToArray(userfacenormal_, !file_.empty()); - } - - // copy user texcoord - if (!userfacetexcoord_.empty()) { - // check repeated - if (facetexcoord_) { - throw mjCError(this, "repeated facetexcoord specification"); - } - - facetexcoord_ = VecToArray(userfacetexcoord_, !file_.empty()); + // check facenormal size + if (!facenormal_.empty() && facenormal_.size()!=3*nface()) { + throw mjCError(this, "face data must have the same size as face normal data"); } // no facetexcoord: copy from faces - if (!facetexcoord_ && texcoord_) { - facetexcoord_ = (int*) mju_malloc(3*nface_*sizeof(int)); - memcpy(facetexcoord_, face_, 3*nface_*sizeof(int)); + if (facetexcoord_.empty() && !texcoord_.empty()) { + facetexcoord_.assign(3*nface(), 0); + memcpy(facetexcoord_.data(), face_.data(), 3*nface()*sizeof(int)); } // facenormal might not exist if usernormal was specified - if (!facenormal_) { - facenormal_ = (int*) mju_malloc(3*nface_*sizeof(int)); - memcpy(facenormal_, face_, 3*nface_*sizeof(int)); + if (facenormal_.empty()) { + facenormal_.assign(3*nface(), 0); + memcpy(facenormal_.data(), face_.data(), 3*nface()*sizeof(int)); } // scale, center, orient, compute mass and inertia @@ -658,9 +530,9 @@ void mjCMesh::Compile(const mjVFS* vfs) { // make bounding volume hierarchy if (tree_.bvh.empty()) { - face_aabb_.assign(6*nface_, 0); - tree_.AllocateBoundingVolumes(nface_); - for (int i=0; isize[0] = 0; - for (int i=0; isize[0] = mju_max(geom->size[0], dst); @@ -850,7 +721,7 @@ void mjCMesh::FitGeom(mjCGeom* geom, double* meshpos) { // find maximum distance in XY, separately in Z geom->size[0] = 0; geom->size[1] = 0; - for (int i=0; itype==mjGEOM_CAPSULE) { geom->size[1] = 0; - for (int i=0; i(new int[nvert_]); - auto redirect = std::unique_ptr(new int[nvert_]); - for (int i=0; i < nvert_; i++) { + auto index = std::unique_ptr(new int[nvert()]); + auto redirect = std::unique_ptr(new int[nvert()]); + for (int i=0; i < nvert(); i++) { index[i] = redirect[i] = i; } // sort vertices - mjQUICKSORT(index.get(), nvert_, sizeof(int), vertcompare, vert_); + mjQUICKSORT(index.get(), nvert(), sizeof(int), vertcompare, vert_.data()); // find repeated vertices, set redirect - for (int i=1; i < nvert_; i++) { + for (int i=1; i < nvert(); i++) { if (vert_[3*index[i]] == vert_[3*index[i-1]] && vert_[3*index[i]+1] == vert_[3*index[i-1]+1] && vert_[3*index[i]+2] == vert_[3*index[i-1]+2]) { @@ -940,7 +811,7 @@ void mjCMesh::RemoveRepeated() { // compress vertices, change face data if (repeated) { // track redirections until non-redirected vertex, set - for (int i=0; i=nvert_-repeated) { + if (face_[i]<0 || face_[i]>=nvert()-repeated) { throw mjCError( this, "error removing vertices from mesh '%s'", name.c_str()); } } } - // correct vertex count - nvert_ -= repeated; - // resize vert if any vertices were removed if (repeated) { - float* old = vert_; - vert_ = (float*) mju_malloc(3*nvert_*sizeof(float)); - memcpy(vert_, old, 3*nvert_*sizeof(float)); - mju_free(old); + std::vector old = vert_; + vert_.assign(3*(nvert()-repeated), 0); + memcpy(vert_.data(), old.data(), 3*nvert()*sizeof(float)); } } @@ -1016,9 +883,11 @@ void mjCMesh::LoadOBJ(mjResource* resource) { } const auto& attrib = objReader.GetAttrib(); - uservert_ = attrib.vertices; // copy from one std::vector to another - usernormal_ = attrib.normals; - usertexcoord_ = attrib.texcoords; + vert_ = attrib.vertices; // copy from one std::vector to another + normal_ = attrib.normals; + texcoord_ = attrib.texcoords; + facenormal_.clear(); + facetexcoord_.clear(); if (!objReader.GetShapes().empty()) { const auto& mesh = objReader.GetShapes()[0].mesh; @@ -1049,30 +918,30 @@ void mjCMesh::LoadOBJ(mjResource* resource) { // for each vertex, store index, normal, and texcoord for (const auto& mesh_index : face_indices) { - userface_.push_back(mesh_index.vertex_index); + face_.push_back(mesh_index.vertex_index); - if (!usernormal_.empty()) { - userfacenormal_.push_back(mesh_index.normal_index); + if (!normal_.empty()) { + facenormal_.push_back(mesh_index.normal_index); } - if (!usertexcoord_.empty()) { - userfacetexcoord_.push_back(mesh_index.texcoord_index); + if (!texcoord_.empty()) { + facetexcoord_.push_back(mesh_index.texcoord_index); } } } // flip the second texcoord - for (int i=0; iname, resource->timestamp); - asset.AddVector("uservert_", uservert_); - asset.AddVector("usernormal_", usernormal_); - asset.AddVector("usertexcoord_", usertexcoord_); + asset.AddVector("vert_", vert_); + asset.AddVector("normal_", normal_); + asset.AddVector("texcoord_", texcoord_); if (!objReader.GetShapes().empty()) { const auto& mesh = objReader.GetShapes()[0].mesh; @@ -1110,15 +979,15 @@ void mjCMesh::LoadOBJ(mjResource* resource) { // load OBJ from cached asset, return true on success bool mjCMesh::LoadCachedOBJ(const mjCAsset& asset) { // check that asset has all data - if (!asset.HasData("uservert_") || !asset.HasData("usernormal_") - || !asset.HasData("usertexcoord_") || !asset.HasData("num_face_vertices") + if (!asset.HasData("vert_") || !asset.HasData("normal_") + || !asset.HasData("texcoord_") || !asset.HasData("num_face_vertices") || !asset.HasData("vertex_index") || !asset.HasData("normal_index") || !asset.HasData("texcoord_index")) { return false; } - uservert_ = asset.GetVector("uservert_").value(); - usernormal_ = asset.GetVector("usernormal_").value(); - usertexcoord_ = asset.GetVector("usertexcoord_").value(); + vert_ = asset.GetVector("vert_").value(); + normal_ = asset.GetVector("normal_").value(); + texcoord_ = asset.GetVector("texcoord_").value(); vector vertex_index = asset.GetVector("vertex_index").value(); vector normal_index = asset.GetVector("normal_index").value(); @@ -1137,37 +1006,37 @@ bool mjCMesh::LoadCachedOBJ(const mjCAsset& asset) { asset.Id().c_str()); } - userface_.push_back(vertex_index[i]); - userface_.push_back(vertex_index[i + (righthand == 1 ? 1 : 2)]); - userface_.push_back(vertex_index[i + (righthand == 1 ? 2 : 1)]); + face_.push_back(vertex_index[i]); + face_.push_back(vertex_index[i + (righthand == 1 ? 1 : 2)]); + face_.push_back(vertex_index[i + (righthand == 1 ? 2 : 1)]); - if (!usernormal_.empty()) { - userfacenormal_.push_back(normal_index[i]); - userfacenormal_.push_back(normal_index[i + (righthand == 1 ? 1 : 2)]); - userfacenormal_.push_back(normal_index[i + (righthand == 1 ? 2 : 1)]); + if (!normal_.empty()) { + facenormal_.push_back(normal_index[i]); + facenormal_.push_back(normal_index[i + (righthand == 1 ? 1 : 2)]); + facenormal_.push_back(normal_index[i + (righthand == 1 ? 2 : 1)]); } - if (!usertexcoord_.empty()) { - userfacetexcoord_.push_back(texcoord_index[i]); - userfacetexcoord_.push_back(texcoord_index[i + (righthand == 1 ? 1 : 2)]); - userfacetexcoord_.push_back(texcoord_index[i + (righthand == 1 ? 2 : 1)]); + if (!texcoord_.empty()) { + facetexcoord_.push_back(texcoord_index[i]); + facetexcoord_.push_back(texcoord_index[i + (righthand == 1 ? 1 : 2)]); + facetexcoord_.push_back(texcoord_index[i + (righthand == 1 ? 2 : 1)]); } if (nfacevert == 4) { - userface_.push_back(vertex_index[i]); - userface_.push_back(vertex_index[i + (righthand == 1 ? 2 : 3)]); - userface_.push_back(vertex_index[i + (righthand == 1 ? 3 : 2)]); + face_.push_back(vertex_index[i]); + face_.push_back(vertex_index[i + (righthand == 1 ? 2 : 3)]); + face_.push_back(vertex_index[i + (righthand == 1 ? 3 : 2)]); - if (!usernormal_.empty()) { - userfacenormal_.push_back(normal_index[i]); - userfacenormal_.push_back(normal_index[i + (righthand == 1 ? 1 : 2)]); - userfacenormal_.push_back(normal_index[i + (righthand == 1 ? 2 : 1)]); + if (!normal_.empty()) { + facenormal_.push_back(normal_index[i]); + facenormal_.push_back(normal_index[i + (righthand == 1 ? 1 : 2)]); + facenormal_.push_back(normal_index[i + (righthand == 1 ? 2 : 1)]); } - if (!usertexcoord_.empty()) { - userfacetexcoord_.push_back(texcoord_index[i]); - userfacetexcoord_.push_back(texcoord_index[i + (righthand == 1 ? 1 : 2)]); - userfacetexcoord_.push_back(texcoord_index[i + (righthand == 1 ? 2 : 1)]); + if (!texcoord_.empty()) { + facetexcoord_.push_back(texcoord_index[i]); + facetexcoord_.push_back(texcoord_index[i + (righthand == 1 ? 1 : 2)]); + facetexcoord_.push_back(texcoord_index[i + (righthand == 1 ? 2 : 1)]); } } i += nfacevert; @@ -1197,15 +1066,16 @@ void mjCMesh::LoadSTL(mjResource* resource) { } // get number of triangles, check bounds - ReadFromBuffer(&nface_, buffer + 80); - if (nface_<1 || nface_>200000) { + int nfaces = 0; + ReadFromBuffer(&nfaces, buffer + 80); + if (nfaces<1 || nfaces>200000) { throw mjCError(this, "number of faces should be between 1 and 200000 in STL file '%s';" " perhaps this is an ASCII file?", resource->name); } // check remaining buffer size - if (nface_*50 != buffer_sz-84) { + if (nfaces*50 != buffer_sz-84) { throw mjCError(this, "STL file '%s' has wrong size; perhaps this is an ASCII file?", resource->name); @@ -1215,11 +1085,11 @@ void mjCMesh::LoadSTL(mjResource* resource) { const char* stl = buffer + 84; // allocate face and vertex data - face_ = (int*) mju_malloc(3*nface_*sizeof(int)); - vert_ = (float*) mju_malloc(9*nface_*sizeof(float)); + face_.assign(3*nfaces, 0); + vert_.clear(); // add vertices and faces, including repeated for now - for (int i=0; i0 && nnormal_!=nvert_) || - (ntexcoord_>0 && ntexcoord_!=nvert_)) { + if (nvbuf<4 || nfbuf<0 || nnbuf<0 || ntbuf<0 || + (nnbuf>0 && nnbuf!=nvbuf) || + (ntbuf>0 && ntbuf!=nvbuf)) { throw mjCError(this, "invalid sizes in MSH file '%s'", resource->name); } - if (nvert_ >= INT_MAX / sizeof(float) / 3 || - nnormal_ >= INT_MAX / sizeof(float) / 3 || - ntexcoord_ >= INT_MAX / sizeof(float) / 2 || - nface_ >= INT_MAX / sizeof(int) / 3) { + if (nvbuf >= INT_MAX / sizeof(float) / 3 || + nnbuf >= INT_MAX / sizeof(float) / 3 || + ntbuf >= INT_MAX / sizeof(float) / 2 || + nfbuf >= INT_MAX / sizeof(int) / 3) { throw mjCError(this, "too large sizes in MSH file '%s'.", resource->name); } // check file size - if (buffer_sz != 4*sizeof(int) + 3*nvert_*sizeof(float) + 3*nnormal_*sizeof(float) + - 2*ntexcoord_*sizeof(float) + 3*nface_*sizeof(int)) { + if (buffer_sz != 4*sizeof(int) + 3*nvbuf*sizeof(float) + 3*nnbuf*sizeof(float) + + 2*ntbuf*sizeof(float) + 3*nfbuf*sizeof(int)) { throw mjCError(this, "unexpected file size in MSH file '%s'", resource->name); } // allocate and copy using UnalignedFloat = char[sizeof(float)]; auto fdata = reinterpret_cast(buffer + 4*sizeof(int)); - if (nvert_) { - vert_ = (float*) mju_malloc(3*nvert_*sizeof(float)); - memcpy(vert_, fdata, 3*nvert_*sizeof(float)); - fdata += 3*nvert_; + if (nvbuf) { + vert_.assign(3*nvbuf, 0); + memcpy(vert_.data(), fdata, 3*nvert()*sizeof(float)); + fdata += 3*nvert(); } - if (nnormal_) { - normal_ = (float*) mju_malloc(3*nvert_*sizeof(float)); - memcpy(normal_, fdata, 3*nvert_*sizeof(float)); - fdata += 3*nvert_; + if (nnbuf) { + normal_.assign(3*nvert(), 0); + memcpy(normal_.data(), fdata, 3*nvert()*sizeof(float)); + fdata += 3*nvert(); } - if (ntexcoord_) { - texcoord_ = (float*) mju_malloc(2*nvert_*sizeof(float)); - memcpy(texcoord_, fdata, 2*nvert_*sizeof(float)); - fdata += 2*nvert_; + if (ntbuf) { + texcoord_.assign(2*nvert(), 0); + memcpy(texcoord_.data(), fdata, 2*nvert()*sizeof(float)); + fdata += 2*nvert(); } - if (nface_) { - face_ = (int*) mju_malloc(3*nface_*sizeof(int)); - facenormal_ = (int*) mju_malloc(3*nface_*sizeof(int)); - memcpy(face_, fdata, 3*nface_*sizeof(int)); - memcpy(facenormal_, fdata, 3*nface_*sizeof(int)); + if (nfbuf) { + face_.assign(3*nfbuf, 0); + facenormal_.assign(3*nfbuf, 0); + memcpy(face_.data(), fdata, 3*nfbuf*sizeof(int)); + memcpy(facenormal_.data(), fdata, 3*nfbuf*sizeof(int)); } - if (nface_ && texcoord_) { - facetexcoord_= (int*) mju_malloc(3*nface_*sizeof(int)); - memcpy(facetexcoord_, fdata, 3*nface_*sizeof(int)); + if (nfbuf && !texcoord_.empty()) { + facetexcoord_.assign(3*nfbuf, 0); + memcpy(facetexcoord_.data(), fdata, 3*nfbuf*sizeof(int)); } // rearrange face data if left-handed scaling - if (nface_ && !righthand) { - for (int i=0; i=nvert_) { + if (face_[3*i+j]<0 || face_[3*i+j]>=nvert()) { throw mjCError(this, "vertex index out of range in %s (index = %d)", name.c_str(), i); } } // get area and center - double a = _triangle(nrm, cen, vert_+3*face_[3*i], vert_+3*face_[3*i+1], vert_+3*face_[3*i+2]); + float* vv = vert_.data(); + double a = _triangle(nrm, cen, vv+3*face_[3*i], vv+3*face_[3*i+1], vv+3*face_[3*i+2]); // accumulate for (int j=0; j<3; j++) { @@ -1524,7 +1398,7 @@ void mjCMesh::Process() { // re-center mesh at CoM if (type==mjINERTIA_VOLUME || validvolume_<=0) { - for (int i=0; ipoint); - if (pid<0 || pid>=nvert_) { + if (pid<0 || pid>=nvert()) { ok = 0; break; } @@ -1759,7 +1633,7 @@ void mjCMesh::MakeGraph(void) { // point id of face vertex, check int pid1 = qh_pointid(qh, vertex1->point); - if (pid1<0 || pid1>=nvert_) { + if (pid1<0 || pid1>=nvert()) { ok = 0; break; } @@ -1834,7 +1708,7 @@ void mjCMesh::MakeGraph(void) { } // replace global ids with local ids in edge data - for (int i=0; i=0) { // search vert_globalid for match int adr; @@ -1873,19 +1747,18 @@ void mjCMesh::MakeGraph(void) { // copy graph into face data void mjCMesh::CopyGraph(void) { // only if face data is missing - if (face_) { + if (!face_.empty()) { return; } // get info from graph, allocate int numvert = graph_[0]; - nface_ = graph_[1]; - face_ = (int*) mju_malloc(3*nface_*sizeof(int)); + face_.assign(3*graph_[1], 0); // copy faces - for (int i=0; iprefix + spec_bodyname_[i] + m->suffix; + for (auto& name : spec_bodyname_) { + name = m->prefix + name + m->suffix; } } @@ -2180,7 +2050,7 @@ mjCSkin::~mjCSkin() { void mjCSkin::ResolveReferences(const mjCModel* m) { size_t nbone = bodyname_.size(); bodyid.resize(nbone); - for (int i=0; iFindObject(mjOBJ_BODY, bodyname_[i]); if (!pbody) { throw mjCError(this, "unknown body '%s' in skin", bodyname_[i].c_str()); @@ -2288,7 +2158,7 @@ void mjCSkin::Compile(const mjVFS* vfs) { fill(vw.begin(), vw.end(), 0.0f); // accumulate vertex weights from all bones - for (int i=0; iname, i); @@ -2534,8 +2404,8 @@ void mjCFlex::PointToLocal() { void mjCFlex::NameSpace(const mjCModel* m) { - for (int i=0; i<(int)spec_vertbody_.size(); i++) { - spec_vertbody_[i] = m->prefix + spec_vertbody_[i] + m->suffix; + for (auto& name : spec_vertbody_) { + name = m->prefix + name + m->suffix; } } @@ -2574,12 +2444,12 @@ void mjCFlex::DelTexcoord() { void mjCFlex::ResolveReferences(const mjCModel* m) { - for (int i=0; i<(int)vertbody_.size(); i++) { - mjCBase* pbody = m->FindObject(mjOBJ_BODY, vertbody_[i]); + for (const auto& vertbody : vertbody_) { + mjCBase* pbody = m->FindObject(mjOBJ_BODY, vertbody); if (pbody) { vertbodyid.push_back(pbody->id); } else { - throw mjCError(this, "unkown body '%s' in flex", vertbody_[i].c_str()); + throw mjCError(this, "unkown body '%s' in flex", vertbody.c_str()); } } } @@ -2626,8 +2496,8 @@ void mjCFlex::Compile(const mjVFS* vfs) { } // check elem vertex ids - for (int i=0; i<(int)elem_.size(); i++) { - if (elem_[i]<0 || elem_[i]>=nvert) { + for (const auto& elem : elem_) { + if (elem<0 || elem>=nvert) { throw mjCError(this, "elem vertex id out of range"); } } @@ -2666,7 +2536,7 @@ void mjCFlex::Compile(const mjVFS* vfs) { // determine rigid if not already set if (!rigid) { rigid = true; - for (int i=1; i<(int)vertbodyid.size(); i++) { + for (unsigned i=1; i < vertbodyid.size(); i++) { if (vertbodyid[i]!=vertbodyid[0]) { rigid = false; break; @@ -2677,8 +2547,8 @@ void mjCFlex::Compile(const mjVFS* vfs) { // determine centered if not already set if (!centered) { centered = true; - for (int i=0; i<(int)vert_.size(); i++) { - if (vert_[i]!=0) { + for (const auto& vert : vert_) { + if (vert!=0) { centered = false; break; } @@ -2687,7 +2557,7 @@ void mjCFlex::Compile(const mjVFS* vfs) { // compute global vertex positions vertxpos = vector (3*nvert); - for (int i=0; ibodies[b]->xpos0); @@ -2732,7 +2602,7 @@ void mjCFlex::Compile(const mjVFS* vfs) { std::unordered_map, int, PairHash> edge_indices; // insert local edges into global vector - for (int f = 0; f < (int)elem_.size()/(dim+1); f++) { + for (unsigned f = 0; f < elem_.size()/(dim+1); f++) { int* v = elem_.data() + f*(dim+1); for (int e = 0; e < kNumEdges[dim-1]; e++) { auto pair = std::pair( @@ -2760,10 +2630,10 @@ void mjCFlex::Compile(const mjVFS* vfs) { mjXUtil::Vector2String(userface, elem_); mjXUtil::Vector2String(useredge, edgeidx); - for (int i=0; i<(int)vertbodyid.size(); i++) { - if (model->bodies[vertbodyid[i]]->plugin.instance) { + for (const auto& vbodyid : vertbodyid) { + if (model->bodies[vbodyid]->plugin.instance) { mjCPlugin* plugin_instance = - static_cast(model->bodies[vertbodyid[i]]->plugin.instance); + static_cast(model->bodies[vbodyid]->plugin.instance); plugin_instance->config_attribs["face"] = userface; plugin_instance->config_attribs["edge"] = useredge; } @@ -2799,7 +2669,7 @@ void mjCFlex::CreateBVH(void) { mjtNum xmin[3], xmax[3]; mju_copy3(xmin, vertxpos.data() + 3*edata[0]); mju_copy3(xmax, vertxpos.data() + 3*edata[0]); - for (int i=1; i<=dim; i++) { + for (int i=1; i <= dim; i++) { for (int j=0; j<3; j++) { xmin[j] = mjMIN(xmin[j], vertxpos[3*edata[i]+j]); xmax[j] = mjMAX(xmax[j], vertxpos[3*edata[i]+j]); @@ -2965,7 +2835,7 @@ void mjCFlex::CreateShellPair(void) { } // create shell - for (int i=0; i<(int)borderfrag.size(); i++) { + for (unsigned i=0; i < borderfrag.size(); i++) { if (borderfrag[i]) { // add fragment vertices, in original order shell.insert(shell.end(), fragspec[i].begin()+dim+1, fragspec[i].end()); @@ -2989,9 +2859,9 @@ void mjCFlex::CreateShellPair(void) { change = false; // process edges of element connectivity graph - for (int i=0; i<(int)connectspec.size(); i++) { - int e1 = connectspec[i][0]; // get element pair for this edge - int e2 = connectspec[i][1]; + for (const auto& connect : connectspec) { + int e1 = connect[0]; // get element pair for this edge + int e2 = connect[1]; if (elemlayer[e1]>elemlayer[e2]+1) { elemlayer[e1] = elemlayer[e2]+1; // better value found for e1: update change = true; @@ -3006,20 +2876,20 @@ void mjCFlex::CreateShellPair(void) { // create evpairs in 1D and 2D if (dim<3) { // process connected element pairs containing a border element - for (int n=0; n<(int)connectspec.size(); n++) { - if (border[connectspec[n][0]] || border[connectspec[n][1]]) { + for (const auto& connect : connectspec) { + if (border[connect[0]] || border[connect[1]]) { // extract common fragment - vector frag = {connectspec[n].begin()+2, connectspec[n].end()}; + vector frag = {connect.begin()+2, connect.end()}; // process both elements - for (int ei=0; ei<2; ei++) { - const int* edata = elem_.data() + connectspec[n][ei]*(dim+1); + for (int ei=0; ei < 2; ei++) { + const int* edata = elem_.data() + connect[ei]*(dim+1); // find element vertex that is not in the common fragment - for (int i=0; i<=dim; i++) { + for (int i=0; i <= dim; i++) { if (frag.end() == std::find(frag.begin(), frag.end(), edata[i])) { // add ev pair, involving the other element in connectspec - evpair.push_back(connectspec[n][1-ei]); + evpair.push_back(connect[1-ei]); evpair.push_back(edata[i]); // one such vertex exists diff --git a/src/user/user_objects.h b/src/user/user_objects.h index 91ad4f5c..068b1502 100644 --- a/src/user/user_objects.h +++ b/src/user/user_objects.h @@ -722,24 +722,25 @@ class mjCMesh_ : public mjCBase { std::string content_type_; // content type of file std::string file_; // mesh file - std::vector uservert_; // user vertex data - std::vector usernormal_; // user normal data - std::vector usertexcoord_; // user texcoord data - std::vector userface_; // user vertex indices - std::vector userfacenormal_; // user normal indices + std::vector vert_; // vertex data + std::vector normal_; // normal data + std::vector texcoord_; // texcoord data + std::vector face_; // vertex indices + std::vector facenormal_; // normal indices + std::vector facetexcoord_; // texcoord indices std::string spec_content_type_; std::string spec_file_; - std::vector spec_uservert_; - std::vector spec_usernormal_; - std::vector spec_usertexcoord_; - std::vector spec_userface_; - std::vector spec_userfacenormal_; + std::vector spec_vert_; + std::vector spec_normal_; + std::vector spec_texcoord_; + std::vector spec_face_; + std::vector spec_facenormal_; + std::vector spec_facetexcoord_; // used by the compiler bool visual_; // true: the mesh is only visual - std::vector userfacetexcoord_; // user texcoord indices - std::vector< std::pair > useredge_; // user half-edge data + std::vector< std::pair > halfedge_; // half-edge data // mesh properties that indicate a well-formed mesh std::pair invalidorientation_; // indices of invalid edge; -1 if none @@ -763,10 +764,6 @@ class mjCMesh_ : public mjCBase { double surface_; // surface of the mesh // size of mesh data to be copied into mjModel - int nvert_; // number of vertices - int nnormal_; // number of normals - int ntexcoord_; // number of texcoords - int nface_; // number of faces int szgraph_; // size of graph data in ints bool needhull_; // needs convex hull for collisions @@ -802,19 +799,19 @@ class mjCMesh: public mjCMesh_, private mjsMesh { void set_needhull(bool needhull); // public getters for user data - const std::vector& get_uservert() const { return uservert_; } - const std::vector& get_usernormal() const { return usernormal_; } - const std::vector& get_usertexcoord() const { return usertexcoord_; } - const std::vector& get_userface() const { return userface_; } + const std::vector& get_uservert() const { return spec_vert_; } + const std::vector& get_usernormal() const { return spec_normal_; } + const std::vector& get_usertexcoord() const { return spec_texcoord_; } + const std::vector& get_userface() const { return spec_face_; } // mesh properties computed by Compile const double* aamm() const { return aamm_; } // number of vertices, normals, texture coordinates, and faces - int nvert() const { return nvert_; } - int nnormal() const { return nnormal_; } - int ntexcoord() const { return ntexcoord_; } - int nface() const { return nface_; } + int nvert() const { return vert_.size()/3; } + int nnormal() const { return normal_.size()/3; } + int ntexcoord() const { return texcoord_.size()/2; } + int nface() const { return face_.size()/3; } // return size of graph data in ints int szgraph() const { return szgraph_; } @@ -863,13 +860,7 @@ class mjCMesh: public mjCMesh_, private mjsMesh { void CheckMesh(mjtGeomInertia type); // check if the mesh is valid // mesh data to be copied into mjModel - float* vert_; // vertex data (3*nvert), relative to (pos, quat) - float* normal_; // vertex normal data (3*nnormal) double* center_; // face circumcenter data (3*nface) - float* texcoord_; // vertex texcoord data (2*ntexcoord or NULL) - int* face_; // face vertex indices (3*nface) - int* facenormal_; // face normal indices (3*nface) - int* facetexcoord_; // face texcoord indices (3*nface) int* graph_; // convex graph data // compute the volume and center-of-mass of the mesh given the face center