From 8bd37a10e6f8960be55b8400fb6d3bfd7dfd5602 Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@student.kit.edu>
Date: Wed, 26 Jun 2019 17:11:30 +0200
Subject: [PATCH] Moved body sanitizers

---
 VirtualRobot/CMakeLists.txt                   |  12 +-
 VirtualRobot/XML/mujoco/BodySanitizer.cpp     |  15 --
 VirtualRobot/XML/mujoco/BodySanitizer.h       |  44 ----
 .../XML/mujoco/DummyMassBodySanitizer.cpp     |  51 ----
 .../XML/mujoco/DummyMassBodySanitizer.h       |  25 --
 .../XML/mujoco/MergingBodySanitizer.cpp       | 239 ------------------
 .../XML/mujoco/MergingBodySanitizer.h         |  88 -------
 VirtualRobot/XML/mujoco/MujocoIO.cpp          |   4 +-
 VirtualRobot/XML/mujoco/MujocoIO.h            |   2 +-
 9 files changed, 9 insertions(+), 471 deletions(-)
 delete mode 100644 VirtualRobot/XML/mujoco/BodySanitizer.cpp
 delete mode 100644 VirtualRobot/XML/mujoco/BodySanitizer.h
 delete mode 100644 VirtualRobot/XML/mujoco/DummyMassBodySanitizer.cpp
 delete mode 100644 VirtualRobot/XML/mujoco/DummyMassBodySanitizer.h
 delete mode 100644 VirtualRobot/XML/mujoco/MergingBodySanitizer.cpp
 delete mode 100644 VirtualRobot/XML/mujoco/MergingBodySanitizer.h

