diff --git a/Base/Collision/CollisionDetection/imstkMeshToCapsuleCD.cpp b/Base/Collision/CollisionDetection/imstkMeshToCapsuleCD.cpp
index 329d9324820000227b12cf8d8f863613e86a81a4..006da9dd963a75d686938a4ff41014b4fa3dd314 100644
--- a/Base/Collision/CollisionDetection/imstkMeshToCapsuleCD.cpp
+++ b/Base/Collision/CollisionDetection/imstkMeshToCapsuleCD.cpp
@@ -38,13 +38,13 @@ MeshToCapsuleCD::computeCollisionData()
     m_colData.clearAll();
 
     auto capsulePos = m_capsule->getPosition();
-    auto height = m_capsule->getHeight() * m_capsule->getScaling();
-    auto radius = m_capsule->getRadius() * m_capsule->getScaling();
+    auto length = m_capsule->getLength();
+    auto radius = m_capsule->getRadius();
 
     // Get position of end points of the capsule
     // TODO: Fix this issue of extra computation in future
     auto p0 = capsulePos;
-    auto p1 = m_capsule->getOrientation()*Vec3d(0., height, 0.) + capsulePos;
+    auto p1 = p0 + m_capsule->getOrientationAxis() * length;
     auto mid = 0.5*(p0 + p1);
     auto p = p1 - p0;
     auto pDotp = p.dot(p);
@@ -54,7 +54,7 @@ MeshToCapsuleCD::computeCollisionData()
     for (const auto& q : m_mesh->getVertexPositions())
     {
         // First, check collision with bounding sphere
-        if ((mid - q).norm() > (radius + height*0.5))
+        if ((mid - q).norm() > (radius + length*0.5))
         {
             nodeId++;
             continue;
@@ -77,4 +77,4 @@ MeshToCapsuleCD::computeCollisionData()
     }
 }
 
-} // imstk
\ No newline at end of file
+} // imstk
diff --git a/Base/Collision/CollisionDetection/imstkMeshToPlaneCD.cpp b/Base/Collision/CollisionDetection/imstkMeshToPlaneCD.cpp
index 87dcfed324898db57f90e6c08443a903c7482d78..9ed3033169df4b90cc02692906d1c863d002cd39 100644
--- a/Base/Collision/CollisionDetection/imstkMeshToPlaneCD.cpp
+++ b/Base/Collision/CollisionDetection/imstkMeshToPlaneCD.cpp
@@ -41,19 +41,19 @@ MeshToPlaneCD::computeCollisionData()
     auto planePos = m_plane->getPosition();
 
     // TODO: Fix this issue of extra computation in future
-    auto rotatedNormal = m_plane->getOrientation()*m_plane->getNormal();
+    auto planeNormal = m_plane->getNormal();
 
     size_t nodeId = 0;
     for (const auto& p : m_mesh->getVertexPositions())
     {
-        auto peneDistance = (planePos - p).dot(rotatedNormal);
+        auto peneDistance = (planePos - p).dot(planeNormal);
         if (peneDistance <= 0.0)
         {
-            m_colData.MAColData.push_back({ nodeId, rotatedNormal * -peneDistance });
+            m_colData.MAColData.push_back({ nodeId, planeNormal * -peneDistance });
         }
         nodeId++;
     }
 
 }
 
-} // imstk
\ No newline at end of file
+} // imstk
diff --git a/Base/Collision/CollisionDetection/imstkMeshToSphereCD.cpp b/Base/Collision/CollisionDetection/imstkMeshToSphereCD.cpp
index 5b9ce7c92f7926c354b2647072ba55db473437c2..c4eaaf63ab5210c9d37bd1e64047e02669598ab1 100644
--- a/Base/Collision/CollisionDetection/imstkMeshToSphereCD.cpp
+++ b/Base/Collision/CollisionDetection/imstkMeshToSphereCD.cpp
@@ -39,7 +39,7 @@ MeshToSphereCD::computeCollisionData()
 
     // Get sphere properties
     auto spherePos = m_sphere->getPosition();
-    auto radius = m_sphere->getRadius() * m_sphere->getScaling();
+    auto radius = m_sphere->getRadius();
 
     size_t nodeId = 0;
     for (const auto& p : m_mesh->getVertexPositions())
@@ -56,4 +56,4 @@ MeshToSphereCD::computeCollisionData()
 
 }
 
-} // imstk
\ No newline at end of file
+} // imstk
diff --git a/Base/Collision/CollisionDetection/imstkSphereToSphereCD.cpp b/Base/Collision/CollisionDetection/imstkSphereToSphereCD.cpp
index 8c23a2d33cffa9ef164b5c7bfa87a8024fb75f54..4f02db7be5f3fdba2e3f27b70842a2322290c200 100644
--- a/Base/Collision/CollisionDetection/imstkSphereToSphereCD.cpp
+++ b/Base/Collision/CollisionDetection/imstkSphereToSphereCD.cpp
@@ -37,9 +37,9 @@ SphereToSphereCD::computeCollisionData()
 
     // Get geometry properties
     Vec3d sphereAPos = m_sphereA->getPosition();
-    double rA = m_sphereA->getRadius() * m_sphereA->getScaling();
+    double rA = m_sphereA->getRadius();
     Vec3d sphereBPos = m_sphereB->getPosition();
-    double rB = m_sphereB->getRadius() * m_sphereB->getScaling();
+    double rB = m_sphereB->getRadius();
 
     // Compute direction vector
     Vec3d dirAToB = sphereBPos - sphereAPos;
diff --git a/Base/Collision/CollisionDetection/imstkTetraToTetraCD.cpp b/Base/Collision/CollisionDetection/imstkTetraToTetraCD.cpp
index b64343db25f6cfc6a71998913af2a5e13e318d08..e8d28ab30fabcf92ee789e27024d125eb95bb4df 100644
--- a/Base/Collision/CollisionDetection/imstkTetraToTetraCD.cpp
+++ b/Base/Collision/CollisionDetection/imstkTetraToTetraCD.cpp
@@ -46,8 +46,10 @@ TetraToTetraCD::findCollisionsForMeshWithinHashTable(const std::shared_ptr<Tetra
     const double eps2 = 1e-10;
     
     //tetrahedron belonging part of penetration type does not change
-    PointTetrahedronCollisionData::CollisionType cType
-        = static_cast<PointTetrahedronCollisionData::CollisionType>(idOffset > 0);
+    auto cType = static_cast<PointTetrahedronCollisionData::CollisionType>(idOffset > 0);
+
+    auto nodesMeshA = m_meshA->getVertexPositions();
+    auto nodesMeshB = m_meshB->getVertexPositions();
 
     for (size_t tId = 0; tId < mesh->getNumTetrahedra(); ++tId) //TODO: parallelize!
     {
@@ -73,13 +75,13 @@ TetraToTetraCD::findCollisionsForMeshWithinHashTable(const std::shared_ptr<Tetra
                     //and gets vertex position
                     if (vId < m_meshA->getNumVertices())
                     {
-                        vPos = m_meshA->getVertexPosition(vId);
+                        vPos = nodesMeshA[vId];
                         cType = static_cast<PointTetrahedronCollisionData::CollisionType>((cType & 1) + 0);
                     }
                     else
                     {
                         vId -= m_meshA->getNumVertices();
-                        vPos = m_meshB->getVertexPosition(vId);
+                        vPos = nodesMeshB[vId];
                         cType = static_cast<PointTetrahedronCollisionData::CollisionType>((cType & 1) + 2);
                     }
 
diff --git a/Base/Collision/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp b/Base/Collision/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp
index 8ac2e4f45d7687bf242167676276214e59cb3360..19b5f779e3c2187f05bf2d95261aea74e803b3af 100644
--- a/Base/Collision/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp
+++ b/Base/Collision/CollisionDetection/imstkUnidirectionalPlaneToSphereCD.cpp
@@ -38,7 +38,7 @@ UnidirectionalPlaneToSphereCD::computeCollisionData()
 
     // Get geometry properties
     const Vec3d sphereBPos = m_sphereB->getPosition();
-    const double r = m_sphereB->getRadius() * m_sphereB->getScaling();
+    const double r = m_sphereB->getRadius();
     const Vec3d planeAPos = m_planeA->getPosition();
     const Vec3d n = m_planeA->getNormal();
 
diff --git a/Base/Collision/CollisionHandling/imstkVirtualCouplingCH.cpp b/Base/Collision/CollisionHandling/imstkVirtualCouplingCH.cpp
index c02e01234b9e42980a425a3e07cbc40d93eb7988..654da95f87fddb6dd114dbc4526979aa2a1c35d5 100644
--- a/Base/Collision/CollisionHandling/imstkVirtualCouplingCH.cpp
+++ b/Base/Collision/CollisionHandling/imstkVirtualCouplingCH.cpp
@@ -23,6 +23,7 @@
 
 #include "imstkCollidingObject.h"
 #include "imstkCollisionData.h"
+#include "imstkAnalyticalGeometry.h"
 
 #include <g3log/g3log.hpp>
 
@@ -32,12 +33,15 @@ namespace imstk
 void
 VirtualCouplingCH::computeContactForces()
 {
+    const auto collidingGeometry = std::static_pointer_cast<AnalyticalGeometry>(m_object->getCollidingGeometry());
+    const auto visualGeometry =  std::static_pointer_cast<AnalyticalGeometry>(m_object->getVisualGeometry());
+
     // Check if any collisions
-    const auto collidingObjPos = m_object->getCollidingGeometry()->getPosition();
+    const auto collidingObjPos = collidingGeometry->getPosition();
     if (m_colData.PDColData.empty())
     {
         // Set the visual object position same as the colliding object position
-        m_object->getVisualGeometry()->setPosition(collidingObjPos);
+        visualGeometry->setPosition(collidingObjPos);
         return;
     }
 
@@ -50,7 +54,7 @@ VirtualCouplingCH::computeContactForces()
 
     // Update the visual object position
     const auto visualObjPos = collidingObjPos + t;
-    m_object->getVisualGeometry()->setPosition(visualObjPos);
+    visualGeometry->setPosition(visualObjPos);
 
     // Spring force
     Vec3d  force = m_stiffness * (visualObjPos - collidingObjPos);
@@ -67,4 +71,4 @@ VirtualCouplingCH::computeContactForces()
     m_prevPos = collidingObjPos;
 }
 
-}// iMSTK
\ No newline at end of file
+}// iMSTK
diff --git a/Base/Core/imstkAPIUtilities.h b/Base/Core/imstkAPIUtilities.h
index b418c2f5dd047d81967509e76e3eecb45e43a1e5..41adcc7311390d94f2821cb497cae0e564f6aa86 100644
--- a/Base/Core/imstkAPIUtilities.h
+++ b/Base/Core/imstkAPIUtilities.h
@@ -92,15 +92,15 @@ createVisualAnalyticalSceneObject(imstk::Geometry::Type type,
         return nullptr;
     }
 
-    geom->scale(scale);
-    geom->translate(t);
+    geom->scale(scale, Geometry::TransformType::ApplyToData);
+    geom->translate(t, Geometry::TransformType::ApplyToData);
 
     auto sceneObj = std::make_shared<imstk::VisualObject>(objName);
     sceneObj->setVisualGeometry(geom);
     scene->addSceneObject(sceneObj);
 
     return sceneObj;
-};
+}
 
 ///
 /// \brief Create a analytical colliding scene object that and add it to the scene
@@ -144,8 +144,8 @@ createCollidingAnalyticalSceneObject(imstk::Geometry::Type type,
         return nullptr;
     }
 
-    geom->scale(scale);
-    geom->translate(t);
+    geom->scale(scale, Geometry::TransformType::ApplyToData);
+    geom->translate(t, Geometry::TransformType::ApplyToData);
 
     auto sceneObj = std::make_shared<imstk::CollidingObject>(objName);
     sceneObj->setVisualGeometry(geom);
@@ -153,7 +153,7 @@ createCollidingAnalyticalSceneObject(imstk::Geometry::Type type,
     scene->addSceneObject(sceneObj);
 
     return sceneObj;
-};
+}
 
 ///
 /// \brief Read a mesh, create a visual scene object and add to the scene
@@ -185,7 +185,7 @@ createAndAddVisualSceneObject(std::shared_ptr<imstk::Scene> scene,
     scene->addSceneObject(meshSceneObject);
 
     return meshSceneObject;
-};
+}
 
 ///
 /// \brief Create a non-linear system using FEM dynamic model
@@ -215,10 +215,10 @@ createNonLinearSystem(std::shared_ptr<imstk::FEMDeformableBodyModel> dynaModel)
     nlSystem->setUpdatePreviousStatesFunction(dynaModel->getUpdatePrevStateFunction());
 
     return nlSystem;
-};
+}
 
 } //apiutils
 
 } // imstk
 
-#endif // imstkAPIUtilities_h
\ No newline at end of file
+#endif // imstkAPIUtilities_h
diff --git a/Base/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h b/Base/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h
index 4f664ea8b510ba66765a09bea781efac629d825a..4419a8195b402e66f26802e89eb7e899d189344c 100644
--- a/Base/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h
+++ b/Base/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.h
@@ -189,7 +189,7 @@ public:
     ///
     /// \brief Update states
     ///
-    void updateBodyStates(const Vectord& solution, const stateUpdateType updateType);
+    void updateBodyStates(const Vectord& solution, const stateUpdateType updateType) override;
     void updateBodyIntermediateStates(const Vectord& solution, const stateUpdateType updateType);
 
     ///
