From a60a1e25dbc8fded67432f67c2ffaef410c17876 Mon Sep 17 00:00:00 2001
From: jean_patrick_mathes <uomnk@student.kit.edu>
Date: Wed, 20 Jul 2022 12:47:20 +0200
Subject: [PATCH] Replace modifying primitive meshes with scaling of the mesh
 instance

---
 .../arviz_godot/lib/avi/scene/Converter.cpp   | 41 ++++++++++---------
 .../lib/avi/scene/CubeElementNode.cpp         | 22 ++++++----
 .../lib/avi/scene/CubeElementNode.h           |  9 ++--
 .../lib/avi/scene/CylinderElementNode.cpp     | 26 ++++++++----
 .../lib/avi/scene/CylinderElementNode.h       |  8 ++--
 .../lib/avi/scene/CylindroidElementNode.cpp   | 20 +++++----
 .../lib/avi/scene/CylindroidElementNode.h     | 10 ++---
 .../lib/avi/scene/EllipsoidElementNode.cpp    | 32 +++++++++------
 .../lib/avi/scene/EllipsoidElementNode.h      |  7 ++--
 .../lib/avi/scene/MeshElementNode.cpp         |  9 +++-
 .../lib/avi/scene/MeshElementNode.h           |  1 +
 .../lib/avi/scene/SphereElementNode.cpp       | 22 ++++++----
 .../lib/avi/scene/SphereElementNode.h         |  8 ++--
 13 files changed, 130 insertions(+), 85 deletions(-)