diff --git a/VirtualRobot/CMakeLists.txt b/VirtualRobot/CMakeLists.txt
index ed462ed94..b769b0486 100644
--- a/VirtualRobot/CMakeLists.txt
+++ b/VirtualRobot/CMakeLists.txt
@@ -376,13 +376,13 @@ SET(SOURCES
     XML/SceneIO.cpp
     
     XML/mujoco/exceptions.cpp
-    XML/mujoco/BodySanitizer.cpp
-    XML/mujoco/DummyMassBodySanitizer.cpp
-    XML/mujoco/MergingBodySanitizer.cpp
     XML/mujoco/Mesh.cpp
     XML/mujoco/MeshConverter.cpp
     XML/mujoco/MujocoIO.cpp
     XML/mujoco/RobotMjcf.cpp
+    XML/mujoco/body_sanitizer/BodySanitizer.cpp
+    XML/mujoco/body_sanitizer/DummyMassBodySanitizer.cpp
+    XML/mujoco/body_sanitizer/MergingBodySanitizer.cpp
 )
 
 SET(INCLUDES
@@ -605,13 +605,13 @@ SET(INCLUDES
     XML/SceneIO.h
     
     XML/mujoco/exceptions.h
-    XML/mujoco/BodySanitizer.h
-    XML/mujoco/DummyMassBodySanitizer.h
-    XML/mujoco/MergingBodySanitizer.h
     XML/mujoco/Mesh.h
     XML/mujoco/MeshConverter.h
     XML/mujoco/MujocoIO.h
     XML/mujoco/RobotMjcf.h
+    XML/mujoco/body_sanitizer/BodySanitizer.h
+    XML/mujoco/body_sanitizer/DummyMassBodySanitizer.h
+    XML/mujoco/body_sanitizer/MergingBodySanitizer.h
     
 )
 
diff --git a/VirtualRobot/XML/mujoco/BodySanitizer.cpp b/VirtualRobot/XML/mujoco/BodySanitizer.cpp
deleted file mode 100644
index fce60b3f9..000000000
--- a/VirtualRobot/XML/mujoco/BodySanitizer.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "BodySanitizer.h"
-
-
-namespace VirtualRobot::mujoco
-{
-
-const std::string BodySanitizer::t = "| ";
-        
-
-BodySanitizer::BodySanitizer() = default;
-
-BodySanitizer::~BodySanitizer() = default;
-
-
-}
diff --git a/VirtualRobot/XML/mujoco/BodySanitizer.h b/VirtualRobot/XML/mujoco/BodySanitizer.h
deleted file mode 100644
index 2c9a985bc..000000000
--- a/VirtualRobot/XML/mujoco/BodySanitizer.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#pragma once
-
-#include <VirtualRobot/MJCF/Document.h>
-
-
-namespace VirtualRobot::mujoco
-{
-
-    /**
-     * @brief Sanitizer for MJCF bodies without mass.
-     * 
-     * MuJoCo does not allow non-static bodies to have 0 mass. However, this
-     * is the case when the robot model contains elements representing joints,
-     * which are not associated with some geometry.
-     * 
-     * A body sanitizer edits massless bodies to fix this issue.
-     */
-    class BodySanitizer
-    {
-    public:
-        
-        /// Constructor.
-        BodySanitizer();
-        
-        /// Virtual destructor.
-        virtual ~BodySanitizer();
-        
-        
-        /**
-         * @brief Sanitize the given root body and its direct and indirect children.
-         * @param document The MJCF document.
-         * @param root The root body to sanitize.
-         */
-        virtual void sanitize(mjcf::Document& document, mjcf::Body root) = 0;
-        
-        
-    protected:
-        
-        /// "Tab" string for logging.
-        static const std::string t;
-        
-    };
-
-}
diff --git a/VirtualRobot/XML/mujoco/DummyMassBodySanitizer.cpp b/VirtualRobot/XML/mujoco/DummyMassBodySanitizer.cpp
deleted file mode 100644
index 8c65b879b..000000000
--- a/VirtualRobot/XML/mujoco/DummyMassBodySanitizer.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "DummyMassBodySanitizer.h"
-
-
-namespace VirtualRobot::mujoco
-{
-
-struct DummyMassVisitor : public mjcf::Visitor
-{
-    DummyMassVisitor(mjcf::Document& document, const std::string& t = "| ");
-    
-    virtual bool visitEnter(const mjcf::AnyElement& element) override;
-    
-    const std::string& t;
-};
-
-DummyMassVisitor::DummyMassVisitor(mjcf::Document& document, const std::string& t) :
-    mjcf::Visitor(document), t(t)
-{}
-
-bool DummyMassVisitor::visitEnter(const mjcf::AnyElement& element)
-{
-    static const bool front = true;
-    
-    if (element.is<mjcf::Body>())
-    {
-        mjcf::Body body = element.as<mjcf::Body>();
-        if (!body.hasMass())
-        {
-            std::cout << t << "Body '" << body.name << ": \tAdd dummy inertial." << std::endl;
-            body.addDummyInertial(front);
-        }
-    }
-    return true;
-}
-
-
-
-DummyMassBodySanitizer::DummyMassBodySanitizer()
-{}
-
-void DummyMassBodySanitizer::sanitize(mjcf::Document& document, mjcf::Body root)
-{
-    DummyMassVisitor visitor(document, t);
-    root.accept(visitor);
-}
-
-
-
-
-
-}
diff --git a/VirtualRobot/XML/mujoco/DummyMassBodySanitizer.h b/VirtualRobot/XML/mujoco/DummyMassBodySanitizer.h
deleted file mode 100644
index 10f363221..000000000
--- a/VirtualRobot/XML/mujoco/DummyMassBodySanitizer.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-
-#include "BodySanitizer.h"
-
-
-namespace VirtualRobot::mujoco
-{
-
-    /**
-     * @brief A body sanitizer adding a small dummy mass to massless bodies.
-     */
-    class DummyMassBodySanitizer : public BodySanitizer
-    {
-    public:
-        
-        /// Constructor.
-        DummyMassBodySanitizer();
-
-        
-        /// @see BodySanitizer::sanitize()
-        virtual void sanitize(mjcf::Document& document, mjcf::Body root) override;
-        
-    };
-
-}
diff --git a/VirtualRobot/XML/mujoco/MergingBodySanitizer.cpp b/VirtualRobot/XML/mujoco/MergingBodySanitizer.cpp
deleted file mode 100644
index 08998fd81..000000000
--- a/VirtualRobot/XML/mujoco/MergingBodySanitizer.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-#include "MergingBodySanitizer.h"
-
-#include <boost/algorithm/string/join.hpp>
-
-#include <VirtualRobot/math/Helpers.h>
-
-
-namespace VirtualRobot::mujoco
-{
-
-using namespace mjcf;
-
-
-// MergedBodyList
-
-MergedBodyList::MergedBodyList() = default;
-
-MergedBodyList::MergedBodyList(const std::string& bodyName)
-{
-    addBody(bodyName);
-}
-
-void MergedBodyList::addBody(const std::string& bodyName)
-{
-    originalBodyNames.push_back(bodyName);
-    updateMergedBodyName();
-}
-
-bool MergedBodyList::containsBody(const std::string& bodyName) const
-{
-    return std::find(originalBodyNames.begin(), originalBodyNames.end(),
-                     bodyName) != originalBodyNames.end();
-}
-
-const std::string& MergedBodyList::getMergedBodyName() const
-{
-    return mergedBodyName;
-}
-
-void MergedBodyList::updateMergedBodyName()
-{
-    mergedBodyName = boost::algorithm::join(originalBodyNames, "~");
-}
-
-
-// MergingBodySanitizer
-
-MergingBodySanitizer::MergingBodySanitizer(RobotPtr robot) : robot(robot)
-{}
-
-void MergingBodySanitizer::setLengthScale(float toMeter)
-{
-    this->lengthScale = toMeter;
-}
-
-void MergingBodySanitizer::sanitize(Document&, Body root)
-{
-    // Merge body leaf nodes with parent if they do not have a mass (inertial or geom).
-    
-    for (Body body = root.firstChild<Body>(); body; body = body.nextSiblingElement<Body>())
-    {
-        sanitizeRecursive(body);
-    }
-}
-
-
-void MergingBodySanitizer::sanitizeRecursive(mjcf::Body body)
-{
-    RobotNodePtr bodyNode = robot->getRobotNode(body.name);
-    Eigen::Matrix4f accChildPose = Eigen::Matrix4f::Identity();
-    
-    while (!body.hasMass())
-    {
-        std::cout << t << body.name << ": \t";
-        
-        if (!body.hasChild<Body>())
-        {
-            // Leaf => end of recursion.
-            sanitizeLeafBody(body);
-            return;
-        }
-        
-        // Non-leaf body.
-        // Check whether there is only one child body.
-        Body childBody = body.firstChild<Body>();
-        if (!childBody.nextSiblingElement<Body>())
-        {
-            mergeBodies(body, childBody, accChildPose);
-        }
-        else
-        {
-            std::cout << "Adding dummy inertial to massless body with >1 child bodies." << std::endl;
-            // add a small mass
-            body.addDummyInertial();
-            break;
-        }
-    }
-    
-    // recursive descend
-    for (Body child = body.firstChild<Body>();
-         child; child = child.nextSiblingElement<Body>())
-    {
-        sanitizeRecursive(child);
-    }
-}
-
-static void updatePos(AnyElement element, const Eigen::Matrix4f& accChildPose)
-{
-    const Eigen::Vector3f pos = element.getAttribute<Eigen::Vector3f>("pos", Eigen::Vector3f::Zero());
-    element.setAttribute("pos", math::Helpers::TransformPosition(accChildPose, pos));
-}
-
-static void updateOri(AnyElement element, const Eigen::Matrix3f& accChildOri)
-{
-    if (element.is<Joint>())
-    {
-        Joint joint = element.as<Joint>();
-        joint.axis = accChildOri * joint.axis.get();
-    }
-    else if (element.is<Light>())
-    {
-        Light light = element.as<Light>();
-        light.dir = accChildOri * light.dir.get();
-    }
-    else
-    {
-        const Eigen::Quaternionf quat = 
-                element.getAttribute<Eigen::Quaternionf>("quat", Eigen::Quaternionf::Identity());
-        element.setAttribute("quat", Eigen::Quaternionf(accChildOri * quat));
-    }
-}
-
-void copyChildren(Body body, Body child, const Eigen::Matrix4f& childPose)
-{
-    // Merge childBody into body => move all its elements here.
-    // While doing this, apply accChildPose to elements.
-    for (AnyElement grandChild = child.firstChild<AnyElement>();
-         grandChild; grandChild = grandChild.template nextSiblingElement<AnyElement>())
-    {
-        // Clone grandchild.
-        AnyElement elem = grandChild.deepClone();
-        
-        if (elem)
-        {
-            /* Adapt pose/axis elements in child. Their poses/axes will be
-             * relative to body's frame, so the transformation from body
-             * to child will be lost. Therefore, apply accChildPose to
-             * their poses/axes. */
-            
-            updatePos(elem, childPose);
-            updateOri(elem, math::Helpers::Orientation(childPose));
-        }
-        
-        // Insert to body
-        body.insertEndChild(elem);
-    }
-}
-
-
-
-void MergingBodySanitizer::mergeBodies(Body body, Body childBody, Eigen::Matrix4f& accChildPose)
-{
-    std::cout << "Merging with '" << childBody.name << "' " << std::endl;
-
-    RobotNodePtr childNode = robot->getRobotNode(childBody.name);
-    Eigen::Matrix4f childPose = childNode->getTransformationFrom(childNode->getParent());
-    
-    // Scale position.
-    math::Helpers::Position(childPose) = lengthScale * math::Helpers::Position(childPose);
-    
-    // Update accumulated child pose.
-    // Merged child's frame w.r.t. body's frame.
-    accChildPose = childPose * accChildPose;
-    
-    // Merge childBody into body => move all its elements here.
-    // While doing this, apply accChildPose to elements.
-    copyChildren(body, childBody, accChildPose);
-    
-    // Update body name.
-    MergedBodyList& bodySet = getMergedBodySetWith(body.name);
-    bodySet.addBody(childBody.name);
-    body.name = bodySet.getMergedBodyName();
-    
-    std::cout << t << "\t(new name: '" << bodySet.getMergedBodyName() << "')" << std::endl;
-    
-    // Delete child.
-    body.deleteChild(childBody);
-}
-
-
-void MergingBodySanitizer::sanitizeLeafBody(Body body)
-{
-    VR_ASSERT_MESSAGE(!body.hasChild<Body>(), "Leaf body must not have a child body.");
-    VR_ASSERT_MESSAGE(!body.hasMass(), "Leaf body must not have mass.");
-    
-    if (!body.hasChildren()) // is completely empty?
-    {
-        // Leaf without geom: make it a site.
-        std::cout << "Changing to site." << std::endl;
-        body.transform<Site>();
-    }
-    else
-    {
-        // Add a small mass.
-        std::cout << "Adding dummy inertial to massless leaf body with children." << std::endl;
-        body.addDummyInertial();
-    }
-}
-
-const std::vector<MergedBodyList>& MergingBodySanitizer::getMergedBodyLists() const
-{
-    return mergedBodyLists;
-}
-
-const std::string& MergingBodySanitizer::getMergedBodyName(const std::string& originalBodyName)
-{
-    return getMergedBodySetWith(originalBodyName).getMergedBodyName();
-}
-
-MergedBodyList& MergingBodySanitizer::getMergedBodySetWith(const std::string& bodyName)
-{
-    for (auto& set : mergedBodyLists)
-    {
-        if (set.containsBody(bodyName))
-        {
-           return set;
-        }
-    }
-    
-    // Not found => add.
-    mergedBodyLists.push_back(MergedBodyList(bodyName));
-    
-    return mergedBodyLists.back();
-}
-
-
-
-
-}
diff --git a/VirtualRobot/XML/mujoco/MergingBodySanitizer.h b/VirtualRobot/XML/mujoco/MergingBodySanitizer.h
deleted file mode 100644
index b62df97c6..000000000
--- a/VirtualRobot/XML/mujoco/MergingBodySanitizer.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#pragma once
-
-#include <VirtualRobot/Robot.h>
-
-#include "BodySanitizer.h"
-
-
-namespace VirtualRobot::mujoco
-{
-    class MergedBodyList
-    {
-    public:
-        
-        MergedBodyList();
-        MergedBodyList(const std::string& bodyName);
-        
-        void addBody(const std::string& bodyName);
-        bool containsBody(const std::string& bodyName) const;
-        
-        const std::string& getMergedBodyName() const;
-        
-        
-    private:
-        
-        void updateMergedBodyName();
-        
-        std::string mergedBodyName;
-        std::vector<std::string> originalBodyNames;
-        
-    };
-
-    
-    /**
-     * @brief A body sanitizer merging massless bodies to new bodies.
-     * 
-     * Massless bodies are merged along a kinematic chain until a body with 
-     * mass or a body with multiple children is encountered. The encountered
-     * body is the last one included in the merged body.
-     * 
-     * If the last body has multiple children but no mass, a small dummy mass
-     * is added.
-     */
-    class MergingBodySanitizer : public BodySanitizer
-    {
-    public:
-        
-        /// Constructor.
-        MergingBodySanitizer(RobotPtr robot);
-        
-        
-        /// Set the scaling for lengths (e.g. positions) (to m).
-        void setLengthScale(float toMeter);
-        
-        
-        /// @see BodySanitizer::sanitize()
-        /// @param document Ignored by this class.
-        virtual void sanitize(mjcf::Document& document, mjcf::Body root) override;
-        
-        
-        // Results.
-        
-        const std::vector<MergedBodyList>& getMergedBodyLists() const;
-
-        const std::string& getMergedBodyName(const std::string& originalBodyName);
-        
-        MergedBodyList& getMergedBodySetWith(const std::string& bodyName);
-        
-        
-    private:
-        
-        void sanitizeRecursive(mjcf::Body body);
-        void sanitizeLeafBody(mjcf::Body body);
-        
-        void mergeBodies(mjcf::Body body, mjcf::Body childBody, Eigen::Matrix4f& accChildPose);
-        
-        /// The robot.
-        RobotPtr robot;
-        
-        /// Scaling factor of lengths (to m).
-        float lengthScale = 1.0f;
-
-        
-        // Results.
-        std::vector<MergedBodyList> mergedBodyLists;
-        
-    };
-
-}
diff --git a/VirtualRobot/XML/mujoco/MujocoIO.cpp b/VirtualRobot/XML/mujoco/MujocoIO.cpp
index 0654a5cef..ad33526dc 100644
--- a/VirtualRobot/XML/mujoco/MujocoIO.cpp
+++ b/VirtualRobot/XML/mujoco/MujocoIO.cpp
@@ -9,8 +9,8 @@
 #include <VirtualRobot/Visualization/TriMeshModel.h>
 #include <VirtualRobot/XML/RobotIO.h>
 
-#include "DummyMassBodySanitizer.h"
-#include "MergingBodySanitizer.h"
+#include "body_sanitizer/DummyMassBodySanitizer.h"
+#include "body_sanitizer/MergingBodySanitizer.h"
 
 
 namespace fs = std::filesystem;
diff --git a/VirtualRobot/XML/mujoco/MujocoIO.h b/VirtualRobot/XML/mujoco/MujocoIO.h
index a7c073896..d85e99369 100644
--- a/VirtualRobot/XML/mujoco/MujocoIO.h
+++ b/VirtualRobot/XML/mujoco/MujocoIO.h
@@ -5,8 +5,8 @@
 #include <VirtualRobot/Robot.h>
 #include <VirtualRobot/MJCF/Document.h>
 
-#include "BodySanitizer.h"
 #include "RobotMjcf.h"
+#include "body_sanitizer/BodySanitizer.h"
 
 
 namespace VirtualRobot::mujoco
-- 
GitLab