diff --git a/Base/Geometry/Analytic/imstkAnalyticalGeometry.cpp b/Base/Geometry/Analytic/imstkAnalyticalGeometry.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf35a99d0ea2187ade3f386b59d1a0a063cd9e5e
--- /dev/null
+++ b/Base/Geometry/Analytic/imstkAnalyticalGeometry.cpp
@@ -0,0 +1,113 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#include "imstkAnalyticalGeometry.h"
+
+namespace imstk
+{
+
+void
+AnalyticalGeometry::print() const
+{
+    LOG(INFO) << "Position: (" << m_position.x() << ", " << m_position.y() << ", " << m_position.z() << ")";
+    LOG(INFO) << "Orientation Axis: (" << m_orientationAxis.x() << ", " << m_orientationAxis.y() << ", " << m_orientationAxis.z() << ")";
+}
+
+Vec3d
+AnalyticalGeometry::getPosition(DataType type /* = DataType::PostTransform */)
+{
+    if (type == DataType::PostTransform)
+    {
+        this->updatePostTransformData();
+        return m_positionPostTransform;
+    }
+    return m_position;
+}
+
+void
+AnalyticalGeometry::setPosition(const Vec3d p)
+{
+    if (m_position == p)
+    {
+        return;
+    }
+
+    m_position = p;
+    m_dataModified = true;
+    m_transformApplied = false;
+}
+
+void
+AnalyticalGeometry::setPosition(const double x, const double y, const double z)
+{
+    this->setPosition(Vec3d(x, y, z));
+}
+
+Vec3d
+AnalyticalGeometry::getOrientationAxis(DataType type /* = DataType::PostTransform */)
+{
+    if (type == DataType::PostTransform)
+    {
+        this->updatePostTransformData();
+        return m_orientationAxisPostTransform;
+    }
+    return m_orientationAxis;
+}
+
+void
+AnalyticalGeometry::setOrientationAxis(const Vec3d orientation)
+{
+    if (orientation == Vec3d::Zero())
+    {
+        LOG(WARNING) << "AnalyticalGeometry::setOrientationAxis error: "
+                     << "orientation can not be defined by a null vector.";
+        return;
+    }
+    if (m_orientationAxis == orientation)
+    {
+        return;
+    }
+    m_orientationAxis = orientation.normalized();
+    m_dataModified = true;
+    m_transformApplied = false;
+}
+
+void
+AnalyticalGeometry::applyTranslation(const Vec3d t)
+{
+    this->setPosition(m_position + t);
+}
+
+void
+AnalyticalGeometry::applyRotation(const Mat3d r)
+{
+    this->setOrientationAxis(r * m_orientationAxis);
+}
+
+void
+AnalyticalGeometry::updatePostTransformData()
+{
+    m_orientationAxisPostTransform = m_transform.rotation() * m_orientationAxis;
+    m_orientationAxisPostTransform.normalize();
+    m_positionPostTransform = m_position + m_transform.translation();
+}
+
+} // imstk
diff --git a/Base/Geometry/Analytic/imstkAnalyticalGeometry.h b/Base/Geometry/Analytic/imstkAnalyticalGeometry.h
new file mode 100644
index 0000000000000000000000000000000000000000..e30279cf116ae01c314ef94c1653160fccc77d64
--- /dev/null
+++ b/Base/Geometry/Analytic/imstkAnalyticalGeometry.h
@@ -0,0 +1,82 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#ifndef imstkAnalyticalGeometry_h
+#define imstkAnalyticalGeometry_h
+
+#include "imstkGeometry.h"
+#include "imstkMath.h"
+
+namespace imstk
+{
+
+///
+/// \class AnalyticalGeometry
+///
+/// \brief Base class for any analytical geometrical representation
+///
+class AnalyticalGeometry : public Geometry
+{
+public:
+
+    ///
+    /// \brief Destructor
+    ///
+    virtual ~AnalyticalGeometry() = default;
+
+    ///
+    /// \brief Print
+    ///
+    virtual void print() const override;
+
+    // Accessors
+
+    ///
+    /// \brief Get/Set position
+    ///
+    Vec3d getPosition(DataType type = DataType::PostTransform);
+    void setPosition(const Vec3d p);
+    void setPosition(const double x, const double y, const double z);
+
+    ///
+    /// \brief Get/Set orientation axis
+    ///
+    Vec3d getOrientationAxis(DataType type = DataType::PostTransform);
+    void setOrientationAxis(const Vec3d axis);
+
+protected:
+
+    AnalyticalGeometry(Type type) : Geometry(type) {}
+
+    void applyTranslation(const Vec3d t) override;
+    void applyRotation(const Mat3d r) override;
+    virtual void updatePostTransformData() override;
+
+    Vec3d  m_position = WORLD_ORIGIN;              ///> position
+    Vec3d  m_positionPostTransform = WORLD_ORIGIN; ///> position once transform applied
+
+    Vec3d  m_orientationAxis = UP_VECTOR;              ///> orientation
+    Vec3d  m_orientationAxisPostTransform = UP_VECTOR; ///> orientation once transform applied
+};
+
+} //imstk
+
+#endif // ifndef imstkGeometry_h
diff --git a/Base/Geometry/Analytic/imstkCapsule.cpp b/Base/Geometry/Analytic/imstkCapsule.cpp
index 53e29867b11761d028a86a56ad230e33129ada73..b0401361bc0281432cca5c769b3a46dbf6a62891 100644
--- a/Base/Geometry/Analytic/imstkCapsule.cpp
+++ b/Base/Geometry/Analytic/imstkCapsule.cpp
@@ -26,21 +26,32 @@
 namespace imstk
 {
 
-void
-Capsule::print() const
+void Capsule::print() const
 {
     Geometry::print();
     LOG(INFO) << "Radius: " << m_radius;
+    LOG(INFO) << "Length: " << m_length;
 }
 
 double
 Capsule::getVolume() const
 {
-    return PI * m_radius * m_radius *(m_height + 4.0 / 3.0 * m_radius);
+    return PI * m_radius * m_radius *(m_length + 4.0 / 3.0 * m_radius);
+}
+
+double
+Capsule::getRadius(DataType type /* = DataType::PostTransform */)
+{
+    if (type == DataType::PostTransform)
+    {
+        this->updatePostTransformData();
+        return m_radiusPostTransform;
+    }
+    return m_radius;
 }
 
 void
-Capsule::setRadius(const double& r)
+Capsule::setRadius(const double r)
 {
     if(r <= 0)
     {
@@ -48,17 +59,51 @@ Capsule::setRadius(const double& r)
         return;
     }
     m_radius = r;
+    m_dataModified = true;
+    m_transformApplied = false;
 }
 
+double
+Capsule::getLength(DataType type /* = DataType::PostTransform */)
+{
+    if (type == DataType::PostTransform)
+    {
+        this->updatePostTransformData();
+        return m_radiusPostTransform;
+    }
+    return m_radius;
+}
 void
-Capsule::setHeight(const double& h)
+Capsule::setLength(const double l)
 {
-    if (h <= 0)
+    if (l <= 0)
     {
         LOG(WARNING) << "Capsule::setHeight error: height should be positive.";
         return;
     }
-    m_height = h;
+    m_length = l;
+    m_dataModified = true;
+    m_transformApplied = false;
+}
+
+void
+Capsule::applyScaling(const double s)
+{
+    this->setRadius(m_radius * s);
+    this->setLength(m_length * s);
+}
+
+void
+Capsule::updatePostTransformData()
+{
+    if (m_transformApplied)
+    {
+        return;
+    }
+    AnalyticalGeometry::updatePostTransformData();
+    m_radiusPostTransform = m_scaling * m_radius;
+    m_lengthPostTransform = m_scaling * m_length;
+    m_transformApplied = true;
 }
 
 } // imstk
diff --git a/Base/Geometry/Analytic/imstkCapsule.h b/Base/Geometry/Analytic/imstkCapsule.h
index abeac2bc0c5e4856d17a530ebe9574d461a4ab02..8204b3995650c02eaf5d85191765b86379def962 100644
--- a/Base/Geometry/Analytic/imstkCapsule.h
+++ b/Base/Geometry/Analytic/imstkCapsule.h
@@ -23,7 +23,7 @@
 #define imstkCapsule_h
 
 // imstk
-#include "imstkGeometry.h"
+#include "imstkAnalyticalGeometry.h"
 
 namespace imstk
 {
@@ -33,20 +33,13 @@ namespace imstk
 ///
 /// \brief Capsule geometry
 ///
-class Capsule : public Geometry
+class Capsule : public AnalyticalGeometry
 {
 public:
     ///
     /// \brief Constructor
     ///
-    Capsule(const Vec3d& position = WORLD_ORIGIN,
-            const double& radius = 1.,
-            const double& height = 1.) :
-            m_radius(radius),
-            m_height(height),
-            Geometry(Geometry::Type::Capsule,
-                     position,
-                     Quatd::Identity()){}
+    Capsule() : AnalyticalGeometry(Type::Capsule) {}
 
     ///
     /// \brief Default destructor
@@ -63,33 +56,38 @@ public:
     ///
     double getVolume() const override;
 
-    // Accessors
     ///
     /// \brief Returns the radius of the capsule
     ///
-    const double& getRadius() const{ return m_radius; };
+    double getRadius(DataType type = DataType::PostTransform);
 
     ///
     /// \brief Sets the radius of the capsule
     ///
-    void setRadius(const double& r);
+    void setRadius(const double r);
 
     ///
-    /// \brief Returns the height of the capsule
+    /// \brief Returns the length of the capsule
     ///
-    const double& getHeight() const { return m_height; }
+    double getLength(DataType type = DataType::PostTransform);
 
     ///
-    /// \brief Sets the height of the capsule
+    /// \brief Sets the length of the capsule
     ///
-    void setHeight(const double& h);
+    void setLength(const double l);
 
 protected:
+    friend class VTKCapsuleRenderDelegate;
 
-    double m_radius; ///> Radius of the hemispheres at the end of the capsule
-    double m_height; ///> Length between the centers of two hemispheres
+    void applyScaling(const double s) override;
+    void updatePostTransformData() override;
+
+    double m_radius = 1.0;              ///> Radius of the hemispheres at the end of the capsule
+    double m_radiusPostTransform = 1.0; ///> Radius after transform
+    double m_length = 1.0;              ///> Length between the centers of two hemispheres
+    double m_lengthPostTransform = 1.0; ///> Length after transform
 };
 
 } // imstk
 
-#endif // ifndef imstkCapsule_h
\ No newline at end of file
+#endif // ifndef imstkCapsule_h
diff --git a/Base/Geometry/Analytic/imstkCube.cpp b/Base/Geometry/Analytic/imstkCube.cpp
index b80ca5859363f9ab3bb5c33e6f0ebedca9f84c5b..323e3912666f4e6db7eb3deea3e50d17908b60b9 100644
--- a/Base/Geometry/Analytic/imstkCube.cpp
+++ b/Base/Geometry/Analytic/imstkCube.cpp
@@ -37,21 +37,50 @@ Cube::getVolume() const
     return m_width*m_width*m_width;
 }
 
-const double&
-Cube::getWidth() const
+double
+Cube::getWidth(DataType type /* = DataType::PostTransform */)
 {
+    if (type == DataType::PostTransform)
+    {
+        this->updatePostTransformData();
+        return m_widthPostTransform;
+    }
     return m_width;
 }
 
 void
-Cube::setWidth(const double& width)
+Cube::setWidth(const double w)
 {
-    if(width <= 0)
+    if (w <= 0)
     {
         LOG(WARNING) << "Cube::setWidth error: width should be positive.";
         return;
     }
-    m_width = width;
+    if (m_width == w)
+    {
+        return;
+    }
+    m_width = w;
+    m_dataModified = true;
+    m_transformApplied = false;
+}
+
+void
+Cube::applyScaling(const double s)
+{
+    this->setWidth(m_width * s);
+}
+
+void
+Cube::updatePostTransformData()
+{
+    if (m_transformApplied)
+    {
+        return;
+    }
+    AnalyticalGeometry::updatePostTransformData();
+    m_widthPostTransform = m_scaling * m_width;
+    m_transformApplied = true;
 }
 
 } // imstk
diff --git a/Base/Geometry/Analytic/imstkCube.h b/Base/Geometry/Analytic/imstkCube.h
index cb943969028efbc67e72da73add81e556a5d1472..af3db37d8af327f3831e927bed3f0278c24e243a 100644
--- a/Base/Geometry/Analytic/imstkCube.h
+++ b/Base/Geometry/Analytic/imstkCube.h
@@ -22,7 +22,7 @@
 #ifndef imstkCube_h
 #define imstkCube_h
 
-#include "imstkGeometry.h"
+#include "imstkAnalyticalGeometry.h"
 
 namespace imstk {
 
@@ -31,17 +31,11 @@ namespace imstk {
 ///
 /// \brief Cube geometry
 ///
-class Cube : public Geometry
+class Cube : public AnalyticalGeometry
 {
 public:
 
-    Cube(const Vec3d & position = WORLD_ORIGIN,
-         const double& width = 1) :
-        Geometry(Geometry::Type::Cube,
-                 position,
-                 Quatd::Identity()),
-        m_width(width)
-    {}
+    Cube() : AnalyticalGeometry(Type::Cube) {}
 
     ~Cube() = default;
 
@@ -55,20 +49,25 @@ public:
     ///
     double getVolume() const override;
 
-    // Accessors
     ///
     /// \brief Returns the width of the cube
     ///
-    const double& getWidth() const;
+    double getWidth(DataType type = DataType::PostTransform);
 
     ///
     /// \brief Sets the width of the cube
     ///
-    void setWidth(const double& width);
+    void setWidth(const double w);
 
 protected:
+    friend class VTKCubeRenderDelegate;
+
+    void applyScaling(const double s) override;
+    void updatePostTransformData() override;
+
+    double m_width = 1.0;               ///> Width of the cube
+    double m_widthPostTransform = 1.0;  ///> Width of the cube once transform applied
 
-    double m_width; ///> width of the cube
 };
 }
 
diff --git a/Base/Geometry/Analytic/imstkPlane.cpp b/Base/Geometry/Analytic/imstkPlane.cpp
index 7528ad9f7f0453b483bbb8b3b3f8ab7a1cb0f07b..9404f26422e4634841bea0473c9f44866c20a364 100644
--- a/Base/Geometry/Analytic/imstkPlane.cpp
+++ b/Base/Geometry/Analytic/imstkPlane.cpp
@@ -27,7 +27,7 @@ namespace imstk
 void
 Plane::print() const
 {
-    Geometry::print();
+    AnalyticalGeometry::print();
     LOG(INFO) << "Width: " << m_width;
 }
 
@@ -38,37 +38,67 @@ Plane::getVolume() const
 }
 
 Vec3d
-Plane::getNormal() const
+Plane::getNormal(DataType type /* = DataType::PostTransform */)
 {
-    return m_normal;
+    return this->getOrientationAxis(type);
 }
 
 void
-Plane::setNormal(const Vec3d& normal)
+Plane::setNormal(const Vec3d n)
 {
-    if(normal == Vec3d::Zero())
+    this->setOrientationAxis(n);
+}
+
+void
+Plane::setNormal(double x, double y, double z)
+{
+    this->setNormal(Vec3d(x, y, z));
+}
+
+double
+Plane::getWidth(DataType type /* = DataType::PostTransform */)
+{
+    if (type == DataType::PostTransform)
+    {
+        this->updatePostTransformData();
+        return m_widthPostTransform;
+    }
+    return m_width;
+}
+
+void
+Plane::setWidth(const double w)
+{
+    if (w <= 0)
     {
-        LOG(WARNING) << "Plane::setNormal: can't set normal to zero vector";
+        LOG(WARNING) << "Plane::setWidth error: width should be positive.";
         return;
     }
-    m_normal = normal;
+    if (m_width == w)
+    {
+        return;
+    }
+    m_width = w;
+    m_dataModified = true;
+    m_transformApplied = false;
 }
 
-const double&
-Plane::getWidth() const
+void
+Plane::applyScaling(const double s)
 {
-    return m_width;
+    this->setWidth(m_width * s);
 }
 
 void
-Plane::setWidth(const double& width)
+Plane::updatePostTransformData()
 {
-    if(width <= 0)
+    if (m_transformApplied)
     {
-        LOG(WARNING) << "Plane::setWidth error: width should be positive.";
         return;
     }
-    m_width = width;
+    AnalyticalGeometry::updatePostTransformData();
+    m_widthPostTransform = m_scaling * m_width;
+    m_transformApplied = true;
 }
 
 } // imstk
diff --git a/Base/Geometry/Analytic/imstkPlane.h b/Base/Geometry/Analytic/imstkPlane.h
index 1fa1d0eda1d031832dc8920ef9eb7e1342f3216b..2ec015fdd6d6dc2a706fd24265b78071b5a93aa3 100644
--- a/Base/Geometry/Analytic/imstkPlane.h
+++ b/Base/Geometry/Analytic/imstkPlane.h
@@ -23,7 +23,7 @@
 #define imstkPlane_h
 
 // imstk
-#include "imstkGeometry.h"
+#include "imstkAnalyticalGeometry.h"
 
 namespace imstk
 {
@@ -33,21 +33,13 @@ namespace imstk
 ///
 /// \brief Plane geometry
 ///
-class Plane : public Geometry
+class Plane : public AnalyticalGeometry
 {
 public:
     ///
     /// \brief Constructor
     ///
-    Plane(const Vec3d & position = WORLD_ORIGIN,
-          const Vec3d & normal = UP_VECTOR,
-          const double& width = 1) :
-        Geometry(Geometry::Type::Plane,
-                 position,
-                 Quatd::FromTwoVectors(UP_VECTOR, normal)),
-        m_width(width),
-        m_normal(normal)
-    {}
+    Plane() : AnalyticalGeometry(Type::Plane) {}
 
     ///
     /// \brief Default destructor
@@ -64,30 +56,35 @@ public:
     ///
     double getVolume() const override;
 
-    // Accessors
     ///
     /// \brief Returns the normal of the plane
     ///
-    Vec3d getNormal() const;
+    Vec3d getNormal(DataType type = DataType::PostTransform);
 
     ///
     /// \brief Sets the normal to the plane
     ///
-    void setNormal(const Vec3d& normal);
+    void setNormal(const Vec3d n);
+    void setNormal(double x, double y, double z);
 
     ///
     /// \brief Returns the width of the plane
     ///
-    const double& getWidth() const;
+    double getWidth(DataType type = DataType::PostTransform);
 
     ///
     /// \brief Sets the width of the plane
     ///
-    void setWidth(const double& width);
+    void setWidth(const double w);
 
 protected:
-    double m_width; ///> Width of the plane (for display)
-    Vec3d m_normal; ///> Normal of the plane
+    friend class VTKPlaneRenderDelegate;
+
+    void applyScaling(const double s) override;
+    void updatePostTransformData() override;
+
+    double m_width = 1.0;               ///> Width of the plane
+    double m_widthPostTransform = 1.0;  ///> Width of the plane once transform applied
 };
 
 } // imstk
diff --git a/Base/Geometry/Analytic/imstkSphere.cpp b/Base/Geometry/Analytic/imstkSphere.cpp
index 9e5cbbadbf62ed09d10d4aac47f8f14bdc00a997..8ed46b0a9d6bf5c73474de0bf72fde407296408b 100644
--- a/Base/Geometry/Analytic/imstkSphere.cpp
+++ b/Base/Geometry/Analytic/imstkSphere.cpp
@@ -29,7 +29,7 @@ namespace imstk
 void
 Sphere::print() const
 {
-    Geometry::print();
+    AnalyticalGeometry::print();
     LOG(INFO) << "Radius: " << m_radius;
 }
 