diff --git a/source/arviz_godot/lib/avi/scene/Converter.cpp b/source/arviz_godot/lib/avi/scene/Converter.cpp
index a919eb43..1ffc6f7a 100644
--- a/source/arviz_godot/lib/avi/scene/Converter.cpp
+++ b/source/arviz_godot/lib/avi/scene/Converter.cpp
@@ -156,52 +156,53 @@ avi::scene::Converter::createElement(avi::scene::LayerNode* layer,
     {
         case connection::SentElementType::BOX:
         {
-            godot::CubeMesh* mesh = godot::CubeMesh::_new();
-            avi::scene::CubeElementNode* boxNode = avi::scene::CubeElementNode::newCubeElementNode(
-                mesh, avi::connection::SentElementType::BOX, elementInfo->id, layer);
+            avi::scene::CubeElementNode* boxNode =
+                avi::scene::CubeElementNode::newCubeElementNode(elementInfo->id, layer);
 
             boxNode->update(elementInfo);
+            boxNode->setShapeFromMesh();
+
             created = boxNode;
-            boxNode->setShape(mesh);
+
             break;
         }
 
         case connection::SentElementType::SPHERE:
         {
-            godot::SphereMesh* mesh = godot::SphereMesh::_new();
             avi::scene::MeshElementNode* sphereNode =
-                avi::scene::SphereElementNode::newSphereElementNode(
-                    mesh, avi::connection::SentElementType::SPHERE, elementInfo->id, layer);
+                avi::scene::SphereElementNode::newSphereElementNode(elementInfo->id, layer);
 
             sphereNode->update(elementInfo);
+            sphereNode->setShapeFromMesh();
+
             created = sphereNode;
-            sphereNode->setShape(mesh);
+
             break;
         }
 
         case connection::SentElementType::CYLINDER:
         {
-            godot::CylinderMesh* mesh = godot::CylinderMesh::_new();
             avi::scene::MeshElementNode* cylinderNode =
-                avi::scene::CylinderElementNode::newCylinderElementNode(
-                    mesh, avi::connection::SentElementType::CYLINDER, elementInfo->id, layer);
+                avi::scene::CylinderElementNode::newCylinderElementNode(elementInfo->id, layer);
 
             cylinderNode->update(elementInfo);
+            cylinderNode->setShapeFromMesh();
+
             created = cylinderNode;
-            cylinderNode->setShape(mesh);
+
             break;
         }
 
         case connection::SentElementType::ELLIPSOID:
         {
-            godot::SphereMesh* mesh = godot::SphereMesh::_new();
             avi::scene::MeshElementNode* ellipsoidNode =
-                avi::scene::EllipsoidElementNode::newEllipsoidElementNode(
-                    mesh, avi::connection::SentElementType::ELLIPSOID, elementInfo->id, layer);
+                avi::scene::EllipsoidElementNode::newEllipsoidElementNode(elementInfo->id, layer);
 
             ellipsoidNode->update(elementInfo);
+            ellipsoidNode->setShapeFromMesh();
+
             created = ellipsoidNode;
-            ellipsoidNode->setShape(mesh);
+
             break;
         }
 
@@ -209,14 +210,14 @@ avi::scene::Converter::createElement(avi::scene::LayerNode* layer,
         {
             auto cylindroid =
                 IceInternal::Handle<armarx::viz::data::ElementCylindroid>::dynamicCast(elementInfo);
-            godot::CylinderMesh* mesh = godot::CylinderMesh::_new();
             avi::scene::CylindroidElementNode* cylindroidNode =
-                avi::scene::CylindroidElementNode::newCylindroidElementNode(
-                    mesh, avi::connection::SentElementType::CYLINDROID, cylindroid->id, layer);
+                avi::scene::CylindroidElementNode::newCylindroidElementNode(cylindroid->id, layer);
 
             cylindroidNode->update(elementInfo);
+            cylindroidNode->setShapeFromMesh();
+
             created = cylindroidNode;
-            cylindroidNode->setShape(mesh);
+
             break;
         }
 
diff --git a/source/arviz_godot/lib/avi/scene/CubeElementNode.cpp b/source/arviz_godot/lib/avi/scene/CubeElementNode.cpp
index 13f57f03..f702d417 100644
--- a/source/arviz_godot/lib/avi/scene/CubeElementNode.cpp
+++ b/source/arviz_godot/lib/avi/scene/CubeElementNode.cpp
@@ -1,5 +1,8 @@
 #include "CubeElementNode.h"
 
+#include <utility>
+
+#include <arviz_godot/lib/avi/core/Utilities.h>
 #include <arviz_godot/lib/avi/scene/Converter.h>
 
 void
@@ -22,8 +25,14 @@ void
 avi::scene::CubeElementNode::update(IceInternal::Handle<armarx::viz::data::Element> elementInfo)
 {
     auto box = IceInternal::Handle<armarx::viz::data::ElementBox>::dynamicCast(elementInfo);
-    auto* mesh = godot::Object::cast_to<godot::CubeMesh>(getMesh());
-    mesh->set_size(godot::Vector3(box->size.e0, box->size.e1, box->size.e2));
+
+    godot::Vector3 newSize = {box->size.e0, box->size.e1, box->size.e2};
+    if (!avi::core::utilities::is_equal_approx(size, newSize))
+    {
+        size = newSize;
+        getMeshInstance()->set_scale(size / 2);
+    }
+
     updateAttributes(box->interaction.enableFlags,
                      box->interaction.contextMenuOptions,
                      avi::scene::Converter::getPosition(box->pose),
@@ -33,13 +42,12 @@ avi::scene::CubeElementNode::update(IceInternal::Handle<armarx::viz::data::Eleme
 }
 
 avi::scene::CubeElementNode*
-avi::scene::CubeElementNode::newCubeElementNode(godot::Mesh* mesh,
-                                                avi::connection::SentElementType type,
-                                                std::string name,
-                                                avi::core::Layer* layer)
+avi::scene::CubeElementNode::newCubeElementNode(std::string name, avi::core::Layer* layer)
 {
     CubeElementNode* node = CubeElementNode::_new();
-    node->setStartAttributes(mesh, type, name, layer);
+    godot::Mesh* mesh = godot::CubeMesh::_new();
+
+    node->setStartAttributes(mesh, avi::connection::SentElementType::BOX, std::move(name), layer);
 
     return node;
 }
diff --git a/source/arviz_godot/lib/avi/scene/CubeElementNode.h b/source/arviz_godot/lib/avi/scene/CubeElementNode.h
index cdd828da..c893d560 100644
--- a/source/arviz_godot/lib/avi/scene/CubeElementNode.h
+++ b/source/arviz_godot/lib/avi/scene/CubeElementNode.h
@@ -18,11 +18,12 @@ namespace avi::scene
 
         void _init();
 
-        static CubeElementNode* newCubeElementNode(godot::Mesh* mesh,
-                                                   avi::connection::SentElementType type,
-                                                   std::string name,
-                                                   avi::core::Layer* layer);
+        static avi::scene::CubeElementNode* newCubeElementNode(std::string name,
+                                                               avi::core::Layer* layer);
 
         void update(IceInternal::Handle<armarx::viz::data::Element> elementInfo) override;
+
+    private:
+        godot::Vector3 size;
     };
 } // namespace avi::scene
diff --git a/source/arviz_godot/lib/avi/scene/CylinderElementNode.cpp b/source/arviz_godot/lib/avi/scene/CylinderElementNode.cpp
index 2b36c490..4389c68c 100644
--- a/source/arviz_godot/lib/avi/scene/CylinderElementNode.cpp
+++ b/source/arviz_godot/lib/avi/scene/CylinderElementNode.cpp
@@ -1,5 +1,7 @@
 #include "CylinderElementNode.h"
 
+#include <utility>
+
 #include "Converter.h"
 
 void
@@ -23,10 +25,16 @@ avi::scene::CylinderElementNode::update(IceInternal::Handle<armarx::viz::data::E
 {
     auto cylinder =
         IceInternal::Handle<armarx::viz::data::ElementCylinder>::dynamicCast(elementInfo);
-    auto* mesh = godot::Object::cast_to<godot::CylinderMesh>(getMesh());
-    mesh->set_height(cylinder->height);
-    mesh->set_top_radius(cylinder->radius);
-    mesh->set_bottom_radius(cylinder->radius);
+
+    if (!godot::Math::is_equal_approx(height, cylinder->height) ||
+        !godot::Math::is_equal_approx(radius, cylinder->radius))
+    {
+        radius = cylinder->radius;
+        height = cylinder->height;
+
+        getMeshInstance()->set_scale({radius, height / 2, radius});
+    }
+
     updateAttributes(cylinder->interaction.enableFlags,
                      cylinder->interaction.contextMenuOptions,
                      avi::scene::Converter::getPosition(cylinder->pose),
@@ -36,12 +44,12 @@ avi::scene::CylinderElementNode::update(IceInternal::Handle<armarx::viz::data::E
 }
 
 avi::scene::CylinderElementNode*
-avi::scene::CylinderElementNode::newCylinderElementNode(godot::Mesh* mesh,
-                                                        avi::connection::SentElementType type,
-                                                        std::string name,
-                                                        avi::core::Layer* layer)
+avi::scene::CylinderElementNode::newCylinderElementNode(std::string name, avi::core::Layer* layer)
 {
     CylinderElementNode* node = CylinderElementNode::_new();
-    node->setStartAttributes(mesh, type, name, layer);
+    godot::Mesh* mesh = godot::CylinderMesh::_new();
+
+    node->setStartAttributes(
+        mesh, avi::connection::SentElementType::CYLINDER, std::move(name), layer);
     return node;
 }
diff --git a/source/arviz_godot/lib/avi/scene/CylinderElementNode.h b/source/arviz_godot/lib/avi/scene/CylinderElementNode.h
index 5bc09f80..e5fa3630 100644
--- a/source/arviz_godot/lib/avi/scene/CylinderElementNode.h
+++ b/source/arviz_godot/lib/avi/scene/CylinderElementNode.h
@@ -18,11 +18,13 @@ namespace avi::scene
 
         void _init();
 
-        static CylinderElementNode* newCylinderElementNode(godot::Mesh* mesh,
-                                                           avi::connection::SentElementType type,
-                                                           std::string name,
+        static CylinderElementNode* newCylinderElementNode(std::string name,
                                                            avi::core::Layer* layer);
 
         void update(IceInternal::Handle<armarx::viz::data::Element> elementInfo) override;
+
+    private:
+        float height = 0.0f;
+        float radius = 0.0f;
     };
 } // namespace avi::scene
diff --git a/source/arviz_godot/lib/avi/scene/CylindroidElementNode.cpp b/source/arviz_godot/lib/avi/scene/CylindroidElementNode.cpp
index 32c5a898..f8dfde10 100644
--- a/source/arviz_godot/lib/avi/scene/CylindroidElementNode.cpp
+++ b/source/arviz_godot/lib/avi/scene/CylindroidElementNode.cpp
@@ -24,10 +24,14 @@ avi::scene::CylindroidElementNode::update(
 {
     auto cylindroid =
         IceInternal::Handle<armarx::viz::data::ElementCylindroid>::dynamicCast(elementInfo);
-    auto* mesh = godot::Object::cast_to<godot::CylinderMesh>(getMesh());
-    mesh->set_height(cylindroid->height);
-    mesh->set_top_radius(1);
-    mesh->set_bottom_radius(1);
+
+    if (!godot::Math::is_equal_approx(height, cylindroid->height))
+    {
+        height = cylindroid->height;
+
+        getMeshInstance()->set_scale({1, height / 2, 1});
+    }
+
     updateAttributes(cylindroid->interaction.enableFlags,
                      cylindroid->interaction.contextMenuOptions,
                      avi::scene::Converter::getPosition(cylindroid->pose),
@@ -37,12 +41,12 @@ avi::scene::CylindroidElementNode::update(
 }
 
 avi::scene::CylindroidElementNode*
-avi::scene::CylindroidElementNode::newCylindroidElementNode(godot::Mesh* mesh,
-                                                            avi::connection::SentElementType type,
-                                                            std::string name,
+avi::scene::CylindroidElementNode::newCylindroidElementNode(std::string name,
                                                             avi::core::Layer* layer)
 {
     CylindroidElementNode* node = CylindroidElementNode::_new();
-    node->setStartAttributes(mesh, type, name, layer);
+    godot::Mesh* mesh = godot::CylinderMesh::_new();
+
+    node->setStartAttributes(mesh, avi::connection::SentElementType::CYLINDROID, name, layer);
     return node;
 }
diff --git a/source/arviz_godot/lib/avi/scene/CylindroidElementNode.h b/source/arviz_godot/lib/avi/scene/CylindroidElementNode.h
index f098f7a9..773f29b9 100644
--- a/source/arviz_godot/lib/avi/scene/CylindroidElementNode.h
+++ b/source/arviz_godot/lib/avi/scene/CylindroidElementNode.h
@@ -18,12 +18,12 @@ namespace avi::scene
 
         void _init();
 
-        static CylindroidElementNode*
-        newCylindroidElementNode(godot::Mesh* mesh,
-                                 avi::connection::SentElementType type,
-                                 std::string name,
-                                 avi::core::Layer* layer);
+        static CylindroidElementNode* newCylindroidElementNode(std::string name,
+                                                               avi::core::Layer* layer);
 
         void update(IceInternal::Handle<armarx::viz::data::Element> elementInfo) override;
+
+    private:
+        float height = 0.0f;
     };
 } // namespace avi::scene
diff --git a/source/arviz_godot/lib/avi/scene/EllipsoidElementNode.cpp b/source/arviz_godot/lib/avi/scene/EllipsoidElementNode.cpp
index 9bb8eb96..8f2aa640 100644
--- a/source/arviz_godot/lib/avi/scene/EllipsoidElementNode.cpp
+++ b/source/arviz_godot/lib/avi/scene/EllipsoidElementNode.cpp
@@ -1,5 +1,6 @@
 #include "EllipsoidElementNode.h"
 
+#include <arviz_godot/lib/avi/core/Utilities.h>
 #include <arviz_godot/lib/avi/scene/Converter.h>
 
 void
@@ -24,29 +25,34 @@ avi::scene::EllipsoidElementNode::update(
 {
     auto ellipsoid =
         IceInternal::Handle<armarx::viz::data::ElementEllipsoid>::dynamicCast(elementInfo);
-    auto* mesh = godot::Object::cast_to<godot::SphereMesh>(getMesh());
-    mesh->set_height(2);
-    mesh->set_radius(1);
-    armarx::Vector3f scale = ellipsoid->scale;
-    godot::Vector3 meshScale = {
+
+    godot::Vector3 newScale = {
         ellipsoid->axisLengths.e0, ellipsoid->axisLengths.e1, ellipsoid->axisLengths.e2};
-    godot::MeshInstance* meshInstance = getMeshInstance();
-    meshInstance->set_scale(meshScale);
+
+    if (!avi::core::utilities::is_equal_approx(scale, newScale))
+    {
+        scale = newScale;
+        getMeshInstance()->set_scale(scale);
+    }
+
     updateAttributes(ellipsoid->interaction.enableFlags,
                      ellipsoid->interaction.contextMenuOptions,
                      avi::scene::Converter::getPosition(ellipsoid->pose),
-                     avi::scene::Converter::getScale(scale),
+                     avi::scene::Converter::getScale(ellipsoid->scale),
                      avi::scene::Converter::getRotation(ellipsoid->pose),
                      avi::scene::Converter::getColor(ellipsoid->color));
 }
 
 avi::scene::EllipsoidElementNode*
-avi::scene::EllipsoidElementNode::newEllipsoidElementNode(godot::Mesh* mesh,
-                                                          avi::connection::SentElementType type,
-                                                          std::string name,
-                                                          avi::core::Layer* layer)
+avi::scene::EllipsoidElementNode::newEllipsoidElementNode(std::string name, avi::core::Layer* layer)
 {
     EllipsoidElementNode* node = EllipsoidElementNode::_new();
-    node->setStartAttributes(mesh, type, name, layer);
+    godot::SphereMesh* mesh = godot::SphereMesh::_new();
+
+    mesh->set_height(2);
+    mesh->set_radius(1);
+
+    node->setStartAttributes(mesh, avi::connection::SentElementType::ELLIPSOID, name, layer);
+
     return node;
 }
diff --git a/source/arviz_godot/lib/avi/scene/EllipsoidElementNode.h b/source/arviz_godot/lib/avi/scene/EllipsoidElementNode.h
index 23488d23..9524d002 100644
--- a/source/arviz_godot/lib/avi/scene/EllipsoidElementNode.h
+++ b/source/arviz_godot/lib/avi/scene/EllipsoidElementNode.h
@@ -18,11 +18,12 @@ namespace avi::scene
 
         void _init();
 
-        static EllipsoidElementNode* newEllipsoidElementNode(godot::Mesh* mesh,
-                                                             avi::connection::SentElementType type,
-                                                             std::string name,
+        static EllipsoidElementNode* newEllipsoidElementNode(std::string name,
                                                              avi::core::Layer* layer);
 
         void update(IceInternal::Handle<armarx::viz::data::Element> elementInfo) override;
+
+    private:
+        godot::Vector3 scale;
     };
 } // namespace avi::scene
diff --git a/source/arviz_godot/lib/avi/scene/MeshElementNode.cpp b/source/arviz_godot/lib/avi/scene/MeshElementNode.cpp
index f7ab3a6f..b1b834f7 100644
--- a/source/arviz_godot/lib/avi/scene/MeshElementNode.cpp
+++ b/source/arviz_godot/lib/avi/scene/MeshElementNode.cpp
@@ -18,7 +18,7 @@ avi::scene::MeshElementNode::getVolume()
 {
     godot::AABB correctedAABB = meshInstance->get_aabb();
     correctedAABB.position = staticBody->get_transform().origin;
-    correctedAABB.size = correctedAABB.size * staticBody->get_scale() * 0.5;
+    correctedAABB.size *= staticBody->get_scale() * meshInstance->get_scale() * 0.5;
 
     return correctedAABB;
 }
@@ -150,6 +150,12 @@ avi::scene::MeshElementNode::setShape(godot::Mesh* mesh)
     collisionShape->set_scale(meshInstance->get_scale());
 }
 
+void
+avi::scene::MeshElementNode::setShapeFromMesh()
+{
+    setShape(getMesh());
+}
+
 godot::Transform
 avi::scene::MeshElementNode::getTransform()
 {
@@ -172,3 +178,4 @@ avi::scene::MeshElementNode::getMeshInstance()
 {
     return meshInstance;
 }
+
diff --git a/source/arviz_godot/lib/avi/scene/MeshElementNode.h b/source/arviz_godot/lib/avi/scene/MeshElementNode.h
index ada8c4dd..8c9b555d 100644
--- a/source/arviz_godot/lib/avi/scene/MeshElementNode.h
+++ b/source/arviz_godot/lib/avi/scene/MeshElementNode.h
@@ -37,6 +37,7 @@ namespace avi::scene
         void setMesh(godot::Mesh* mesh);
 
         void setShape(godot::Mesh* mesh);
+        void setShapeFromMesh();
 
         godot::Vector3 getPosition();
 
diff --git a/source/arviz_godot/lib/avi/scene/SphereElementNode.cpp b/source/arviz_godot/lib/avi/scene/SphereElementNode.cpp
index 478e4a9e..a2d074d2 100644
--- a/source/arviz_godot/lib/avi/scene/SphereElementNode.cpp
+++ b/source/arviz_godot/lib/avi/scene/SphereElementNode.cpp
@@ -23,9 +23,16 @@ void
 avi::scene::SphereElementNode::update(IceInternal::Handle<armarx::viz::data::Element> elementInfo)
 {
     auto sphere = IceInternal::Handle<armarx::viz::data::ElementSphere>::dynamicCast(elementInfo);
-    auto* mesh = godot::Object::cast_to<godot::SphereMesh>(getMesh());
-    mesh->set_radius(sphere->radius);
-    mesh->set_height(2 * sphere->radius);
+
+    float newRadius = sphere->radius;
+
+    if (!godot::Math::is_equal_approx(radius, newRadius))
+    {
+        radius = newRadius;
+
+        getMeshInstance()->set_scale({radius, radius, radius});
+    }
+
     updateAttributes(sphere->interaction.enableFlags,
                      sphere->interaction.contextMenuOptions,
                      avi::scene::Converter::getPosition(sphere->pose),
@@ -35,13 +42,12 @@ avi::scene::SphereElementNode::update(IceInternal::Handle<armarx::viz::data::Ele
 }
 
 avi::scene::SphereElementNode*
-avi::scene::SphereElementNode::newSphereElementNode(godot::Mesh* mesh,
-                                                    avi::connection::SentElementType type,
-                                                    std::string name,
-                                                    avi::core::Layer* layer)
+avi::scene::SphereElementNode::newSphereElementNode(std::string name, avi::core::Layer* layer)
 {
     SphereElementNode* node = SphereElementNode::_new();
-    node->setStartAttributes(mesh, type, name, layer);
+    godot::Mesh* mesh = godot::SphereMesh::_new();
+
+    node->setStartAttributes(mesh, avi::connection::SentElementType::SPHERE, name, layer);
 
     return node;
 }
diff --git a/source/arviz_godot/lib/avi/scene/SphereElementNode.h b/source/arviz_godot/lib/avi/scene/SphereElementNode.h
index c11ea6bd..2fe61243 100644
--- a/source/arviz_godot/lib/avi/scene/SphereElementNode.h
+++ b/source/arviz_godot/lib/avi/scene/SphereElementNode.h
@@ -17,11 +17,11 @@ namespace avi::scene
 
         void _init();
 
-        static SphereElementNode* newSphereElementNode(godot::Mesh* mesh,
-                                                       avi::connection::SentElementType type,
-                                                       std::string name,
-                                                       avi::core::Layer* layer);
+        static SphereElementNode* newSphereElementNode(std::string name, avi::core::Layer* layer);
 
         void update(IceInternal::Handle<armarx::viz::data::Element> elementInfo) override;
+
+    private:
+        float radius = 0.0f;
     };
 } // namespace avi::scene
-- 
GitLab