diff --git a/src/user/user_mesh.cc b/src/user/user_mesh.cc index d3f8f597..c30ba7ac 100644 --- a/src/user/user_mesh.cc +++ b/src/user/user_mesh.cc @@ -780,7 +780,6 @@ void mjCMesh::TryCompile(const mjVFS* vfs) { if (!plugin.active) { tmd::TriangleMeshDistance sdf(vert_.data(), nvert(), face_.data(), nface()); - // TODO: do not evaluate the SDF multiple times at the same vertex // TODO: the value at hanging vertices should be computed from the parent for (int i = 0; i < octree_.NumNodes(); ++i) { for (int j = 0; j < 8; j++) { diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index 23f7cae1..3896df33 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -31,6 +30,7 @@ #include #include #include +#include #include #include @@ -623,7 +623,8 @@ void mjCOctree::CreateOctree(const double aamm[6]) { std::vector elements_ptrs(elements.size()); std::transform(elements.begin(), elements.end(), elements_ptrs.begin(), [](Triangle& triangle) { return ▵ }); - MakeOctree(elements_ptrs, box); + std::unordered_map vert_map; + MakeOctree(elements_ptrs, box, 0, vert_map); } @@ -684,7 +685,8 @@ static bool boxTriangle(const Triangle& v, const double aamm[6]) { } -int mjCOctree::MakeOctree(const std::vector& elements, const double aamm[6], int lev) { +int mjCOctree::MakeOctree(const std::vector& elements, const double aamm[6], int lev, + std::unordered_map& vert_map) { node_.push_back(OctNode()); OctNode& node = node_.back(); node.level = lev; @@ -697,11 +699,17 @@ int mjCOctree::MakeOctree(const std::vector& elements, const double a (aamm[4] - aamm[1]) / 2, (aamm[5] - aamm[2]) / 2}; node.aabb = aabb; for (int i = 0; i < 8; i++) { - Point v = {(i & 1) ? aamm[3] : aamm[0], - (i & 2) ? aamm[4] : aamm[1], - (i & 4) ? aamm[5] : aamm[2]}; - vert_.push_back(v); - node.vertid[i] = nvert_++; + Point v = {{(i & 1) ? aamm[3] : aamm[0], + (i & 2) ? aamm[4] : aamm[1], + (i & 4) ? aamm[5] : aamm[2]}}; + auto it = vert_map.find(v); + if (it != vert_map.end()) { + node.vertid[i] = it->second; + } else { + node.vertid[i] = nvert_; + vert_map[v] = nvert_++; + vert_.push_back(v); + } node.child[i] = -1; } @@ -731,7 +739,7 @@ int mjCOctree::MakeOctree(const std::vector& elements, const double a // recursive calls to create sub-boxes for (int i = 0; i < 8; i++) { - node_[index].child[i] = MakeOctree(colliding, new_aamm[i], lev + 1); + node_[index].child[i] = MakeOctree(colliding, new_aamm[i], lev + 1, vert_map); } return index; diff --git a/src/user/user_objects.h b/src/user/user_objects.h index 4b2a403d..86bfd61e 100644 --- a/src/user/user_objects.h +++ b/src/user/user_objects.h @@ -17,10 +17,10 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -215,8 +215,37 @@ class mjCBoundingVolumeHierarchy : public mjCBoundingVolumeHierarchy_ { //------------------------- class mjCOctree -------------------------------------------------------- -typedef std::array Point; -typedef std::array Triangle; +struct Point { + std::array p; + + double& operator[](size_t i) { return p[i]; } + const double& operator[](size_t i) const { return p[i]; } + + bool operator==(const Point& other) const { + constexpr double kEpsilon = 1e-9; + return std::abs(this->p[0] - other.p[0]) < kEpsilon && + std::abs(this->p[1] - other.p[1]) < kEpsilon && + std::abs(this->p[2] - other.p[2]) < kEpsilon; + } +}; + +namespace std { +template <> +struct hash { + size_t operator()(const Point& pt) const { + size_t h1 = hash()(pt.p[0]); + size_t h2 = hash()(pt.p[1]); + size_t h3 = hash()(pt.p[2]); + // combine hashes + size_t seed = h1; + seed ^= h2 + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= h3 + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; +} // namespace std + +typedef std::array, 3> Triangle; struct OctNode { int level = 0; // level of the node @@ -246,7 +275,7 @@ class mjCOctree : public mjCOctree_ { void CopyChild(int* child) const; void CopyAabb(mjtNum* aabb) const; void CopyCoeff(mjtNum* coeff) const; - const double* Vert(int n, int v) const { return vert_[node_[n].vertid[v]].data(); } + const double* Vert(int n, int v) const { return vert_[node_[n].vertid[v]].p.data(); } void SetFace(const std::vector& vert, const std::vector& face); int Size() const { return sizeof(OctNode) * node_.size() + sizeof(Triangle) * face_.size() + @@ -260,7 +289,8 @@ class mjCOctree : public mjCOctree_ { private: void Make(std::vector& elements); - int MakeOctree(const std::vector& elements, const double aamm[6], int lev = 0); + int MakeOctree(const std::vector& elements, const double aamm[6], int lev, + std::unordered_map& vert_map); };