@@ -39,21 +39,50 @@ Sphere::getVolume() const
     return 4.0 / 3.0 * PI * m_radius * m_radius * m_radius;
 }
 
-const double&
-Sphere::getRadius() const
+double
+Sphere::getRadius(DataType type /* = DataType::PostTransform */)
 {
+    if (type == DataType::PostTransform)
+    {
+        this->updatePostTransformData();
+        return m_radiusPostTransform;
+    }
     return m_radius;
 }
 
 void
-Sphere::setRadius(const double& radius)
+Sphere::setRadius(const double r)
 {
-    if(radius <= 0)
+    if(r <= 0)
     {
         LOG(WARNING) << "Sphere::setRadius error: radius should be positive.";
         return;
     }
-    m_radius = radius;
+    if (m_radius == r)
+    {
+        return;
+    }
+    m_radius = r;
+    m_dataModified = true;
+    m_transformApplied = false;
+}
+
+void
+Sphere::applyScaling(const double s)
+{
+    this->setRadius(m_radius * s);
+}
+
+void
+Sphere::updatePostTransformData()
+{
+    if (m_transformApplied)
+    {
+        return;
+    }
+    AnalyticalGeometry::updatePostTransformData();
+    m_radiusPostTransform = m_scaling * m_radius;
+    m_transformApplied = true;
 }
 
 } // imstk
diff --git a/Base/Geometry/Analytic/imstkSphere.h b/Base/Geometry/Analytic/imstkSphere.h
index e990663769ddd066321d76d512a7b975c4f35c3c..ec16100f8591dd53bcc114cd1ecba5eff9346384 100644
--- a/Base/Geometry/Analytic/imstkSphere.h
+++ b/Base/Geometry/Analytic/imstkSphere.h
@@ -23,7 +23,7 @@
 #define imstkSphere_h
 
 // imstk
-#include "imstkGeometry.h"
+#include "imstkAnalyticalGeometry.h"
 
 namespace imstk
 {
@@ -33,19 +33,13 @@ namespace imstk
 ///
 /// \brief Sphere geometry
 ///
-class Sphere : public Geometry
+class Sphere : public AnalyticalGeometry
 {
 public:
     ///
     /// \brief Constructor
     ///
-    Sphere(const Vec3d & position = WORLD_ORIGIN,
-           const double& radius = 1) :
-        Geometry(Geometry::Type::Sphere,
-                 position,
-                 Quatd::Identity()),
-        m_radius(radius)
-    {}
+    Sphere() : AnalyticalGeometry(Type::Sphere) {}
 
     ///
     /// \brief Default destructor
@@ -62,20 +56,24 @@ public:
     ///
     double getVolume() const override;
 
-    // Accessors
     ///
     /// \brief Returns the radius of the sphere
     ///
-    const double& getRadius() const;
+    double getRadius(DataType type = DataType::PostTransform);
 
     ///
     /// \brief Sets the radius of the sphere
     ///
-    void setRadius(const double& radius);
+    void setRadius(const double r);
 
 protected:
+    friend class VTKSphereRenderDelegate;
 
-    double m_radius; ///> Radius of the sphere
+    void applyScaling(const double s) override;
+    void updatePostTransformData() override;
+
+    double m_radius = 1.0;              ///> Radius of the sphere
+    double m_radiusPostTransform = 1.0; ///> Radius of the sphere once transform applied
 };
 
 } // imstk
diff --git a/Base/Geometry/Map/imstkIdentityMap.cpp b/Base/Geometry/Map/imstkIdentityMap.cpp
index 7e4047e1ba4bfeb39dab548ed75d44fe24adfe64..9a1adb0ba848a4aa55d50a0b2402c129fec43164 100644
--- a/Base/Geometry/Map/imstkIdentityMap.cpp
+++ b/Base/Geometry/Map/imstkIdentityMap.cpp
@@ -42,8 +42,8 @@ IdentityMap::apply()
     }
 
     // Set the follower mesh configuration to be same as that of master
-    m_slave->setPosition(m_master->getPosition());
-    m_slave->setOrientation(m_master->getOrientation());
+    m_slave->setTranslation(m_master->getTranslation());
+    m_slave->setRotation(m_master->getRotation());
 }
 
 const RigidTransform3d
diff --git a/Base/Geometry/Map/imstkIdentityMap.h b/Base/Geometry/Map/imstkIdentityMap.h
index 9b1510a5bdb73c7391fdbcd05a733cb0356597ea..7866b20c413719a76f651fcc9a88952ae0fe7f78 100644
--- a/Base/Geometry/Map/imstkIdentityMap.h
+++ b/Base/Geometry/Map/imstkIdentityMap.h
@@ -53,7 +53,7 @@ public:
     ///
     /// \brief Check the validity of the map
     ///
-    bool isValid() const { return true; };
+    bool isValid() const override { return true; }
 
     // Accessors
 
diff --git a/Base/Geometry/Map/imstkIsometricMap.cpp b/Base/Geometry/Map/imstkIsometricMap.cpp
index ff52025be9b9d8655af3963b1168283c7dbdc8bb..fb828d831d9ac5e3f0c318a2c9c8a9426c573224 100644
--- a/Base/Geometry/Map/imstkIsometricMap.cpp
+++ b/Base/Geometry/Map/imstkIsometricMap.cpp
@@ -42,8 +42,8 @@ IsometricMap::apply()
     }
 
     // Set the follower mesh configuration to that of master
-    m_slave->setPosition(m_master->getPosition());
-    m_slave->setOrientation(m_master->getOrientation());
+    m_slave->setTranslation(m_master->getTranslation());
+    m_slave->setRotation(m_master->getRotation());
 
     // Apply the offset transform
     m_slave->transform(m_rigidTransform);
diff --git a/Base/Geometry/Mesh/imstkHexahedralMesh.cpp b/Base/Geometry/Mesh/imstkHexahedralMesh.cpp
index 039fb2dc2da96e46f3ef56b814665b2f1c570866..64b44d848484f500988f426709891f03f8b7a5d5 100644
--- a/Base/Geometry/Mesh/imstkHexahedralMesh.cpp
+++ b/Base/Geometry/Mesh/imstkHexahedralMesh.cpp
@@ -72,7 +72,7 @@ HexahedralMesh::getVolume() const
     {
         for (int i = 0; i < 8; ++i)
         {
-            v[i] = this->getVertexPosition(hexArray[i]);
+            v[i] = m_vertexPositions[hexArray[i]];
         }
 
         a = v[7] - v[0];
diff --git a/Base/Geometry/Mesh/imstkMesh.cpp b/Base/Geometry/Mesh/imstkMesh.cpp
index ac578f73a521f814efd5f89821bd27207c4034ad..41d8f9458211bd16eb3ec56a0b3c709631a67016 100644
--- a/Base/Geometry/Mesh/imstkMesh.cpp
+++ b/Base/Geometry/Mesh/imstkMesh.cpp
@@ -29,8 +29,6 @@ Mesh::initialize(const StdVectorOfVec3d& vertices)
 {
     this->setInitialVertexPositions(vertices);
     this->setVertexPositions(vertices);
-    StdVectorOfVec3d disp = StdVectorOfVec3d(vertices.size(), imstk::Vec3d(0.0, 0.0, 0.0));
-    this->setVertexDisplacements(disp);
 }
 
 void
@@ -38,7 +36,7 @@ Mesh::clear()
 {
     m_initialVertexPositions.clear();
     m_vertexPositions.clear();
-    m_vertexDisplacements.clear();
+    m_vertexPositionsPostTransform.clear();
 }
 
 void
@@ -84,7 +82,6 @@ void
 Mesh::setInitialVertexPositions(const StdVectorOfVec3d& vertices)
 {
     m_initialVertexPositions = vertices;
-    m_vertexDisplacements= vertices;
 }
 
 const StdVectorOfVec3d&
@@ -103,11 +100,18 @@ void
 Mesh::setVertexPositions(const StdVectorOfVec3d& vertices)
 {
     m_vertexPositions = vertices;
+    m_dataModified = true;
+    m_transformApplied = false;
 }
 
 const StdVectorOfVec3d&
-Mesh::getVertexPositions() const
+Mesh::getVertexPositions(DataType type /* = DataType::PostTransform */)
 {
+    if (type == DataType::PostTransform)
+    {
+        this->updatePostTransformData();
+        return m_vertexPositionsPostTransform;
+    }
     return m_vertexPositions;
 }
 
@@ -115,60 +119,50 @@ void
 Mesh::setVertexPosition(const size_t& vertNum, const Vec3d& pos)
 {
     m_vertexPositions.at(vertNum) = pos;
+    m_dataModified = true;
+    m_transformApplied = false;
 }
 
 const Vec3d&
-Mesh::getVertexPosition(const size_t& vertNum) const
+Mesh::getVertexPosition(const size_t& vertNum, DataType type)
 {
-    return m_vertexPositions.at(vertNum);
+    return this->getVertexPositions(type).at(vertNum);
 }
 
 void
 Mesh::setVertexDisplacements(const StdVectorOfVec3d& diff)
 {
-    m_vertexDisplacements = diff;
+    assert(diff.size() == m_vertexPositions.size());
+    for (size_t i = 0; i < m_vertexPositions.size(); ++i)
+    {
+        m_vertexPositions[i] = m_initialVertexPositions[i] + diff[i];
+    }
+    m_dataModified = true;
+    m_transformApplied = false;
 }
 
 void
 Mesh::setVertexDisplacements(const Vectord& u)
 {
-    assert(u.size() == 3 * m_vertexDisplacements.size());
+    assert(u.size() == 3 * m_vertexPositions.size());
     size_t dofId = 0;
-    for (auto &vDisp : m_vertexDisplacements)
-    {
-        vDisp = Vec3d(u(dofId), u(dofId + 1), u(dofId + 2));
-        dofId += 3;
-    }
-
     for (size_t i = 0; i < m_vertexPositions.size(); ++i)
     {
-        m_vertexPositions[i] = m_initialVertexPositions[i] + m_vertexDisplacements[i];
+        m_vertexPositions[i] = m_initialVertexPositions[i] + Vec3d(u(dofId), u(dofId + 1), u(dofId + 2));
+        dofId += 3;
     }
+    m_dataModified = true;
+    m_transformApplied = false;
 }
 
 void Mesh::translateVertices(const Vec3d& t)
 {
-    for (auto &vDisp : m_vertexDisplacements)
-    {
-        vDisp += t;
-    }
-
     for (size_t i = 0; i < m_vertexPositions.size(); ++i)
     {
-        m_vertexPositions[i] = m_initialVertexPositions[i] + m_vertexDisplacements[i];
+        m_vertexPositions[i] += t;
     }
-}
-
-const StdVectorOfVec3d&
-Mesh::getVertexDisplacements() const
-{
-    return m_vertexDisplacements;
-}
-
-const Vec3d&
-Mesh::getVertexDisplacement(const size_t& vertNum) const
-{
-    return m_vertexDisplacements.at(vertNum);
+    m_dataModified = true;
+    m_transformApplied = false;
 }
 
 void
@@ -195,7 +189,7 @@ Mesh::setPointDataArray(const std::string& arrayName, const StdVectorOfVectorf&
     m_pointDataMap[arrayName] = arrayData;
 }
 
-const StdVectorOfVectorf* const
+const StdVectorOfVectorf*
 Mesh::getPointDataArray(const std::string& arrayName) const
 {
     auto it = m_pointDataMap.find(arrayName);
@@ -213,4 +207,61 @@ Mesh::getNumVertices() const
     return m_initialVertexPositions.size();
 }
 
+
+void
+Mesh::applyTranslation(const Vec3d t)
+{
+    for (size_t i = 0; i < m_vertexPositions.size(); ++i)
+    {
+        m_vertexPositions[i] += t;
+    }
+    m_dataModified = true;
+    m_transformApplied = false;
+}
+
+void
+Mesh::applyRotation(const Mat3d r)
+{
+    for (size_t i = 0; i < m_vertexPositions.size(); ++i)
+    {
+        m_vertexPositions[i] = r * m_vertexPositions[i];
+    }
+    m_dataModified = true;
+    m_transformApplied = false;
+}
+
+void
+Mesh::applyScaling(const double s)
+{
+    for (size_t i = 0; i < m_vertexPositions.size(); ++i)
+    {
+        m_vertexPositions[i] = s * m_vertexPositions[i];
+    }
+    m_dataModified = true;
+    m_transformApplied = false;
+}
+
+void
+Mesh::updatePostTransformData()
+{
+    if (m_transformApplied)
+    {
+        return;
+    }
+
+    if (m_vertexPositionsPostTransform.size() != m_vertexPositions.size())
+    {
+        m_vertexPositionsPostTransform.clear();
+        m_vertexPositionsPostTransform.resize(m_vertexPositions.size());
+    }
+    for (size_t i = 0; i < m_vertexPositions.size(); ++i)
+    {
+        // NOTE: Right now scaling is appended on top of the rigid transform
+        // for scaling around the mesh center, and not concatenated within
+        // the transform, for ease of use.
+        m_vertexPositionsPostTransform[i] = m_transform * (m_vertexPositions[i]* m_scaling);
+    }
+    m_transformApplied = true;
+}
+
 } // imstk
diff --git a/Base/Geometry/Mesh/imstkMesh.h b/Base/Geometry/Mesh/imstkMesh.h
index 8d5a0891007a4764b75e94b112917ed2536a5534..9e53fb6ec5c0eaad74321c4fb0d3973849cde1cc 100644
--- a/Base/Geometry/Mesh/imstkMesh.h
+++ b/Base/Geometry/Mesh/imstkMesh.h
@@ -86,7 +86,7 @@ public:
     ///
     /// \brief Returns the vector of current positions of the mesh vertices
     ///
-    const StdVectorOfVec3d& getVertexPositions() const;
+    const StdVectorOfVec3d& getVertexPositions(DataType type = DataType::PostTransform);
 
     ///
     /// \brief Set the current position of a vertex given its index to certain position
@@ -96,7 +96,8 @@ public:
     ///
     /// \brief Returns the position of a vertex given its index
     ///
-    const Vec3d& getVertexPosition(const size_t& vertNum) const;
+    const Vec3d& getVertexPosition(const size_t& vertNum,
+                                   DataType type = DataType::PostTransform);
 
     ///
     /// \brief Sets the displacements of mesh vertices from an array
@@ -109,27 +110,17 @@ public:
     void setVertexDisplacements(const Vectord& u);
 
     ///
-    /// \brief Deep translation of vertices using the given 3D vector
+    /// \brief Concatenate the displacements of mesh vertices using the given 3D vector
     ///
     void translateVertices(const Vec3d& t);
 
     ///
-    /// \brief Returns the vector displacements of mesh vertices
-    ///
-    const StdVectorOfVec3d& getVertexDisplacements() const;
-
-    ///
-    /// \brief Returns the displacement of a given vertex
-    ///
-    const Vec3d& getVertexDisplacement(const size_t& vertNum) const;
-
-    ///
-    /// \brief Sets the point data for all arrays at each vertice
+    /// \brief Sets the point data for all arrays at each vertex
     ///
     void setPointDataMap(const std::map<std::string, StdVectorOfVectorf>& pointData);
 
     ///
-    /// \brief Get the map of the point data for all arrays at each vertice
+    /// \brief Get the map of the point data for all arrays at each vertex
     ///
     const std::map<std::string, StdVectorOfVectorf>& getPointDataMap() const;
 
@@ -141,7 +132,7 @@ public:
     ///
     /// \brief Get a specific data array. If the array name cannot be found, nullptr is returned.
     ///
-    const StdVectorOfVectorf* const getPointDataArray(const std::string& arrayName) const;
+    const StdVectorOfVectorf* getPointDataArray(const std::string& arrayName) const;
 
     ///
     /// \brief Returns the number of total vertices in the mesh
@@ -153,7 +144,7 @@ protected:
     ///
     /// \brief Protected constructor
     ///
-    Mesh(Geometry::Type type) : Geometry(type) {}
+    Mesh(Type type) : Geometry(type) {}
 
     friend class VTKSurfaceMeshRenderDelegate;
     friend class VTKTetrahedralMeshRenderDelegate;
@@ -163,18 +154,19 @@ protected:
     ///
     /// \brief Get vertices positions
     ///
-    StdVectorOfVec3d& getVerticesPositionsNotConst()
+    StdVectorOfVec3d& getVertexPositionsNotConst()
     {
         return m_vertexPositions;
     }
 
-    //   Orientation * Scaling * initialVerticesPositions
-    // + Position (Initial translation)
-    // + verticesDisplacements
-    // = verticesPositions
-    StdVectorOfVec3d m_initialVertexPositions; //> Initial positions of vertices
-    StdVectorOfVec3d m_vertexPositions; //> Current positions of vertices
-    StdVectorOfVec3d m_vertexDisplacements; //> Displacements of vertices
+    void applyTranslation(const Vec3d t) override;
+    void applyRotation(const Mat3d r) override;
+    void applyScaling(const double s) override;
+    void updatePostTransformData() override;
+
+    StdVectorOfVec3d m_initialVertexPositions;       ///> Initial positions of vertices
+    StdVectorOfVec3d m_vertexPositions;              ///> Current positions of vertices
+    StdVectorOfVec3d m_vertexPositionsPostTransform; ///> Positions of vertices after transform
 
     std::map<std::string, StdVectorOfVectorf> m_pointDataMap; ///> vector of data arrays per vertice
 };
diff --git a/Base/Geometry/Mesh/imstkSurfaceMesh.cpp b/Base/Geometry/Mesh/imstkSurfaceMesh.cpp
index 56b17fd1f15bc75443580f0894d0b646af730c46..e3e7f254f2df7268836601caa3f6d921569e02fe 100644
--- a/Base/Geometry/Mesh/imstkSurfaceMesh.cpp
+++ b/Base/Geometry/Mesh/imstkSurfaceMesh.cpp
@@ -36,7 +36,7 @@ SurfaceMesh::initialize(const StdVectorOfVec3d& vertices,
 
     if (computeDerivedData)
     {
-        computeVerticesNormals();
+        computeVertexNormals();
     }
 }
 
@@ -133,7 +133,7 @@ SurfaceMesh::computeTrianglesNormals()
 }
 
 void
-SurfaceMesh::computeVerticesNormals()
+SurfaceMesh::computeVertexNormals()
 {
     m_vertexNormals.resize(m_vertexPositions.size());
 
diff --git a/Base/Geometry/Mesh/imstkSurfaceMesh.h b/Base/Geometry/Mesh/imstkSurfaceMesh.h
index aa6a17cef5647bf479d686fa61fefd111c51adc4..f1969201b58a2d8be7973ed1a55d93a5d12370f9 100644
--- a/Base/Geometry/Mesh/imstkSurfaceMesh.h
+++ b/Base/Geometry/Mesh/imstkSurfaceMesh.h
@@ -96,7 +96,7 @@ public:
     ///
     /// \brief Computes the normals of all the vertices
     ///
-    void computeVerticesNormals();
+    void computeVertexNormals();
 
     ///
     /// \brief Rewire the node order and triangle connectivity to optimize for memory layout
diff --git a/Base/Geometry/Mesh/imstkTetrahedralMesh.cpp b/Base/Geometry/Mesh/imstkTetrahedralMesh.cpp
index 3138181862a81bc18e95249b835e14b2243dfd8a..6e1d8af197b64e1f05bcc58a8e929f02c890d5e7 100644
--- a/Base/Geometry/Mesh/imstkTetrahedralMesh.cpp
+++ b/Base/Geometry/Mesh/imstkTetrahedralMesh.cpp
@@ -71,7 +71,7 @@ TetrahedralMesh::getVolume() const
     {
         for (int i = 0; i < 4; ++i)
         {
-            v[i] = this->getVertexPosition(tetVertices[i]);
+            v[i] = m_vertexPositions[tetVertices[i]];
         }
 
         A << v[0][0], v[0][1], v[0][2], 1,
@@ -226,7 +226,7 @@ TetrahedralMesh::computeBarycentricWeights(const size_t& tetId, const Vec3d& pos
 
     for (int i = 0; i < 4; ++i)
     {
-        v[i] = this->getVertexPosition(tetVertices[i]);
+        v[i] = m_vertexPositions[tetVertices[i]];
     }
 
     Mat4d A;
@@ -250,10 +250,10 @@ TetrahedralMesh::computeBarycentricWeights(const size_t& tetId, const Vec3d& pos
 void
 TetrahedralMesh::computeTetrahedronBoundingBox(const size_t& tetId, Vec3d& min, Vec3d& max) const
 {
-    auto v1 = this->getVertexPosition(m_tetrahedraVertices.at(tetId)[0]);
-    auto v2 = this->getVertexPosition(m_tetrahedraVertices.at(tetId)[1]);
-    auto v3 = this->getVertexPosition(m_tetrahedraVertices.at(tetId)[2]);
-    auto v4 = this->getVertexPosition(m_tetrahedraVertices.at(tetId)[3]);
+    auto v1 = m_vertexPositions[m_tetrahedraVertices.at(tetId)[0]];
+    auto v2 = m_vertexPositions[m_tetrahedraVertices.at(tetId)[1]];
+    auto v3 = m_vertexPositions[m_tetrahedraVertices.at(tetId)[2]];
+    auto v4 = m_vertexPositions[m_tetrahedraVertices.at(tetId)[3]];
 
     std::array<double, 4> arrayx = { v1[0], v2[0], v3[0], v4[0] };
     std::array<double, 4> arrayy = { v1[1], v2[1], v3[1], v4[1] };
diff --git a/Base/Geometry/Reader/imstkAssimpMeshIO.cpp b/Base/Geometry/Reader/imstkAssimpMeshIO.cpp
index 6be06186059a1adc5f8b3b0cd7cf903e8a162897..23c0c1b638c7f87e3f1cc181875329f9fdc7ec1b 100644
--- a/Base/Geometry/Reader/imstkAssimpMeshIO.cpp
+++ b/Base/Geometry/Reader/imstkAssimpMeshIO.cpp
@@ -149,11 +149,10 @@ AssimpMeshIO::readMeshData(const std::string& filePath)
             UV[1] = texcoords[i].y;
             UVs[i] = UV;
         }
+        mesh->setDefaultTCoords("tCoords");
+        mesh->setPointDataArray("tCoords",UVs);
     }
 
-    mesh->setDefaultTCoords("tCoords");
-    mesh->setPointDataArray("tCoords",UVs);
-
     return mesh;
 }
 
diff --git a/Base/Geometry/Testing/imstkGeometryTest.cpp b/Base/Geometry/Testing/imstkGeometryTest.cpp
index 90b1eee49588644370c8215a4b4bcc7bc82586ce..4d40aa5c6216d1c2a7b1717982baf30e6a38d1c2 100644
--- a/Base/Geometry/Testing/imstkGeometryTest.cpp
+++ b/Base/Geometry/Testing/imstkGeometryTest.cpp
@@ -51,25 +51,25 @@ TEST_F(imstkGeometryTest, GetSetScaling)
     EXPECT_GT(m_geometry.getScaling(), 0);
 }
 
-TEST_F(imstkGeometryTest, GetSetPosition)
+TEST_F(imstkGeometryTest, GetSetTranslation)
 {
     auto p1 = Vec3d(12, 0.0005, -400000);
     auto p2 = Vec3d(-500, 30, 0.23);
 
-    m_geometry.setPosition(p1);
-    EXPECT_EQ(m_geometry.getPosition(), p1);
+    m_geometry.setTranslation(p1);
+    EXPECT_EQ(m_geometry.getTranslation(), p1);
 
-    m_geometry.setPosition(p2);
-    EXPECT_EQ(m_geometry.getPosition(), p2);
+    m_geometry.setTranslation(p2);
+    EXPECT_EQ(m_geometry.getTranslation(), p2);
 
-    m_geometry.setPosition(p1[0], p1[1], p1[2]);
-    EXPECT_EQ(m_geometry.getPosition(), p1);
+    m_geometry.setTranslation(p1[0], p1[1], p1[2]);
+    EXPECT_EQ(m_geometry.getTranslation(), p1);
 
-    m_geometry.setPosition(p2[0], p2[1], p2[2]);
-    EXPECT_EQ(m_geometry.getPosition(), p2);
+    m_geometry.setTranslation(p2[0], p2[1], p2[2]);
+    EXPECT_EQ(m_geometry.getTranslation(), p2);
 }
 
-TEST_F(imstkGeometryTest, GetSetOrientation)
+TEST_F(imstkGeometryTest, GetSetRotation)
 {
     auto angle1 = 15;
     auto axis1 = Vec3d(12, 0, -0.5);
@@ -80,24 +80,23 @@ TEST_F(imstkGeometryTest, GetSetOrientation)
     auto axis2 = Vec3d(4000, -1, 0);
     auto aa2 = Rotd(angle2, axis2);
     auto mat2 = Mat3d(aa2);
-    auto q2 = Quatd(mat2);
 
     auto angle3 = 800;
     auto axis3 = Vec3d(-0, 100, 2000000);
     auto aa3 = Rotd(angle3, axis3);
-    auto q3 = Quatd(aa3);
+    auto mat3 = Mat3d(aa3);
 
     // NOTE: '==' not defined for Eigen::Quaternion, using 'isApprox'.
     // See https://forum.kde.org/viewtopic.php?f=74&t=118598
 
-    m_geometry.setOrientation(q1);
-    EXPECT_TRUE(m_geometry.getOrientation().isApprox(q1));
+    m_geometry.setRotation(q1);
+    EXPECT_TRUE(Quatd(m_geometry.getRotation()).isApprox(q1));
 
-    m_geometry.setOrientation(mat2);
-    EXPECT_TRUE(m_geometry.getOrientation().isApprox(q2));
+    m_geometry.setRotation(mat2);
+    EXPECT_TRUE(m_geometry.getRotation().isApprox(mat2));
 
-    m_geometry.setOrientation(axis3, angle3);
-    EXPECT_TRUE(m_geometry.getOrientation().isApprox(q3));
+    m_geometry.setRotation(axis3, angle3);
+    EXPECT_TRUE(m_geometry.getRotation().isApprox(mat3));
 }
 
 int imstkGeometryTest(int argc, char* argv[])
diff --git a/Base/Geometry/Testing/imstkPlaneTest.cpp b/Base/Geometry/Testing/imstkPlaneTest.cpp
index 66465d228db7c7488cc3cf9951b8f0c0445bcdc3..9ba22311650cf389dc0b0ec4fbc34d0ad34b769e 100644
--- a/Base/Geometry/Testing/imstkPlaneTest.cpp
+++ b/Base/Geometry/Testing/imstkPlaneTest.cpp
@@ -52,17 +52,21 @@ TEST_F(imstkPlaneTest, SetGetWidth)
 
 TEST_F(imstkPlaneTest, SetGetNormal)
 {
-    m_plane.setNormal(Vec3d(0.2, -0.3, 0.9));
-    EXPECT_EQ(m_plane.getNormal(), Vec3d(0.2, -0.3, 0.9));
+    Vec3d n1 = Vec3d(0.2, -0.3, 0.9);
+    Vec3d n2 = Vec3d(0.003, -0.001, 0.002);
+    Vec3d n3 = Vec3d(400000000, -500000000, 600000000);
 
-    m_plane.setNormal(Vec3d(0.003, -0.001, 0.002));
-    EXPECT_EQ(m_plane.getNormal(), Vec3d(0.003, -0.001, 0.002));
+    m_plane.setNormal(n1);
+    EXPECT_TRUE(m_plane.getNormal().isApprox(n1.normalized()));
 
-    m_plane.setNormal(Vec3d(400000000, -500000000, 600000000));
-    EXPECT_EQ(m_plane.getNormal(), Vec3d(400000000, -500000000, 600000000));
+    m_plane.setNormal(n2);
+    EXPECT_TRUE(m_plane.getNormal().isApprox(n2.normalized()));
 
-    m_plane.setNormal(WORLD_ORIGIN);
-    EXPECT_NE(m_plane.getNormal(), WORLD_ORIGIN);
+    m_plane.setNormal(n3);
+    EXPECT_TRUE(m_plane.getNormal().isApprox(n3.normalized()));
+
+    m_plane.setNormal(0, 0, 0);
+    EXPECT_FALSE(m_plane.getNormal().isApprox(Vec3d(0, 0, 0)));
 }
 
 TEST_F(imstkPlaneTest, GetVolume)
diff --git a/Base/Geometry/imstkGeometry.cpp b/Base/Geometry/imstkGeometry.cpp
index 28056200a6fbe09212fb2b1ba64afd3b38e5c534..f495e2103f601dffa63385af3702b85da2a8675b 100644
--- a/Base/Geometry/imstkGeometry.cpp
+++ b/Base/Geometry/imstkGeometry.cpp
@@ -28,133 +28,183 @@ void
 Geometry::print() const
 {
     LOG(INFO) << this->getTypeName();
-    LOG(INFO) << "Position: " << "(" << m_position.x() << ", " << m_position.y() << ", " << m_position.z() << ")";
-    LOG(INFO) << "Orientation:\n" << m_orientation.toRotationMatrix();
+
+    Vec3d t = m_transform.translation();
+    Mat3d r = m_transform.rotation();
     LOG(INFO) << "Scaling: " << m_scaling;
+    LOG(INFO) << "Translation: " << "(" << t.x() << ", " << t.y() << ", " << t.z() << ")";
+    LOG(INFO) << "Rotation:\n" << r;
 }
 
 void
-Geometry::translate(const Vec3d& t)
+Geometry::translate(const Vec3d& t, TransformType type)
 {
-    m_position += t;
+    if (t.isApprox(Vec3d::Zero()))
+    {
+        return;
+    }
+
+    if (type == TransformType::ConcatenateToTransform)
+    {
+        m_transform.translate(t);
+        m_transformModified = true;
+        m_transformApplied = false;
+    }
+    else
+    {
+        this->applyTranslation(t);
+        m_dataModified = true;
+    }
 }
 
 void
-Geometry::translate(const double& x,
-                    const double& y,
-                    const double& z)
+Geometry::translate(double x, double y, double z, TransformType type)
 {
-    this->translate(Vec3d(x, y, z));
+    this->translate(Vec3d(x, y, z), type);
 }
 
 void
-Geometry::rotate(const Quatd& r)
+Geometry::rotate(const Mat3d& r, TransformType type)
 {
-    m_orientation = r * m_orientation;
+    if (r.isApprox(Mat3d::Identity()))
+    {
+        return;
+    }
+
+    if (type == TransformType::ConcatenateToTransform)
+    {
+        m_transform.rotate(r);
+        m_transformModified = true;
+        m_transformApplied = false;
+    }
+    else
+    {
+        this->applyRotation(r);
+        m_dataModified = true;
+    }
 }
 
 void
-Geometry::rotate(const Mat3d& r)
+Geometry::rotate(const Quatd& q, TransformType type)
 {
-    this->rotate(Quatd(r));
+    this->rotate(q.toRotationMatrix(), type);
 }
 
 void
-Geometry::rotate(const Vec3d& axis, const double& angle)
+Geometry::rotate(const Vec3d& axis, double angle, TransformType type)
 {
-    this->rotate(Quatd(Rotd(angle, axis)));
+    this->rotate(Rotd(angle, axis).toRotationMatrix(), type);
 }
 
 void
-Geometry::scale(const double& scaling)
+Geometry::scale(double s, TransformType type)
 {
-    if(scaling <= 0)
+    if(s <= 0)
     {
         LOG(WARNING) << "Geometry::scale error: scaling should be positive.";
         return;
     }
-    m_scaling *= scaling;
-}
+    if (s == 1.0)
+    {
+        return;
+    }
 
-void
-Geometry::transform(const RigidTransform3d& transform)
-{
-    this->rotate(transform.rotation());
-    this->translate(transform.translation());
+    if (type == TransformType::ConcatenateToTransform)
+    {
+        m_scaling *= s;
+        m_transformModified = true;
+        m_transformApplied = false;
+    }
+    else
+    {
+        this->applyScaling(s);
+        m_dataModified = true;
+    }
 }
 
-bool
-Geometry::isMesh() const
+void
+Geometry::transform(RigidTransform3d T, TransformType type)
 {
-    return (this->m_type == Type::HexahedralMesh ||
-            this->m_type == Type::SurfaceMesh ||
-            this->m_type == Type::TetrahedralMesh ||
-            this->m_type == Type::LineMesh
-            ) ? true : false;
+    if (type == TransformType::ConcatenateToTransform)
+    {
+        m_transform = T * m_transform;
+        m_transformModified = true;
+        m_transformApplied = false;
+    }
+    else
+    {
+        this->applyTranslation(T.translation());
+        this->applyRotation(T.rotation());
+        m_dataModified = true;
+    }
 }
 
-const Vec3d&
-Geometry::getPosition() const
+Vec3d
+Geometry::getTranslation() const
 {
-    return m_position;
+    return m_transform.translation();
 }
 
 void
-Geometry::setPosition(const Vec3d& position)
+Geometry::setTranslation(const Vec3d t)
 {
-    m_position = position;
+    m_transform.translation() = t;
+    m_transformModified = true;
+    m_transformApplied = false;
 }
 
 void
-Geometry::setPosition(const double& x,
-                      const double& y,
-                      const double& z)
+Geometry::setTranslation(const double x, const double y, const double z)
 {
-    this->setPosition(Vec3d(x, y, z));
+    this->setTranslation(Vec3d(x, y, z));
 }
 
-const Quatd&
-Geometry::getOrientation() const
+Mat3d
+Geometry::getRotation() const
 {
-    return m_orientation;
+    return m_transform.linear();
 }
 
 void
-Geometry::setOrientation(const Quatd& orientation)
+Geometry::setRotation(const Mat3d m)
 {
-    m_orientation = orientation;
+    m_transform.linear() = m;
+    m_transformModified = true;
+    m_transformApplied = false;
 }
 
 void
-Geometry::setOrientation(const Mat3d& orientation)
+Geometry::setRotation(const Quatd q)
 {
-    this->setOrientation(Quatd(orientation));
+    this->setRotation(q.toRotationMatrix());
 }
 
 void
-Geometry::setOrientation(const Vec3d& axis, const double& angle)
+Geometry::setRotation(const Vec3d axis, const double angle)
 {
-    this->setOrientation(Quatd(Rotd(angle, axis)));
+    this->setRotation(Rotd(angle, axis).toRotationMatrix());
 }
 
-const double&
+double
 Geometry::getScaling() const
 {
     return m_scaling;
 }
 
 void
-Geometry::setScaling(const double& scaling)
+Geometry::setScaling(double s)
 {
-    if(scaling <= 0)
+    if(s <= 0)
     {
         LOG(WARNING) << "Geometry::setScaling error: scaling should be positive.";
         return;
     }
-    m_scaling = scaling;
+    m_scaling = s;
+    m_transformModified = true;
+    m_transformApplied = false;
 }
 
-const Geometry::Type&
+Geometry::Type
 Geometry::getType() const
 {
     return m_type;
@@ -182,6 +232,16 @@ Geometry::getTypeName() const
     }
 }
 
+bool
+Geometry::isMesh() const
+{
+    return (this->m_type == Type::HexahedralMesh ||
+            this->m_type == Type::SurfaceMesh ||
+            this->m_type == Type::TetrahedralMesh ||
+            this->m_type == Type::LineMesh
+            ) ? true : false;
+}
+
 void
 Geometry::setRenderMaterial(std::shared_ptr<RenderMaterial> renderMaterial)
 {
diff --git a/Base/Geometry/imstkGeometry.h b/Base/Geometry/imstkGeometry.h
index ed97f02264faad7f49b0ae504269486ea750323f..74024353025bfd82680030dc5254f64a4e2df6d1 100644
--- a/Base/Geometry/imstkGeometry.h
+++ b/Base/Geometry/imstkGeometry.h
@@ -53,15 +53,32 @@ public:
         Capsule
     };
 
+    ///
+    /// \brief Enumeration for the transformation to apply
+    /// \params ApplyToTransform to apply the transformation to the data
+    /// \params ApplyToTransform to apply the transformation to the transform matrix
+    ///
+    enum class TransformType
+    {
+        ApplyToData,
+        ConcatenateToTransform
+    };
+
+    ///
+    /// \brief Enumeration for the data to retrieve
+    /// \params PreTransform for data where transform matrix is not applied
+    /// \params PostTransform for data where transform matrix is applied
+    ///
+    enum class DataType
+    {
+        PreTransform,
+        PostTransform
+    };
+
     ///
     /// \brief Constructor
     ///
-    Geometry(Type type,
-             const Vec3d& position = WORLD_ORIGIN,
-             const Quatd& orientation = Quatd::Identity()) :
-        m_type(type),
-        m_position(position),
-        m_orientation(orientation){}
+    Geometry(Type type) : m_type(type) {}
 
     ///
     /// \brief Destructor
@@ -81,69 +98,69 @@ public:
     ///
     /// \brief Translate the geometry in Cartesian space
     ///
-    void         translate(const Vec3d& t);
-    void         translate(const double& x,
-                           const double& y,
-                           const double& z);
+    void translate(const Vec3d& t,
+                   TransformType type = TransformType::ConcatenateToTransform);
+    void translate(double x, double y, double z,
+                   TransformType type = TransformType::ConcatenateToTransform);
 
     ///
     /// \brief Rotate the geometry in Cartesian space
     ///
-    void         rotate(const Quatd& r);
-    void         rotate(const Mat3d& r);
-    void         rotate(const Vec3d & axis,
-                        const double& angle);
+    void rotate(const Quatd& q,
+                TransformType type = TransformType::ConcatenateToTransform);
+    void rotate(const Mat3d& m,
+                TransformType type = TransformType::ConcatenateToTransform);
+    void rotate(const Vec3d& axis, double angle,
+                TransformType type = TransformType::ConcatenateToTransform);
 
     ///
     /// \brief Scale in Cartesian directions
     ///
-    void         scale(const double& scaling);
+    void scale(double scaling,
+               TransformType type = TransformType::ConcatenateToTransform);
 
     ///
     /// \brief Applies a rigid transform to the geometry
     ///
-    void        transform(const RigidTransform3d& transform);
+    void transform(RigidTransform3d T,
+                   TransformType type = TransformType::ConcatenateToTransform);
 
     ///
-    /// \brief Returns true if the geometry is a mesh, else returns false
+    /// \brief Get/Set translation
     ///
-    bool isMesh() const;
-
-    // Accessors
+    Vec3d getTranslation() const;
+    void setTranslation(const Vec3d t);
+    void setTranslation(double x, double y, double z);
 
     ///
-    /// \brief Get/Set position
+    /// \brief Get/Set rotation
     ///
-    const Vec3d& getPosition() const;
-    void         setPosition(const Vec3d& position);
-    void         setPosition(const double& x,
-                             const double& y,
-                             const double& z);
+    Mat3d getRotation() const;
+    void setRotation(const Mat3d m);
+    void setRotation(const Quatd q);
+    void setRotation(const Vec3d axis, const double angle);
 
     ///
-    /// \brief Get/Set orientation
-    ///
-    const Quatd       & getOrientation() const;
-    void                setOrientation(const Quatd& orientation);
-    void                setOrientation(const Mat3d& orientation);
-    void                setOrientation(const Vec3d & axis,
-                                       const double& angle);
-    ///
     /// \brief Get/Set scaling
     ///
-    const double      & getScaling() const;
-    void                setScaling(const double& scaling);
+    double getScaling() const;
+    void setScaling(const double s);
 
     ///
     /// \brief Returns the type of the geometry
     ///
-    const Type& getType() const;
+    Type getType() const;
 
     ///
     /// \brief Returns the string representing the type name of the geometry
     ///
     const std::string getTypeName() const;
 
+    ///
+    /// \brief Returns true if the geometry is a mesh, else returns false
+    ///
+    bool isMesh() const;
+
     ///
     /// \brief Set/Get render material
     ///
@@ -151,12 +168,23 @@ public:
     std::shared_ptr<RenderMaterial> getRenderMaterial() const;
 
 protected:
+    friend class VTKRenderDelegate;
+
+    virtual void applyTranslation(const Vec3d t) = 0;
+    virtual void applyRotation(const Mat3d r) = 0;
+    virtual void applyScaling(const double s) = 0;
+    virtual void updatePostTransformData() = 0;
 
     Type m_type; ///> Geometry type
-    Vec3d  m_position; ///> position
-    Quatd  m_orientation; ///> orientation
-    double m_scaling = 1; ///> Scaling
-    std::shared_ptr<RenderMaterial> m_renderMaterial = nullptr; // Render material
+
+    bool m_dataModified = false;
+    bool m_transformModified = false;
+    bool m_transformApplied = true;
+
+    RigidTransform3d m_transform = RigidTransform3d::Identity(); ///> Transform
+    double m_scaling = 1.0;
+
+    std::shared_ptr<RenderMaterial> m_renderMaterial = nullptr; ///> Render material
 };
 
 } //imstk
diff --git a/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
index 7a1189bc154f8e0fca9197f86fe2727f4592e9de..d0fa15403b2a2e1c12a7e851b612b17db9448a32 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
@@ -21,26 +21,55 @@
 
 #include "imstkVTKCapsuleRenderDelegate.h"
 
+#include "vtkCapsuleSource.h"
+
 namespace imstk
 {
 
 VTKCapsuleRenderDelegate::VTKCapsuleRenderDelegate(std::shared_ptr<Capsule> capsule) :
-m_capsuleGeometry(capsule)
+    m_geometry(capsule),
+    m_transformFilter(vtkSmartPointer<vtkTransformPolyDataFilter>::New())
+{
+    Geometry::DataType type = Geometry::DataType::PreTransform;
+    auto capsuleSource = vtkSmartPointer<vtkCapsuleSource>::New();
+    capsuleSource->SetRadius(m_geometry->getRadius(type));
+    capsuleSource->SetCylinderLength(m_geometry->getLength(type));
+    capsuleSource->SetLatLongTessellation(20);
+    capsuleSource->SetPhiResolution(20);
+    capsuleSource->SetThetaResolution(20);
+
+    m_transformFilter->SetInputConnection(capsuleSource->GetOutputPort());
+    m_transformFilter->SetTransform(vtkSmartPointer<vtkTransform>::New());
+
+    this->update();
+    this->setUpMapper(m_transformFilter->GetOutputPort(), true);
+}
+
+void
+VTKCapsuleRenderDelegate::updateDataSource()
 {
-    auto source = vtkSmartPointer<vtkCapsuleSource>::New();
+    if (!m_geometry->m_dataModified)
+    {
+        return;
+    }
+
+    Geometry::DataType type = Geometry::DataType::PreTransform;
 
-    source->SetCenter(WORLD_ORIGIN[0], WORLD_ORIGIN[1], WORLD_ORIGIN[2]);
-    source->SetRadius(m_capsuleGeometry->getRadius());
-    source->SetCylinderLength(m_capsuleGeometry->getHeight());
+    AffineTransform3d T = AffineTransform3d::Identity();
+    T.translate(m_geometry->getPosition(type));
+    T.rotate(Quatd::FromTwoVectors(UP_VECTOR, m_geometry->getOrientationAxis(type)));
+    T.matrix().transposeInPlace();
 
-    // Set the resolution for rendering
-    source->SetLatLongTessellation(10);
-    source->SetPhiResolution(10);
-    source->SetThetaResolution(10);
+    auto vtkT = vtkTransform::SafeDownCast(m_transformFilter->GetTransform());
+    vtkT->SetMatrix(T.data());
 
-    // Setup Mapper & Actor
-    this->setUpMapper(source->GetOutputPort(), true);
-    this->updateActorTransform();
+    m_geometry->m_dataModified = false;
+}
+
+std::shared_ptr<Geometry>
+VTKCapsuleRenderDelegate::getGeometry() const
+{
+    return m_geometry;
 }
 
-} // imstk
\ No newline at end of file
+} // imstk
diff --git a/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.h b/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.h
index 79bd2cd5ca284321f2c5c15284b2f2db2e4c474d..a7e31e178462b96d54199d43f6a418989a57b522 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.h
+++ b/Base/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.h
@@ -27,7 +27,7 @@
 #include "imstkVTKRenderDelegate.h"
 #include "imstkCapsule.h"
 
-#include "vtkCapsuleSource.h"
+#include "vtkTransformPolyDataFilter.h"
 
 namespace imstk
 {
@@ -41,24 +41,30 @@ class VTKCapsuleRenderDelegate : public VTKRenderDelegate
 {
 public:
     ///
-    /// \brief Default destructor
+    /// \brief Constructor
+    ///
+    VTKCapsuleRenderDelegate(std::shared_ptr<Capsule> capsule);
+
+    ///
+    /// \brief destructor
     ///
     ~VTKCapsuleRenderDelegate() = default;
 
     ///
-    /// \brief Constructor
+    /// \brief Update capsule source based on the capsule geometry
     ///
-    VTKCapsuleRenderDelegate(std::shared_ptr<Capsule> capsule);
+    void updateDataSource() override;
 
     ///
-    /// \brief Returns the capsule geometry object
+    /// \brief Returns the capsule geometry
     ///
-    std::shared_ptr<Geometry>getGeometry() const override { return m_capsuleGeometry; }
+    std::shared_ptr<Geometry> getGeometry() const override;
 
 protected:
-    std::shared_ptr<Capsule> m_capsuleGeometry; ///>Capsule geometry
+    std::shared_ptr<Capsule> m_geometry; ///> Geometry
+    vtkSmartPointer<vtkTransformPolyDataFilter> m_transformFilter; ///> Source
 };
 
 } // imstk
 
-#endif // ifndef imstkCapsuleRenderDelegate_h
\ No newline at end of file
+#endif // ifndef imstkCapsuleRenderDelegate_h
diff --git a/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
index d68578d4b7c39e80286f217e141e51178b161f0b..37035991d1f6a0ad03855344505bc4f13ab65431 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
@@ -21,26 +21,48 @@
 
 #include "imstkVTKCubeRenderDelegate.h"
 
-#include "g3log/g3log.hpp"
+#include "vtkCubeSource.h"
 
 namespace imstk
 {
 
 VTKCubeRenderDelegate::VTKCubeRenderDelegate(std::shared_ptr<Cube>cube) :
-    m_geometry(cube)
+    m_geometry(cube),
+    m_transformFilter(vtkSmartPointer<vtkTransformPolyDataFilter>::New())
 {
-    auto width = m_geometry->getWidth();
+    auto cubeSource = vtkSmartPointer<vtkCubeSource>::New();
+    cubeSource->SetCenter(0, 0, 0);
+    cubeSource->SetXLength(1.0);
+    cubeSource->SetYLength(1.0);
+    cubeSource->SetZLength(1.0);
 
-    auto source = vtkSmartPointer<vtkCubeSource>::New();
+    m_transformFilter->SetInputConnection(cubeSource->GetOutputPort());
+    m_transformFilter->SetTransform(vtkSmartPointer<vtkTransform>::New());
 
-    source->SetCenter(WORLD_ORIGIN[0], WORLD_ORIGIN[1], WORLD_ORIGIN[2]);
-    source->SetXLength(width);
-    source->SetYLength(width);
-    source->SetZLength(width);
+    this->update();
+    this->setUpMapper(m_transformFilter->GetOutputPort(), true);
+}
+
+void
+VTKCubeRenderDelegate::updateDataSource()
+{
+    if (!m_geometry->m_dataModified)
+    {
+        return;
+    }
+
+    Geometry::DataType type = Geometry::DataType::PreTransform;
+
+    AffineTransform3d T = AffineTransform3d::Identity();
+    T.translate(m_geometry->getPosition(type));
+    T.rotate(Quatd::FromTwoVectors(UP_VECTOR, m_geometry->getOrientationAxis(type)));
+    T.scale(m_geometry->getWidth(type));
+    T.matrix().transposeInPlace();
+
+    auto vtkT = vtkTransform::SafeDownCast(m_transformFilter->GetTransform());
+    vtkT->SetMatrix(T.data());
 
-    // Setup Mapper & Actor
-    this->setUpMapper(source->GetOutputPort(), true);
-    this->updateActorTransform();
+    m_geometry->m_dataModified = false;
 }
 
 std::shared_ptr<Geometry>
diff --git a/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.h b/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.h
index 94f7b03688bf16c55901109690aac0662b7e7baa..af4c08342f57d86e747c4f752447cf96dce3e171 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.h
+++ b/Base/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.h
@@ -27,7 +27,7 @@
 #include "imstkVTKRenderDelegate.h"
 #include "imstkCube.h"
 
-#include "vtkCubeSource.h"
+#include "vtkTransformPolyDataFilter.h"
 
 namespace imstk
 {
@@ -43,7 +43,7 @@ public:
     ///
     /// \brief Constructor
     ///
-    VTKCubeRenderDelegate(std::shared_ptr<Cube>cube);
+    VTKCubeRenderDelegate(std::shared_ptr<Cube> cube);
 
     ///
     /// \brief Destructor
@@ -51,12 +51,19 @@ public:
     ~VTKCubeRenderDelegate() = default;
 
     ///
-    /// \brief Get the geometry
+    /// \brief Update cube source based on the cube geometry
     ///
-    std::shared_ptr<Geometry>getGeometry() const override;
+    void updateDataSource() override;
+
+    ///
+    /// \brief Returns the cube geometry
+    ///
+    std::shared_ptr<Geometry> getGeometry() const override;
 
 protected:
     std::shared_ptr<Cube> m_geometry;   ///> Geometry
+
+    vtkSmartPointer<vtkTransformPolyDataFilter> m_transformFilter; ///> Source
 };
 
 } // imstk
diff --git a/Base/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp
index a50b194be41483f94af3fd7d3dd53abbcf19256c..c9d003e00b7a8418182ccd80558efdf9d91630c3 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp
@@ -30,18 +30,16 @@
 #include <vtkCellArray.h>
 #include <vtkProperty.h>
 
-#include "g3log/g3log.hpp"
-
 namespace imstk
 {
 
 VTKHexahedralMeshRenderDelegate::VTKHexahedralMeshRenderDelegate(std::shared_ptr<HexahedralMesh> hexahedralMesh) :
-    m_geometry(hexahedralMesh)
+    m_geometry(hexahedralMesh),
+    m_mappedVertexArray(vtkSmartPointer<vtkDoubleArray>::New())
 {
     // Map vertices
-    StdVectorOfVec3d& vertices = m_geometry->getVerticesPositionsNotConst();
+    StdVectorOfVec3d& vertices = m_geometry->getVertexPositionsNotConst();
     double* vertData = reinterpret_cast<double*>(vertices.data());
-    m_mappedVertexArray = vtkSmartPointer<vtkDoubleArray>::New();
     m_mappedVertexArray->SetNumberOfComponents(3);
     m_mappedVertexArray->SetArray(vertData, vertices.size()*3, 1);
 
@@ -66,26 +64,28 @@ VTKHexahedralMeshRenderDelegate::VTKHexahedralMeshRenderDelegate(std::shared_ptr
     auto unstructuredGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
     unstructuredGrid->SetPoints(points);
     unstructuredGrid->SetCells(VTK_HEXAHEDRON, cells);
+    m_geometry->m_dataModified = false;
 
-    // Mapper
+    // Mapper & Actor
     auto mapper = vtkSmartPointer<vtkDataSetMapper>::New();
     mapper->SetInputData(unstructuredGrid);
-
-    // Actor
     m_actor->SetMapper(mapper);
-    m_actor->GetProperty()->EdgeVisibilityOn();
 
-    // Transform
-    this->updateActorTransform();
+    // Update Transform, Render Properties
+    this->update();
 }
 
 void
-VTKHexahedralMeshRenderDelegate::update()
+VTKHexahedralMeshRenderDelegate::updateDataSource()
 {
-    // Base class update
-    VTKRenderDelegate::update();
+    if (!m_geometry->m_dataModified)
+    {
+        return;
+    }
+
+    m_mappedVertexArray->Modified();
 
-    m_mappedVertexArray->Modified(); // TODO: only modify if vertices change
+    m_geometry->m_dataModified = false;
 }
 
 
diff --git a/Base/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h b/Base/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h
index 4c7e37c84c47abdfef49dd137da7768c9d134858..db9ede875a92a8bc72338060dffd5800fc322fb3 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h
+++ b/Base/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h
@@ -42,29 +42,29 @@ class VTKHexahedralMeshRenderDelegate : public VTKRenderDelegate
 {
 public:
     ///
-    /// \brief
+    /// \brief Constructor
     ///
-    ~VTKHexahedralMeshRenderDelegate() = default;
+    VTKHexahedralMeshRenderDelegate(std::shared_ptr<HexahedralMesh> hexahedralMesh);
 
     ///
-    /// \brief
+    /// \brief Destructor
     ///
-    VTKHexahedralMeshRenderDelegate(std::shared_ptr<HexahedralMesh> hexahedralMesh);
+    ~VTKHexahedralMeshRenderDelegate() = default;
 
     ///
-    /// \brief
+    /// \brief Update unstructured grid source based on the hexahedral mesh
     ///
-    void update() override;
+    void updateDataSource() override;
 
     ///
-    /// \brief
+    /// \brief Returns the hexahedral mesh
     ///
     std::shared_ptr<Geometry> getGeometry() const override;
 
 protected:
 
-    std::shared_ptr<HexahedralMesh> m_geometry; ///> Geometry to render
-    vtkSmartPointer<vtkDoubleArray> m_mappedVertexArray; ///> Mapped array of vertices
+    std::shared_ptr<HexahedralMesh> m_geometry;             ///> Geometry to render
+    vtkSmartPointer<vtkDoubleArray> m_mappedVertexArray;    ///> Mapped array of vertices
 };
 
 } // imstk
diff --git a/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
index 2828291ad26ac8f21e25cf535a124d8a70469c89..8985470a5d36818297de819e711e44a4323a88e1 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
@@ -28,18 +28,16 @@
 #include <vtkPoints.h>
 #include <vtkDoubleArray.h>
 
-#include "g3log/g3log.hpp"
-
 namespace imstk
 {
 
 VTKLineMeshRenderDelegate::VTKLineMeshRenderDelegate(std::shared_ptr<LineMesh> lineMesh) :
-    m_geometry(lineMesh)
+    m_geometry(lineMesh),
+    m_mappedVertexArray(vtkSmartPointer<vtkDoubleArray>::New())
 {
     // Map vertices
-    StdVectorOfVec3d& vertices = m_geometry->getVerticesPositionsNotConst();
+    StdVectorOfVec3d& vertices = m_geometry->getVertexPositionsNotConst();
     double* vertData = reinterpret_cast<double*>(vertices.data());
-    m_mappedVertexArray = vtkSmartPointer<vtkDoubleArray>::New();
     m_mappedVertexArray->SetNumberOfComponents(3);
     m_mappedVertexArray->SetArray(vertData, vertices.size()*3, 1);
 
@@ -51,19 +49,26 @@ VTKLineMeshRenderDelegate::VTKLineMeshRenderDelegate(std::shared_ptr<LineMesh> l
     // Create line
     auto lines = vtkSmartPointer<vtkLineSource>::New();
     lines->SetPoints(points);
+    m_geometry->m_dataModified = false;
 
     // Setup Mapper & Actor
     this->setUpMapper(lines->GetOutputPort(), true);
-    this->updateActorTransform();
+
+    // Update Transform, Render Properties
+    this->update();
 }
 
 void
-VTKLineMeshRenderDelegate::update()
+VTKLineMeshRenderDelegate::updateDataSource()
 {
-    // Base class update
-    VTKRenderDelegate::update();
+    if (!m_geometry->m_dataModified)
+    {
+        return;
+    }
+
+    m_mappedVertexArray->Modified();
 
-    m_mappedVertexArray->Modified(); // TODO: only modify if vertices change
+    m_geometry->m_dataModified = false;
 }
 
 std::shared_ptr<Geometry>
diff --git a/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.h b/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.h
index a96a7846fcdbcb7cba53a75df0232e809f98185e..30ef313fbb7b41ec17c5e7a58e638815d2e61d7b 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.h
+++ b/Base/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.h
@@ -42,29 +42,29 @@ class VTKLineMeshRenderDelegate : public VTKRenderDelegate
 {
 public:
     ///
-    /// \brief
+    /// \brief Constructor
     ///
-    ~VTKLineMeshRenderDelegate() = default;
+    VTKLineMeshRenderDelegate(std::shared_ptr<LineMesh> lineMesh);
 
     ///
-    /// \brief
+    /// \brief Destructor
     ///
-    VTKLineMeshRenderDelegate(std::shared_ptr<LineMesh> lineMesh);
+    ~VTKLineMeshRenderDelegate() = default;
 
     ///
-    /// \brief
+    /// \brief Update line source based on the line mesh
     ///
-    void update() override;
+    void updateDataSource() override;
 
     ///
-    /// \brief
+    /// \brief Returns the line mesh
     ///
     std::shared_ptr<Geometry>getGeometry() const override;
 
 protected:
 
-    std::shared_ptr<LineMesh>  m_geometry; ///> Geometry to render
-    vtkSmartPointer<vtkDoubleArray> m_mappedVertexArray; ///> Mapped array of vertices
+    std::shared_ptr<LineMesh>  m_geometry;                  ///> Geometry to render
+    vtkSmartPointer<vtkDoubleArray> m_mappedVertexArray;    ///> Mapped array of vertices
 
 };
 
diff --git a/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
index 8e4b3aff0e8a40485c4e0940e6d304daa3415633..9815bea8ef1add98cc85f6b66a9a036605911e4a 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
@@ -21,22 +21,46 @@
 
 #include "imstkVTKPlaneRenderDelegate.h"
 
-#include "g3log/g3log.hpp"
+#include "vtkPlaneSource.h"
 
 namespace imstk
 {
 
 VTKPlaneRenderDelegate::VTKPlaneRenderDelegate(std::shared_ptr<Plane>plane) :
-    m_geometry(plane)
+    m_geometry(plane),
+    m_transformFilter(vtkSmartPointer<vtkTransformPolyDataFilter>::New())
 {
-    auto source = vtkSmartPointer<vtkPlaneSource>::New();
+    auto planeSource = vtkSmartPointer<vtkPlaneSource>::New();
+    planeSource->SetCenter(0, 0, 0);
+    planeSource->SetNormal(0, 1, 0);
 
-    source->SetCenter(WORLD_ORIGIN[0], WORLD_ORIGIN[1], WORLD_ORIGIN[2]);
-    source->SetNormal(m_geometry->getNormal().data());
+    m_transformFilter->SetInputConnection(planeSource->GetOutputPort());
+    m_transformFilter->SetTransform(vtkSmartPointer<vtkTransform>::New());
 
-    // Setup Mapper & Actor
-    this->setUpMapper(source->GetOutputPort(), true);
-    this->updateActorTransform();
+    this->update();
+    this->setUpMapper(m_transformFilter->GetOutputPort(), true);
+}
+
+void
+VTKPlaneRenderDelegate::updateDataSource()
+{
+    if (!m_geometry->m_dataModified)
+    {
+        return;
+    }
+
+    Geometry::DataType type = Geometry::DataType::PreTransform;
+
+    AffineTransform3d T = AffineTransform3d::Identity();
+    T.translate(m_geometry->getPosition(type));
+    T.rotate(Quatd::FromTwoVectors(UP_VECTOR, m_geometry->getNormal(type)));
+    T.scale(m_geometry->getWidth(type));
+    T.matrix().transposeInPlace();
+
+    auto vtkT = vtkTransform::SafeDownCast(m_transformFilter->GetTransform());
+    vtkT->SetMatrix(T.data());
+
+    m_geometry->m_dataModified = false;
 }
 
 std::shared_ptr<Geometry>
diff --git a/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.h b/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.h
index 0e69af9c8d69052d8d1c1d2a1421383f748bb562..d2a788ec354b98bae09b6736598e42526544c284 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.h
+++ b/Base/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.h
@@ -27,7 +27,7 @@
 #include "imstkVTKRenderDelegate.h"
 #include "imstkPlane.h"
 
-#include "vtkPlaneSource.h"
+#include "vtkTransformPolyDataFilter.h"
 
 namespace imstk
 {
@@ -41,23 +41,30 @@ class VTKPlaneRenderDelegate : public VTKRenderDelegate
 {
 public:
     ///
-    /// \brief
+    /// \brief Constructor
     ///
-    VTKPlaneRenderDelegate(std::shared_ptr<Plane>plane);
+    VTKPlaneRenderDelegate(std::shared_ptr<Plane> plane);
 
     ///
-    /// \brief
+    /// \brief Destructor
     ///
     ~VTKPlaneRenderDelegate() = default;
 
     ///
-    /// \brief
+    /// \brief Update plane source based on the plane geometry
     ///
-    std::shared_ptr<Geometry>getGeometry() const override;
+    void updateDataSource() override;
+
+    ///
+    /// \brief Returns the plane geometry
+    ///
+    std::shared_ptr<Geometry> getGeometry() const override;
 
 protected:
 
     std::shared_ptr<Plane> m_geometry;  ///> Geometry
+
+    vtkSmartPointer<vtkTransformPolyDataFilter> m_transformFilter;
 };
 
 } // imstk
diff --git a/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.cpp
index 47ac655270810d277fabda8cc21776f6574dea01..3fed43e1767a7876eea28720f4fe1bcb76b391b4 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.cpp
@@ -137,7 +137,7 @@ VTKRenderDelegate::getVtkActor() const
 void
 VTKRenderDelegate::update()
 {
-    // TODO : only when rigid transform applied
+    this->updateDataSource();
     this->updateActorTransform();
     this->updateActorProperties();
 }
@@ -145,19 +145,16 @@ VTKRenderDelegate::update()
 void
 VTKRenderDelegate::updateActorTransform()
 {
-    auto scaling   = this->getGeometry()->getScaling();
-    auto pos       = this->getGeometry()->getPosition();
-    auto quat      = this->getGeometry()->getOrientation();
-    auto angleAxis = Rotd(quat);
-
-    m_transform->Identity();
-    m_transform->PostMultiply();
-    m_transform->Scale(scaling, scaling, scaling);
-    m_transform->RotateWXYZ(angleAxis.angle() * 180 / PI,
-                          angleAxis.axis()[0],
-                          angleAxis.axis()[1],
-                          angleAxis.axis()[2]);
-    m_transform->Translate(pos[0], pos[1], pos[2]);
+    auto geom = this->getGeometry();
+    if (!geom->m_transformModified)
+    {
+        return;
+    }
+    AffineTransform3d T(geom->m_transform.matrix());
+    T.scale(geom->getScaling());
+    T.matrix().transposeInPlace();
+    m_transform->SetMatrix(T.data());
+    geom->m_transformModified = false;
 }
 
 void
diff --git a/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.h b/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.h
index 11512be1499d7c575da1e7fd9eb1d5539aa68562..38cfb67d8d3b8ce62e886d9d545bd73153f89336 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.h
+++ b/Base/Rendering/RenderDelegate/imstkVTKRenderDelegate.h
@@ -76,7 +76,7 @@ public:
     ///
     /// \brief Update render delegate
     ///
-    virtual void update();
+    void update();
 
     ///
     /// \brief Update rendere delegate transform based on the geometry shallow transform
@@ -88,6 +88,11 @@ public:
     ///
     void updateActorProperties();
 
+    ///
+    /// \brief Update render delegate source based on the geometry internal data
+    ///
+    virtual void updateDataSource() = 0;
+
 protected:
     ///
     /// \brief Default constructor (protected)
diff --git a/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
index 55e1450453631e0ddbab62ee48f38bd711140ef7..b745009bce588b44c90fa9ce9e1e6fcdf215f239 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
@@ -21,24 +21,47 @@
 
 #include "imstkVTKSphereRenderDelegate.h"
 
-#include "g3log/g3log.hpp"
+#include "vtkSphereSource.h"
 
 namespace imstk
 {
 
 VTKSphereRenderDelegate::VTKSphereRenderDelegate(std::shared_ptr<Sphere>sphere) :
-    m_geometry(sphere)
+    m_geometry(sphere),
+    m_transformFilter(vtkSmartPointer<vtkTransformPolyDataFilter>::New())
 {
-    auto source = vtkSmartPointer<vtkSphereSource>::New();
+    auto sphereSource = vtkSmartPointer<vtkSphereSource>::New();
+    sphereSource->SetCenter(0, 0, 0);
+    sphereSource->SetRadius(1.0);
+    sphereSource->SetPhiResolution(20);
+    sphereSource->SetThetaResolution(20);
 
-    source->SetCenter(WORLD_ORIGIN[0], WORLD_ORIGIN[1], WORLD_ORIGIN[2]);
-    source->SetRadius(m_geometry->getRadius());
-    source->SetPhiResolution(20);
-    source->SetThetaResolution(20);
+    m_transformFilter->SetInputConnection(sphereSource->GetOutputPort());
+    m_transformFilter->SetTransform(vtkSmartPointer<vtkTransform>::New());
 
-    // Setup Mapper & Actor
-    this->setUpMapper(source->GetOutputPort(), true);
-    this->updateActorTransform();
+    this->update();
+    this->setUpMapper(m_transformFilter->GetOutputPort(), true);
+}
+
+void
+VTKSphereRenderDelegate::updateDataSource()
+{
+    if (!m_geometry->m_dataModified)
+    {
+        return;
+    }
+
+    Geometry::DataType type = Geometry::DataType::PreTransform;
+
+    AffineTransform3d T = AffineTransform3d::Identity();
+    T.translate(m_geometry->getPosition(type));
+    T.rotate(Quatd::FromTwoVectors(UP_VECTOR, m_geometry->getOrientationAxis(type)));
+    T.scale(m_geometry->getRadius(type));
+    T.matrix().transposeInPlace();
+
+    auto vtkT = vtkTransform::SafeDownCast(m_transformFilter->GetTransform());
+    vtkT->SetMatrix(T.data());
+    m_geometry->m_dataModified = false;
 }
 
 std::shared_ptr<Geometry>
diff --git a/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.h b/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.h
index b5daa11b1b7efb3be818c477e00495b58c8a2744..3f3cd5eabf5cb6a5a68f6ed39cf43502cebbd7da 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.h
+++ b/Base/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.h
@@ -27,7 +27,7 @@
 #include "imstkVTKRenderDelegate.h"
 #include "imstkSphere.h"
 
-#include "vtkSphereSource.h"
+#include "vtkTransformPolyDataFilter.h"
 
 namespace imstk
 {
@@ -41,22 +41,28 @@ class VTKSphereRenderDelegate : public VTKRenderDelegate
 {
 public:
     ///
-    /// \brief
+    /// \brief Constructor
+    ///
+    VTKSphereRenderDelegate(std::shared_ptr<Sphere> sphere);
+
+    ///
+    /// \brief Destructor
     ///
     ~VTKSphereRenderDelegate() = default;
 
     ///
-    /// \brief
+    /// \brief Update sphere source based on the sphere geometry
     ///
-    VTKSphereRenderDelegate(std::shared_ptr<Sphere>sphere);
+    void updateDataSource() override;
 
     ///
-    /// \brief
+    /// \brief Returns the sphere geometry
     ///
-    std::shared_ptr<Geometry>getGeometry() const override;
+    std::shared_ptr<Geometry> getGeometry() const override;
 
 protected:
-    std::shared_ptr<Sphere> m_geometry; ///>
+    std::shared_ptr<Sphere> m_geometry;         ///> Geometry
+    vtkSmartPointer<vtkTransformPolyDataFilter> m_transformFilter;
 };
 
 } // imstk
diff --git a/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
index 6be283723ab01026e02d50df1cd071d8f29654dd..c88f69e0a61a8c72238a0bcb1d4ddde1e805a0eb 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
@@ -38,18 +38,16 @@
 #include <vtkProperty.h>
 #include <vtkOpenGLPolyDataMapper.h>
 
-#include "g3log/g3log.hpp"
-
 namespace imstk
 {
 
 VTKSurfaceMeshRenderDelegate::VTKSurfaceMeshRenderDelegate(std::shared_ptr<SurfaceMesh> surfaceMesh) :
-    m_geometry(surfaceMesh)
+    m_geometry(surfaceMesh),
+    m_mappedVertexArray(vtkSmartPointer<vtkDoubleArray>::New())
 {
     // Map vertices
-    StdVectorOfVec3d& vertices = m_geometry->getVerticesPositionsNotConst();
+    StdVectorOfVec3d& vertices = m_geometry->getVertexPositionsNotConst();
     double* vertData = reinterpret_cast<double*>(vertices.data());
-    m_mappedVertexArray = vtkSmartPointer<vtkDoubleArray>::New();
     m_mappedVertexArray->SetNumberOfComponents(3);
     m_mappedVertexArray->SetArray(vertData, vertices.size()*3, 1);
 
@@ -85,7 +83,9 @@ VTKSurfaceMeshRenderDelegate::VTKSurfaceMeshRenderDelegate(std::shared_ptr<Surfa
     // Create connection source
     auto source = vtkSmartPointer<vtkTrivialProducer>::New();
     source->SetOutput(polydata);
+    m_geometry->m_dataModified = false;
 
+    // Setup texture coordinates
     if (m_geometry->getDefaultTCoords() != "")
     {
         // Convert texture coordinates
@@ -110,25 +110,22 @@ VTKSurfaceMeshRenderDelegate::VTKSurfaceMeshRenderDelegate(std::shared_ptr<Surfa
         }
     }
 
-    // Setup Mapper & Actor
+    // Update Transform, Render Properties
+    this->update();
     this->setUpMapper(source->GetOutputPort(), false);
-    this->updateActorTransform();
-    this->updateActorProperties();
 }
 
 void
-VTKSurfaceMeshRenderDelegate::update()
+VTKSurfaceMeshRenderDelegate::updateDataSource()
 {
-    // Base class update
-    VTKRenderDelegate::update();
+    if (!m_geometry->m_dataModified)
+    {
+        return;
+    }
 
-    m_mappedVertexArray->Modified(); // TODO: only modify if vertices change
-}
+    m_mappedVertexArray->Modified();
 
-std::shared_ptr<Geometry>
-VTKSurfaceMeshRenderDelegate::getGeometry() const
-{
-    return m_geometry;
+    m_geometry->m_dataModified = false;
 }
 
 void
@@ -173,4 +170,10 @@ VTKSurfaceMeshRenderDelegate::initializeTextures(TextureManager<VTKTextureDelega
     }
 }
 
+std::shared_ptr<Geometry>
+VTKSurfaceMeshRenderDelegate::getGeometry() const
+{
+    return m_geometry;
+}
+
 } // imstk
diff --git a/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h b/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h
index fd4e96b6e03a4e7c184d5f2b89c5858759b69364..d913fbf9a65dc369b808560f5b4f869a097becaf 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h
+++ b/Base/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h
@@ -44,34 +44,34 @@ class VTKSurfaceMeshRenderDelegate : public VTKRenderDelegate
 {
 public:
     ///
-    /// \brief
-    ///
-    ~VTKSurfaceMeshRenderDelegate() = default;
-
-    ///
-    /// \brief
+    /// \brief Constructor
     ///
     VTKSurfaceMeshRenderDelegate(std::shared_ptr<SurfaceMesh> surfaceMesh);
 
     ///
-    /// \brief
+    /// \brief Destructor
     ///
-    void update() override;
+    ~VTKSurfaceMeshRenderDelegate() = default;
 
     ///
-    /// \brief
+    /// \brief Update polydata source based on the surface mesh geometry
     ///
-    std::shared_ptr<Geometry> getGeometry() const override;
+    void updateDataSource() override;
 
     ///
     /// \brief Initialize textures
     ///
     void initializeTextures(TextureManager<VTKTextureDelegate>& textureManager);
 
+    ///
+    /// \brief Returns the surface mesh
+    ///
+    std::shared_ptr<Geometry> getGeometry() const override;
+
 protected:
 
-    std::shared_ptr<SurfaceMesh> m_geometry; ///> Geometry to render
-    vtkSmartPointer<vtkDoubleArray> m_mappedVertexArray; ///> Mapped array of vertices
+    std::shared_ptr<SurfaceMesh> m_geometry;                ///> Geometry to render
+    vtkSmartPointer<vtkDoubleArray> m_mappedVertexArray;    ///> Mapped array of vertices
 };
 
 }
diff --git a/Base/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp b/Base/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp
index 6179a2c76e4a7d8f6d375088ffc2d21cc082ef57..f639cd57f8ee89bbe41dda0d7b491c1df7c41050 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp
+++ b/Base/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp
@@ -29,18 +29,16 @@
 #include <vtkDoubleArray.h>
 #include <vtkCellArray.h>
 
-#include "g3log/g3log.hpp"
-
 namespace imstk
 {
 
 VTKTetrahedralMeshRenderDelegate::VTKTetrahedralMeshRenderDelegate(std::shared_ptr<TetrahedralMesh> tetrahedralMesh) :
-    m_geometry(tetrahedralMesh)
+    m_geometry(tetrahedralMesh),
+    m_mappedVertexArray(vtkSmartPointer<vtkDoubleArray>::New())
 {
     // Map vertices
-    StdVectorOfVec3d& vertices = m_geometry->getVerticesPositionsNotConst();
+    StdVectorOfVec3d& vertices = m_geometry->getVertexPositionsNotConst();
     double* vertData = reinterpret_cast<double*>(vertices.data());
-    m_mappedVertexArray = vtkSmartPointer<vtkDoubleArray>::New();
     m_mappedVertexArray->SetNumberOfComponents(3);
     m_mappedVertexArray->SetArray(vertData, vertices.size()*3, 1);
 
@@ -65,25 +63,28 @@ VTKTetrahedralMeshRenderDelegate::VTKTetrahedralMeshRenderDelegate(std::shared_p
     auto unstructuredGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
     unstructuredGrid->SetPoints(points);
     unstructuredGrid->SetCells(VTK_TETRA, cells);
+    m_geometry->m_dataModified = false;
 
-    // Mapper
+    // Mapper & Actor
     auto mapper = vtkSmartPointer<vtkDataSetMapper>::New();
     mapper->SetInputData(unstructuredGrid);
-
-    // Actor
     m_actor->SetMapper(mapper);
 
-    // Transform
-    this->updateActorTransform();
+    // Update Transform, Render Properties
+    this->update();
 }
 
 void
-VTKTetrahedralMeshRenderDelegate::update()
+VTKTetrahedralMeshRenderDelegate::updateDataSource()
 {
-    // Base class update
-    VTKRenderDelegate::update();
+    if (!m_geometry->m_dataModified)
+    {
+        return;
+    }
+
+    m_mappedVertexArray->Modified();
 
-    m_mappedVertexArray->Modified(); // TODO: only modify if vertices change
+    m_geometry->m_dataModified = false;
 }
 
 
diff --git a/Base/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h b/Base/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h
index 6d6cb27d729898701e6398fb16fde5678440cb5a..5e299b8f6797b96dc58d4736f1c60dc2f6fea874 100644
--- a/Base/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h
+++ b/Base/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h
@@ -42,29 +42,29 @@ class VTKTetrahedralMeshRenderDelegate : public VTKRenderDelegate
 {
 public:
     ///
-    /// \brief
+    /// \brief Constructor
     ///
-    ~VTKTetrahedralMeshRenderDelegate() = default;
+    VTKTetrahedralMeshRenderDelegate(std::shared_ptr<TetrahedralMesh> tetrahedralMesh);
 
     ///
-    /// \brief
+    /// \brief Destructor
     ///
-    VTKTetrahedralMeshRenderDelegate(std::shared_ptr<TetrahedralMesh> tetrahedralMesh);
+    ~VTKTetrahedralMeshRenderDelegate() = default;
 
     ///
-    /// \brief
+    /// \brief Update unstructured grid source based on the tetrahedral mesh
     ///
-    void update() override;
+    void updateDataSource() override;
 
     ///
-    /// \brief
+    /// \brief Returns the tetrahedral mesh
     ///
     std::shared_ptr<Geometry> getGeometry() const override;
 
 protected:
 
-    std::shared_ptr<TetrahedralMesh> m_geometry; ///> Geometry to render
-    vtkSmartPointer<vtkDoubleArray> m_mappedVertexArray; ///> Mapped array of vertices
+    std::shared_ptr<TetrahedralMesh> m_geometry;            ///> Geometry to render
+    vtkSmartPointer<vtkDoubleArray> m_mappedVertexArray;    ///> Mapped array of vertices
 };
 
 } // imstk
diff --git a/Base/SceneElements/Controllers/imstkLaparoscopicToolController.cpp b/Base/SceneElements/Controllers/imstkLaparoscopicToolController.cpp
index 523db4d8aad4f4a1a7a9e5cec182ebc5dfca666a..f7718167540ec7b615777089717a716c9902d3e4 100644
--- a/Base/SceneElements/Controllers/imstkLaparoscopicToolController.cpp
+++ b/Base/SceneElements/Controllers/imstkLaparoscopicToolController.cpp
@@ -34,8 +34,8 @@ namespace imstk
 void
 LaparoscopicToolController::initOffsets()
 {
-    m_trackingController->setTranslationOffset(m_shaft->getMasterGeometry()->getPosition());
-    m_trackingController->setRotationOffset(m_shaft->getMasterGeometry()->getOrientation());
+    m_trackingController->setTranslationOffset(m_shaft->getMasterGeometry()->getTranslation());
+    m_trackingController->setRotationOffset(Quatd(m_shaft->getMasterGeometry()->getRotation()));
 
     m_trackingController->getDeviceClient()->setButtonsEnabled(true);
 }
@@ -71,18 +71,18 @@ LaparoscopicToolController::updateControlledObjects()
     // Update orientation of parts
     Quatd jawRotUpper;
     jawRotUpper = r*Rotd(m_jawAngle, m_jawRotationAxis);
-    m_upperJaw->getMasterGeometry()->setOrientation(jawRotUpper);
+    m_upperJaw->getMasterGeometry()->setRotation(jawRotUpper);
 
     Quatd jawRotLower;
     jawRotLower = r*Rotd(-m_jawAngle, m_jawRotationAxis);
-    m_lowerJaw->getMasterGeometry()->setOrientation(jawRotLower);
+    m_lowerJaw->getMasterGeometry()->setRotation(jawRotLower);
 
-    m_shaft->getMasterGeometry()->setOrientation(r);
+    m_shaft->getMasterGeometry()->setRotation(r);
 
     // Update positions of parts
-    m_shaft->getMasterGeometry()->setPosition(p);
-    m_upperJaw->getMasterGeometry()->setPosition(p);
-    m_lowerJaw->getMasterGeometry()->setPosition(p);
+    m_shaft->getMasterGeometry()->setTranslation(p);
+    m_upperJaw->getMasterGeometry()->setTranslation(p);
+    m_lowerJaw->getMasterGeometry()->setTranslation(p);
 }
 
 void
diff --git a/Base/SceneElements/Controllers/imstkSceneObjectController.cpp b/Base/SceneElements/Controllers/imstkSceneObjectController.cpp
index d0d92b4d748121f56a51d7c69518a67fc8204304..53e6c634035a8c446a0f13e4d96cdd50ab78aad6 100644
--- a/Base/SceneElements/Controllers/imstkSceneObjectController.cpp
+++ b/Base/SceneElements/Controllers/imstkSceneObjectController.cpp
@@ -34,8 +34,8 @@ namespace imstk
 void
 SceneObjectController::initOffsets()
 {
-    m_trackingController->setTranslationOffset(m_sceneObject->getMasterGeometry()->getPosition());
-    m_trackingController->setRotationOffset(m_sceneObject->getMasterGeometry()->getOrientation());
+    m_trackingController->setTranslationOffset(m_sceneObject->getMasterGeometry()->getTranslation());
+    m_trackingController->setRotationOffset(Quatd(m_sceneObject->getMasterGeometry()->getRotation()));
 }
 
 void
@@ -51,8 +51,8 @@ SceneObjectController::updateControlledObjects()
     }
 
     // Update colliding geometry
-    m_sceneObject->getMasterGeometry()->setPosition(m_trackingController->getPosition());
-    m_sceneObject->getMasterGeometry()->setOrientation(m_trackingController->getRotation());
+    m_sceneObject->getMasterGeometry()->setTranslation(m_trackingController->getPosition());
+    m_sceneObject->getMasterGeometry()->setRotation(m_trackingController->getRotation());
 }
 
 void
diff --git a/Base/SceneElements/Objects/imstkVirtualCouplingPBDObject.cpp b/Base/SceneElements/Objects/imstkVirtualCouplingPBDObject.cpp
index d97aaaab3b4d35d81e0ba9a869fd1d5a404fb941..b0e95466c40db2cdc100ced43b165df4914fcdde 100644
--- a/Base/SceneElements/Objects/imstkVirtualCouplingPBDObject.cpp
+++ b/Base/SceneElements/Objects/imstkVirtualCouplingPBDObject.cpp
@@ -33,8 +33,8 @@ namespace imstk
 void
 VirtualCouplingPBDObject::initOffsets()
 {
-    m_translationOffset = m_collidingGeometry->getPosition();
-    m_rotationOffset = m_collidingGeometry->getOrientation();
+    m_translationOffset = m_collidingGeometry->getTranslation();
+    m_rotationOffset = m_collidingGeometry->getRotation();
 }
 
 void
@@ -50,11 +50,11 @@ VirtualCouplingPBDObject::updateFromDevice()
     }
 
     Vec3d p = getPosition();
-    Quatd r = getRotation();
+    Quatd r = Quatd(getRotation());
 
     // Update colliding geometry
-    m_visualGeometry->setPosition(p);
-    m_visualGeometry->setOrientation(r);
+    m_visualGeometry->setTranslation(p);
+    m_visualGeometry->setRotation(r);
 
     computeTransform(p, r, transform);
 
diff --git a/Examples/Sandbox/main.cpp b/Examples/Sandbox/main.cpp
index 02f2b5a05695e93bffabf25db3b7bb319cf7cf4d..f224938bf0b363aa68d2db5e984fb44335f103b8 100644
--- a/Examples/Sandbox/main.cpp
+++ b/Examples/Sandbox/main.cpp
@@ -129,6 +129,7 @@ void testDeformableBodyCollision();
 void liverToolInteraction();
 void testCapsule();
 void testVirtualCoupling();
+void testGeometryTransforms();
 
 int main()
 {
@@ -139,7 +140,7 @@ int main()
     /*------------------
     Test rendering
     ------------------*/
-    testMultiObjectWithTextures();
+    //testMultiObjectWithTextures();
     //testViewer();
     //testScreenShotUtility();
     //testCapsule();
@@ -161,6 +162,7 @@ int main()
     //testOneToOneNodalMap();
     //testSurfaceMeshOptimizer();
     //testAnalyticalGeometry();
+    testGeometryTransforms();
 
 
     /*------------------
@@ -292,7 +294,7 @@ void testMshAndVegaIO()
 
     // Create object B
     auto objectB = std::make_shared<imstk::VisualObject>("meshObjectVEGA");
-    surfaceMeshB->translate(Vec3d(3, 0, 0));
+    surfaceMeshB->translate(Vec3d(3, 0, 0), Geometry::TransformType::ApplyToData);
     objectB->setVisualGeometry(surfaceMeshB);
 
     // Add objects to the scene
@@ -313,7 +315,7 @@ void testMultiObjectWithTextures()
     // Read surface mesh
     auto objMesh = imstk::MeshIO::read(iMSTK_DATA_ROOT"/textured_organs/heart.obj");
     auto surfaceMesh = std::dynamic_pointer_cast<imstk::SurfaceMesh>(objMesh);
-    surfaceMesh->setPosition(-8, 0, 0);
+    surfaceMesh->translate(-8, 0, 0, Geometry::TransformType::ApplyToData);
 
     // Read and setup texture/material
     auto texture = std::make_shared<Texture>(iMSTK_DATA_ROOT"/textured_organs/texture_set_1/diffuse.png");
@@ -334,7 +336,6 @@ void testMultiObjectWithTextures()
         // Read surface mesh1
         auto objMesh1 = imstk::MeshIO::read(iMSTK_DATA_ROOT"/textured_organs/heart.obj");
         auto surfaceMesh1 = std::dynamic_pointer_cast<imstk::SurfaceMesh>(objMesh1);
-        surfaceMesh1->setPosition(0, 0, 0);
 
         // Read and setup texture/material
         if (secondObjectTexture)
@@ -606,7 +607,7 @@ void testTwoOmnis()
     auto cam = scene->getCamera();
     cam->setPosition(imstk::Vec3d(0, 0, 10));
     auto sphere0Geom = sphere0Obj->getVisualGeometry();
-    cam->setFocalPoint(sphere0Geom->getPosition());
+    cam->setFocalPoint(Vec3d(-2, 2.5, 0));
 
     // Run
     sdk->setCurrentScene(scene);
@@ -631,8 +632,8 @@ void testObjectController()
 
     // Object
     auto geom = std::make_shared<imstk::Cube>();
-    geom->setPosition(imstk::UP_VECTOR);
-    geom->scale(2);
+    geom->setPosition(0, 1, 0);
+    geom->setWidth(2);
 
     auto object = std::make_shared<imstk::CollidingObject>("VirtualObject");
     object->setVisualGeometry(geom);
@@ -744,8 +745,9 @@ void testViewer()
     auto cubeObj = apiutils::createVisualAnalyticalSceneObject(
         imstk::Geometry::Type::Cube, sceneTest, "VisualCube", 0.5, Vec3d(1.0, -1.0, 0.5));
     auto cubeGeom = cubeObj->getVisualGeometry();
-    cubeGeom->rotate(imstk::UP_VECTOR, imstk::PI_4);
-    cubeGeom->rotate(imstk::RIGHT_VECTOR, imstk::PI_4);
+    // rotates could be replaced by cubeGeom->setOrientationAxis(1,1,1) (normalized inside)
+    cubeGeom->rotate(imstk::UP_VECTOR, imstk::PI_4, Geometry::TransformType::ApplyToData);
+    cubeGeom->rotate(imstk::RIGHT_VECTOR, imstk::PI_4, Geometry::TransformType::ApplyToData);
 
     // Sphere
     auto sphereObj = apiutils::createVisualAnalyticalSceneObject(
@@ -755,6 +757,7 @@ void testViewer()
     auto whiteLight = std::make_shared<imstk::Light>("whiteLight");
     whiteLight->setPosition(imstk::Vec3d(5, 8, 5));
     whiteLight->setPositional();
+    sceneTest->addLight(whiteLight);
 
     // Light (red)
     auto colorLight = std::make_shared<imstk::Light>("colorLight");
@@ -763,12 +766,6 @@ void testViewer()
     colorLight->setColor(imstk::Color::Red);
     colorLight->setPositional();
     colorLight->setSpotAngle(15);
-
-    // Add in scene
-    sceneTest->addSceneObject(planeObj);
-    sceneTest->addSceneObject(cubeObj);
-    sceneTest->addSceneObject(sphereObj);
-    sceneTest->addLight(whiteLight);
     sceneTest->addLight(colorLight);
 
     // Update Camera
@@ -792,9 +789,10 @@ void testCapsule()
 
     // Capsule
     auto capsuleObj = apiutils::createVisualAnalyticalSceneObject(
-        imstk::Geometry::Type::Capsule, scene, "VisualCapsule", 2., Vec3d(0., 1., 0.));
+        imstk::Geometry::Type::Capsule, scene, "VisualCapsule", 2.0, Vec3d(0., 1., 0.));
     auto capsuleGeom = capsuleObj->getVisualGeometry();
-    capsuleGeom->rotate(imstk::RIGHT_VECTOR, imstk::PI_4);
+    // rotates could be replaced by cubeGeom->setOrientationAxis(1,1,0) (normalized inside)
+    capsuleGeom->rotate(imstk::RIGHT_VECTOR, imstk::PI_4, Geometry::TransformType::ApplyToData);
 
 #ifdef iMSTK_USE_OPENHAPTICS
     // Device Client
@@ -839,7 +837,7 @@ void testAnalyticalGeometry()
     LOG(INFO) << "w = " << width;
 
     LOG(INFO) << "-- Plane : Create";
-    auto plane = std::make_shared<imstk::Plane>(pos, norm, width);
+    auto plane = std::make_shared<imstk::Plane>();
     LOG(INFO) << "p = " << plane->getPosition();
     LOG(INFO) << "n = " << plane->getNormal();
     LOG(INFO) << "w = " << plane->getWidth();
@@ -849,7 +847,7 @@ void testAnalyticalGeometry()
     LOG(INFO) << "p = " << plane->getPosition();
 
     LOG(INFO) << "-- Plane : Translate";
-    plane->translate(imstk::Vec3d(2, 1, -3));
+    plane->translate(imstk::Vec3d(2, 1, -3), Geometry::TransformType::ApplyToData);
     LOG(INFO) << "p = " << plane->getPosition();
 
     LOG(INFO) << "-- Plane : Set Normal";
@@ -857,7 +855,7 @@ void testAnalyticalGeometry()
     LOG(INFO) << "n = " << plane->getNormal();
 
     LOG(INFO) << "-- Plane : Rotate";
-    plane->rotate(imstk::UP_VECTOR, imstk::PI_2);
+    plane->rotate(imstk::UP_VECTOR, imstk::PI_2, Geometry::TransformType::ApplyToData);
     LOG(INFO) << "n = " << plane->getNormal();
 }
 
@@ -915,13 +913,13 @@ void testIsometricMap()
 
     // Cube
     auto cubeGeom = std::make_shared<imstk::Cube>();
-    cubeGeom->scale(0.5);
+    cubeGeom->setWidth(0.5);
     auto cubeObj = std::make_shared<imstk::VisualObject>("VisualCube");
     cubeObj->setVisualGeometry(cubeGeom);
 
     // Sphere
     auto sphereGeom = std::make_shared<imstk::Sphere>();
-    sphereGeom->scale(0.3);
+    sphereGeom->setRadius(0.3);
     auto sphereObj = std::make_shared<imstk::VisualObject>("VisualSphere");
     sphereObj->setVisualGeometry(sphereGeom);
 
@@ -932,7 +930,7 @@ void testIsometricMap()
     // Isometric Map
     auto transform = imstk::RigidTransform3d::Identity();
     transform.translate(imstk::Vec3d(0.0, 1.0, 0.0));
-    transform.rotate(imstk::Rotd(imstk::PI_4, imstk::Vec3d(0, 1.0, 0)));
+    transform.rotate(Rotd(PI_4, imstk::Vec3d(0, 1.0, 0)));
 
     auto rigidMap = std::make_shared<imstk::IsometricMap>();
     rigidMap->setMaster(sphereObj->getVisualGeometry());
@@ -1237,8 +1235,8 @@ void testDeformableBody()
 
     // f. Scene object 2: Plane
     auto planeGeom = std::make_shared<Plane>();
-    planeGeom->scale(40);
-    planeGeom->translate(0, -6, 0);
+    planeGeom->setWidth(40);
+    planeGeom->setPosition(0, -6, 0);
     auto planeObj = std::make_shared<CollidingObject>("Plane");
     planeObj->setVisualGeometry(planeGeom);
     planeObj->setCollidingGeometry(planeGeom);
@@ -1383,8 +1381,8 @@ void testPbdVolume()
 
 
     auto planeGeom = std::make_shared<Plane>();
-    planeGeom->scale(40);
-    planeGeom->translate(0, -6, 0);
+    planeGeom->setWidth(40);
+    planeGeom->setTranslation(0, -6, 0);
     auto planeObj = std::make_shared<CollidingObject>("Plane");
     planeObj->setVisualGeometry(planeGeom);
     planeObj->setCollidingGeometry(planeGeom);
@@ -2162,23 +2160,24 @@ void testScreenShotUtility()
 
     // Plane
     auto planeGeom = std::make_shared<imstk::Plane>();
-    planeGeom->scale(10);
+    planeGeom->setWidth(10);
     auto planeObj = std::make_shared<imstk::VisualObject>("VisualPlane");
     planeObj->setVisualGeometry(planeGeom);
 
     // Cube
     auto cubeGeom = std::make_shared<imstk::Cube>();
-    cubeGeom->scale(0.5);
-    cubeGeom->rotate(imstk::UP_VECTOR, imstk::PI_4);
-    cubeGeom->rotate(imstk::RIGHT_VECTOR, imstk::PI_4);
-    cubeGeom->translate(1.0, -1.0, 0.5);
+    cubeGeom->setWidth(0.5);
+    cubeGeom->setPosition(1.0, -1.0, 0.5);
+    // rotates could be replaced by cubeGeom->setOrientationAxis(1,1,1) (normalized inside)
+    cubeGeom->rotate(imstk::UP_VECTOR, imstk::PI_4, Geometry::TransformType::ApplyToData);
+    cubeGeom->rotate(imstk::RIGHT_VECTOR, imstk::PI_4, Geometry::TransformType::ApplyToData);
     auto cubeObj = std::make_shared<imstk::VisualObject>("VisualCube");
     cubeObj->setVisualGeometry(cubeGeom);
 
     // Sphere
     auto sphereGeom = std::make_shared<imstk::Sphere>();
-    sphereGeom->scale(0.3);
-    sphereGeom->translate(0, 2, 0);
+    sphereGeom->setRadius(0.3);
+    sphereGeom->setPosition(0, 2, 0);
     auto sphereObj = std::make_shared<imstk::VisualObject>("VisualSphere");
     sphereObj->setVisualGeometry(sphereGeom);
 
@@ -2227,10 +2226,10 @@ void testDeformableBodyCollision()
     auto sdk = std::make_shared<imstk::SimulationManager>();
     auto scene = sdk->createNewScene("OneTetraCH");
 
-    auto geom = std::make_shared<imstk::Plane>(WORLD_ORIGIN, -UP_VECTOR, 1.);
+    auto geom = std::make_shared<imstk::Plane>();
 
-    geom->scale(100);
-    geom->translate(Vec3d(0., -20., 0.));
+    geom->setWidth(100);
+    geom->setPosition(Vec3d(0., -20., 0.));
 
     auto planeObj = std::make_shared<imstk::CollidingObject>("VisualPlane");
     planeObj->setVisualGeometry(geom);
@@ -2465,9 +2464,9 @@ void testVirtualCoupling()
     auto scene = sdk->createNewScene("VirtualCoupling");
 
     // Create a plane in the scene
-    auto planeGeom = std::make_shared<imstk::Plane>(WORLD_ORIGIN, UP_VECTOR, 1.0);
-    planeGeom->scale(400);
-    planeGeom->translate(Vec3d(0., -50, 0.));
+    auto planeGeom = std::make_shared<imstk::Plane>();
+    planeGeom->setWidth(400);
+    planeGeom->setPosition(0.0, -50, 0.0);
     auto planeObj = std::make_shared<imstk::CollidingObject>("Plane");
     planeObj->setVisualGeometry(planeGeom);
     planeObj->setCollidingGeometry(planeGeom);
@@ -2488,8 +2487,10 @@ void testVirtualCoupling()
     auto deviceTracker = std::make_shared<imstk::DeviceTracker>(client);
 
     // Create a virtual coupling object
-    auto visualGeom = std::make_shared<imstk::Sphere>(WORLD_ORIGIN, 20);
-    auto collidingGeom = std::make_shared<imstk::Sphere>(WORLD_ORIGIN, 20);
+    auto visualGeom = std::make_shared<imstk::Sphere>();
+    visualGeom->setRadius(20);
+    auto collidingGeom = std::make_shared<imstk::Sphere>();
+    collidingGeom->setRadius(20);
     auto obj = std::make_shared<CollidingObject>("VirtualCouplingObject");
     obj->setCollidingGeometry(collidingGeom);
     obj->setVisualGeometry(visualGeom);
@@ -2524,3 +2525,52 @@ void testVirtualCoupling()
     sdk->setCurrentScene(scene);
     sdk->startSimulation(false);
 }
+
+void testGeometryTransforms()
+{
+
+    // SDK and Scene
+    auto sdk = std::make_shared<imstk::SimulationManager>();
+    auto scene = sdk->createNewScene("testGeometryTransforms");
+
+    auto sceneObj = apiutils::createAndAddVisualSceneObject(scene, iMSTK_DATA_ROOT"/asianDragon/asianDragon.obj", "Dragon");
+
+    auto surfaceMesh = sceneObj->getVisualGeometry();
+    surfaceMesh->scale(5., Geometry::TransformType::ConcatenateToTransform);
+
+    //  Plane
+    auto planeGeom = std::make_shared<Plane>();
+    planeGeom->scale(80, Geometry::TransformType::ConcatenateToTransform);
+    planeGeom->translate(0, -20, 0, Geometry::TransformType::ConcatenateToTransform);
+    planeGeom->rotate(Vec3d(0, 1., 0), PI/4, Geometry::TransformType::ConcatenateToTransform);
+
+    auto planeObj = std::make_shared<VisualObject>("Plane");
+    planeObj->setVisualGeometry(planeGeom);
+    scene->addSceneObject(planeObj);
+
+    //  Cube
+    auto cubeGeom = std::make_shared<Cube>();
+    cubeGeom->setWidth(20.);
+    cubeGeom->scale(0.5, Geometry::TransformType::ConcatenateToTransform);
+    cubeGeom->rotate(Vec3d(1., 1., 0), PI / 4, Geometry::TransformType::ApplyToData);
+
+    auto cubeObj = std::make_shared<VisualObject>("Cube");
+    cubeObj->setVisualGeometry(cubeGeom);
+    scene->addSceneObject(cubeObj);
+
+    // Rotate the dragon every frame
+    auto rotateFunc = [&surfaceMesh](Module* module)
+    {
+        surfaceMesh->rotate(Vec3d(1., 0, 0), PI / 1000, Geometry::TransformType::ApplyToData);
+    };
+    sdk->getSceneManager("testGeometryTransforms")->setPostUpdateCallback(rotateFunc);
+
+    // Set Camera configuration
+    auto cam = scene->getCamera();
+    cam->setPosition(imstk::Vec3d(0, 30, 30));
+    cam->setFocalPoint(imstk::Vec3d(0, 0, 0));
+
+    // Run
+    sdk->setCurrentScene(scene);
+    sdk->startSimulation(false);
+}