diff --git a/CMake/External/CMakeLists.txt b/CMake/External/CMakeLists.txt
index 420a1b2c2de92d174342a1c6fbc772b537424064..415e69095cc8d696a1f4b4e32ff6fb15f5fa0b2e 100644
--- a/CMake/External/CMakeLists.txt
+++ b/CMake/External/CMakeLists.txt
@@ -100,14 +100,12 @@ ExternalProject_Add( ${PROJECT_NAME}
     -D${PROJECT_NAME}_ENABLE_AUDIO:BOOL=${${PROJECT_NAME}_ENABLE_AUDIO}
     -D${PROJECT_NAME}_USE_VRPN:BOOL=${${PROJECT_NAME}_USE_VRPN}
     -D${PROJECT_NAME}_COLOR_OUTPUT:BOOL=${${PROJECT_NAME}_COLOR_OUTPUT}
-    -D${PROJECT_NAME}_USE_Pulse:BOOL=${${PROJECT_NAME}_USE_Pulse}
     # External Libraries
     -DEigen3_DIR:PATH=${Eigen3_DIR}
     -Dglm_DIR:PATH=${glm_DIR}
     -DGTest_DIR:PATH=${GTest_DIR}
     -DVegaFEM_DIR:PATH=${VegaFEM_DIR}
     -DVTK_DIR:PATH=${VTK_DIR}
-    -DPulse_DIR:PATH=${Pulse_DIR}
     # I don't think this is needed by the inner build
     # -DPHYSX_CONFIGURATION:STRING=${${PROJECT_NAME}_PHYSX_CONFIGURATION}
   DEPENDS ${${PROJECT_NAME}_DEPENDENCIES}
diff --git a/CMake/External/External_Pulse.cmake b/CMake/External/External_Pulse.cmake
deleted file mode 100644
index e3120b29408617d9f69e1f1b7a3d071d5bd86fc3..0000000000000000000000000000000000000000
--- a/CMake/External/External_Pulse.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-#-----------------------------------------------------------------------------
-# Add Pulse External Project
-#-----------------------------------------------------------------------------
-
-include(imstkAddExternalProject)
-imstk_add_external_project( Pulse
-  GIT_REPOSITORY https://gitlab.kitware.com/physiology/engine.git
-  GIT_TAG f4d501c2f7cc091dc053a96ab5a56f79b7528c4f
-  GIT_SHALLOW TRUE
-  #URL https://gitlab.kitware.com/physiology/engine/-/archive/3.x/archive.zip
-  #URL_HASH 4189591a6859df46920bbc35f160eef23fc33ffd
-  CMAKE_CACHE_ARGS
-    -DPulse_SLAVE_BUILD:BOOL=ON
-    -DPulse_JAVA_API:BOOL=OFF
-    -DPulse_PYTHON_API:BOOL=OFF
-  INSTALL_COMMAND $(SKIP_STEP_COMMAND)
-)
-
-if(NOT USE_SYSTEM_Pulse)
-  set(Pulse_DIR ${CMAKE_INSTALL_PREFIX}/lib/cmake/Pulse-3.0)
-  #message(STATUS "Pulse_DIR : ${Pulse_DIR}")
-endif()
diff --git a/CMake/Utilities/imstkAddExecutable.cmake b/CMake/Utilities/imstkAddExecutable.cmake
index d9d32251e5caa9449c1f2cbe850cd504646bc86d..0800c1517f14065b616fcc29875b72195442d538 100644
--- a/CMake/Utilities/imstkAddExecutable.cmake
+++ b/CMake/Utilities/imstkAddExecutable.cmake
@@ -15,13 +15,13 @@ macro(imstk_add_executable target)
       $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
           -Wall -Wno-unused-function -fdiagnostics-color=always>
       $<$<CXX_COMPILER_ID:MSVC>:
-          -W4 -MP>)
+          -W4 -MP -wd4505>)
   else()
     target_compile_options(${target} PRIVATE
     $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
         -Wall -Wno-unused-function>
     $<$<CXX_COMPILER_ID:MSVC>:
-        -W4 -MP>)
+        -W4 -MP -wd4505>)
   endif()
 
   set_target_properties(${target} PROPERTIES
diff --git a/CMake/Utilities/imstkAddLibrary.cmake b/CMake/Utilities/imstkAddLibrary.cmake
index 20c3ecce5bad5276648aaf26c2cd2056cb33f9db..b4b99c361b384d2bf3dc6f9c85c0137df3ba2aa3 100644
--- a/CMake/Utilities/imstkAddLibrary.cmake
+++ b/CMake/Utilities/imstkAddLibrary.cmake
@@ -96,13 +96,13 @@ function(imstk_add_library target)
       $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
           -Wall -Wno-unused-function -fdiagnostics-color=always>
       $<$<CXX_COMPILER_ID:MSVC>:
-          -W4 -MP>)
+          -W4 -MP -wd4505>)
   else()
     target_compile_options(${target} PRIVATE
     $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
         -Wall -Wno-unused-function>
     $<$<CXX_COMPILER_ID:MSVC>:
-        -W4 -MP>)
+        -W4 -MP -wd4505>)
   endif()
 
   #-----------------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f64b47f96590c16af17c327fa2e739fda9874c55..1e9703ff803a526c4c31d11ec612a55d3c957637 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -137,11 +137,6 @@ if(${PROJECT_NAME}_SUPERBUILD)
   option(${PROJECT_NAME}_USE_Vulkan "Use the custom Vulkan renderer." OFF)
   option(${PROJECT_NAME}_USE_OpenHaptics "Use OpenHaptic Support." OFF)
   
-  option(${PROJECT_NAME}_USE_Pulse "Use Pulse Physiology engine." OFF)
-  if(${PROJECT_NAME}_USE_Pulse)
-    imstk_define_dependency(Pulse)
-  endif()
-  
   imstk_define_dependency(Assimp)
   imstk_define_dependency(Eigen3)
   imstk_define_dependency(g3log)
@@ -249,13 +244,6 @@ set(PHYSX_RELEASE_TYPES "RELEASE;CHECKED;PROFILE" CACHE INTERNAL "List of availa
 set_property(CACHE PHYSX_CONFIGURATION PROPERTY STRINGS ${PHYSX_RELEASE_TYPES})
 find_package(PhysX REQUIRED)
 
-if(${PROJECT_NAME}_USE_Pulse)
-  add_definitions( -DiMSTK_USE_Pulse )
-  find_package( Pulse REQUIRED )
-else()
-  remove_definitions( -DiMSTK_USE_Pulse )
-endif()
-
 # SCCD
 find_package( SCCD REQUIRED )
 
@@ -404,8 +392,8 @@ add_subdirectory(Source/CollisionHandling)
 add_subdirectory(Source/Scene)
 add_subdirectory(Source/SimulationManager)
 add_subdirectory(Source/apiUtilities)
-add_subdirectory(Source/Pulse)
 add_subdirectory(Source/Filtering)
+add_subdirectory(Source/FilteringCore)
 
 #--------------------------------------------------------------------------
 # Add Examples subdirectories
diff --git a/Data/NOTICE.txt b/DATANOTICE.txt
similarity index 100%
rename from Data/NOTICE.txt
rename to DATANOTICE.txt
diff --git a/Examples/DeformableBody/DeformableBodyExample.cpp b/Examples/DeformableBody/DeformableBodyExample.cpp
index 4cab50fb50f9acd73212895a3f32b10a9fa7378b..3e6e0e4f998a22ac2be2c156484f664b13a58aa0 100644
--- a/Examples/DeformableBody/DeformableBodyExample.cpp
+++ b/Examples/DeformableBody/DeformableBodyExample.cpp
@@ -148,9 +148,7 @@ main()
 std::shared_ptr<FeDeformableObject>
 makeFEDeformableObject(std::shared_ptr<TetrahedralMesh> tetMesh)
 {
-    imstkNew<SurfaceMesh> surfMesh;
-    tetMesh->extractSurfaceMesh(surfMesh, true);
-    surfMesh->flipNormals();
+    std::shared_ptr<SurfaceMesh> surfMesh = tetMesh->extractSurfaceMesh();
 
     // Configure dynamic model
     imstkNew<FEMDeformableBodyModel> dynaModel;
@@ -169,7 +167,7 @@ makeFEDeformableObject(std::shared_ptr<TetrahedralMesh> tetMesh)
     mat->setPointSize(10.0);
     mat->setLineWidth(2.0);
     mat->setEdgeColor(Color::Orange);
-    imstkNew<VisualModel> surfMeshModel(surfMesh.get());
+    imstkNew<VisualModel> surfMeshModel(surfMesh);
     surfMeshModel->setRenderMaterial(mat);
 
     // Scene object 1: Dragon
diff --git a/Examples/FemurCut/FemurCutExample.cpp b/Examples/FemurCut/FemurCutExample.cpp
index 704074a4c31904e5fe0640c72eb970583390275f..40c976569dec5f7f38711b79d1c661b6912c3fad 100644
--- a/Examples/FemurCut/FemurCutExample.cpp
+++ b/Examples/FemurCut/FemurCutExample.cpp
@@ -47,7 +47,6 @@
 #include "FemurObject.h"
 
 using namespace imstk;
-using namespace imstk::expiremental;
 
 std::shared_ptr<RigidObject2>
 makeRigidObj(const std::string& name)
@@ -79,7 +78,7 @@ makeRigidObj(const std::string& name)
         rigidObj->setPhysicsGeometry(toolMesh);
         rigidObj->setCollidingGeometry(toolMesh);
         rigidObj->setDynamicalModel(rbdModel);
-        rigidObj->getRigidBody()->m_mass = 1.0;
+        rigidObj->getRigidBody()->m_mass = 10.0;
         rigidObj->getRigidBody()->m_intertiaTensor = Mat3d::Identity() * 10000.0;
         rigidObj->getRigidBody()->m_initPos = Vec3d(0.0, 1.0, 2.0);
     }
@@ -159,7 +158,7 @@ main()
         imstkNew<RigidObjectController> controller(rbdObj, hapticDeviceClient);
         {
             controller->setLinearKd(1000.0);
-            controller->setLinearKs(100000.0);
+            controller->setLinearKs(200000.0);
             controller->setAngularKs(300000000.0);
             controller->setAngularKd(400000.0);
             controller->setForceScaling(0.001);
diff --git a/Examples/GeometryProcessing/GeometryProcessingExample.cpp b/Examples/GeometryProcessing/GeometryProcessingExample.cpp
index d464313a3dfac3e2d72ec2b90762082e1ec87519..5e198b2b1cbd1697bc6d1376b6376131f71e4dfd 100644
--- a/Examples/GeometryProcessing/GeometryProcessingExample.cpp
+++ b/Examples/GeometryProcessing/GeometryProcessingExample.cpp
@@ -52,9 +52,8 @@ main()
     // simManager and Scene
     imstkNew<Scene> scene("GeometryProcessing");
 
-    auto                  coarseTetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
-    imstkNew<SurfaceMesh> coarseSurfMesh;
-    coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true);
+    auto                         coarseTetMesh  = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
+    std::shared_ptr<SurfaceMesh> coarseSurfMesh = coarseTetMesh->extractSurfaceMesh();
 
     // Compute DT
     imstkNew<SurfaceMeshDistanceTransform> createSdf;
@@ -95,7 +94,7 @@ main()
     }
     // Create the original mesh visual model
     {
-        imstkNew<VisualModel>    surfMeshModel(coarseSurfMesh.get());
+        imstkNew<VisualModel>    surfMeshModel(coarseSurfMesh);
         imstkNew<RenderMaterial> material;
         material->setColor(Color::Red);
         material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
diff --git a/Examples/GeometryTransforms/GeometryTransformsExample.cpp b/Examples/GeometryTransforms/GeometryTransformsExample.cpp
index d0235eb9c2033fb017d018eeaaabd2be5780314d..d612eed653d9ef84097ad211a076d604f4183767 100644
--- a/Examples/GeometryTransforms/GeometryTransformsExample.cpp
+++ b/Examples/GeometryTransforms/GeometryTransformsExample.cpp
@@ -21,13 +21,13 @@
 
 #include "imstkAPIUtilities.h"
 #include "imstkCamera.h"
-#include "imstkCube.h"
 #include "imstkCylinder.h"
 #include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
 #include "imstkLogger.h"
 #include "imstkMouseSceneControl.h"
 #include "imstkNew.h"
+#include "imstkOrientedBox.h"
 #include "imstkPlane.h"
 #include "imstkRenderMaterial.h"
 #include "imstkScene.h"
@@ -75,8 +75,8 @@ main()
     scene->addSceneObject(planeObj);
 
     //  Cube
-    imstkNew<Cube> cubeGeom;
-    cubeGeom->setWidth(10.0);
+    imstkNew<OrientedBox> cubeGeom;
+    cubeGeom->setExtents(5.0, 5.0, 5.0);
     cubeGeom->scale(0.5, Geometry::TransformType::ConcatenateToTransform);
     cubeGeom->rotate(Vec3d(1.0, 1.0, 0.0), PI_4, Geometry::TransformType::ApplyToData);
     cubeGeom->translate(Vec3d(0.0, 0.0, 10.0));
diff --git a/Examples/Levelset/levelsetExample.cpp b/Examples/Levelset/levelsetExample.cpp
index b373cae74f6b7324bfae15ec708ecf111d979475..0256682ce45d2657e631d6086d9d894216dcee51 100644
--- a/Examples/Levelset/levelsetExample.cpp
+++ b/Examples/Levelset/levelsetExample.cpp
@@ -20,23 +20,16 @@
 =========================================================================*/
 
 #include "imstkCamera.h"
-#include "imstkCube.h"
-#include "imstkImageData.h"
-#include "imstkImplicitGeometryToImageData.h"
 #include "imstkKeyboardSceneControl.h"
 #include "imstkLevelSetDeformableObject.h"
 #include "imstkLevelSetModel.h"
 #include "imstkLight.h"
-#include "imstkLogger.h"
 #include "imstkMeshIO.h"
 #include "imstkMouseSceneControl.h"
 #include "imstkNew.h"
-#include "imstkPlane.h"
-#include "imstkRenderMaterial.h"
 #include "imstkScene.h"
 #include "imstkSceneManager.h"
 #include "imstkSimulationManager.h"
-#include "imstkSphere.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkSurfaceMeshDistanceTransform.h"
 #include "imstkVisualModel.h"
diff --git a/Examples/MultipleScenes/multipleScenes.cpp b/Examples/MultipleScenes/multipleScenes.cpp
index 63da34f8ef82e0d164178dbe27eb0d022cef6cda..e1b4897380f75eee9db89b4ea16503da0f2588ae 100644
--- a/Examples/MultipleScenes/multipleScenes.cpp
+++ b/Examples/MultipleScenes/multipleScenes.cpp
@@ -155,12 +155,11 @@ createSoftBodyScene(std::string sceneName)
     auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
 
     // Extract the surface mesh
-    imstkNew<SurfaceMesh> surfMesh;
-    tetMesh->extractSurfaceMesh(surfMesh, true);
+    std::shared_ptr<SurfaceMesh> surfMesh = tetMesh->extractSurfaceMesh();
 
     imstkNew<RenderMaterial> material;
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    imstkNew<VisualModel> surfMeshModel(surfMesh.get());
+    imstkNew<VisualModel> surfMeshModel(surfMesh);
     surfMeshModel->setRenderMaterial(material);
 
     imstkNew<PbdObject> deformableObj("Dragon");
diff --git a/Examples/NonlinearSolver/nonlinearSolver.cpp b/Examples/NonlinearSolver/nonlinearSolver.cpp
index 9d4feec4f9f2febb5723cde8db1e6245d33a3901..d50ec775c579b98ea89f332ab622cba54386ace4 100644
--- a/Examples/NonlinearSolver/nonlinearSolver.cpp
+++ b/Examples/NonlinearSolver/nonlinearSolver.cpp
@@ -31,6 +31,7 @@ using namespace imstk;
 
 ///
 /// \brief This example is for demonstration of how to use a NewtonSolver and its verification
+/// \todo move this to a unit test
 ///
 int
 main()
diff --git a/Examples/ObjectController/ObjectControllerExample.cpp b/Examples/ObjectController/ObjectControllerExample.cpp
index df3c210ccb1f56fbb093de3c7756793c4213edeb..99db5e0b61ded5a77456a7e3b9ac6274d6918394 100644
--- a/Examples/ObjectController/ObjectControllerExample.cpp
+++ b/Examples/ObjectController/ObjectControllerExample.cpp
@@ -20,19 +20,24 @@
 =========================================================================*/
 
 #include "imstkCamera.h"
+#include "imstkCapsule.h"
 #include "imstkCollidingObject.h"
-#include "imstkCube.h"
+#include "imstkCylinder.h"
 #include "imstkHapticDeviceClient.h"
 #include "imstkHapticDeviceManager.h"
+#include "imstkKeyboardDeviceClient.h"
 #include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
 #include "imstkLogger.h"
 #include "imstkMouseSceneControl.h"
 #include "imstkNew.h"
+#include "imstkOrientedBox.h"
+#include "imstkPlane.h"
 #include "imstkScene.h"
 #include "imstkSceneManager.h"
 #include "imstkSceneObjectController.h"
 #include "imstkSimulationManager.h"
+#include "imstkSphere.h"
 #include "imstkVTKViewer.h"
 
 using namespace imstk;
@@ -52,14 +57,18 @@ main()
 
     // Device Server
     imstkNew<HapticDeviceManager>       server;
-    const std::string                   deviceName = "";
-    std::shared_ptr<HapticDeviceClient> client     = server->makeDeviceClient(deviceName);
-
-    // Object
-    imstkNew<Cube>            geom(Vec3d(0.0, 1.0, 0.0), 2.0);
-    imstkNew<CollidingObject> object("VirtualObject");
-    object->setVisualGeometry(geom);
-    object->setCollidingGeometry(geom);
+    std::shared_ptr<HapticDeviceClient> client = server->makeDeviceClient();
+
+    std::shared_ptr<AnalyticalGeometry> geometries[] = {
+        std::make_shared<OrientedBox>(Vec3d::Zero(), Vec3d(1.0, 5.0, 1.0)),
+        std::make_shared<Plane>(Vec3d::Zero(), Vec3d(0.0, 1.0, 0.0)),
+        std::make_shared<Capsule>(Vec3d::Zero(), 0.5, 1.0),
+        std::make_shared<Cylinder>(Vec3d::Zero(), 5.0, 1.0),
+        std::make_shared<Sphere>(Vec3d::Zero(), 2.0)
+    };
+
+    imstkNew<SceneObject> object("VirtualObject");
+    object->setVisualGeometry(geometries[0]);
     scene->addSceneObject(object);
 
     imstkNew<SceneObjectController> controller(object, client);
@@ -69,7 +78,7 @@ main()
     // Update Camera position
     std::shared_ptr<Camera> cam = scene->getActiveCamera();
     cam->setPosition(Vec3d(0.0, 0.0, 10.0));
-    cam->setFocalPoint(geom->getPosition());
+    cam->setFocalPoint(geometries[0]->getPosition());
 
     // Light
     imstkNew<DirectionalLight> light("light");
@@ -86,11 +95,13 @@ main()
         // Setup a scene manager to advance the scene
         imstkNew<SceneManager> sceneManager("Scene Manager 1");
         sceneManager->setActiveScene(scene);
+        sceneManager->setExecutionType(Module::ExecutionType::ADAPTIVE);
 
         imstkNew<SimulationManager> driver;
         driver->addModule(viewer);
         driver->addModule(sceneManager);
         driver->addModule(server);
+        driver->setDesiredDt(0.01);
 
         // Add mouse and keyboard controls to the viewer
         {
diff --git a/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp b/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp
index ea17a3ba2bb244231ec352ff772a937328f5633e..8d586705c6c8cb8a38ccecfd6b28cffeb971afa4 100644
--- a/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp
+++ b/Examples/ObjectControllerDummyClient/ObjectCtrlDummyClientExample.cpp
@@ -21,11 +21,11 @@
 
 #include "imstkCamera.h"
 #include "imstkCollidingObject.h"
-#include "imstkCube.h"
 #include "imstkDummyClient.h"
 #include "imstkLight.h"
 #include "imstkLogger.h"
 #include "imstkNew.h"
+#include "imstkOrientedBox.h"
 #include "imstkScene.h"
 #include "imstkSceneManager.h"
 #include "imstkSceneObjectController.h"
@@ -49,9 +49,7 @@ main()
     imstkNew<DummyClient> client("DummyClient");
 
     // Object
-    imstkNew<Cube> geom;
-    geom->setPosition(0.0, 1.0, 0.0);
-    geom->setWidth(2.0);
+    imstkNew<OrientedBox> geom(Vec3d(0.0, 1.0, 0.0), Vec3d(1.0, 1.0, 1.0));
 
     imstkNew<CollidingObject> object("VirtualObject");
     object->setVisualGeometry(geom);
diff --git a/Examples/PBD/PBDCloth/CMakeLists.txt b/Examples/PBD/PBDCloth/CMakeLists.txt
index 8e1aec6197321a303041ca440844ba24046b06c0..37c29064fe37c6b298bc5b4f58747cb5704c204d 100644
--- a/Examples/PBD/PBDCloth/CMakeLists.txt
+++ b/Examples/PBD/PBDCloth/CMakeLists.txt
@@ -23,6 +23,7 @@ project(Example-PBDCloth)
 #-----------------------------------------------------------------------------
 imstk_add_executable(${PROJECT_NAME} pbdClothExample.cpp)
 
+target_compile_options(${PROJECT_NAME} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/bigobj>)
 #-----------------------------------------------------------------------------
 # Add the target to Examples folder
 #-----------------------------------------------------------------------------
diff --git a/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp b/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp
index 3c722a9d2106c0b0c6141f59fc3c96d8411ac809..7f18e4e6e26d9f0dff1855353019a15012865b4b 100644
--- a/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp
+++ b/Examples/PBD/PBDCollisionMultipleObjects/PBDCollisionMultipleObjectsExample.cpp
@@ -231,10 +231,7 @@ generateDragon(const std::shared_ptr<imstk::Scene>& scene,
     const auto positions = tetMesh->getVertexPositions();
     (void)positions;
 
-    static int count = -1;
-    ++count;
-    surfMesh = std::make_shared<SurfaceMesh>("Dragon-" + std::to_string(count));
-    tetMesh->extractSurfaceMesh(surfMesh, true);
+    surfMesh = tetMesh->extractSurfaceMesh();
 
     imstkNew<RenderMaterial> material;
 #if 0
@@ -250,6 +247,8 @@ generateDragon(const std::shared_ptr<imstk::Scene>& scene,
     imstkNew<VisualModel> surfMeshModel(surfMesh);
     surfMeshModel->setRenderMaterial(material);
 
+    static int count = -1;
+    ++count;
     deformableObj = std::make_shared<PbdObject>("Dragon-" + std::to_string(count));
     deformableObj->addVisualModel(surfMeshModel);
     deformableObj->setCollidingGeometry(surfMesh);
@@ -290,7 +289,7 @@ createUniformSurfaceMesh(const double width, const double height, const int nRow
 
     imstkNew<VecDataArray<double, 3>> verticesPtr;
     VecDataArray<double, 3>&          vertices = *verticesPtr.get();
-    vertices.resize(static_cast<int>(nRows * nCols));
+    vertices.resize(nRows * nCols);
     for (int i = 0; i < nRows; i++)
     {
         for (int j = 0; j < nCols; j++)
diff --git a/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp b/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp
index e1e82c3e405161e7628d8077fe1df9514c65d529..3030d295400ebf80e4f13578682afa017d0d6cbe 100644
--- a/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp
+++ b/Examples/PBD/PBDCollisionOneObject/PBDCollisionOneObjectExample.cpp
@@ -78,10 +78,9 @@ main()
         scene->getActiveCamera()->setFocalPoint(0.0, -10.0, 0.0);
 
         // set up the meshes
-        auto                  highResSurfMesh = MeshIO::read<SurfaceMesh>(surfMeshFileName);
-        auto                  coarseTetMesh   = MeshIO::read<TetrahedralMesh>(tetMeshFileName);
-        imstkNew<SurfaceMesh> coarseSurfMesh;
-        coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true);
+        auto                         highResSurfMesh = MeshIO::read<SurfaceMesh>(surfMeshFileName);
+        auto                         coarseTetMesh   = MeshIO::read<TetrahedralMesh>(tetMeshFileName);
+        std::shared_ptr<SurfaceMesh> coarseSurfMesh  = coarseTetMesh->extractSurfaceMesh();
 
         // set up visual model based on high res mesh
         imstkNew<RenderMaterial> material;
diff --git a/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp b/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp
index 0c711c040a1dc1eb751f2ee0e1e81fc4ad5b3296..0debfcc58d5663da36c893b8ae6565de27d24055 100644
--- a/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp
+++ b/Examples/PBD/PBDCollisionStairs/PBDCollisionStairsExample.cpp
@@ -114,8 +114,7 @@ makeArmadilloPbdObject(const std::string& name)
     tetMesh->scale(Vec3d(0.07, 0.07, 0.07), Geometry::TransformType::ApplyToData);
     tetMesh->rotate(Vec3d(1.0, 0.0, 0.0), 1.3, Geometry::TransformType::ApplyToData);
     tetMesh->translate(Vec3d(0.0f, 10.0f, 0.0f), Geometry::TransformType::ApplyToData);
-    imstkNew<SurfaceMesh> surfMesh;
-    tetMesh->extractSurfaceMesh(surfMesh, true);
+    std::shared_ptr<SurfaceMesh> surfMesh = tetMesh->extractSurfaceMesh();
 
     // Setup the Parameters
     imstkNew<PBDModelConfig> pbdParams;
@@ -138,7 +137,7 @@ makeArmadilloPbdObject(const std::string& name)
     // Setup the VisualModel
     imstkNew<RenderMaterial> material;
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    imstkNew<VisualModel> surfMeshModel(surfMesh.get());
+    imstkNew<VisualModel> surfMeshModel(surfMesh);
     surfMeshModel->setRenderMaterial(material);
 
     // Setup the Object
diff --git a/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp b/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp
index 40b2fc15894cf5718f7180472529f09ed8a9d5e7..726fb4546cf007b78013ce0249eee9b17dd2b9b8 100644
--- a/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp
+++ b/Examples/PBD/PBDDeformableObject/PBD3DDeformableObject.cpp
@@ -109,9 +109,7 @@ createAndAddPbdObject(const std::string& tetMeshName)
 {
     auto tetMesh = MeshIO::read<TetrahedralMesh>(tetMeshName);
     tetMesh->rotate(Vec3d(1.0, 0.0, 0.0), -1.3, Geometry::TransformType::ApplyToData);
-    imstkNew<SurfaceMesh> surfMesh;
-    tetMesh->extractSurfaceMesh(surfMesh, true);
-    surfMesh->flipNormals();
+    std::shared_ptr<SurfaceMesh> surfMesh = tetMesh->extractSurfaceMesh();
 
     imstkNew<RenderMaterial> material;
     material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
@@ -121,7 +119,8 @@ createAndAddPbdObject(const std::string& tetMeshName)
     material->setEdgeColor(Color::Teal);
     material->setShadingModel(RenderMaterial::ShadingModel::Phong);
     material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    imstkNew<VisualModel> visualModel(surfMesh.get());
+    imstkNew<VisualModel> visualModel;
+    visualModel->setGeometry(surfMesh);
     visualModel->setRenderMaterial(material);
 
     imstkNew<PbdObject> deformableObj("DeformableObject");
diff --git a/Examples/PBD/PBDString/CMakeLists.txt b/Examples/PBD/PBDString/CMakeLists.txt
index ebfc89726577b3c07b3037e56dffad62a5c853ac..e33b613267b34278518145d412451e062bfcdf03 100644
--- a/Examples/PBD/PBDString/CMakeLists.txt
+++ b/Examples/PBD/PBDString/CMakeLists.txt
@@ -23,6 +23,7 @@ project(Example-PBDString)
 #-----------------------------------------------------------------------------
 imstk_add_executable(${PROJECT_NAME} pbdStringExample.cpp)
 
+target_compile_options(${PROJECT_NAME} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/bigobj>)
 #-----------------------------------------------------------------------------
 # Add the target to Examples folder
 #-----------------------------------------------------------------------------
diff --git a/Examples/PBDPicking/PBDPickingExample.cpp b/Examples/PBDPicking/PBDPickingExample.cpp
index 7fa7b148c83afa317e0fdea8f46bd192d6042482..dad7bf92fde3ac27d71e7e9cc7fbe736aecba2ab 100644
--- a/Examples/PBDPicking/PBDPickingExample.cpp
+++ b/Examples/PBDPicking/PBDPickingExample.cpp
@@ -173,7 +173,7 @@ main()
     imstkNew<Capsule> geomShaft;
     geomShaft->setLength(20.0);
     geomShaft->setRadius(1.0);
-    geomShaft->setOrientationAxis(Vec3d(0.0, 0.0, 1.0));
+    geomShaft->setOrientation(Quatd(Rotd(PI_2, Vec3d(1.0, 0.0, 0.0))));
     geomShaft->setTranslation(Vec3d(0.0, 0.0, 10.0));
     imstkNew<CollidingObject> objShaft("ShaftObject");
     objShaft->setVisualGeometry(pivotSurfMesh);
@@ -184,7 +184,7 @@ main()
     geomUpperJaw->setLength(25.0);
     geomUpperJaw->setTranslation(Vec3d(0.0, 1.0, -12.5));
     geomUpperJaw->setRadius(2.0);
-    geomUpperJaw->setOrientationAxis(Vec3d(0.0, 0.0, 1.0));
+    geomUpperJaw->setOrientation(Quatd(Rotd(PI_2, Vec3d(1.0, 0.0, 0.0))));
     imstkNew<CollidingObject> objUpperJaw("UpperJawObject");
     objUpperJaw->setVisualGeometry(upperSurfMesh);
     objUpperJaw->setCollidingGeometry(geomUpperJaw);
@@ -194,7 +194,7 @@ main()
     geomLowerJaw->setLength(25.0);
     geomLowerJaw->setTranslation(Vec3d(0.0, -1.0, -12.5));
     geomLowerJaw->setRadius(2.0);
-    geomLowerJaw->setOrientationAxis(Vec3d(0.0, 0.0, 1.0));
+    geomLowerJaw->setOrientation(Quatd(Rotd(PI_2, Vec3d(1.0, 0.0, 0.0))));
     imstkNew<CollidingObject> objLowerJaw("LowerJawObject");
     objLowerJaw->setVisualGeometry(lowerSurfMesh);
     objLowerJaw->setCollidingGeometry(geomLowerJaw);
diff --git a/Examples/Rendering/RenderingExample.cpp b/Examples/Rendering/RenderingExample.cpp
index d65c174849df3269e7fa42e6b4092f1a932a1164..f5dbc59b964f5bd9ed305af8e792ebaf375f4f8d 100644
--- a/Examples/Rendering/RenderingExample.cpp
+++ b/Examples/Rendering/RenderingExample.cpp
@@ -35,6 +35,7 @@
 #include "imstkSurfaceMesh.h"
 #include "imstkVisualModel.h"
 #include "imstkVTKViewer.h"
+#include "imstkLogger.h"
 
 using namespace imstk;
 
@@ -45,6 +46,9 @@ using namespace imstk;
 int
 main()
 {
+    // Write log to stdout and file
+    Logger::startLogger();
+
     imstkNew<Scene> scene("Rendering");
     {
         // Add IBL Probe
diff --git a/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp b/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp
index d8b1d0dd8393471e15cb109495f746491780ee8f..01b4d27ea8705b0bf9bff6d5e7fce8ad9a84db53 100644
--- a/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp
+++ b/Examples/RigidBodyDynamics/RigidBodyDynamicsExample.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkCamera.h"
-#include "imstkCube.h"
 #include "imstkIsometricMap.h"
 #include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
@@ -28,6 +27,7 @@
 #include "imstkMeshIO.h"
 #include "imstkMouseSceneControl.h"
 #include "imstkNew.h"
+#include "imstkOrientedBox.h"
 #include "imstkPlane.h"
 #include "imstkRenderMaterial.h"
 #include "imstkRigidBodyModel.h"
@@ -51,16 +51,13 @@ makeMeshRigidObject(const std::string& name, const Vec3d& pos)
 
     // Load a tetrahedral mesh
     auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
-
-    // Extract the surface mesh
-    imstkNew<SurfaceMesh> surfMesh;
-
     tetMesh->scale(15., Geometry::TransformType::ApplyToData);
     tetMesh->translate(pos, Geometry::TransformType::ApplyToData);
-    tetMesh->extractSurfaceMesh(surfMesh, true);
+
+    std::shared_ptr<SurfaceMesh> surfMesh = tetMesh->extractSurfaceMesh();
 
     // add visual model
-    imstkNew<VisualModel>    renderModel(surfMesh.get());
+    imstkNew<VisualModel>    renderModel(surfMesh);
     imstkNew<RenderMaterial> mat;
     mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
     mat->setLineWidth(2.);
@@ -87,8 +84,7 @@ makeCubeRigidObject(std::string& name, const Vec3d& pos)
     imstkNew<RigidObject> cubeObj(name);
 
     // Create cube geometry
-    imstkNew<Cube> cubeGeom;
-    cubeGeom->setWidth(20.0);
+    imstkNew<OrientedBox> cubeGeom(Vec3d::Zero(), Vec3d(10.0, 10.0, 10.0));
     cubeGeom->translate(pos);
 
     // Create cube VisualModel
diff --git a/Examples/RigidBodyDynamics2/RigidBodyDynamicsExample2.cpp b/Examples/RigidBodyDynamics2/RigidBodyDynamicsExample2.cpp
index 5ac1029795c73ca47358a6dc32eb4ddc1171fdca..5968337071aad3bc76fea619a45b4e5469c1b3ff 100644
--- a/Examples/RigidBodyDynamics2/RigidBodyDynamicsExample2.cpp
+++ b/Examples/RigidBodyDynamics2/RigidBodyDynamicsExample2.cpp
@@ -22,7 +22,6 @@
 #include "imstkCamera.h"
 #include "imstkCollisionGraph.h"
 #include "imstkCompositeImplicitGeometry.h"
-#include "imstkCube.h"
 #include "imstkGeometryUtilities.h"
 #include "imstkImplicitGeometryToImageData.h"
 #include "imstkKeyboardDeviceClient.h"
@@ -31,6 +30,7 @@
 #include "imstkLogger.h"
 #include "imstkMouseSceneControl.h"
 #include "imstkNew.h"
+#include "imstkOrientedBox.h"
 #include "imstkPlane.h"
 #include "imstkRbdConstraint.h"
 #include "imstkRenderMaterial.h"
@@ -49,7 +49,6 @@
 #include "imstkVTKViewer.h"
 
 using namespace imstk;
-using namespace imstk::expiremental;
 
 ///
 /// \brief This example demonstrates a rigid body model. The rigid body model uses
@@ -117,9 +116,8 @@ main()
 
         // Create surface mesh cube (so we can use pointset for point->implicit collision)
         {
-            imstkNew<Cube> cubeGeom;
-            cubeGeom->setWidth(4.0);
-            std::shared_ptr<SurfaceMesh> surfMesh = GeometryUtils::toCubeSurfaceMesh(cubeGeom);
+            imstkNew<OrientedBox>        cubeGeom(Vec3d::Zero(), Vec3d(1.5, 3.0, 1.0));
+            std::shared_ptr<SurfaceMesh> surfMesh = GeometryUtils::toSurfaceMesh(cubeGeom);
 
             imstkNew<SurfaceMeshSubdivide> subdivide;
             subdivide->setInputMesh(surfMesh);
diff --git a/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp b/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp
index 05c39ba5530e316aa3e341688a5bd9f99158a1c5..0dcc94293ce39ada4257f2e345e47e91d7651a15 100644
--- a/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp
+++ b/Examples/RigidBodyVirtualCoupling/RigidBodyVirtualCouplingExample.cpp
@@ -20,7 +20,6 @@
 =========================================================================*/
 
 #include "imstkCamera.h"
-#include "imstkCube.h"
 #include "imstkHapticDeviceClient.h"
 #include "imstkHapticDeviceManager.h"
 #include "imstkIsometricMap.h"
@@ -30,6 +29,7 @@
 #include "imstkMeshIO.h"
 #include "imstkMouseSceneControl.h"
 #include "imstkNew.h"
+#include "imstkOrientedBox.h"
 #include "imstkPlane.h"
 #include "imstkRenderMaterial.h"
 #include "imstkRigidBodyModel.h"
@@ -60,19 +60,19 @@ makeMeshRigidObject(const std::string& name, const Vec3d& pos)
     }
 
     // Extract the surface mesh
-    imstkNew<SurfaceMesh> surfMesh;
     tetMesh->scale(15.0, Geometry::TransformType::ApplyToData);
     tetMesh->translate(pos, Geometry::TransformType::ApplyToData);
-    tetMesh->extractSurfaceMesh(surfMesh, true);
+    std::shared_ptr<SurfaceMesh> surfMesh = tetMesh->extractSurfaceMesh();
 
     // Add visual model
-    imstkNew<VisualModel>    renderModel(surfMesh.get());
+    imstkNew<VisualModel> visualModel;
+    visualModel->setGeometry(surfMesh);
     imstkNew<RenderMaterial> mat;
     mat->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
     mat->setLineWidth(2.0);
     mat->setColor(Color::Green);
-    renderModel->setRenderMaterial(mat);
-    meshObj->addVisualModel(renderModel);
+    visualModel->setRenderMaterial(mat);
+    meshObj->addVisualModel(visualModel);
 
     // add dynamic model
     imstkNew<RigidBodyModel>  rigidModel;
@@ -93,7 +93,7 @@ makeCubeRigidObject(const std::string& name, const Vec3d& pos)
     imstkNew<RigidObject> cubeObj(name);
 
     // Create Cube object
-    imstkNew<Cube> cubeGeom(pos, 20.0);
+    imstkNew<OrientedBox> cubeGeom(pos, Vec3d(10.0, 15.0, 10.0));
 
     // cube visual model
     auto surfMesh = MeshIO::read<SurfaceMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.obj");
@@ -268,7 +268,7 @@ main()
             const Vec3d& devPos = controller->getPosition();
             const Quatd& devQ   = controller->getRotation();
             rbdModel->getModelGeometry()->rotate(devQ);
-            auto cubeGeo = std::dynamic_pointer_cast<Cube>(cubeObj->getPhysicsGeometry());
+            auto cubeGeo = std::dynamic_pointer_cast<OrientedBox>(cubeObj->getPhysicsGeometry());
             const Vec3d cubePos      = rbdModel->getModelGeometry()->getTranslation();
             const Vec3d cubeVelocity = (cubePos - prevCubePos) / 2.0;
             const Vec3d damp  = -1000000 * cubeVelocity;
diff --git a/Examples/SPH-FEM-PBD/sphFemPbdExample.cpp b/Examples/SPH-FEM-PBD/sphFemPbdExample.cpp
index 0a58d452fb6e9b42f24a7a88ebbc23c942f7864c..a1f989310065fe46dcc5003db1182050900004bb 100644
--- a/Examples/SPH-FEM-PBD/sphFemPbdExample.cpp
+++ b/Examples/SPH-FEM-PBD/sphFemPbdExample.cpp
@@ -154,8 +154,7 @@ makeFEDragonObject(const std::string& name, const Vec3d& position)
     // Setup the Geometry
     auto tetMesh = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
     tetMesh->translate(position, Geometry::TransformType::ApplyToData);
-    imstkNew<SurfaceMesh> surfMesh;
-    tetMesh->extractSurfaceMesh(surfMesh, true);
+    std::shared_ptr<SurfaceMesh> surfMesh = tetMesh->extractSurfaceMesh();
 
     // Setup the Parameters
     imstkNew<FEMModelConfig> config;
@@ -170,7 +169,8 @@ makeFEDragonObject(const std::string& name, const Vec3d& position)
     dynaModel->setTimeIntegrator(timeIntegrator);
 
     // Setup the VisualModel
-    imstkNew<VisualModel>    surfMeshModel(surfMesh.get());
+    imstkNew<VisualModel> surfMeshModel;
+    surfMeshModel->setGeometry(surfMesh);
     imstkNew<RenderMaterial> material;
     material->setDisplayMode(RenderMaterial::DisplayMode::Surface);
     surfMeshModel->setRenderMaterial(material);
@@ -200,8 +200,7 @@ makePBDDragonObject(const std::string& name, const Vec3d& position)
     auto coarseTetMesh   = MeshIO::read<TetrahedralMesh>(iMSTK_DATA_ROOT "/asianDragon/asianDragon.veg");
     highResSurfMesh->translate(position, Geometry::TransformType::ApplyToData);
     coarseTetMesh->translate(position, Geometry::TransformType::ApplyToData);
-    imstkNew<SurfaceMesh> coarseSurfMesh;
-    coarseTetMesh->extractSurfaceMesh(coarseSurfMesh, true);
+    std::shared_ptr<SurfaceMesh> coarseSurfMesh = coarseTetMesh->extractSurfaceMesh();
 
     // Setup the Parameters
     imstkNew<PBDModelConfig> pbdParams;
diff --git a/Examples/Screenshot/ScreenshotExample.cpp b/Examples/Screenshot/ScreenshotExample.cpp
index db0f30d9c89d00ebf173af90f6e38f18c19a4a3e..7d5f00659ad6f0cbc7f04dbeca286453db64c41d 100644
--- a/Examples/Screenshot/ScreenshotExample.cpp
+++ b/Examples/Screenshot/ScreenshotExample.cpp
@@ -20,13 +20,13 @@
 =========================================================================*/
 
 #include "imstkCamera.h"
-#include "imstkCube.h"
 #include "imstkKeyboardDeviceClient.h"
 #include "imstkKeyboardSceneControl.h"
 #include "imstkLight.h"
 #include "imstkLogger.h"
 #include "imstkMouseSceneControl.h"
 #include "imstkNew.h"
+#include "imstkOrientedBox.h"
 #include "imstkPlane.h"
 #include "imstkScene.h"
 #include "imstkSceneManager.h"
@@ -57,10 +57,7 @@ main()
     planeObj->setVisualGeometry(planeGeom);
 
     // Cube
-    imstkNew<Cube> cubeGeom;
-    cubeGeom->setWidth(0.5);
-    cubeGeom->setPosition(1.0, -1.0, 0.5);
-    // rotates could be replaced by cubeGeom->setOrientationAxis(1,1,1) (normalized inside)
+    imstkNew<OrientedBox> cubeGeom(Vec3d(1.0, -1.0, 0.5), Vec3d(0.25, 0.25, 0.25));
     cubeGeom->rotate(UP_VECTOR, PI_4, Geometry::TransformType::ApplyToData);
     cubeGeom->rotate(RIGHT_VECTOR, PI_4, Geometry::TransformType::ApplyToData);
     imstkNew<SceneObject> cubeObj("VisualCube");
diff --git a/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp b/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp
index ea86b9ff362779132109905d0cf4bed9e698c800..f34c9ebd37338f6753ee8276f7ad5c8d1bf6e11e 100644
--- a/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp
+++ b/Examples/TaskGraph/Configuration/taskGraphConfigureExample.cpp
@@ -112,17 +112,21 @@ makeClothObj(const std::string& name, double width, double height, int nRows, in
     pbdModel->setModelGeometry(clothMesh);
     pbdModel->configure(pbdParams);
 
-    // Setup the VisualModel
-    imstkNew<RenderMaterial> material;
-    material->setBackFaceCulling(false);
-    material->setColor(Color::LightGray);
-    material->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-
-    auto clothVisualModel = std::make_shared<VisualModel>(clothMesh);
-    clothVisualModel->setRenderMaterial(material);
+    // Setup visual models
+    imstkNew<VisualModel> clothModel;
+    clothModel->setGeometry(clothMesh);
+    clothModel->getRenderMaterial()->setBackFaceCulling(false);
+    clothModel->getRenderMaterial()->setColor(Color::LightGray);
+    clothModel->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+
+    imstkNew<VisualModel> clothSurfaceNormals;
+    clothSurfaceNormals->setGeometry(clothMesh);
+    clothSurfaceNormals->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::SurfaceNormals);
+    clothSurfaceNormals->getRenderMaterial()->setPointSize(0.5);
 
     // Setup the Object
-    clothObj->addVisualModel(clothVisualModel);
+    clothObj->addVisualModel(clothModel);
+    clothObj->addVisualModel(clothSurfaceNormals);
     clothObj->setPhysicsGeometry(clothMesh);
     clothObj->setDynamicalModel(pbdModel);
 
@@ -153,7 +157,7 @@ main()
 
     // Setup some scalars
     auto clothGeometry = std::dynamic_pointer_cast<SurfaceMesh>(clothObj->getPhysicsGeometry());
-    auto scalarsPtr    = std::make_shared<DataArray<double>>(static_cast<int>(clothGeometry->getNumVertices()));
+    auto scalarsPtr    = std::make_shared<DataArray<double>>(clothGeometry->getNumVertices());
     std::fill_n(scalarsPtr->getPointer(), scalarsPtr->size(), 0.0);
     clothGeometry->setVertexScalars("scalars", scalarsPtr);
 
diff --git a/Examples/TaskGraph/Timing/CMakeLists.txt b/Examples/TaskGraph/Timing/CMakeLists.txt
index ea4991855fcfe14cb594f62e1370b62de19b2eff..4b2a8e023800fbac6732433a418b722d2cd3ffe4 100644
--- a/Examples/TaskGraph/Timing/CMakeLists.txt
+++ b/Examples/TaskGraph/Timing/CMakeLists.txt
@@ -23,6 +23,7 @@ project(Example-TaskGraphTiming)
 #-----------------------------------------------------------------------------
 imstk_add_executable(${PROJECT_NAME} taskGraphTimingExample.cpp)
 
+target_compile_options(${PROJECT_NAME} PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/bigobj>)
 #-----------------------------------------------------------------------------
 # Add the target to Examples folder
 #-----------------------------------------------------------------------------
diff --git a/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp b/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp
index 0ca97a0facb1deebda456dc68577a59e2ef60455..36955a10100c8dda5652db72585a9dfad002a36e 100644
--- a/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp
+++ b/Examples/TaskGraph/Timing/taskGraphTimingExample.cpp
@@ -41,7 +41,7 @@ using namespace imstk;
 /// \brief Create pbd string geometry
 ///
 static std::shared_ptr<LineMesh>
-makeStringGeometry(const Vec3d& pos, const size_t numVerts, const double stringLength)
+makeStringGeometry(const Vec3d& pos, const int numVerts, const double stringLength)
 {
     const double vertexSpacing = stringLength / numVerts;
 
@@ -50,8 +50,8 @@ makeStringGeometry(const Vec3d& pos, const size_t numVerts, const double stringL
 
     imstkNew<VecDataArray<double, 3>> verticesPtr;
     VecDataArray<double, 3>&          vertices = *verticesPtr.get();
-    vertices.resize(static_cast<int>(numVerts));
-    for (size_t j = 0; j < numVerts; j++)
+    vertices.resize(numVerts);
+    for (int j = 0; j < numVerts; j++)
     {
         vertices[j] = pos - Vec3d(0.0, static_cast<double>(j) * vertexSpacing, 0.0);
     }
@@ -121,8 +121,8 @@ makePbdString(
 }
 
 static std::vector<std::shared_ptr<PbdObject>>
-makePbdStrings(const size_t numStrings,
-               const size_t numVerts,
+makePbdStrings(const int    numStrings,
+               const int    numVerts,
                const double stringSpacing,
                const double stringLength,
                const Color& startColor,
@@ -132,7 +132,7 @@ makePbdStrings(const size_t numStrings,
 
     const double size = stringSpacing * (numStrings - 1);
 
-    for (unsigned int i = 0; i < numStrings; i++)
+    for (int i = 0; i < numStrings; i++)
     {
         const Vec3d  tipPos = Vec3d(static_cast<double>(i) * stringSpacing - size * 0.5, stringLength * 0.5, 0.0);
         const double t      = static_cast<double>(i) / (numStrings - 1);
@@ -151,8 +151,8 @@ makePbdStrings(const size_t numStrings,
 
 const double dt            = 0.0005;
 const double radius        = 1.5;
-const size_t numStrings    = 8;                    // Number of strings
-const size_t numVerts      = 30;                   // Number of vertices on each string
+const int    numStrings    = 8;                    // Number of strings
+const int    numVerts      = 30;                   // Number of vertices on each string
 const double stringSpacing = 2.0;                  // How far each string is apart
 const double stringLength  = 10.0;                 // Total length of string
 const Color  startColor    = Color(1.0, 0.0, 0.0); // Color of first string
diff --git a/Source/Animation/Particles/imstkRenderParticleEmitter.cpp b/Source/Animation/Particles/imstkRenderParticleEmitter.cpp
index 1f5e994b4dde0ded3c408bde95a2ce5c66ccd95f..965af42874edd803352f05f2636307d0929f0678 100644
--- a/Source/Animation/Particles/imstkRenderParticleEmitter.cpp
+++ b/Source/Animation/Particles/imstkRenderParticleEmitter.cpp
@@ -56,7 +56,7 @@ void
 RenderParticleEmitter::setGeometry(
     std::shared_ptr<Geometry> geometry)
 {
-    CHECK(geometry->getTypeName() == "RenderParticles") << "Geometry must be RenderParticles";
+    CHECK(geometry->getTypeName() == "RenderParticles") << "Error: Geometry must be RenderParticles";
 
     m_animationGeometry = geometry;
     m_particles = &std::static_pointer_cast<RenderParticles>(m_animationGeometry)->getParticles();
diff --git a/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCCD.cpp
index 481fdc523aecdf51273fbb8fe3afc22ed7afad4a..9ec5bf8aed42692031ab3b68bed88ef6361c459f 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCCD.cpp
@@ -39,7 +39,7 @@ ImplicitGeometryToPointSetCCD::ImplicitGeometryToPointSetCCD(std::shared_ptr<Imp
         centralGrad.setDx(sdf->getImage()->getSpacing());
     }
 
-    displacementsPtr = std::make_shared<VecDataArray<double, 3>>(static_cast<int>(m_pointSetB->getNumVertices()));
+    displacementsPtr = std::make_shared<VecDataArray<double, 3>>(m_pointSetB->getNumVertices());
     m_pointSetB->setVertexAttribute("displacements", displacementsPtr);
 }
 
diff --git a/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp
index c8a24faf2b419a5130e7dee052a1589bc9488be4..40e16b3c42b82290bf7ea644240bb04d4a254f8c 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp
@@ -57,7 +57,7 @@ MeshToMeshBruteForceCD::computeCollisionData()
         const VecDataArray<double, 3>& mesh1Vertices = *lineMesh->getVertexPositions();
 
         // brute force, use BVH or spatial grid would be much better
-        for (int i = 0; i < static_cast<int>(lineMesh->getNumVertices()); ++i)
+        for (int i = 0; i < lineMesh->getNumVertices(); ++i)
         {
             const Vec3d p = mesh1Vertices[i];
 
@@ -145,7 +145,7 @@ MeshToMeshBruteForceCD::computeCollisionData()
 
         // brute force, use BVH or spatial grid would be much better
         // point
-        for (int i = 0; i < static_cast<int>(pointSet->getNumVertices()); ++i)
+        for (int i = 0; i < pointSet->getNumVertices(); ++i)
         {
             const auto p = mesh1Vertices[i];
 
@@ -174,7 +174,7 @@ MeshToMeshBruteForceCD::computeCollisionData()
 
         // brute force, use BVH or spatial grid would be much better
         // point
-        for (int i = 0; i < static_cast<int>(surfMesh->getNumVertices()); ++i)
+        for (int i = 0; i < surfMesh->getNumVertices(); ++i)
         {
             const Vec3d p = mesh1Vertices[i];
 
diff --git a/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp
index 4b2159bd28e0d47b4ba0d2f1ea742128457e92d8..96802ef63dbc43a7cb3b682ce4a40c694fe41361 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkNarrowPhaseCD.cpp
@@ -155,7 +155,7 @@ sphereToCylinder(Sphere* const sphere, Cylinder* const cylinder,
     const double rSphere   = sphere->getRadius();
 
     const Vec3d  cylinderPos  = cylinder->getPosition();
-    const Vec3d  cylinderAxis = cylinder->getOrientationAxis();
+    const Vec3d  cylinderAxis = cylinder->getOrientation().toRotationMatrix().col(1);
     const double rCylinder    = cylinder->getRadius();
 
     // Compute shortest distance
@@ -255,7 +255,7 @@ pointToCapsule(const Vec3r& point, uint32_t pointIdx, Capsule* capsule,
     // Get position of end points of the capsule
     // TODO: Fix this issue of extra computation in future
     const Vec3d mid    = capsulePos;
-    const Vec3d p1     = mid + 0.5 * capsule->getOrientationAxis() * length;
+    const Vec3d p1     = mid + 0.5 * capsule->getRotation().transpose().col(1) * length;
     const Vec3d p0     = 2 * mid - p1;
     const Vec3d p      = p1 - p0;
     const auto  pDotp  = p.dot(p);
diff --git a/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp
index 3ec543fccacabb6854d3c9fb1d9aea35960a2924..b39eeecca437c3512285e04d60be83b8244a19bf 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkSurfaceMeshToSurfaceMeshCCD.cpp
@@ -38,7 +38,7 @@ SurfaceMeshToSurfaceMeshCCD::SurfaceMeshToSurfaceMeshCCD(std::shared_ptr<Surface
 
     // Copy data A
     const VecDataArray<int, 3>& indicesA = *meshA->getTriangleIndices();
-    for (int i = 0; i < static_cast<int>(meshA->getNumTriangles()); i++)
+    for (int i = 0; i < meshA->getNumTriangles(); i++)
     {
         for (int j = 0; j < 3; j++)
         {
@@ -46,14 +46,14 @@ SurfaceMeshToSurfaceMeshCCD::SurfaceMeshToSurfaceMeshCCD(std::shared_ptr<Surface
         }
     }
     const VecDataArray<double, 3>& positionsA = *meshA->getVertexPositions();
-    for (int i = 0; i < static_cast<int>(meshA->getNumVertices()); i++)
+    for (int i = 0; i < meshA->getNumVertices(); i++)
     {
         m_positionsA[i] = positionsA[i];
     }
 
     // Copy data B
     const VecDataArray<int, 3>& indicesB = *meshB->getTriangleIndices();
-    for (int i = 0; i < static_cast<int>(meshB->getNumTriangles()); i++)
+    for (int i = 0; i < meshB->getNumTriangles(); i++)
     {
         for (int j = 0; j < 3; j++)
         {
@@ -61,7 +61,7 @@ SurfaceMeshToSurfaceMeshCCD::SurfaceMeshToSurfaceMeshCCD(std::shared_ptr<Surface
         }
     }
     const VecDataArray<double, 3>& positionsB = *meshB->getVertexPositions();
-    for (int i = 0; i < static_cast<int>(meshB->getNumVertices()); i++)
+    for (int i = 0; i < meshB->getNumVertices(); i++)
     {
         m_positionsB[i] = positionsB[i];
     }
@@ -86,12 +86,12 @@ SurfaceMeshToSurfaceMeshCCD::computeCollisionData()
     m_colData->clearAll();
 
     const VecDataArray<double, 3>& positionsA = *m_meshA->getVertexPositions();
-    for (int i = 0; i < static_cast<int>(m_meshA->getNumVertices()); i++)
+    for (int i = 0; i < m_meshA->getNumVertices(); i++)
     {
         m_positionsA[i] = positionsA[i];
     }
     const VecDataArray<double, 3>& positionsB = *m_meshB->getVertexPositions();
-    for (int i = 0; i < static_cast<int>(m_meshB->getNumVertices()); i++)
+    for (int i = 0; i < m_meshB->getNumVertices(); i++)
     {
         m_positionsB[i] = positionsB[i];
     }
diff --git a/Source/CollisionDetection/imstkCDObjectFactory.cpp b/Source/CollisionDetection/imstkCDObjectFactory.cpp
index 76fced2e2376aa22425eed531d3c61f41518f9c3..817ef273879f045b9805cc2a97cb2599dc042ff9 100644
--- a/Source/CollisionDetection/imstkCDObjectFactory.cpp
+++ b/Source/CollisionDetection/imstkCDObjectFactory.cpp
@@ -216,7 +216,7 @@ makeCollisionDetectionObject(const CollisionDetection::Type type,
     }
     default:
     {
-        LOG(FATAL) << "makeCollisionDetectionObject error: type not implemented.";
+        LOG(FATAL) << "error: type not implemented.";
         return nullptr;
     }
     }
diff --git a/Source/CollisionHandling/imstkBoneDrillingCH.cpp b/Source/CollisionHandling/imstkBoneDrillingCH.cpp
index 73f8251b01c365e02841061e43296a2b2ff836a5..4b87a33822db1102eabf71abe4d32fbdafcddd94 100644
--- a/Source/CollisionHandling/imstkBoneDrillingCH.cpp
+++ b/Source/CollisionHandling/imstkBoneDrillingCH.cpp
@@ -36,7 +36,7 @@ BoneDrillingCH::BoneDrillingCH(const Side&                          side,
 {
     auto boneMesh = std::dynamic_pointer_cast<TetrahedralMesh>(m_bone->getCollidingGeometry());
 
-    CHECK(boneMesh != nullptr) << "BoneDrillingCH::BoneDrillingCH Error:The bone colliding geometry is not a mesh!";
+    CHECK(boneMesh != nullptr) << "Error:The bone colliding geometry is not a mesh!";
 
     // Initialize bone density values
     m_nodalDensity.reserve(boneMesh->getNumVertices());
diff --git a/Source/CollisionHandling/imstkLevelSetCH.cpp b/Source/CollisionHandling/imstkLevelSetCH.cpp
index fa91068268676ba4e434988a6e3c0a125a215545..c0cea7eefb4e8c80b3e21e8f5c50e1ecd09aa257 100644
--- a/Source/CollisionHandling/imstkLevelSetCH.cpp
+++ b/Source/CollisionHandling/imstkLevelSetCH.cpp
@@ -29,8 +29,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 LevelSetCH::LevelSetCH(const Side&                               side,
                        const std::shared_ptr<CollisionData>      colData,
                        std::shared_ptr<LevelSetDeformableObject> lvlSetObj,
@@ -91,7 +89,7 @@ LevelSetCH::processCollisionData()
 
     if (grid == nullptr)
     {
-        LOG(FATAL) << "LevelSetCH::processCollisionData: level set model geometry is not ImageData";
+        LOG(FATAL) << "Error: level set model geometry is not ImageData";
         return;
     }
 
@@ -168,10 +166,9 @@ void
 LevelSetCH::maskAllPoints()
 {
     std::shared_ptr<PointSet> pointSet = std::dynamic_pointer_cast<PointSet>(m_rigidObj->getCollidingGeometry());
-    for (int i = 0; i < static_cast<int>(pointSet->getNumVertices()); i++)
+    for (int i = 0; i < pointSet->getNumVertices(); i++)
     {
         m_ptIdMask.insert(i);
     }
 }
-}
 }
\ No newline at end of file
diff --git a/Source/CollisionHandling/imstkLevelSetCH.h b/Source/CollisionHandling/imstkLevelSetCH.h
index 39cda0e6bf11ceeb08b7ceab6c50d27bbdda22b4..c3d2e91f6e81fa8bfe3f2e4706ca32a97b550f99 100644
--- a/Source/CollisionHandling/imstkLevelSetCH.h
+++ b/Source/CollisionHandling/imstkLevelSetCH.h
@@ -28,11 +28,8 @@
 
 namespace imstk
 {
-class LevelSetDeformableObject;
 struct CollisionData;
-
-namespace expiremental
-{
+class LevelSetDeformableObject;
 class RigidObject2;
 
 ///
@@ -104,5 +101,4 @@ private:
     double  m_kernelSigma   = 1.0;
     double* m_kernelWeights = nullptr;
 };
-}
 }
\ No newline at end of file
diff --git a/Source/CollisionHandling/imstkPBDPickingCH.cpp b/Source/CollisionHandling/imstkPBDPickingCH.cpp
index 350faae392756214f6c347428167ce39b921bda8..765c6c1a2c1a34ae0b34ac86be1677a5a6005006 100644
--- a/Source/CollisionHandling/imstkPBDPickingCH.cpp
+++ b/Source/CollisionHandling/imstkPBDPickingCH.cpp
@@ -56,8 +56,7 @@ void
 PBDPickingCH::processCollisionData()
 {
     CHECK(m_pbdObj != nullptr && m_pickObj != nullptr)
-        << "PBDPickingCH::handleCollision error: "
-        << "no picking collision handling available the object";
+        << "Error: invalid input pbd objects for collision handling";
 
     if (m_isPicking)
     {
@@ -108,8 +107,7 @@ PBDPickingCH::addPickConstraints(std::shared_ptr<PbdObject> pbdObj, std::shared_
     }
 
     CHECK(pbdObj != nullptr && pickObj != nullptr)
-        << "PBDPickingCH:addPickConstraints error: "
-        << "no pdb object or colliding object.";
+        << "Error: no pdb object or colliding object.";
 
     std::shared_ptr<PbdModel>           model    = pbdObj->getPbdModel();
     std::shared_ptr<AnalyticalGeometry> pickGeom = std::dynamic_pointer_cast<AnalyticalGeometry>(pickObj->getCollidingGeometry());
diff --git a/Source/CollisionHandling/imstkPenaltyCH.cpp b/Source/CollisionHandling/imstkPenaltyCH.cpp
index f862f10e59e6322c32edb3c2fa10200e17cb008d..3cab0c35f822b775b484119235ebb70901c20390 100644
--- a/Source/CollisionHandling/imstkPenaltyCH.cpp
+++ b/Source/CollisionHandling/imstkPenaltyCH.cpp
@@ -48,7 +48,7 @@ PenaltyCH::processCollisionData()
     }
     else
     {
-        LOG(FATAL) << "no penalty collision handling available for " << m_object->getName()
+        LOG(FATAL) << "No penalty collision handling available for " << m_object->getName()
                    << " (rigid mesh not yet supported).";
     }
 }
@@ -90,7 +90,7 @@ PenaltyCH::computeContactForcesDiscreteDeformable(const std::shared_ptr<FeDeform
         return;
     }
 
-    CHECK(deformableObj != nullptr) << "PenaltyRigidCH::computeContactForcesDiscreteDeformable error: "
+    CHECK(deformableObj != nullptr) << "error: "
                                     << m_object->getName() << " is not a deformable object.";
 
     // Get current force vector
diff --git a/Source/CollisionHandling/imstkPickingCH.cpp b/Source/CollisionHandling/imstkPickingCH.cpp
index 6b25b3cd64418f9a933469e3f546f30eaa5b405b..613ad440f3725b0e83d7e59f610442a8c0b98aae 100644
--- a/Source/CollisionHandling/imstkPickingCH.cpp
+++ b/Source/CollisionHandling/imstkPickingCH.cpp
@@ -40,8 +40,7 @@ PickingCH::PickingCH(const CollisionHandling::Side&       side,
 void
 PickingCH::processCollisionData()
 {
-    CHECK(m_object != nullptr) << "PickingCH::handleCollision error: "
-                               << "no picking collision handling available the object";
+    CHECK(m_object != nullptr) << "error: no picking collision handling available the object";
 
     this->addPickConstraints(m_object);
 }
@@ -56,8 +55,7 @@ PickingCH::addPickConstraints(std::shared_ptr<FeDeformableObject> deformableObj)
         return;
     }
 
-    CHECK(deformableObj != nullptr) << "PenaltyRigidCH::addPickConstraints error: "
-                                    << " not a deformable object.";
+    CHECK(deformableObj != nullptr) << "error: not a deformable object.";
 
     std::shared_ptr<FEMDeformableBodyModel> model = deformableObj->getFEMModel();
     const Vectord&                          Uprev = model->getCurrentState()->getQ();
diff --git a/Source/CollisionHandling/imstkRigidBodyCH.cpp b/Source/CollisionHandling/imstkRigidBodyCH.cpp
index 6578957e1569f01229880a20b578f6c2aadc400d..dc070c7fd498d454b8922b842b5521f8543e3e8d 100644
--- a/Source/CollisionHandling/imstkRigidBodyCH.cpp
+++ b/Source/CollisionHandling/imstkRigidBodyCH.cpp
@@ -28,8 +28,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 RigidBodyCH::RigidBodyCH(const Side&                          side,
                          const std::shared_ptr<CollisionData> colData,
                          std::shared_ptr<RigidObject2>        rbdObjectA,
@@ -200,5 +198,4 @@ RigidBodyCH::processAB()
         }
     }
 }
-}
 }
\ No newline at end of file
diff --git a/Source/CollisionHandling/imstkRigidBodyCH.h b/Source/CollisionHandling/imstkRigidBodyCH.h
index 87816827cf1fd19ed1886a1a86bbbb98720132c5..51ea81cfdb8b3ed1b1d776693d7eb650d18ff96a 100644
--- a/Source/CollisionHandling/imstkRigidBodyCH.h
+++ b/Source/CollisionHandling/imstkRigidBodyCH.h
@@ -28,8 +28,6 @@
 namespace imstk
 {
 struct CollisionData;
-namespace expiremental
-{
 class RigidObject2;
 
 ///
@@ -76,5 +74,4 @@ private:
     double m_frictionalCoefficient = 0.8;
     bool   m_useFriction = true;
 };
-}
-}
+}
\ No newline at end of file
diff --git a/Source/Common/TaskGraph/imstkTaskGraph.cpp b/Source/Common/TaskGraph/imstkTaskGraph.cpp
index 1f0555a9d9e2aec4de776eac7d7c5fbe807759cc..3e697b6c21f4707fd7ccc1b01462a61ff02df459 100644
--- a/Source/Common/TaskGraph/imstkTaskGraph.cpp
+++ b/Source/Common/TaskGraph/imstkTaskGraph.cpp
@@ -77,6 +77,17 @@ TaskGraph::containsEdge(std::shared_ptr<TaskNode> srcNode, std::shared_ptr<TaskN
 void
 TaskGraph::addEdge(std::shared_ptr<TaskNode> srcNode, std::shared_ptr<TaskNode> destNode)
 {
+    if (!containsNode(srcNode))
+    {
+        LOG(WARNING) << "srcNode " << srcNode->m_name << " does not exist in graph";
+        return;
+    }
+    if (!containsNode(destNode))
+    {
+        LOG(WARNING) << "destNode " << destNode->m_name << " does not exist n graph";
+        return;
+    }
+
     m_adjList[srcNode].insert(destNode);
     m_invAdjList[destNode].insert(srcNode);
 }
diff --git a/Source/Common/TaskGraph/imstkTaskGraph.h b/Source/Common/TaskGraph/imstkTaskGraph.h
index 3e7d00bd8e68059d42efe5685862966a95286c7a..b38b474df84053e74b8a2056a7e2675471700ea2 100644
--- a/Source/Common/TaskGraph/imstkTaskGraph.h
+++ b/Source/Common/TaskGraph/imstkTaskGraph.h
@@ -206,7 +206,15 @@ public:
     ///
     static std::shared_ptr<TaskGraph> reduce(std::shared_ptr<TaskGraph> graph)
     {
-        return removeRedundantNodes(transitiveReduce(graph));
+        std::shared_ptr<TaskGraph> reducedGraph = transitiveReduce(graph);
+        if (reducedGraph != nullptr)
+        {
+            return removeRedundantNodes(reducedGraph);
+        }
+        else
+        {
+            return nullptr;
+        }
     }
 
     ///
diff --git a/Source/Common/Testing/imstkDataArrayTest.cpp b/Source/Common/Testing/imstkDataArrayTest.cpp
index 28039ffb5c62cf6c43a7c81733a5c806fb9d525a..89094a240f3949f9ffb2040b3b4952d3d807e4c0 100644
--- a/Source/Common/Testing/imstkDataArrayTest.cpp
+++ b/Source/Common/Testing/imstkDataArrayTest.cpp
@@ -162,6 +162,48 @@ TEST(imstkDataArrayTest, Iterators)
     }
 }
 
+TEST(imstkDataArrayTest, ScalarType)
+{
+    DataArray<int> a;
+    EXPECT_EQ(IMSTK_INT, a.getScalarType());
+    DataArray<double> b;
+    EXPECT_EQ(IMSTK_DOUBLE, b.getScalarType());
+}
+
+TEST(imstkDataArrayTest, TypeCast)
+{
+    DataArray<int> a{ 1, 2, 3, 4 };
+
+    auto b = a.cast<double>();
+
+    ASSERT_EQ(IMSTK_DOUBLE, b.getScalarType());
+    ASSERT_EQ(a.size(), b.size());
+
+    for (int i = 0; i < a.size(); ++i)
+    {
+        EXPECT_DOUBLE_EQ(static_cast<double>(a[i]), b[i]);
+    }
+}
+
+TEST(imstkDataArrayTest, ParameterCast)
+{
+    DataArray<int>     a{ 1, 2, 3, 4 };
+    AbstractDataArray* abstractA = &a;
+
+    auto b = abstractA->cast(IMSTK_DOUBLE);
+    ASSERT_NE(nullptr, b);
+
+    auto actualB = dynamic_cast<DataArray<double>*>(b.get());
+    ASSERT_NE(nullptr, actualB);
+    ASSERT_EQ(IMSTK_DOUBLE, actualB->getScalarType());
+    ASSERT_EQ(a.size(), actualB->size());
+
+    for (int i = 0; i < a.size(); ++i)
+    {
+        EXPECT_DOUBLE_EQ(static_cast<double>(a[i]), (*actualB)[i]);
+    }
+}
+
 int
 imstkDataArrayTest(int argc, char* argv[])
 {
diff --git a/Source/Common/Testing/imstkVecDataArrayTest.cpp b/Source/Common/Testing/imstkVecDataArrayTest.cpp
index b6e8fc74cbaa92e0102f63d04792f3a8944df66b..47ae1ab9bbf5386739de2837fd35cdf50c53eb22 100644
--- a/Source/Common/Testing/imstkVecDataArrayTest.cpp
+++ b/Source/Common/Testing/imstkVecDataArrayTest.cpp
@@ -198,6 +198,46 @@ TEST(imstkVecDataArrayTest, Erase)
     EXPECT_EQ(2, a.getCapacity());
 }
 
+TEST(imstkVecDataArrayTest, ExplicitCast)
+{
+    {
+        VecDataArray<double, 2> a;
+        VecDataArray<int, 2>    b;
+        EXPECT_NO_THROW(b = a.cast<int>());
+        EXPECT_EQ(a.size(), b.size());
+    }
+
+    {
+        VecDataArray<int, 2> a{ Vec2i(1, 2), Vec2i(3, 4), Vec2i(5, 6), Vec2i(7, 8) };
+        auto                 b = a.cast<double>();
+
+        ASSERT_EQ(a.size(), b.size());
+        EXPECT_EQ(IMSTK_DOUBLE, b.getScalarType());
+        for (int i = 0; i < a.size(); ++i)
+        {
+            EXPECT_TRUE(a[i].cast<double>().isApprox(b[i]));
+        }
+    }
+}
+
+TEST(imstkVecDataArrayTest, ParameterCast)
+{
+    VecDataArray<int, 2> a{ Vec2i(1, 2), Vec2i(3, 4), Vec2i(5, 6), Vec2i(7, 8) };
+    AbstractDataArray*   abstractA = &a;
+
+    auto b = abstractA->cast(IMSTK_DOUBLE);
+
+    EXPECT_EQ(IMSTK_DOUBLE, b->getScalarType());
+
+    auto actualB = dynamic_cast<VecDataArray<double, 2>*>(b.get());
+    ASSERT_NE(nullptr, actualB);
+    ASSERT_EQ(a.size(), actualB->size());
+    for (int i = 0; i < a.size(); ++i)
+    {
+        EXPECT_TRUE(a[i].cast<double>().isApprox((*actualB)[i]));
+    }
+}
+
 int
 imstkVecDataArrayTest(int argc, char* argv[])
 {
diff --git a/Source/Common/imstkAbstractDataArray.h b/Source/Common/imstkAbstractDataArray.h
index 602b5356f0e4d20426b303eebc6a11eca32b5395..5bc27d326d8dd314beb58201b2506bcea25183ec 100644
--- a/Source/Common/imstkAbstractDataArray.h
+++ b/Source/Common/imstkAbstractDataArray.h
@@ -33,8 +33,7 @@ namespace imstk
 ///
 class AbstractDataArray : public EventObject
 {
-// Users should not be able to construct
-protected:
+public:
     AbstractDataArray() : m_scalarType(IMSTK_VOID), m_size(0), m_capacity(0) { }
 
     AbstractDataArray(const int size) : m_scalarType(IMSTK_VOID), m_size(size), m_capacity(size) { }
@@ -44,8 +43,9 @@ protected:
     ///
     virtual ~AbstractDataArray() { };
 
-public:
-    SIGNAL(AbstractDataArray,modified);
+    // *INDENT-OFF*
+    SIGNAL(AbstractDataArray, modified);
+    // *INDENT-ON*
 
 public:
     ///
@@ -71,22 +71,28 @@ public:
     ///
     /// \brief Get number of values/tuples
     ///
-    inline int size() const{ return m_size; }
+    inline int size() const { return m_size; }
 
     ///
     /// \brief Returns the scalar type of this array
     ///
-    inline ScalarType getScalarType() const{ return m_scalarType; }
+    inline ScalarType getScalarType() const { return m_scalarType; }
 
     ///
     /// \brief Return the capacity of the array
     ///
-    inline int getCapacity() const{ return m_capacity; }
+    inline int getCapacity() const { return m_capacity; }
 
     ///
     /// \brief Returns the number of components
     ///
-    inline virtual int getNumberOfComponents() const{ return 1; }
+    inline virtual int getNumberOfComponents() const { return 1; }
+
+    ///
+    /// \brief cast the content to the given imstk scalar type without
+    ///        having to know the type of the enclosed array
+    ///
+    virtual std::shared_ptr<AbstractDataArray> cast(ScalarType) = 0;
 
 public:
     ///
diff --git a/Source/Common/imstkDataArray.h b/Source/Common/imstkDataArray.h
index f9f1850788e28f5a412cebcb50d4504341117785..7171597221de02444772c26a0fb983a3f62492c9 100644
--- a/Source/Common/imstkDataArray.h
+++ b/Source/Common/imstkDataArray.h
@@ -376,6 +376,42 @@ public:
 
     inline virtual int getNumberOfComponents() const override { return 1; }
 
+    ///
+    /// \brief Cast array to specific c++ type
+    ///
+    template<typename N>
+    DataArray<N> cast()
+    {
+        if (m_mapped)
+        {
+            throw(std::runtime_error("Can't cast a mapped array"));
+        }
+        DataArray<N> result;
+        result.reserve(size());
+        for (auto& i : *this)
+        {
+            result.push_back(static_cast<N>(i));
+        }
+        return result;
+    }
+
+    ///
+    /// \brief Cast array to the IMSTK type on the abstract interface
+    ///
+    std::shared_ptr<AbstractDataArray> cast(ScalarType type) override
+    {
+        if (type == AbstractDataArray::m_scalarType)
+        {
+            return std::make_shared<DataArray<T>>(*this);
+        }
+        switch (type)
+        {
+            TemplateMacro(return std::make_shared<DataArray<IMSTK_TT>>(cast<IMSTK_TT>()));
+        default:
+            throw(std::runtime_error("Unknown scalar type"));
+        }
+    }
+
 protected:
     bool m_mapped;
     T*   m_data;
diff --git a/Source/Common/imstkMath.h b/Source/Common/imstkMath.h
index 3534389bc15ee64254b151f9b6d94b0f97253bbf..97cf6c1f77f088065df2e2df0a425ebc1e35dd4f 100644
--- a/Source/Common/imstkMath.h
+++ b/Source/Common/imstkMath.h
@@ -234,4 +234,56 @@ mat4dTRS(const Mat4d& m, Vec3d& t, Mat3d& r, Vec3d& s)
 
     t = m.block<3, 1>(0, 3);
 }
+
+///
+/// \brief Computes tet signed volume/determinant
+///
+static double
+tetVolume(Vec3d p0, Vec3d p1, Vec3d p2, Vec3d p3)
+{
+    Mat4d m;
+    m.block<1, 3>(0, 0) = p0;
+    m.block<1, 3>(1, 0) = p1;
+    m.block<1, 3>(2, 0) = p2;
+    m.block<1, 3>(3, 0) = p3;
+    m(0, 3) = m(1, 3) = m(2, 3) = m(3, 3) = 1.0;
+    return m.determinant() / 6.0;
+}
+
+///
+/// \brief Compute bary centric coordinates (u,v,w) given triangle in 2d space (and point p on triangle)
+///
+static Vec3d
+baryCentric(const Vec2d& p, const Vec2d& a, const Vec2d& b, const Vec2d& c)
+{
+    const Vec2d  v0  = b - a;
+    const Vec2d  v1  = c - a;
+    const Vec2d  v2  = p - a;
+    const double den = v0[0] * v1[1] - v1[0] * v0[1];
+    const double v   = (v2[0] * v1[1] - v1[0] * v2[1]) / den;
+    const double w   = (v0[0] * v2[1] - v2[0] * v0[1]) / den;
+    const double u   = 1.0 - v - w;
+    return Vec3d(u, v, w);
+}
+
+///
+/// \brief Compute bary centric coordinates (u,v,w) given triangle in 3d space (and point p on triangle)
+///
+static Vec3d
+baryCentric(const Vec3d& p, const Vec3d& a, const Vec3d& b, const Vec3d& c)
+{
+    const Vec3d  v0    = b - a;
+    const Vec3d  v1    = c - a;
+    const Vec3d  v2    = p - a;
+    const double d00   = v0.dot(v0);
+    const double d01   = v0.dot(v1);
+    const double d11   = v1.dot(v1);
+    const double d20   = v2.dot(v0);
+    const double d21   = v2.dot(v1);
+    const double denom = d00 * d11 - d01 * d01;
+    const double v     = (d11 * d20 - d01 * d21) / denom;
+    const double w     = (d00 * d21 - d01 * d20) / denom;
+    const double u     = 1.0 - v - w;
+    return Vec3d(u, v, w);
 }
+}
\ No newline at end of file
diff --git a/Source/Common/imstkModule.h b/Source/Common/imstkModule.h
index 6412a50fde01e025c3299e98f273dbef5e937e49..7d2f88e7cf8f39f9d7add0c69664980c26c724f0 100644
--- a/Source/Common/imstkModule.h
+++ b/Source/Common/imstkModule.h
@@ -52,43 +52,45 @@ public:
 
 public:
     Module() = default;
-    virtual ~Module() override= default;
+    virtual ~Module() override = default;
 
 public:
+    // *INDENT-OFF*
     ///
     /// \brief Posted before updateModule is called
     ///
-    SIGNAL(Module,preUpdate);
+    SIGNAL(Module, preUpdate);
 
     ///
     /// \brief Posted after updateModule is called
     ///
-    SIGNAL(Module,postUpdate);
+    SIGNAL(Module, postUpdate);
 
     ///
     /// \brief Posted when module wants to end
     ///
-    SIGNAL(Module,end);
+    SIGNAL(Module, end);
+    // *INDENT-ON*
 
 public:
     ///
     /// \brief Get/Set the timestep
     ///
-    double getDt() const{ return m_dt; }
+    double getDt() const { return m_dt; }
     void setDt(const double dt) { m_dt = dt; }
 
     ///
     /// \brief Get whether the module is initialized yet
     ///
-    bool getInit() const{ return m_init; }
+    bool getInit() const { return m_init; }
 
     ///
     /// \brief Set/Get whether the module is currently paused
     ///
-    bool getPaused() const{ return m_paused; }
+    bool getPaused() const { return m_paused; }
     void setPaused(const bool paused) { m_paused = paused; }
 
-    ExecutionType getExecutionType() const{ return m_executionType; }
+    ExecutionType getExecutionType() const { return m_executionType; }
     void setExecutionType(const ExecutionType type) { m_executionType = type; }
 
     void setSleepDelay(const double ms) { sleepDelay = ms; }
@@ -105,7 +107,7 @@ public:
         {
             if (sleepDelay != 0.0)
             {
-                std::this_thread::sleep_for(std::chrono::duration<double,std::milli>(sleepDelay));
+                std::this_thread::sleep_for(std::chrono::duration<double, std::milli>(sleepDelay));
             }
 
             if (muteUpdateEvents)
diff --git a/Source/Common/imstkNew.h b/Source/Common/imstkNew.h
index 1ae7204d6b4b7f6cafe0f7a731cb749eef5d35c0..4080a0d349efd9411b67e40c6a43a04cc12e6c0f 100644
--- a/Source/Common/imstkNew.h
+++ b/Source/Common/imstkNew.h
@@ -58,7 +58,7 @@ public:
 
 public:
     T* operator->() const { return object.get(); }
-    T& operator*() const { return *static_cast<T*>(object); }
+    T& operator*() const { return *object.get(); }
 
     ///
     /// \brief Returns the raw pointer
diff --git a/Source/Common/imstkTypes.h b/Source/Common/imstkTypes.h
index 9df8095178f9a052bb7b495c9dbd611d819cb817..fd23c941eb3914c4ea1be922cbbb22dde10f3bad 100644
--- a/Source/Common/imstkTypes.h
+++ b/Source/Common/imstkTypes.h
@@ -58,8 +58,10 @@ using ScalarType = unsigned char;
 #define IMSTK_UNSIGNED_LONG_MIN std::numeric_limits<unsigned long>::min()
 #define IMSTK_FLOAT_MAX std::numeric_limits<float>::max()
 #define IMSTK_FLOAT_MIN std::numeric_limits<float>::lowest()
+#define IMSTK_FLOAT_EPS std::numeric_limits<float>::epsilon()
 #define IMSTK_DOUBLE_MAX std::numeric_limits<double>::max()
 #define IMSTK_DOUBLE_MIN std::numeric_limits<double>::lowest()
+#define IMSTK_DOUBLE_EPS std::numeric_limits<double>::epsilon()
 #define IMSTK_LONG_LONG_MAX std::numeric_limits<long>::max()
 #define IMSTK_LONG_LONG_MIN std::numeric_limits<long>::min()
 #define IMSTK_UNSIGNED_LONG_LONG_MAX std::numeric_limits<unsigned long long>::max()
diff --git a/Source/Common/imstkVecDataArray.h b/Source/Common/imstkVecDataArray.h
index 6685be6d1adb099c40f7f649b108821e52746e12..873126e3a814986db4d092913239ca557df68545 100644
--- a/Source/Common/imstkVecDataArray.h
+++ b/Source/Common/imstkVecDataArray.h
@@ -173,6 +173,40 @@ public:
 
     virtual ~VecDataArray() override = default;
 
+    ///
+    /// \brief Templated copy the current array with a new internal data type, does not change the number
+    ///        of components, pass in the new type as a template argument
+    ///
+    template<typename U>
+    VecDataArray<U, N> cast()
+    {
+        if (DataArray<T>::m_mapped)
+        {
+            throw(std::runtime_error("Can't cast a mapped array"));
+        }
+        VecDataArray<U, N> other;
+        other.reserve(size());
+        for (auto item : *this)
+        {
+            other.push_back(item.template cast<U>());
+        }
+        return other;
+    }
+
+    std::shared_ptr<AbstractDataArray> cast(ScalarType type) override
+    {
+        if (type == AbstractDataArray::m_scalarType)
+        {
+            return std::make_shared<VecDataArray<T, N>>(*this);
+        }
+        switch (type)
+        {
+            TemplateMacro(return (std::make_shared<VecDataArray<IMSTK_TT, N>>(cast<IMSTK_TT>())));
+        default:
+            throw(std::runtime_error("Unknown scalar type"));
+        }
+    }
+
 public:
     ///
     /// \brief Resize data array to hold exactly size number of values
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.cpp
index c15b9ef5a7683fa6625bd9618f614f036ba2afb6..6a561bd95618aa42f47db9b8f44c563bbbef0c7b 100644
--- a/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.cpp
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.cpp
@@ -25,8 +25,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 void
 RigidBody::setInertiaFromPointSet(std::shared_ptr<PointSet> pointset, const double scale, const bool useBoundingBoxOrigin)
 {
@@ -57,5 +55,4 @@ RigidBody::setInertiaFromPointSet(std::shared_ptr<PointSet> pointset, const doub
     results(1, 2)    = results(2, 1);
     m_intertiaTensor = results * m_mass * scale;
 }
-}
 }
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.h
index 2c469d8f9799c2845a3b93a6d2630765d156e4ad..7f1f629e85dd0580b49a8886442fedbd05241673 100644
--- a/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.h
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdConstraint.h
@@ -29,8 +29,6 @@ namespace imstk
 {
 class PointSet;
 
-namespace expiremental
-{
 ///
 /// \brief Serves as a handle to the body
 ///
@@ -117,5 +115,4 @@ public:
 
     Side m_side = Side::AB;
 };
-}
 }
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.cpp
index 60e4632b40ca69e48eed566545129d734108a999..4a6ed77ce1f1cffa1ceb327862c2325234e4f066 100644
--- a/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.cpp
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.cpp
@@ -23,8 +23,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 void
 RbdContactConstraint::compute(double dt)
 {
@@ -51,5 +49,4 @@ RbdContactConstraint::compute(double dt)
 
     vu = m_contactDepth * m_beta / dt;
 }
-}
-};
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.h
index 19e741900dd21e49ba21343cf281481926d4e26d..06be94ea942d53e4fedfa700dd7de7fabe45ed74 100644
--- a/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.h
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdContactConstraint.h
@@ -27,8 +27,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 ///
 /// \class RbdContactConstraint
 ///
@@ -61,5 +59,4 @@ private:
     double m_contactDepth;
     double m_beta = 0.05;
 };
-}
 }
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.cpp
index 3e1d0fd0ebfbe00cdee47f36baf25a9aad45b5db..9f027834c58e8077bc6ad0c28a27f834fe67c677 100644
--- a/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.cpp
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.cpp
@@ -24,8 +24,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 RbdDistanceConstraint::RbdDistanceConstraint(
     std::shared_ptr<RigidBody> obj1,
     std::shared_ptr<RigidBody> obj2,
@@ -60,5 +58,4 @@ RbdDistanceConstraint::compute(double imstkNotUsed(dt))
         J(2, 0) = diff[2]; J(2, 1) = c[2];
     }
 }
-}
 }
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.h
index dc6d436f85e02eec0e1d1c48d0c72e1b2b5c0b8b..2f50fa3755e61aab664f7693c203b67548c3d72d 100644
--- a/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.h
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdDistanceConstraint.h
@@ -25,8 +25,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 ///
 /// \class RbdDistanceConstraint
 ///
@@ -52,5 +50,4 @@ private:
     Vec3d  m_p2   = Vec3d(0.0, 0.0, 0.0);
     double m_dist = 1.0;
 };
-}
 }
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.cpp b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.cpp
index 68c5a54ffa111964528cb4d56ef428d8fa7fbc9b..e26364e29f173f52f1a107f4ebd8f1c4c923460c 100644
--- a/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.cpp
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.cpp
@@ -24,8 +24,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 RbdFrictionConstraint::RbdFrictionConstraint(
     std::shared_ptr<RigidBody> obj1,
     std::shared_ptr<RigidBody> obj2,
@@ -96,5 +94,4 @@ RbdFrictionConstraint::compute(double imstkNotUsed(dt))
         range[1] = fu;
     }*/
 }
-}
-};
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.h b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.h
index 7853975d82cef4ca6f11facbc154e51034d10ad3..80c92feace32fa5ed8d9e5b2b00c32da7dde6a23 100644
--- a/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.h
+++ b/Source/Constraint/RigidBodyConstraints/imstkRbdFrictionConstraint.h
@@ -25,8 +25,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 ///
 /// \class RbdFrictionConstraint
 ///
@@ -54,5 +52,4 @@ private:
     double m_contactDepth;
     double m_frictionCoefficient;
 };
-}
 }
\ No newline at end of file
diff --git a/Source/Controllers/imstkCameraController.cpp b/Source/Controllers/imstkCameraController.cpp
index 611b860faa2e6e57e1c929d61b0dd94956f4457a..dece5559eda86fbd7d8d83b34cdfdae455701ec1 100644
--- a/Source/Controllers/imstkCameraController.cpp
+++ b/Source/Controllers/imstkCameraController.cpp
@@ -39,7 +39,7 @@ CameraController::update(const double dt)
     {
         if (!updateTrackingData(dt))
         {
-            LOG(WARNING) << "CameraController::update warning: could not update tracking info.";
+            LOG(WARNING) << "warning: could not update tracking info.";
             return;
         }
     }
diff --git a/Source/Controllers/imstkDeviceControl.h b/Source/Controllers/imstkDeviceControl.h
index 961bf52d228cc4063ad235423dc5c1a95b17bab4..46df3b1be27fc0e4ecdc856d47602b7bba763ec0 100644
--- a/Source/Controllers/imstkDeviceControl.h
+++ b/Source/Controllers/imstkDeviceControl.h
@@ -46,10 +46,12 @@ public:
     virtual ~DeviceControl() = default;
 
 public:
-    SIGNAL(TrackingDeviceControl,modified);
+    // *INDENT-OFF*
+    SIGNAL(TrackingDeviceControl, modified);
+    // *INDENT-ON*
 
 public:
-    std::shared_ptr<DeviceClient> getDevice() const{ return m_deviceClient; }
+    std::shared_ptr<DeviceClient> getDevice() const { return m_deviceClient; }
 
     virtual void setDevice(std::shared_ptr<DeviceClient> device) { m_deviceClient = device; }
 
diff --git a/Source/Controllers/imstkLaparoscopicToolController.cpp b/Source/Controllers/imstkLaparoscopicToolController.cpp
index 92c711c1dc73f87869d8e2af8927904b551b5b82..3cd91d57b98e002b2780cca918d4ef9ab7ca0fdb 100644
--- a/Source/Controllers/imstkLaparoscopicToolController.cpp
+++ b/Source/Controllers/imstkLaparoscopicToolController.cpp
@@ -57,7 +57,7 @@ LaparoscopicToolController::update(const double dt)
     {
         if (!updateTrackingData(dt))
         {
-            LOG(WARNING) << "LaparoscopicToolController::updateControlledObjects warning: could not update tracking info.";
+            LOG(WARNING) << "warning: could not update tracking info.";
             return;
         }
     }
diff --git a/Source/Controllers/imstkRigidObjectController.cpp b/Source/Controllers/imstkRigidObjectController.cpp
index cea86ee63ad0225f8c15ae0591cda11357470f9f..43ee6996d3865ec5043dd88454b81361e1bbb039 100644
--- a/Source/Controllers/imstkRigidObjectController.cpp
+++ b/Source/Controllers/imstkRigidObjectController.cpp
@@ -27,8 +27,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 RigidObjectController::RigidObjectController(std::shared_ptr<RigidObject2> rigidObject,
                                              std::shared_ptr<DeviceClient> trackingDevice) :
     SceneObjectController(rigidObject, trackingDevice),
@@ -52,7 +50,7 @@ RigidObjectController::update(const double dt)
     {
         if (!updateTrackingData(dt))
         {
-            LOG(WARNING) << "RigidObjectController::update warning: could not update tracking info.";
+            LOG(WARNING) << "warning: could not update tracking info.";
             return;
         }
     }
@@ -157,5 +155,4 @@ RigidObjectController::applyForces()
         m_deviceClient->setForce(Vec3d(0.0, 0.0, 0.0));
     }
 }
-}
-}
+}
\ No newline at end of file
diff --git a/Source/Controllers/imstkRigidObjectController.h b/Source/Controllers/imstkRigidObjectController.h
index b047dfb8655a66f8569660c9d8183f1f5378060c..cc87a5970e9a13587e08ce32192db1f91a0521d6 100644
--- a/Source/Controllers/imstkRigidObjectController.h
+++ b/Source/Controllers/imstkRigidObjectController.h
@@ -25,8 +25,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 class RigidObject2;
 
 ///
@@ -145,5 +143,4 @@ protected:
     std::deque<Vec3d> m_forces;
     Vec3d m_forceSum = Vec3d::Zero();
 };
-}
-}
+}
\ No newline at end of file
diff --git a/Source/Controllers/imstkSceneObjectController.cpp b/Source/Controllers/imstkSceneObjectController.cpp
index f684e266f3895a938e0375c77f82cb4e3e228fa7..ff46f20103afb083eda8a8324db9c0f4e4cd55c4 100644
--- a/Source/Controllers/imstkSceneObjectController.cpp
+++ b/Source/Controllers/imstkSceneObjectController.cpp
@@ -41,7 +41,7 @@ SceneObjectController::update(const double dt)
     {
         if (!updateTrackingData(dt))
         {
-            LOG(WARNING) << "SceneObjectController::update warning: could not update tracking info.";
+            LOG(WARNING) << "warning: could not update tracking info.";
             return;
         }
     }
diff --git a/Source/Controllers/imstkTrackingDeviceControl.cpp b/Source/Controllers/imstkTrackingDeviceControl.cpp
index 05819cecc26d5f3e2da8abd385f55a56c9ab83fa..e88ed07f2b811b9a81ebcebe5ffa89e8aca5ce5a 100644
--- a/Source/Controllers/imstkTrackingDeviceControl.cpp
+++ b/Source/Controllers/imstkTrackingDeviceControl.cpp
@@ -44,7 +44,7 @@ TrackingDeviceControl::updateTrackingData(const double dt)
 {
     if (m_deviceClient == nullptr)
     {
-        LOG(WARNING) << "DeviceTracker::getTrackingData warning: no controlling device set.";
+        LOG(WARNING) << "warning: no controlling device set.";
         return false;
     }
 
diff --git a/Source/Devices/imstkDeviceClient.cpp b/Source/Devices/imstkDeviceClient.cpp
index 49e12640e9bc64cf78f2425708d87c99605d9dad..22beb0ceedb3e5008260e105af0f4982af5d5ea3 100644
--- a/Source/Devices/imstkDeviceClient.cpp
+++ b/Source/Devices/imstkDeviceClient.cpp
@@ -34,111 +34,61 @@ DeviceClient::DeviceClient(const std::string& name, const std::string& ip) :
 {
 }
 
-const std::string&
-DeviceClient::getIp()
+const Vec3d
+DeviceClient::getPosition()
 {
-    return m_ip;
+    Vec3d pos;
+    m_transformLock.lock();
+    pos = m_position;
+    m_transformLock.unlock();
+    return pos;
 }
 
-void
-DeviceClient::setIp(const std::string& ip)
-{
-    m_ip = ip;
-}
-
-const std::string&
-DeviceClient::getDeviceName()
-{
-    return m_deviceName;
-}
-
-void
-DeviceClient::setDeviceName(const std::string& deviceName)
-{
-    m_deviceName = deviceName;
-}
-
-const bool&
-DeviceClient::getTrackingEnabled() const
-{
-    return m_trackingEnabled;
-}
-
-void
-DeviceClient::setTrackingEnabled(const bool& status)
-{
-    m_trackingEnabled = status;
-}
-
-const bool&
-DeviceClient::getAnalogicEnabled() const
-{
-    return m_analogicEnabled;
-}
-
-void
-DeviceClient::setAnalogicEnabled(const bool& status)
-{
-    m_analogicEnabled = status;
-}
-
-const bool&
-DeviceClient::getButtonsEnabled() const
-{
-    return m_buttonsEnabled;
-}
-
-void
-DeviceClient::setButtonsEnabled(const bool& status)
-{
-    m_buttonsEnabled = status;
-}
-
-const bool&
-DeviceClient::getForceEnabled() const
-{
-    return m_forceEnabled;
-}
-
-void
-DeviceClient::setForceEnabled(const bool& status)
-{
-    m_forceEnabled = status;
-}
-
-const Vec3d&
-DeviceClient::getPosition() const
-{
-    return m_position;
-}
-
-const Vec3d&
-DeviceClient::getVelocity() const
+const Vec3d
+DeviceClient::getVelocity()
 {
-    return m_velocity;
+    Vec3d vel;
+    m_transformLock.lock();
+    vel = m_velocity;
+    m_transformLock.unlock();
+    return vel;
 }
 
-const Vec3d&
-DeviceClient::getAngularVelocity() const
+const Vec3d
+DeviceClient::getAngularVelocity()
 {
-    return m_angularVelocity;
+    Vec3d angVel;
+    m_transformLock.lock();
+    angVel = m_angularVelocity;
+    m_transformLock.unlock();
+    return angVel;
 }
 
-const Quatd&
-DeviceClient::getOrientation() const
+const Quatd
+DeviceClient::getOrientation()
 {
-    return m_orientation;
+    Quatd orientation;
+    m_transformLock.lock();
+    orientation = m_orientation;
+    m_transformLock.unlock();
+    return orientation;
 }
 
-const Vec3d&
-DeviceClient::getForce() const
+const Vec3d
+DeviceClient::getForce()
 {
-    return m_force;
+    Vec3d force;
+    m_transformLock.lock();
+    force = m_force;
+    m_transformLock.unlock();
+    return force;
 }
 
 void
 DeviceClient::setForce(Vec3d force)
 {
+    m_forceLock.lock();
     m_force = force;
+    m_forceLock.unlock();
 }
 } // imstk
diff --git a/Source/Devices/imstkDeviceClient.h b/Source/Devices/imstkDeviceClient.h
index e775cab236e6960da355a11348f82af2197c15f5..6eb4d65c42cee7852b4bda8a4768987c0e7ff605 100644
--- a/Source/Devices/imstkDeviceClient.h
+++ b/Source/Devices/imstkDeviceClient.h
@@ -23,6 +23,7 @@
 
 #include "imstkMath.h"
 #include "imstkEventObject.h"
+#include "imstkSpinLock.h"
 
 #include <unordered_map>
 
@@ -50,7 +51,7 @@ public:
     {
     }
 
-    virtual ~ButtonEvent() override= default;
+    virtual ~ButtonEvent() override = default;
 
 public:
     ButtonStateType m_buttonState;
@@ -74,71 +75,76 @@ public:
     virtual ~DeviceClient() = default;
 
 public:
+    // *INDENT-OFF*
     SIGNAL(DeviceClient,buttonStateChanged);
+    // *INDENT-ON*
 
 public:
     ///
     /// \brief Get/Set the device IP
     ///
-    const std::string& getIp();
-    void setIp(const std::string& ip);
+    const std::string& getIp() { return m_ip; }
+    void setIp(const std::string& ip) { m_ip = ip; }
 
     ///
     /// \brief Get/Set the device name
     ///
-    const std::string& getDeviceName();
-    void setDeviceName(const std::string& deviceName);
+    const std::string& getDeviceName() { return m_deviceName; }
+    void setDeviceName(const std::string& deviceName) { m_deviceName = deviceName; }
 
     ///
     /// \brief Get/Set what listeners to enable on the device: tracking, analogic, force, buttons.
     ///
-    const bool& getTrackingEnabled() const;
-    void setTrackingEnabled(const bool& status);
-    const bool& getAnalogicEnabled() const;
-    void setAnalogicEnabled(const bool& status);
-    const bool& getButtonsEnabled() const;
-    void setButtonsEnabled(const bool& status);
-    const bool& getForceEnabled() const;
-    void setForceEnabled(const bool& status);
+    const bool getTrackingEnabled() const { return m_trackingEnabled; }
+    void setTrackingEnabled(const bool status) { m_trackingEnabled = status; }
+    const bool getAnalogicEnabled() const { return m_analogicEnabled; }
+    void setAnalogicEnabled(const bool status) { m_analogicEnabled = status; }
+    const bool getButtonsEnabled() const { return m_buttonsEnabled; }
+    void setButtonsEnabled(const bool status) { m_buttonsEnabled = status; }
+    const bool getForceEnabled() const { return m_forceEnabled; }
+    void setForceEnabled(const bool status) { m_forceEnabled = status; }
 
     ///
     /// \brief Get the device position
     ///
-    const Vec3d& getPosition() const;
+    const Vec3d getPosition();
 
     ///
     /// \brief Get the device velocity
     ///
-    const Vec3d& getVelocity() const;
+    const Vec3d getVelocity();
 
     ///
     /// \brief Get the device angular velocity
     ///
-    const Vec3d& getAngularVelocity() const;
+    const Vec3d getAngularVelocity();
 
     ///
     /// \brief Get the device orientation
     ///
-    const Quatd& getOrientation() const;
+    const Quatd getOrientation();
 
     ///
     /// \brief Get offset from position for device end effector
     ///
-    const Vec3d& getOffset() const{ return m_endEffectorOffset; }
+    const Vec3d& getOffset() const { return m_endEffectorOffset; }
 
     ///
     /// \brief Get/Set the device force
     ///
-    const Vec3d& getForce() const;
+    const Vec3d getForce();
     void setForce(Vec3d force);
 
-    const std::unordered_map<int,int>& getButtons() const{ return m_buttons; }
+    ///
+    /// \brief Get button map
+    ///
+    const std::unordered_map<int, int>& getButtons() const { return m_buttons; }
 
     ///
     /// \brief Get the state of a button
     /// returns 0 if can't find button
     ///
-    const int getButton(const int buttonId) const
+    const int getButton(const int buttonId)
     {
         if (m_buttons.find(buttonId) != m_buttons.end())
         {
@@ -150,10 +156,13 @@ public:
         }
     }
 
+    ///
+    /// \brief Do runtime logic
+    ///
     virtual void update() {}
 
 protected:
-    DeviceClient(const std::string& name,const std::string& ip);
+    DeviceClient(const std::string& name, const std::string& ip);
 
     std::string m_deviceName;                         ///< Device Name
     std::string m_ip;                                 ///< Connection device IP
@@ -168,8 +177,11 @@ protected:
     Vec3d m_angularVelocity;                          ///< Angular velocity of the end effector
     Quatd m_orientation;                              ///< Orientation of the end effector
     Vec3d m_force;                                    ///< Force vector
-    Vec3d m_endEffectorOffset = Vec3d(0.0,0.0,0.0);   ///> Offset from origin
+    Vec3d m_endEffectorOffset = Vec3d(0.0, 0.0, 0.0); ///> Offset from origin
+
+    std::unordered_map<int, int> m_buttons;
 
-    std::unordered_map<int,int> m_buttons;
+    ParallelUtils::SpinLock m_transformLock; /// > Used for devices filling data from other threads
+    ParallelUtils::SpinLock m_forceLock;     /// > Used for devices filling data from other threads
 };
 }
diff --git a/Source/Devices/imstkHapticDeviceClient.cpp b/Source/Devices/imstkHapticDeviceClient.cpp
index 10c44d69b405e8d1f0001093dccea352f9cd343e..b970c66e254ca2377f1cbf68e33349c72625ead4 100644
--- a/Source/Devices/imstkHapticDeviceClient.cpp
+++ b/Source/Devices/imstkHapticDeviceClient.cpp
@@ -79,7 +79,7 @@ void
 HapticDeviceClient::update()
 {
     //hdScheduleSynchronous(hapticCallback, this, HD_MAX_SCHEDULER_PRIORITY);
-    hdScheduleAsynchronous(hapticCallback, this, HD_MAX_SCHEDULER_PRIORITY);     // Call sometime later
+    hdScheduleAsynchronous(hapticCallback, this, HD_MAX_SCHEDULER_PRIORITY); // Call sometime later
 }
 
 void
@@ -100,22 +100,30 @@ HapticDeviceClient::hapticCallback(void* pData)
         return HD_CALLBACK_DONE;
     }
 
+    client->m_forceLock.lock();
+    const Vec3d force = client->m_force;
+    client->m_forceLock.unlock();
+
     hdBeginFrame(handle);
 
     hdMakeCurrentDevice(handle);
-    hdSetDoublev(HD_CURRENT_FORCE, client->m_force.data());
+    hdSetDoublev(HD_CURRENT_FORCE, force.data());
     hdGetDoublev(HD_CURRENT_POSITION, state.pos);
     hdGetDoublev(HD_CURRENT_VELOCITY, state.vel);
     hdGetDoublev(HD_CURRENT_ANGULAR_VELOCITY, state.angularVel);
-    hdGetDoublev(HD_CURRENT_TRANSFORM, state.trans);
+    hdGetDoublev(HD_CURRENT_TRANSFORM, state.transform);
     hdGetIntegerv(HD_CURRENT_BUTTONS, &state.buttons);
 
     hdEndFrame(handle);
 
+    // Might be worth locking each part separately
+    const Quatd orientation = Quatd((Eigen::Affine3d(Eigen::Matrix4d(state.transform))).rotation());
+    client->m_transformLock.lock();
     client->m_position << state.pos[0], state.pos[1], state.pos[2];
     client->m_velocity << state.vel[0], state.vel[1], state.vel[2];
     client->m_angularVelocity << state.angularVel[0], state.angularVel[1], state.angularVel[2];
-    client->m_orientation = (Eigen::Affine3d(Eigen::Matrix4d(state.trans))).rotation();
+    client->m_orientation = orientation;
+    client->m_transformLock.unlock();
 
     for (int i = 0; i < 4; i++)
     {
@@ -132,7 +140,6 @@ HapticDeviceClient::hapticCallback(void* pData)
             client->postEvent(ButtonEvent(HapticDeviceClient::buttonStateChanged(), i, BUTTON_RELEASED));
         }
     }
-
     client->m_trackingEnabled = true;
 
     return HD_CALLBACK_DONE;
diff --git a/Source/Devices/imstkHapticDeviceClient.h b/Source/Devices/imstkHapticDeviceClient.h
index db97c366c42148520cc2c3ae5ad74797d56032db..a55e42dee712010cce7fc94936d5a83a34756ec3 100644
--- a/Source/Devices/imstkHapticDeviceClient.h
+++ b/Source/Devices/imstkHapticDeviceClient.h
@@ -33,7 +33,7 @@ struct HDstate
     HDdouble pos[3];
     HDdouble vel[3];
     HDdouble angularVel[3];
-    HDdouble trans[16];
+    HDdouble transform[16];
     HDint buttons;
 };
 
@@ -82,4 +82,4 @@ private:
     HHD     m_handle; ///< device handle
     HDstate m_state;  ///< device reading state
 };
-}
+}
\ No newline at end of file
diff --git a/Source/Devices/imstkKeyboardDeviceClient.h b/Source/Devices/imstkKeyboardDeviceClient.h
index d7ccf8bd9e86a62149e67a623f94fec07ae34ddc..9173803ae989211d17e56cc6219f6b8619bd1385 100644
--- a/Source/Devices/imstkKeyboardDeviceClient.h
+++ b/Source/Devices/imstkKeyboardDeviceClient.h
@@ -35,7 +35,7 @@ class KeyEvent : public Event
 {
 public:
     KeyEvent(const std::string type, const char key, const KeyStateType keyPressType) : Event(type), m_keyPressType(keyPressType), m_key(key) { }
-    virtual ~KeyEvent() override= default;
+    virtual ~KeyEvent() override = default;
 
 public:
     KeyStateType m_keyPressType;
@@ -61,25 +61,27 @@ protected:
     static std::shared_ptr<KeyboardDeviceClient> New();
 
 public:
-    virtual ~KeyboardDeviceClient() override= default;
+    virtual ~KeyboardDeviceClient() override = default;
 
     // Only these classes may provide this object
     friend class VTKInteractorStyle;
     friend class ConsoleModule;
 
 public:
+    // *INDENT-OFF*
     ///
     /// \brief Posted when key is pressed (not continuously)
     ///
-    SIGNAL(KeyboardDeviceClient,keyPress);
+    SIGNAL(KeyboardDeviceClient, keyPress);
 
     ///
     /// \brief Posted when key is released (not continuously)
     ///
-    SIGNAL(KeyboardDeviceClient,keyRelease);
+    SIGNAL(KeyboardDeviceClient, keyRelease);
+    // *INDENT-ON*
 
 public:
-    const std::unordered_map<int,KeyStateType>& getKeyState() const{ return m_buttons; }
+    const std::unordered_map<int, KeyStateType>& getKeyState() const { return m_buttons; }
 
 protected:
     ///
diff --git a/Source/Devices/imstkMouseDeviceClient.h b/Source/Devices/imstkMouseDeviceClient.h
index 5008bb329113d79b8ecc61d3012565a4b7a6cdc3..9ea60581412728517f9423cdaea30ea3a11239f8 100644
--- a/Source/Devices/imstkMouseDeviceClient.h
+++ b/Source/Devices/imstkMouseDeviceClient.h
@@ -54,7 +54,7 @@ public:
     {
     }
 
-    virtual ~MouseEvent() override= default;
+    virtual ~MouseEvent() override = default;
 
 public:
     double m_scrollDx;          ///> Mouse scroll
@@ -81,42 +81,44 @@ protected:
     static std::shared_ptr<MouseDeviceClient> New();
 
 public:
-    virtual ~MouseDeviceClient() override= default;
+    virtual ~MouseDeviceClient() override = default;
 
     // Only the viewer is allowed to provide these objects
     friend class VTKInteractorStyle;
 
 public:
+    // *INDENT-OFF*
     ///
     /// \brief Posted when a button on the mouse is pressed (not continuously)
     ///
-    SIGNAL(MouseDeviceClient,mouseButtonPress);
+    SIGNAL(MouseDeviceClient, mouseButtonPress);
 
     ///
     /// \brief Posted when a button on the mouse is released (not continuously)
     ///
-    SIGNAL(MouseDeviceClient,mouseButtonRelease);
+    SIGNAL(MouseDeviceClient, mouseButtonRelease);
 
     ///
     /// \brief Posted when mouse scrolls
     ///
-    SIGNAL(MouseDeviceClient,mouseScroll);
+    SIGNAL(MouseDeviceClient, mouseScroll);
 
     ///
     /// \brief Posted when mouse moves
     ///
-    SIGNAL(MouseDeviceClient,mouseMove);
+    SIGNAL(MouseDeviceClient, mouseMove);
+    // *INDENT-ON*
 
 public:
     ///
     /// \brief Get the current position of the mouse
     ///
-    const Vec2d& getPos() const{ return m_pos; }
+    const Vec2d& getPos() const { return m_pos; }
 
     ///
     /// \brief Get the previous position of the mouse
     ///
-    const Vec2d& getPrevPos() const{ return m_prevPos; }
+    const Vec2d& getPrevPos() const { return m_prevPos; }
 
     ///
     /// \brief Query if the button is down
@@ -150,7 +152,7 @@ protected:
     void emitButtonPress(const MouseButtonType buttonId)
     {
         m_buttons[buttonId] = MOUSE_PRESS;
-        this->postEvent(MouseEvent(MouseDeviceClient::mouseButtonPress(),buttonId));
+        this->postEvent(MouseEvent(MouseDeviceClient::mouseButtonPress(), buttonId));
     }
 
     ///
@@ -159,13 +161,13 @@ protected:
     void emitButtonRelease(const MouseButtonType buttonId)
     {
         m_buttons[buttonId] = MOUSE_RELEASE;
-        this->postEvent(MouseEvent(MouseDeviceClient::mouseButtonRelease(),buttonId));
+        this->postEvent(MouseEvent(MouseDeviceClient::mouseButtonRelease(), buttonId));
     }
 
     ///
     /// \brief Post a mouse scroll event
     ///
-    void emitScroll(const double dx) { this->postEvent(MouseEvent(MouseDeviceClient::mouseScroll(),dx)); }
+    void emitScroll(const double dx) { this->postEvent(MouseEvent(MouseDeviceClient::mouseScroll(), dx)); }
 
 protected:
     Vec2d m_prevPos;
diff --git a/Source/Devices/imstkVRPNDeviceServer.cpp b/Source/Devices/imstkVRPNDeviceServer.cpp
index 64fc1fbc069bb81309a4a442e9ee5eb5c0371a2c..c1adf8df3be1a0bc0c697032057a1d7f7a324731 100644
--- a/Source/Devices/imstkVRPNDeviceServer.cpp
+++ b/Source/Devices/imstkVRPNDeviceServer.cpp
@@ -39,7 +39,7 @@ VRPNDeviceServer::addDevice(const std::string& deviceName, DeviceType deviceType
 
     if (deviceType == DeviceType::PhantomOmni)
     {
-        LOG(WARNING) << "VRPNDeviceServer::addDevice warning: OpenHaptics support on VRPN "
+        LOG(WARNING) << "warning: OpenHaptics support on VRPN "
                      << "currently unstable for the Phantom Omni (no force feedback implemented).\n"
                      << "Use HDAPIDeviceClient instead of VRPNDeviceServer/Client for ";
     }
@@ -85,7 +85,7 @@ VRPNDeviceServer::initModule()
             m_deviceConnections->add(new vrpn_Tracker_NovintFalcon(name.c_str(), m_serverConnection,
                                                                    id, "4-button", "stamper"));
 #else
-            LOG(WARNING) << "VRPNDeviceServer::initModule error: no support for Novint Falcon in VRPN. "
+            LOG(WARNING) << "error: no support for Novint Falcon in VRPN. "
                          << "Build VRPN with VRPN_USE_LIBNIFALCON.";
 #endif
         } break;
@@ -95,7 +95,7 @@ VRPNDeviceServer::initModule()
             char* deviceName = const_cast<char*>(name.c_str());
             m_deviceConnections->add(new vrpn_Phantom(deviceName, m_serverConnection, 90.0f, deviceName));
 #else
-            LOG(WARNING) << "VRPNDeviceServer::initModule error: no support for Phantom Omni in VRPN. "
+            LOG(WARNING) << "error: no support for Phantom Omni in VRPN. "
                          << "Install OpenHaptics SDK, the omni driver, and build VRPN with VRPN_USE_PHANTOM_SERVER.";
 #endif
         } break;
@@ -111,7 +111,7 @@ VRPNDeviceServer::initModule()
         } break;
         default:
         {
-            LOG(WARNING) << "VRPNDeviceServer::initModule error: can not connect to "
+            LOG(WARNING) << "error: can not connect to "
                          << name << ", device type unknown.";
             return false;
         } break;
diff --git a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp
index 46db618c35231cf0fdae47719295a5be7bedc075..0232cd453a5aa971c122e4c604fec8fb1cc3b524 100644
--- a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp
@@ -222,7 +222,7 @@ FEMDeformableBodyModel::loadInitialStates()
 {
     if (m_numDOF == 0)
     {
-        LOG(WARNING) << "FEMDeformableBodyModel::loadInitialStates() - Num. of degree of freedom is zero!";
+        LOG(WARNING) << "Number of degree of freedom is zero!";
     }
 
     // For now the initial states are set to zero
@@ -250,7 +250,7 @@ FEMDeformableBodyModel::loadBoundaryConditions()
 
         if (file.peek() == std::ifstream::traits_type::eof())
         {
-            LOG(INFO) << "DeformableBodyModel::loadBoundaryConditions: The external boundary conditions file is empty";
+            LOG(INFO) << "The external boundary conditions file is empty";
         }
 
         if (file.is_open())
@@ -266,8 +266,7 @@ FEMDeformableBodyModel::loadBoundaryConditions()
                 }
                 else
                 {
-                    LOG(WARNING) << "FEMDeformableBodyModel::loadBoundaryConditions(): " <<
-                        "The boundary condition node id provided is greater than number of nodes and hence excluded!!";
+                    LOG(WARNING) << "The boundary condition node id provided is greater than number of nodes and hence excluded!!";
                     return false;
                 }
             }
@@ -277,7 +276,7 @@ FEMDeformableBodyModel::loadBoundaryConditions()
         }
         else
         {
-            LOG(FATAL) << "DeformableBodyModel::loadBoundaryConditions: Could not open boundary conditions file!";
+            LOG(FATAL) << "Could not open boundary conditions file!";
             return false;
         }
     }
@@ -322,7 +321,7 @@ FEMDeformableBodyModel::initializeForceModel()
         break;
 
     default:
-        LOG(FATAL) << "DeformableBodyModel::initializeForceModel: Unknown force model type";
+        LOG(FATAL) << "Unknown force model type";
         return false;
     }   //switch
 
@@ -332,7 +331,7 @@ FEMDeformableBodyModel::initializeForceModel()
 bool
 FEMDeformableBodyModel::initializeMassMatrix()
 {
-    CHECK(m_geometry != nullptr) << "DeformableBodyModel::initializeMassMatrix Force model geometry not set!";
+    CHECK(m_geometry != nullptr) << "Force model geometry not set!";
 
     vega::SparseMatrix* vegaMatrix;
     vega::GenerateMassMatrix::computeMassMatrix(m_vegaPhysicsMesh.get(), &vegaMatrix, true);    //caveat
@@ -355,13 +354,13 @@ FEMDeformableBodyModel::initializeDampingMatrix()
 
     if (dampingStiffnessCoefficient == 0.0 && dampingLaplacianCoefficient == 0.0 && dampingMassCoefficient == 0.0)
     {
-        LOG(WARNING) << "FEMDeformableBodyModel::initializeDampingMatrix() - All the damping parameters are zero!";
+        LOG(WARNING) << "All the damping parameters are zero!";
         return true;
     }
 
     if (dampingLaplacianCoefficient < 0.0)
     {
-        LOG(WARNING) << "DeformableBodyModel::initializeDampingMatrix Damping coefficient is negative!";
+        LOG(WARNING) << "Damping coefficient is negative!";
         return false;
     }
 
@@ -372,7 +371,7 @@ FEMDeformableBodyModel::initializeDampingMatrix()
 
     if (!meshGraph)
     {
-        LOG(WARNING) << "DeformableBodyModel::initializeDampingMatrix: Mesh graph not avaliable!";
+        LOG(WARNING) << "Mesh graph not avaliable!";
         return false;
     }
 
@@ -381,7 +380,7 @@ FEMDeformableBodyModel::initializeDampingMatrix()
 
     if (!matrix)
     {
-        LOG(WARNING) << "DeformableBodyModel::initializeDampingMatrix: Mesh Laplacian not avaliable!";
+        LOG(WARNING) << "Mesh Laplacian not avaliable!";
         return false;
     }
 
@@ -400,13 +399,13 @@ bool
 FEMDeformableBodyModel::initializeTangentStiffness()
 {
     CHECK(m_internalForceModel != nullptr)
-        << "DeformableBodyModel::initializeTangentStiffness: Tangent stiffness cannot be initialized without force model";
+        << "Tangent stiffness cannot be initialized without force model";
 
     vega::SparseMatrix* matrix = nullptr;
     m_internalForceModel->getTangentStiffnessMatrixTopology(&matrix);
 
-    CHECK(matrix != nullptr) << "DeformableBodyModel::initializeTangentStiffness - Tangent stiffness matrix topology not avaliable!";
-    CHECK(m_vegaMassMatrix != nullptr) << "DeformableBodyModel::initializeTangentStiffness - Vega mass matrix doesn't exist!";
+    CHECK(matrix != nullptr) << "Tangent stiffness matrix topology not avaliable!";
+    CHECK(m_vegaMassMatrix != nullptr) << "Vega mass matrix doesn't exist!";
 
     matrix->BuildSubMatrixIndices(*m_vegaMassMatrix.get());
 
@@ -480,7 +479,7 @@ FEMDeformableBodyModel::computeImplicitSystemRHS(kinematicState&       stateAtT,
 
         break;
     default:
-        LOG(WARNING) << "FEMDeformableBodyModel::computeImplicitSystemRHS: Update type not supported";
+        LOG(WARNING) << "Update type not supported";
     }
 }
 
@@ -519,7 +518,7 @@ FEMDeformableBodyModel::computeSemiImplicitSystemRHS(kinematicState&       state
         break;
 
     default:
-        LOG(FATAL) << "FEMDeformableBodyModel::computeSemiImplicitSystemRHS: Update type not supported";
+        LOG(FATAL) << "Update type not supported";
     }
 }
 
@@ -547,7 +546,7 @@ FEMDeformableBodyModel::computeImplicitSystemLHS(const kinematicState& imstkNotU
         break;
 
     default:
-        LOG(FATAL) << "FEMDeformableBodyModel::computeImplicitSystemLHS: Update type not supported";
+        LOG(FATAL) << "Update type not supported";
     }
 }
 
@@ -688,7 +687,7 @@ FEMDeformableBodyModel::updateBodyIntermediateStates(
         break;
 
     default:
-        LOG(FATAL) << "DeformableBodyModel::updateBodyIntermediateStates: Unknown state update type";
+        LOG(FATAL) << "Unknown state update type";
     }
     m_qSol = m_currentState->getQ();
 }
diff --git a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp
index fd14a7c8eb8dd0ea0b1307ff79e05118d3484b93..80ca16dc4342a909a41a65e4982c3b33d8057ba7 100644
--- a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp
@@ -94,7 +94,7 @@ PBDModelConfig::setSolverType(const PbdConstraint::SolverType& type)
 void
 PbdModel::configure(std::shared_ptr<PBDModelConfig> params)
 {
-    LOG_IF(FATAL, (!this->getModelGeometry())) << "PbdModel::configure - Set PBD Model geometry before configuration!";
+    LOG_IF(FATAL, (!this->getModelGeometry())) << "Set PBD Model geometry before configuration!";
 
     m_parameters = params;
     this->setNumDegreeOfFreedom(std::dynamic_pointer_cast<PointSet>(m_geometry)->getNumVertices() * 3);
@@ -171,7 +171,14 @@ PbdModel::initialize()
         }
 
         // Partition constraints for parallel computation
-        this->partitionConstraints();
+        if (m_parameters->m_doPartitioning)
+        {
+            this->partitionConstraints();
+        }
+        else
+        {
+            m_partitionedConstraints->clear();
+        }
     }
 
     // Setup the default pbd solver if none exists
@@ -197,7 +204,7 @@ PbdModel::initState()
 {
     // Get the mesh
     m_mesh = std::dynamic_pointer_cast<PointSet>(m_geometry);
-    const int numParticles = static_cast<int>(m_mesh->getNumVertices());
+    const int numParticles = m_mesh->getNumVertices();
 
     m_initialState  = std::make_shared<PbdState>(numParticles);
     m_previousState = std::make_shared<PbdState>(numParticles);
@@ -233,8 +240,8 @@ PbdModel::initState()
             std::fill(m_invMass->begin(), m_invMass->end(), (uniformMass != 0.0) ? 1.0 / uniformMass : 0.0);
 
             m_mesh->setVertexAttribute("Mass", m_mass);
-            m_mesh->setVertexAttribute("InvMass", m_invMass);
         }
+        m_mesh->setVertexAttribute("InvMass", m_invMass);
     }
 
     // Initialize Velocities
@@ -919,22 +926,23 @@ PbdModel::setPointUnfixed(const size_t idx)
 void
 PbdModel::integratePosition()
 {
-    VecDataArray<double, 3>&       prevPos   = *m_previousState->getPositions();
-    VecDataArray<double, 3>&       pos       = *m_currentState->getPositions();
-    VecDataArray<double, 3>&       vel       = *m_currentState->getVelocities();
-    const VecDataArray<double, 3>& accn      = *m_currentState->getAccelerations();
-    const DataArray<double>&       invMasses = *m_invMass;
+    VecDataArray<double, 3>& prevPos   = *m_previousState->getPositions();
+    VecDataArray<double, 3>& pos       = *m_currentState->getPositions();
+    VecDataArray<double, 3>& vel       = *m_currentState->getVelocities();
+    VecDataArray<double, 3>& accn      = *m_currentState->getAccelerations();
+    const DataArray<double>& invMasses = *m_invMass;
 
     ParallelUtils::parallelFor(m_mesh->getNumVertices(),
         [&](const size_t i)
         {
-            if (std::abs(invMasses[i]) > MIN_REAL)
+            if (std::abs(invMasses[i]) > 0.0)
             {
                 vel[i]    += (accn[i] + m_parameters->m_gravity) * m_parameters->m_dt;
+                accn[i]    = Vec3d::Zero();
                 prevPos[i] = pos[i];
                 pos[i]    += (1.0 - m_parameters->m_viscousDampingCoeff) * vel[i] * m_parameters->m_dt;
             }
-        });
+        }, m_mesh->getNumVertices() > 50);
 }
 
 void
@@ -945,13 +953,17 @@ PbdModel::updateVelocity()
     VecDataArray<double, 3>&       vel       = *m_currentState->getVelocities();
     const DataArray<double>&       invMasses = *m_invMass;
 
-    ParallelUtils::parallelFor(m_mesh->getNumVertices(),
-        [&](const size_t i)
-        {
-            if (std::abs(invMasses[i]) > MIN_REAL && m_parameters->m_dt > 0.0)
+    if (m_parameters->m_dt > 0.0)
+    {
+        const double invDt = 1.0 / m_parameters->m_dt;
+        ParallelUtils::parallelFor(m_mesh->getNumVertices(),
+            [&](const size_t i)
             {
-                vel[i] = (pos[i] - prevPos[i]) / m_parameters->m_dt;
-            }
-        });
+                if (std::abs(invMasses[i]) > 0.0)
+                {
+                    vel[i] = (pos[i] - prevPos[i]) * invDt;
+                }
+            }, m_mesh->getNumVertices() > 50);
+    }
 }
 } // imstk
diff --git a/Source/DynamicalModels/ObjectModels/imstkPbdModel.h b/Source/DynamicalModels/ObjectModels/imstkPbdModel.h
index e01e211c05c18ec0dce9156c3eb4761544c7489c..0b90701897215e9c29083a7e12e8a9e74f2cfd8e 100644
--- a/Source/DynamicalModels/ObjectModels/imstkPbdModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkPbdModel.h
@@ -55,6 +55,8 @@ struct PBDModelConfig
     double m_dt = 0.0;                       ///> Time step size
     double m_defaultDt = 0.01;               ///> Default Time step size
 
+    bool m_doPartitioning = true;
+
     std::vector<std::size_t> m_fixedNodeIds; ///> Nodal IDs of the nodes that are fixed
     Vec3r m_gravity = Vec3r(0, -9.81, 0);    ///> Gravity
 
diff --git a/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.cpp b/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.cpp
index 403b0219323590e1b3129ba928b01abf2b7b4833..fc01c102470d52cde97c19ac2d184fc9ef12ed64 100644
--- a/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkReducedStVKBodyModel.cpp
@@ -160,8 +160,7 @@ ReducedStVK::initialize()
 {
     // prerequisite of for successfully initializing
     CHECK(m_geometry != nullptr && m_config != nullptr)
-        << "DeformableBodyModel::initialize: Physics mesh or force model configuration not set "
-        "yet!";
+        << "Physics mesh or force model configuration not set yet!";
 
     // Setup default solver if model wasn't assigned one
     if (m_solver == nullptr)
@@ -240,7 +239,7 @@ ReducedStVK::loadInitialStates()
 {
     if (m_numDOF == 0 || m_numDOFReduced == 0)
     {
-        LOG(WARNING) << "ReducedStVK::loadInitialStates() - Num. of degree of freedom is zero!";
+        LOG(WARNING) << "Num. of degree of freedom is zero!";
     }
 
     // For now the initial states are set to zero
@@ -272,7 +271,7 @@ bool
 ReducedStVK::initializeMassMatrix()
 {
     CHECK(m_geometry != nullptr)
-        << "DeformableBodyModel::initializeMassMatrix Force model geometry not set!";
+        << "Force model geometry not set!";
     this->m_massMatrix.resize(m_numDOFReduced * m_numDOFReduced, 0.0);
 
     // set M to identity
@@ -308,8 +307,7 @@ bool
 ReducedStVK::initializeTangentStiffness()
 {
     CHECK(m_forceModel != nullptr)
-        << "DeformableBodyModel::initializeTangentStiffness: Tangent stiffness cannot be "
-        "initialized without force model";
+        << "Tangent stiffness cannot be initialized without force model";
 
     this->m_stiffnessMatrix.resize(m_numDOFReduced * m_numDOFReduced, 0.0);
     m_forceModel->GetTangentStiffnessMatrix(m_initialStateReduced->getQ().data(),
@@ -373,7 +371,7 @@ ReducedStVK::computeImplicitSystemRHS(kinematicState&       stateAtT,
 
         break;
     default:
-        LOG(WARNING) << "ReducedStVK::computeImplicitSystemRHS: Update type not supported";
+        LOG(WARNING) << "Update type not supported";
     }
 }
 
@@ -417,7 +415,7 @@ ReducedStVK::computeSemiImplicitSystemRHS(kinematicState&       stateAtT,
         break;
 
     default:
-        LOG(FATAL) << "ReducedStVK::computeSemiImplicitSystemRHS: Update type not supported";
+        LOG(FATAL) << "Update type not supported";
     }
 }
 
@@ -451,7 +449,7 @@ ReducedStVK::computeImplicitSystemLHS(const kinematicState& stateAtT,
         break;
 
     default:
-        LOG(FATAL) << "ReducedStVK::computeImplicitSystemLHS: Update type not supported";
+        LOG(FATAL) << "Update type not supported";
     }
 }
 
@@ -561,8 +559,7 @@ ReducedStVK::updateBodyIntermediateStates(const Vectord& solution, const StateUp
         break;
 
     default:
-        LOG(FATAL) << "DeformableBodyModel::updateBodyIntermediateStates: Unknown state update "
-            "type";
+        LOG(FATAL) << "Unknown state update type";
     }
     prolongate(*m_currentStateReduced, *m_currentState);
     m_qSolReduced = m_currentStateReduced->getQ();
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp
index 7f7a201fd08e51318b753a98e78a34b3e97213ba..22ccb891a0bab1159cc657457b4d49a3e578dbf8 100644
--- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp
@@ -20,7 +20,7 @@
 =========================================================================*/
 
 #include "imstkRigidBodyModel.h"
-#include "imstkCube.h"
+#include "imstkOrientedBox.h"
 #include "imstkLogger.h"
 #include "imstkPlane.h"
 #include "imstkSphere.h"
@@ -48,9 +48,9 @@ RigidBodyModel::initialize()
         {
             createSphere();
         }
-        else if (geomType == "Cube")
+        else if (geomType == "OrientedBox")
         {
-            createCube();
+            createOrientedBox();
         }
         else if (geomType == "Plane")
         {
@@ -69,7 +69,7 @@ RigidBodyModel::initialize()
     }
     else
     {
-        LOG(WARNING) << "RigidBodyModel::initialize(): - Cannot initialize without valid model geometry";
+        LOG(WARNING) << "Cannot initialize without valid model geometry";
         return false;
     }
 }
@@ -151,7 +151,7 @@ RigidBodyModel::createPlane()
 }
 
 void
-RigidBodyModel::createCube()
+RigidBodyModel::createOrientedBox()
 {
     const auto physxMaterial = m_rigidBodyWorld->m_Physics->createMaterial((PxReal)m_config->m_staticFriction,
         (PxReal)m_config->m_dynamicFriction,
@@ -160,12 +160,12 @@ RigidBodyModel::createCube()
     const auto physics = m_rigidBodyWorld->m_Physics;
     const auto PxScene = m_rigidBodyWorld->m_Scene;
 
-    const auto cubeGeo = std::dynamic_pointer_cast<imstk::Cube>(m_geometry);
+    const auto obbGeo = std::dynamic_pointer_cast<OrientedBox>(m_geometry);
 
-    auto l = (PxReal)cubeGeo->getWidth();
+    Vec3d extents = obbGeo->getExtents();
 
-    const auto  p = cubeGeo->getPosition() + cubeGeo->getTranslation();
-    const Quatd q(cubeGeo->getRotation());
+    const auto  p = obbGeo->getPosition() + obbGeo->getTranslation();
+    const Quatd q(obbGeo->getRotation());
 
     PxTransform trans((float)p[0], (float)p[1], (float)p[2], PxQuat((float)q.x(), (float)q.y(), (float)q.z(), (float)q.w()));
 
@@ -173,7 +173,10 @@ RigidBodyModel::createCube()
     {
         m_pxStaticActor = PxCreateStatic(*physics,
                                          trans,
-                                         PxBoxGeometry(l / (PxReal)2., l / (PxReal)2., l / (PxReal)2.),
+                                         PxBoxGeometry(
+                                             static_cast<PxReal>(extents[0]),
+                                             static_cast<PxReal>(extents[1]),
+                                             static_cast<PxReal>(extents[2])),
                                          *physxMaterial);
         if (m_pxStaticActor)
         {
@@ -184,7 +187,10 @@ RigidBodyModel::createCube()
     {
         m_pxDynamicActor = PxCreateDynamic(*physics,
                                            trans,
-                                           PxBoxGeometry(l / (PxReal)2., l / (PxReal)2., l / (PxReal)2.),
+                                           PxBoxGeometry(
+                                               static_cast<PxReal>(extents[0]),
+                                               static_cast<PxReal>(extents[1]),
+                                               static_cast<PxReal>(extents[2])),
                                            *physxMaterial,
             (PxReal)0.1);
 
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h
index af70c4dc49ae876f0d40583df94744e542389939..fce924d99314a9a0f5ae15ec488126409e2b95e0 100644
--- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h
@@ -63,7 +63,7 @@ public:
         {
             "Plane",
             "Sphere",
-            "Cube",
+            "OrientedBox",
             "SurfaceMesh"
         };
     };
@@ -183,7 +183,7 @@ private:
     ///
     /// \brief TODO
     ///
-    void createCube();
+    void createOrientedBox();
     ///
     /// \brief TODO
     ///
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.cpp b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.cpp
index eb3bd0ae9f11f13dc7f6862e14478b754fa83a5e..08b81d1b15919ce7d66fabe98bcb065f0cf4e935 100644
--- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.cpp
@@ -28,8 +28,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 RigidBodyModel2::RigidBodyModel2() :
     m_config(std::make_shared<RigidBodyModel2Config>()),
     m_pgsSolver(std::make_shared<ProjectedGaussSeidelSolver<double>>())
@@ -173,16 +171,16 @@ RigidBodyModel2::computeTentativeVelocities()
 
     // Sum gravity to the forces
     ParallelUtils::parallelFor(forces.size(), [&forces, &fG](const int& i)
-            {
-                forces[i] += fG;
+        {
+            forces[i] += fG;
         }, forces.size() > m_maxBodiesParallel);
 
     // Compute the desired velocites, later we will solve for the proper velocities,
     // adjusted for the constraints
     ParallelUtils::parallelFor(tentativeVelocities.size(), [&](const size_t& i)
-            {
-                tentativeVelocities[i] += forces[i] * invMasses[i] * dt;
-                tentativeAngularVelocities[i] += invInteriaTensors[i] * torques[i] * dt;
+        {
+            tentativeVelocities[i] += forces[i] * invMasses[i] * dt;
+            tentativeAngularVelocities[i] += invInteriaTensors[i] * torques[i] * dt;
         }, tentativeVelocities.size() > m_maxBodiesParallel);
 }
 
@@ -361,33 +359,33 @@ RigidBodyModel2::integrate()
     StdVectorOfVec3d& torques = getCurrentState()->getTorques();
 
     ParallelUtils::parallelFor(positions.size(), [&](const size_t& i)
+        {
+            if (!isStatic[i])
             {
-                if (!isStatic[i])
+                velocities[i] += forces[i] * invMasses[i] * dt;
+                velocities[i] *= velocityDamping;
+                angularVelocities[i] += invInteriaTensors[i] * torques[i] * dt;
+                angularVelocities[i] *= angularVelocityDamping;
+                positions[i] += velocities[i] * dt;
                 {
-                    velocities[i] += forces[i] * invMasses[i] * dt;
-                    velocities[i] *= velocityDamping;
-                    angularVelocities[i] += invInteriaTensors[i] * torques[i] * dt;
-                    angularVelocities[i] *= angularVelocityDamping;
-                    positions[i] += velocities[i] * dt;
-                    {
-                        const Quatd q = Quatd(0.0,
+                    const Quatd q = Quatd(0.0,
                             angularVelocities[i][0],
                             angularVelocities[i][1],
                             angularVelocities[i][2]) * orientations[i];
-                        orientations[i].x() += q.x() * dt;
-                        orientations[i].y() += q.y() * dt;
-                        orientations[i].z() += q.z() * dt;
-                        orientations[i].w() += q.w() * dt;
-                        orientations[i].normalize();
-                    }
+                    orientations[i].x() += q.x() * dt;
+                    orientations[i].y() += q.y() * dt;
+                    orientations[i].z() += q.z() * dt;
+                    orientations[i].w() += q.w() * dt;
+                    orientations[i].normalize();
                 }
+            }
 
-                // Reset
-                m_bodies[i]->m_prevForce = forces[i];
-                forces[i]  = Vec3d(0.0, 0.0, 0.0);
-                torques[i] = Vec3d(0.0, 0.0, 0.0);
-                tentativeVelocities[i] = velocities[i];
-                tentativeAngularVelocities[i] = angularVelocities[i];
+            // Reset
+            m_bodies[i]->m_prevForce = forces[i];
+            forces[i]  = Vec3d(0.0, 0.0, 0.0);
+            torques[i] = Vec3d(0.0, 0.0, 0.0);
+            tentativeVelocities[i] = velocities[i];
+            tentativeAngularVelocities[i] = angularVelocities[i];
         }, positions.size() > m_maxBodiesParallel);
 }
 
@@ -399,5 +397,4 @@ RigidBodyModel2::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_pt
     m_taskGraph->addEdge(m_solveNode, m_integrateNode);
     m_taskGraph->addEdge(m_integrateNode, sink);
 }
-}
 }
\ No newline at end of file
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.h b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.h
index fad63f7ea0f54f189ecb8a79b567ebb0c24d6943..29c761c24d0a1999d15cb4cbfe39aa86ff2d860d 100644
--- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.h
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel2.h
@@ -31,9 +31,6 @@ namespace imstk
 {
 template<typename ScalarType>
 class ProjectedGaussSeidelSolver;
-
-namespace expiremental
-{
 class RbdConstraint;
 struct RigidBody;
 
@@ -154,5 +151,4 @@ protected:
 
     Eigen::VectorXd F;               // Reaction forces
 };
-}
 }
\ No newline at end of file
diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHHemorrhage.cpp b/Source/DynamicalModels/ObjectModels/imstkSPHHemorrhage.cpp
deleted file mode 100644
index 44522b8cfcf21e1eeff270b3405499ea149d29ad..0000000000000000000000000000000000000000
--- a/Source/DynamicalModels/ObjectModels/imstkSPHHemorrhage.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*=========================================================================
-
-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 "imstkSPHHemorrhage.h"
-
-namespace imstk
-{
-SPHHemorrhage::SPHHemorrhage(const Vec3d& center, const double radius, const double area, const Vec3d& normal) :
-    m_area(area), m_center(center), m_normal(normal.normalized()), m_radius(radius)
-{
-}
-
-bool
-SPHHemorrhage::pointCrossedHemorrhagePlane(const Vec3d& oldPosition, const Vec3d& newPosition)
-{
-    // todo - loop through points that are near hemorrhage plane instead of all points
-    const double dist = m_normal.dot(newPosition - m_center);
-
-    if (m_normal.dot(oldPosition - m_center) < 0 && dist > 0)
-    {
-        // particle has crossed plane in the correct direction
-        // however, we still need to determine if the particle is in the domain of the hemorrhage area
-        // project point onto plane
-        const Vec3d pointOnPlane = newPosition - dist * m_normal;
-        // check if point is farther than radius from center point
-        const double distFromCenter = (pointOnPlane - m_center).norm();
-
-        if (distFromCenter <= m_radius)
-        {
-            return true;
-        }
-    }
-    return false;
-}
-} // end namespace imstk
diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHHemorrhage.h b/Source/DynamicalModels/ObjectModels/imstkSPHHemorrhage.h
deleted file mode 100644
index a924aa971ae4125596ef5f8a4701b5c590b6bb8a..0000000000000000000000000000000000000000
--- a/Source/DynamicalModels/ObjectModels/imstkSPHHemorrhage.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*=========================================================================
-
-   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.
-
-=========================================================================*/
-
-#pragma once
-
-#include "imstkMath.h"
-
-namespace imstk
-{
-///
-/// \class SPHHemorrhage
-/// \brief Class that holds methods and members for hemorrhage model
-///
-class SPHHemorrhage
-{
-public:
-    // constructor
-    SPHHemorrhage(const Vec3d& center, const double radius, const double area, const Vec3d& normal);
-
-    ///
-    /// \brief Determine if fluid particle crossed the hemorrhage plane
-    ///
-    bool pointCrossedHemorrhagePlane(const Vec3d& oldPosition, const Vec3d& newPosition);
-
-    ///
-    /// \brief Get the outward normal to the hemorrhage plane
-    ///
-    const Vec3d getNormal() { return m_normal; }
-
-    ///
-    /// \brief Get the area of the hemorrhage plane
-    ///
-    const double getHemorrhagePlaneArea() { return m_area; }
-
-    ///
-    /// \brief Get the rate of hemorrhage from SPH
-    ///
-    const double getHemorrhageRate() { return m_hemorrhageRate; }
-
-    ///
-    /// \brief Set the rate of hemorrhage from SPH
-    ///
-    void setHemorrhageRate(const double hemorrhageRate) { m_hemorrhageRate = hemorrhageRate; }
-
-private:
-    double m_area;                    ///> cross-sectional area of hemorrhage plane
-    Vec3d  m_center;                  ///> hemorrhage plane center
-    double m_hemorrhageRate = 0;      ///> rate of hemorrhage
-    Vec3d  m_normal;                  ///> outward unit normal of hemorrhage plane
-    double m_radius;                  ///> hemorrhage plane radius
-};
-} // end namespace imstk
diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp b/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp
index c3eb5af92d85c0c512e4c90edf01841a066e52b7..381144e493ac403e1cbac0ad50c32adde7d35cb4 100644
--- a/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp
@@ -146,7 +146,7 @@ SPHModel::initialize()
 {
     LOG_IF(FATAL, (!this->getModelGeometry())) << "Model geometry is not yet set! Cannot initialize without model geometry.";
     m_pointSetGeometry = std::dynamic_pointer_cast<PointSet>(m_geometry);
-    const int numParticles = static_cast<int>(m_pointSetGeometry->getNumVertices());
+    const int numParticles = m_pointSetGeometry->getNumVertices();
 
     // Allocate init and current state
     m_initialState = std::make_shared<SPHState>(numParticles);
@@ -198,11 +198,6 @@ SPHModel::initialize()
     m_pointSetGeometry->setVertexAttribute("Normals", m_currentState->getNormals());
     m_pointSetGeometry->setVertexAttribute("Accels", m_currentState->getAccelerations());
 
-    if (m_geomUnstructuredGrid)
-    {
-        m_minIndices.resize(m_geomUnstructuredGrid->getNumVertices());
-    }
-
     return true;
 }
 
@@ -769,29 +764,7 @@ SPHModel::moveParticles(const Real timestep)
                 m_sphBoundaryConditions->getBufferIndices().push_back(p);
             }
         }
-
-        if (m_SPHHemorrhage && m_SPHHemorrhage->pointCrossedHemorrhagePlane(oldPosition, newPosition))
-        {
-            averageVelThroughHemorrhage += m_SPHHemorrhage->getNormal() * fullStepVelocities[p].dot(m_SPHHemorrhage->getNormal());
-            numParticlesAcrossHemorrhagePlane++;
-        }
-    }
-
-    if (m_SPHHemorrhage)
-    {
-        if (numParticlesAcrossHemorrhagePlane > 0)
-        {
-            averageVelThroughHemorrhage /= numParticlesAcrossHemorrhagePlane;
-        }
-        else
-        {
-            averageVelThroughHemorrhage = m_prevAvgVelThroughHemorrhage;
-        }
-        m_prevAvgVelThroughHemorrhage = averageVelThroughHemorrhage;
-        const double hemorrhageFlowRate = averageVelThroughHemorrhage.norm() * m_SPHHemorrhage->getHemorrhagePlaneArea();
-        m_SPHHemorrhage->setHemorrhageRate(hemorrhageFlowRate);
     }
-    m_totalTime += m_dt;
     m_timeStepCount++;
 }
 
@@ -844,52 +817,4 @@ SPHModel::findNearestParticleToVertex(const VecDataArray<double, 3>& points, con
         m_minIndices[i] = minIndex;
     }
 }
-
-void
-SPHModel::writeStateToVtk()
-{
-    if (!m_geomUnstructuredGrid)
-    {
-        return;
-    }
-
-    if (m_vtkPreviousTime <= m_vtkTimeModulo && m_totalTime >= m_vtkTimeModulo)
-    {
-        LOG(INFO) << "Writing VTK at time: " << m_totalTime;
-        const VecDataArray<double, 3>& particleVelocities = *getCurrentState()->getFullStepVelocities();
-        const DataArray<double>&       particleDensities  = *getCurrentState()->getDensities();
-
-        std::shared_ptr<VecDataArray<double, 3>> velocityPtr = std::make_shared<VecDataArray<double, 3>>();
-        VecDataArray<double, 3>&                 velocity    = *velocityPtr;
-        std::shared_ptr<DataArray<double>>       pressurePtr = std::make_shared<DataArray<double>>();
-        DataArray<double>&                       pressure    = *pressurePtr;
-        std::shared_ptr<DataArray<double>>       densityPtr  = std::make_shared<DataArray<double>>();
-        DataArray<double>&                       density     = *densityPtr;
-
-        velocity.reserve(static_cast<int>(m_geomUnstructuredGrid->getNumVertices()));
-        pressure.reserve(static_cast<int>(m_geomUnstructuredGrid->getNumVertices()));
-        density.reserve(static_cast<int>(m_geomUnstructuredGrid->getNumVertices()));
-
-        std::vector<std::vector<size_t>> result;
-        m_neighborSearcher->getNeighbors(result, *m_geomUnstructuredGrid->getInitialVertexPositions(), *getCurrentState()->getPositions());
-        findNearestParticleToVertex(*m_geomUnstructuredGrid->getInitialVertexPositions(), result);
-
-        for (auto i : m_minIndices)
-        {
-            velocity.push_back(particleVelocities[i]);
-            density.push_back(particleDensities[i]);
-            pressure.push_back(particlePressure(particleDensities[i]));
-        }
-        m_geomUnstructuredGrid->setVertexAttribute("velocity", velocityPtr);
-        m_geomUnstructuredGrid->setVertexAttribute("pressure", pressurePtr);
-        m_geomUnstructuredGrid->setVertexAttribute("density", densityPtr);
-
-        VTKMeshIO   vtkWriter;
-        std::string filePath = std::string("sph_output_") + std::to_string(m_totalTime) + std::string(".vtu");
-        vtkWriter.write(m_geomUnstructuredGrid, filePath, MeshFileType::VTU);
-
-        m_vtkTimeModulo  += m_writeToOutputModulo;
-        m_vtkPreviousTime = m_totalTime;
-    }
-}
 } // end namespace imstk
diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHModel.h b/Source/DynamicalModels/ObjectModels/imstkSPHModel.h
index 08ab7455c37567f148792f661c4d1ae0bf4402f1..9181d1ebc32b09b845b5c58fc1a5ed09a9c52383 100644
--- a/Source/DynamicalModels/ObjectModels/imstkSPHModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkSPHModel.h
@@ -26,8 +26,6 @@
 #include "imstkSPHKernels.h"
 #include "imstkNeighborSearch.h"
 #include "imstkSPHBoundaryConditions.h"
-#include "imstkSPHHemorrhage.h"
-#include "imstkTetrahedralMesh.h"
 
 namespace imstk
 {
@@ -157,19 +155,11 @@ public:
     /// \brief Write the state to external file
     /// \todo move this out of this class
     ///
-    void setWriteToOutputModulo(const double modulo) { m_writeToOutputModulo = modulo; }
-    double getTotalTime() const { return m_totalTime; }
-    int getTimeStepCount() const { return m_timeStepCount; }
-    void writeStateToVtk();
-    void setGeometryMesh(std::shared_ptr<TetrahedralMesh>& geometryMesh) { m_geomUnstructuredGrid = geometryMesh; }
     void findNearestParticleToVertex(const VecDataArray<double, 3>& points, const std::vector<std::vector<size_t>>& indices);
 
     void setBoundaryConditions(std::shared_ptr<SPHBoundaryConditions> sphBoundaryConditions) { m_sphBoundaryConditions = sphBoundaryConditions; }
     std::shared_ptr<SPHBoundaryConditions> getBoundaryConditions() { return m_sphBoundaryConditions; }
 
-    void setHemorrhageModel(std::shared_ptr<SPHHemorrhage> sPHHemorrhage) { m_SPHHemorrhage = sPHHemorrhage; }
-    std::shared_ptr<SPHHemorrhage> getHemorrhageModel() { return m_SPHHemorrhage; }
-
     void setRestDensity(const Real restDensity) { m_modelParameters->m_restDensity = restDensity; }
 
     std::shared_ptr<TaskNode> getFindParticleNeighborsNode() const { return m_findParticleNeighborsNode; }
@@ -293,19 +283,9 @@ private:
     std::shared_ptr<VecDataArray<double, 3>> m_initialVelocities = nullptr;
     std::shared_ptr<DataArray<double>>       m_initialDensities  = nullptr;
 
-    double m_totalTime           = 0;
-    int    m_timeStepCount       = 0;
-    double m_writeToOutputModulo = 0;
-    double m_vtkPreviousTime     = 0;
-    double m_vtkTimeModulo       = 0;
-    double m_csvPreviousTime     = 0;
-    double m_csvTimeModulo       = 0;
-    Vec3d  m_prevAvgVelThroughHemorrhage = Vec3d(0., 0., 0.);
+    int m_timeStepCount = 0;
 
-    std::shared_ptr<TetrahedralMesh>       m_geomUnstructuredGrid  = nullptr;
     std::shared_ptr<SPHBoundaryConditions> m_sphBoundaryConditions = nullptr;
-    // \todo: Should be refactored out of the base SPHModel
-    std::shared_ptr<SPHHemorrhage> m_SPHHemorrhage = nullptr;
 
     std::vector<size_t> m_minIndices;
 };
diff --git a/Source/Filtering/CMakeLists.txt b/Source/Filtering/CMakeLists.txt
index adffa7aa0c2a7edc280b7812ac1b98353dab960c..8dceaf30326d452814ac0e2c4c68dc00d73cccef 100644
--- a/Source/Filtering/CMakeLists.txt
+++ b/Source/Filtering/CMakeLists.txt
@@ -11,6 +11,5 @@ imstk_add_library( Filtering
   CPP_FILES
     ${cppFiles}
   DEPENDS
-    Geometry
-    DataStructures
-    ${VTK_LIBRARIES})
+    FilteringCore
+    ${VTK_LIBRARIES})
\ No newline at end of file
diff --git a/Source/Filtering/imstkCleanMesh.cpp b/Source/Filtering/imstkCleanMesh.cpp
index 9da413138b7eb46f9eab6be31ce705728890084b..3c3c752a08a1d3de682177b626bc1e6898f64ddf 100644
--- a/Source/Filtering/imstkCleanMesh.cpp
+++ b/Source/Filtering/imstkCleanMesh.cpp
@@ -31,6 +31,8 @@ namespace imstk
 {
 CleanMesh::CleanMesh()
 {
+    setInputPortReq<SurfaceMesh>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<SurfaceMesh>());
diff --git a/Source/Filtering/imstkExtractEdges.cpp b/Source/Filtering/imstkExtractEdges.cpp
index e891a0dc4bd5975a355996c00016403fa1a1cfcf..12e94a658f1f00783b13d2ed16f4afa0582bfdee 100644
--- a/Source/Filtering/imstkExtractEdges.cpp
+++ b/Source/Filtering/imstkExtractEdges.cpp
@@ -32,6 +32,8 @@ namespace imstk
 {
 ExtractEdges::ExtractEdges()
 {
+    setInputPortReq<SurfaceMesh>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<LineMesh>());
diff --git a/Source/Filtering/imstkFastMarch.cpp b/Source/Filtering/imstkFastMarch.cpp
index 5be3a1001a2f4b574f0d3a2273cd52e79e8ffa5f..d5bdd7395daa4c52e1cc2133e1ea31c43a0f0822 100644
--- a/Source/Filtering/imstkFastMarch.cpp
+++ b/Source/Filtering/imstkFastMarch.cpp
@@ -189,9 +189,9 @@ FastMarch::solveNode(Vec3i coord, int index)
             const double spaceFactor = std::sqrt(1.0 / m_spacing[dimReorder[i]]);
             aa += spaceFactor;
             bb += value * spaceFactor;
-            cc += std::pow(value, 2) * spaceFactor;
+            cc += value * value * spaceFactor;
 
-            discrim = std::pow(bb, 2) - aa * cc;
+            discrim = bb * bb - aa * cc;
             if (discrim < 0.0)
             {
                 // Whoops
diff --git a/Source/Filtering/imstkImageDistanceTransform.cpp b/Source/Filtering/imstkImageDistanceTransform.cpp
index 48aaeceab3a948707e14dcc5d3498d358260a950..660e8cce3aed38b826e1c6aee7f1a84bdc7290ca 100644
--- a/Source/Filtering/imstkImageDistanceTransform.cpp
+++ b/Source/Filtering/imstkImageDistanceTransform.cpp
@@ -34,6 +34,8 @@ namespace imstk
 {
 ImageDistanceTransform::ImageDistanceTransform()
 {
+    setInputPortReq<ImageData>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<ImageData>(), 0);
diff --git a/Source/Filtering/imstkImageGradient.cpp b/Source/Filtering/imstkImageGradient.cpp
index a9738f77fe22512c189364be79e63e55d8dc32e2..e1719dc0adfc1a6c983a2f2fc41ff72cd29678d1 100644
--- a/Source/Filtering/imstkImageGradient.cpp
+++ b/Source/Filtering/imstkImageGradient.cpp
@@ -32,6 +32,8 @@ namespace imstk
 {
 ImageGradient::ImageGradient()
 {
+    setInputPortReq<ImageData>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<PointSet>());
diff --git a/Source/Filtering/imstkImageResample.cpp b/Source/Filtering/imstkImageResample.cpp
index e7e52f5bc2cdf636f4e401a9ab4d7b0f38f5c26f..153655af959ad438c14f552436f6bd89fe17a6a1 100644
--- a/Source/Filtering/imstkImageResample.cpp
+++ b/Source/Filtering/imstkImageResample.cpp
@@ -33,6 +33,8 @@ namespace imstk
 {
 ImageResample::ImageResample()
 {
+    setInputPortReq<ImageData>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<ImageData>());
diff --git a/Source/Filtering/imstkImageReslice.cpp b/Source/Filtering/imstkImageReslice.cpp
index 531d3cc3cc0ca397378e356919f3b516ebd1d45b..ab24e5d4e45628e8a2a179f4cf745e8dad423849 100644
--- a/Source/Filtering/imstkImageReslice.cpp
+++ b/Source/Filtering/imstkImageReslice.cpp
@@ -32,6 +32,8 @@ namespace imstk
 {
 ImageReslice::ImageReslice()
 {
+    setInputPortReq<ImageData>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<ImageData>());
diff --git a/Source/Filtering/imstkImplicitGeometryToImageData.cpp b/Source/Filtering/imstkImplicitGeometryToImageData.cpp
index b1f43c4828ca9dfb68def9849ee8edcc41c5819e..0cc636b4c6345548d5463b132c76d3325747a64e 100644
--- a/Source/Filtering/imstkImplicitGeometryToImageData.cpp
+++ b/Source/Filtering/imstkImplicitGeometryToImageData.cpp
@@ -30,6 +30,8 @@ namespace imstk
 {
 ImplicitGeometryToImageData::ImplicitGeometryToImageData()
 {
+    setInputPortReq<ImplicitGeometry>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<ImageData>());
diff --git a/Source/Filtering/imstkLocalMarchingCubes.cpp b/Source/Filtering/imstkLocalMarchingCubes.cpp
index ec6f965be2a4de6701c3652bfcd67b5aa15c591b..331dc08084ff5abcffb468c999c4f222a645546f 100644
--- a/Source/Filtering/imstkLocalMarchingCubes.cpp
+++ b/Source/Filtering/imstkLocalMarchingCubes.cpp
@@ -360,6 +360,8 @@ lerp(double val1, double val2, double isovalue, double spacing)
 
 LocalMarchingCubes::LocalMarchingCubes()
 {
+    setInputPortReq<ImageData>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(0);
 }
diff --git a/Source/Filtering/imstkQuadricDecimate.cpp b/Source/Filtering/imstkQuadricDecimate.cpp
index 38facf819d512705607aa0cc5c81b51260a419ca..230ab092ae24b8b67c254f25ec2741e31118f00c 100644
--- a/Source/Filtering/imstkQuadricDecimate.cpp
+++ b/Source/Filtering/imstkQuadricDecimate.cpp
@@ -31,6 +31,8 @@ namespace imstk
 QuadricDecimate::QuadricDecimate() :
     m_VolumePreserving(true), m_TargetReduction(0.6)
 {
+    setInputPortReq<SurfaceMesh>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<SurfaceMesh>());
diff --git a/Source/Filtering/imstkSelectEnclosedPoints.cpp b/Source/Filtering/imstkSelectEnclosedPoints.cpp
index 2f2aebbaf3d957eda528c19810e6a276c99cfca6..9ca99062980b2fb19a51a2cbf5124f3260f40f62 100644
--- a/Source/Filtering/imstkSelectEnclosedPoints.cpp
+++ b/Source/Filtering/imstkSelectEnclosedPoints.cpp
@@ -32,6 +32,9 @@ namespace imstk
 {
 SelectEnclosedPoints::SelectEnclosedPoints()
 {
+    setInputPortReq<SurfaceMesh>(0);
+    setInputPortReq<PointSet>(1);
+
     setNumberOfInputPorts(2);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<PointSet>());
diff --git a/Source/Filtering/imstkSurfaceMeshCut.cpp b/Source/Filtering/imstkSurfaceMeshCut.cpp
index 11c0f002267d19d7207b04b9447716d21c7b6e2c..583bc1f39a9777189b40911273aa13e70801ad31 100644
--- a/Source/Filtering/imstkSurfaceMeshCut.cpp
+++ b/Source/Filtering/imstkSurfaceMeshCut.cpp
@@ -32,6 +32,8 @@ namespace imstk
 {
 SurfaceMeshCut::SurfaceMeshCut()
 {
+    setInputPortReq<SurfaceMesh>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<SurfaceMesh>());
diff --git a/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp b/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp
index cb42b2000c32243f527bc0a9dfa4a871c6856551..204651aaa18e5f592fb99a0096e841f097c235b9 100644
--- a/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp
+++ b/Source/Filtering/imstkSurfaceMeshDistanceTransform.cpp
@@ -149,7 +149,7 @@ computeNarrowBandedDT(std::shared_ptr<ImageData> imageData, std::shared_ptr<Surf
 }
 
 static void
-computeFullDT(std::shared_ptr<ImageData> imageData, std::shared_ptr<SurfaceMesh> surfMesh)
+computeFullDT(std::shared_ptr<ImageData> imageData, std::shared_ptr<SurfaceMesh> surfMesh, double tolerance)
 {
     // Get the optimal number of threads
     const size_t numThreads = ParallelUtils::ThreadManager::getThreadPoolSize();
@@ -167,6 +167,7 @@ computeFullDT(std::shared_ptr<ImageData> imageData, std::shared_ptr<SurfaceMesh>
             vtkSmartPointer<vtkPolyData> inputPolyData = GeometryUtils::copyToVtkPolyData(surfMesh);
             vtkSmartPointer<vtkImplicitPolyDataDistance> polyDataDist = vtkSmartPointer<vtkImplicitPolyDataDistance>::New();
             polyDataDist->SetInput(inputPolyData);
+            polyDataDist->SetTolerance(tolerance);
             for (int z = static_cast<int>(i); z < dim[2]; z += static_cast<int>(numThreads))
             {
                 int j = z * dim[0] * dim[1];
@@ -201,6 +202,8 @@ computeFullDT(std::shared_ptr<ImageData> imageData, std::shared_ptr<SurfaceMesh>
 
 SurfaceMeshDistanceTransform::SurfaceMeshDistanceTransform()
 {
+    setInputPortReq<SurfaceMesh>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<ImageData>(), 0);
@@ -273,7 +276,7 @@ SurfaceMeshDistanceTransform::requestUpdate()
     }
     else
     {
-        computeFullDT(outputImageData, inputSurfaceMesh);
+        computeFullDT(outputImageData, inputSurfaceMesh, m_Tolerance);
     }
 
     //printf("time: %f\n", timer.getTimeElapsed());
diff --git a/Source/Filtering/imstkSurfaceMeshDistanceTransform.h b/Source/Filtering/imstkSurfaceMeshDistanceTransform.h
index 277fdbe2b628d3313f24f3301f96c14e8c3473a3..fc02268dbcfa0f6bf80ae0dd68a283a100a4fab1 100644
--- a/Source/Filtering/imstkSurfaceMeshDistanceTransform.h
+++ b/Source/Filtering/imstkSurfaceMeshDistanceTransform.h
@@ -31,8 +31,9 @@ class SurfaceMesh;
 ///
 /// \class SurfaceMeshDistanceTransform
 ///
-/// \brief This filter computes brute force signed distance field by computing the nearest
-/// point in one dataset to the other
+/// \brief This filter computes exact signed distance fields using octrees
+/// and psuedonormal computations. One might need to adjust the tolerance
+/// depending on dataset scale.
 ///
 class SurfaceMeshDistanceTransform : public GeometryAlgorithm
 {
@@ -53,6 +54,7 @@ public:
     imstkGetMacro(UseBounds, bool);
     imstkGetMacro(NarrowBanded, bool);
     imstkGetMacro(DilateSize, int);
+    imstkGetMacro(Tolerance, double);
 
     ///
     /// \brief Dimensions of distance transform to fill
@@ -77,15 +79,18 @@ public:
     ///
     imstkSetMacro(DilateSize, int);
 
+    imstkSetMacro(Tolerance, double);
+
     void setDimensions(int dimX, int dimY, int dimZ) { setDimensions(Vec3i(dimX, dimY, dimZ)); }
 
 protected:
     void requestUpdate() override;
 
 private:
-    Vec3i m_Dimensions = Vec3i(0, 0, 0);
-    Vec6d m_Bounds;
-    bool  m_UseBounds = false;
+    Vec3i  m_Dimensions = Vec3i(0, 0, 0);
+    Vec6d  m_Bounds;
+    bool   m_UseBounds = false;
+    double m_Tolerance = 1.0e-10;
 
     int  m_DilateSize   = 4; ///> Only for narrow banded
     bool m_NarrowBanded = false;
diff --git a/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp b/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp
index bc534b3ff537c9031fc00dfda0704f0e0d34d6ec..b3127d94f7022215a37a1d44f99fc5bde031d3de 100644
--- a/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp
+++ b/Source/Filtering/imstkSurfaceMeshFlyingEdges.cpp
@@ -32,6 +32,8 @@ namespace imstk
 {
 SurfaceMeshFlyingEdges::SurfaceMeshFlyingEdges()
 {
+    setInputPortReq<ImageData>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<SurfaceMesh>());
@@ -62,6 +64,7 @@ SurfaceMeshFlyingEdges::requestUpdate()
     vtkNew<vtkFlyingEdges3D> filter;
     filter->SetInputData(GeometryUtils::coupleVtkImageData(inputImage));
     filter->SetValue(0, m_IsoValue);
+    filter->ComputeNormalsOff();
     filter->Update();
 
     std::dynamic_pointer_cast<SurfaceMesh>(getOutput(0))->deepCopy(GeometryUtils::copyToSurfaceMesh(filter->GetOutput()));
diff --git a/Source/Filtering/imstkSurfaceMeshImageMask.cpp b/Source/Filtering/imstkSurfaceMeshImageMask.cpp
index 4cfd37bde90db5a543e40f41fd5b5e2ef8e81a3f..d40be31dec8afb8f7dcef4cd3ea916c92e576438 100644
--- a/Source/Filtering/imstkSurfaceMeshImageMask.cpp
+++ b/Source/Filtering/imstkSurfaceMeshImageMask.cpp
@@ -35,6 +35,9 @@ namespace imstk
 {
 SurfaceMeshImageMask::SurfaceMeshImageMask()
 {
+    setInputPortReq<SurfaceMesh>(0);
+    setInputPortReq<ImageData>(1);
+
     setNumberOfInputPorts(2);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<ImageData>(), 0);
diff --git a/Source/Filtering/imstkSurfaceMeshSmoothen.cpp b/Source/Filtering/imstkSurfaceMeshSmoothen.cpp
index 4e78bb66c573c2161f73279b365837e4be9da7ba..35432eb3b724a06274913fcc855e7ce89c72eece 100644
--- a/Source/Filtering/imstkSurfaceMeshSmoothen.cpp
+++ b/Source/Filtering/imstkSurfaceMeshSmoothen.cpp
@@ -30,6 +30,8 @@ namespace imstk
 {
 SurfaceMeshSmoothen::SurfaceMeshSmoothen()
 {
+    setInputPortReq<SurfaceMesh>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<SurfaceMesh>());
diff --git a/Source/Filtering/imstkSurfaceMeshSubdivide.cpp b/Source/Filtering/imstkSurfaceMeshSubdivide.cpp
index b295edf94ebaf74da896064a3f6fb284cfabdef0..6e15d9e3efdbf143a8c980d7814f0e104d2cb5ce 100644
--- a/Source/Filtering/imstkSurfaceMeshSubdivide.cpp
+++ b/Source/Filtering/imstkSurfaceMeshSubdivide.cpp
@@ -32,6 +32,8 @@ namespace imstk
 {
 SurfaceMeshSubdivide::SurfaceMeshSubdivide()
 {
+    setInputPortReq<SurfaceMesh>(0);
+
     setNumberOfInputPorts(1);
     setNumberOfOutputPorts(1);
     setOutput(std::make_shared<SurfaceMesh>());
diff --git a/Source/Filtering/imstkSurfaceMeshTextureProject.cpp b/Source/Filtering/imstkSurfaceMeshTextureProject.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e728a21130a49dca496114d12ad1fa2ecd874488
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshTextureProject.cpp
@@ -0,0 +1,206 @@
+/*=========================================================================
+
+   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 "imstkSurfaceMeshTextureProject.h"
+#include "imstkLogger.h"
+#include "imstkParallelUtils.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkVecDataArray.h"
+
+namespace imstk
+{
+static Vec3d
+closestPointOnTriangle(const Vec3d& p, const Vec3d& a, const Vec3d& b, const Vec3d& c, int& caseType)
+{
+    const Vec3d ab = b - a;
+    const Vec3d ac = c - a;
+    const Vec3d ap = p - a;
+
+    const double d1 = ab.dot(ap);
+    const double d2 = ac.dot(ap);
+    if (d1 <= 0.0 && d2 <= 0.0)
+    {
+        caseType = 0;
+        return a; // barycentric coordinates (1,0,0)
+    }
+
+    // Check if P in vertex region outside B
+    const Vec3d  bp = p - b;
+    const double d3 = ab.dot(bp);
+    const double d4 = ac.dot(bp);
+    if (d3 >= 0.0 && d4 <= d3)
+    {
+        caseType = 1;
+        return b; // barycentric coordinates (0,1,0)
+    }
+    // Check if P in edge region of AB, if so return projection of P onto AB
+    const double vc = d1 * d4 - d3 * d2;
+    if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0)
+    {
+        caseType = 3;
+        double v = d1 / (d1 - d3);
+        return a + v * ab; // barycentric coordinates (1-v,v,0)
+    }
+
+    // Check if P in vertex region outside C
+    const Vec3d  cp = p - c;
+    const double d5 = ab.dot(cp);
+    const double d6 = ac.dot(cp);
+    if (d6 >= 0.0 && d5 <= d6)
+    {
+        caseType = 2;
+        return c; // barycentric coordinates (0,0,1)
+    }
+
+    // Check if P in edge region of AC, if so return projection of P onto AC
+    const double vb = d5 * d2 - d1 * d6;
+    if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0)
+    {
+        caseType = 5;
+        double w = d2 / (d2 - d6);
+        return a + w * ac; // barycentric coordinates (1-w,0,w)
+    }
+
+    // Check if P in edge region of BC, if so return projection of P onto BC
+    const double va = d3 * d6 - d5 * d4;
+    if (va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0)
+    {
+        caseType = 4;
+        double w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
+        return b + w * (c - b); // barycentric coordinates (0,1-w,w)
+    }
+
+    // P inside face region. Compute Q through its barycentric coordinates (u,v,w)
+    const double denom = 1.0 / (va + vb + vc);
+    const double v     = vb * denom;
+    const double w     = vc * denom;
+    caseType = 6;
+    return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = 1.0f-v-w
+}
+
+template<typename T>
+static T
+baryInterpolate(T v1, T v2, T v3, Vec3d uvw)
+{
+    return v1 * uvw[0] + v2 * uvw[1] + v3 * uvw[2];
+}
+
+SurfaceMeshTextureProject::SurfaceMeshTextureProject()
+{
+    setInputPortReq<SurfaceMesh>(0);
+    setInputPortReq<SurfaceMesh>(1);
+
+    setNumberOfInputPorts(2);
+    setNumberOfOutputPorts(1);
+    setOutput(std::make_shared<SurfaceMesh>(), 0);
+}
+
+void
+SurfaceMeshTextureProject::setSourceMesh(std::shared_ptr<SurfaceMesh> srcMesh)
+{
+    setInput(srcMesh, 0);
+}
+
+void
+SurfaceMeshTextureProject::setDestMesh(std::shared_ptr<SurfaceMesh> destMesh)
+{
+    setInput(destMesh, 1);
+}
+
+std::shared_ptr<SurfaceMesh>
+SurfaceMeshTextureProject::getOutputMesh()
+{
+    return std::dynamic_pointer_cast<SurfaceMesh>(getOutput(0));
+}
+
+void
+SurfaceMeshTextureProject::requestUpdate()
+{
+    std::shared_ptr<SurfaceMesh> inputSrcMesh   = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0));
+    std::shared_ptr<SurfaceMesh> inputDestMesh  = std::dynamic_pointer_cast<SurfaceMesh>(getInput(1));
+    std::shared_ptr<SurfaceMesh> outputDestMesh = std::dynamic_pointer_cast<SurfaceMesh>(getOutput(0));
+    outputDestMesh->deepCopy(inputDestMesh);
+
+    if (inputSrcMesh == nullptr || inputDestMesh == nullptr)
+    {
+        LOG(WARNING) << "Missing input surface mesh";
+        return;
+    }
+
+    std::shared_ptr<VecDataArray<double, 3>> srcVerticesPtr = inputSrcMesh->getVertexPositions();
+    const VecDataArray<double, 3>&           srcVertices    = *srcVerticesPtr;
+    std::shared_ptr<VecDataArray<int, 3>>    srcCellsPtr    = inputSrcMesh->getTriangleIndices();
+    const VecDataArray<int, 3>&              srcCells       = *srcCellsPtr;
+    std::shared_ptr<VecDataArray<float, 2>>  srcTCoordsPtr  = inputSrcMesh->getVertexTCoords();
+    if (srcTCoordsPtr == nullptr)
+    {
+        LOG(WARNING) << "inputSrcMesh does not have texture coordinates";
+        return;
+    }
+    const VecDataArray<float, 2>& inputTexCoords = *srcTCoordsPtr;
+
+    std::shared_ptr<VecDataArray<double, 3>> destVerticesPtr      = inputDestMesh->getVertexPositions();
+    const VecDataArray<double, 3>&           destVertices         = *destVerticesPtr;
+    auto                                     outputDestTCoordsPtr = std::make_shared<VecDataArray<float, 2>>(destVertices.size());
+    outputDestMesh->setVertexTCoords(inputSrcMesh->getActiveVertexTCoords(), outputDestTCoordsPtr);
+    VecDataArray<float, 2>& outputTexCoords = *outputDestTCoordsPtr;
+
+    // For every vertex of the destination mesh
+    for (int i = 0; i < destVertices.size(); i++)
+    {
+        const Vec3d& pos = destVertices[i];
+        double       minDistSqr   = IMSTK_DOUBLE_MAX;
+        int          closestCellI = -1;
+        Vec3d        closestPt    = Vec3d::Zero();
+
+        // Find the closest point on the other mesh
+        for (int j = 0; j < srcCells.size(); j++)
+        {
+            const Vec3i& cell = srcCells[j];
+            const Vec3d& a    = srcVertices[cell[0]];
+            const Vec3d& b    = srcVertices[cell[1]];
+            const Vec3d& c    = srcVertices[cell[2]];
+
+            int          caseType = -1;
+            const Vec3d  ptOnTri  = closestPointOnTriangle(pos, a, b, c, caseType);
+            const double sqrDist  = (ptOnTri - pos).squaredNorm();
+            if (sqrDist < minDistSqr)
+            {
+                minDistSqr   = sqrDist;
+                closestPt    = ptOnTri;
+                closestCellI = j;
+            }
+        }
+
+        // Compute interpolate value
+        const Vec3i& closestCell = srcCells[closestCellI];
+        const Vec2f& va  = inputTexCoords[closestCell[0]];
+        const Vec2f& vb  = inputTexCoords[closestCell[1]];
+        const Vec2f& vc  = inputTexCoords[closestCell[2]];
+        const Vec3d& a   = srcVertices[closestCell[0]];
+        const Vec3d& b   = srcVertices[closestCell[1]];
+        const Vec3d& c   = srcVertices[closestCell[2]];
+        const Vec3d  uvw = baryCentric(closestPt, a, b, c);
+        const Vec2f  val = uvw[0] * va + uvw[1] * vb + uvw[2] * vc;
+        outputTexCoords[i] = val;
+    }
+}
+}
\ No newline at end of file
diff --git a/Source/Filtering/imstkSurfaceMeshTextureProject.h b/Source/Filtering/imstkSurfaceMeshTextureProject.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b8ae676526a0c561966d7fa1daf911fc418d5cb
--- /dev/null
+++ b/Source/Filtering/imstkSurfaceMeshTextureProject.h
@@ -0,0 +1,61 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+#pragma once
+
+#include "imstkGeometryAlgorithm.h"
+
+namespace imstk
+{
+class SurfaceMesh;
+
+///
+/// \class SurfaceMeshTextureProject
+///
+/// \brief This filter projects vertex texture attributes from one SurfaceMesh to
+/// another by finding the closest point on the source mesh and interpolating the
+/// results. This could later be expanded to arbitrary vertex attributes
+///
+class SurfaceMeshTextureProject : public GeometryAlgorithm
+{
+public:
+    SurfaceMeshTextureProject();
+    virtual ~SurfaceMeshTextureProject() override = default;
+
+public:
+    ///
+    /// \brief The mesh with attribute to put on the other
+    ///
+    void setSourceMesh(std::shared_ptr<SurfaceMesh> surfMesh);
+
+    ///
+    /// \brief The mesh to recieve the attribute
+    ///
+    void setDestMesh(std::shared_ptr<SurfaceMesh> destMesh);
+
+    ///
+    /// \brief destMesh copy with the attribute
+    ///
+    std::shared_ptr<SurfaceMesh> getOutputMesh();
+
+protected:
+    void requestUpdate() override;
+};
+}
\ No newline at end of file
diff --git a/Source/FilteringCore/CMakeLists.txt b/Source/FilteringCore/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8b9c7d72792dc9745ea2d76392f1e7bc04ee084c
--- /dev/null
+++ b/Source/FilteringCore/CMakeLists.txt
@@ -0,0 +1,16 @@
+#-----------------------------------------------------------------------------
+# Create target
+#-----------------------------------------------------------------------------
+file(GLOB hFiles *.h)
+file(GLOB cppFiles *cpp)
+
+include(imstkAddLibrary)
+imstk_add_library( FilteringCore
+  H_FILES
+    ${hFiles}
+  CPP_FILES
+    ${cppFiles}
+  DEPENDS
+    Geometry
+    DataStructures
+    ${VTK_LIBRARIES})
diff --git a/Source/Filtering/imstkGeometryAlgorithm.cpp b/Source/FilteringCore/imstkGeometryAlgorithm.cpp
similarity index 65%
rename from Source/Filtering/imstkGeometryAlgorithm.cpp
rename to Source/FilteringCore/imstkGeometryAlgorithm.cpp
index 132968c47ada8f241163eb4ea3727d1a8b54670f..8f11baac28f1a9dec888555bbd84d8047851928a 100644
--- a/Source/Filtering/imstkGeometryAlgorithm.cpp
+++ b/Source/FilteringCore/imstkGeometryAlgorithm.cpp
@@ -18,7 +18,9 @@
    limitations under the License.
 
 =========================================================================*/
+
 #include "imstkGeometryAlgorithm.h"
+#include "imstkGeometry.h"
 #include "imstkLogger.h"
 
 namespace imstk
@@ -70,4 +72,36 @@ GeometryAlgorithm::setNumberOfOutputPorts(size_t numPorts)
         }
     }
 }
+
+bool
+GeometryAlgorithm::checkInputRequirements(
+    const std::unordered_map<size_t, std::shared_ptr<Geometry>>& inputs,
+    const std::unordered_map<size_t, PortReq>& inputPortReqs)
+{
+    // Check input types
+    for (auto i : inputs)
+    {
+        const size_t portId = i.first;
+        if (i.second == nullptr)
+        {
+            LOG(WARNING) << "GeometryAlgorithm input " << portId << " missing!";
+            return false;
+        }
+
+        // If the user added a requirement for this port
+        if (inputPortReqs.count(portId) != 0)
+        {
+            // Check if it's valid
+            if (!inputPortReqs.at(portId).isValid(i.second))
+            {
+                LOG(WARNING) << "GeometryAlgorithm recieved invalid geometry type \"" <<
+                    inputs.at(portId)->getTypeName() << "\" in port " << portId;
+                /*LOG(WARNING) << "GeometryAlgorithm required port " << portId; <<
+                    " to be of type " << inputPortReqs.at(portId).validGeomName();*/
+                return false;
+            }
+        }
+    }
+    return true;
+}
 }
\ No newline at end of file
diff --git a/Source/Filtering/imstkGeometryAlgorithm.h b/Source/FilteringCore/imstkGeometryAlgorithm.h
similarity index 50%
rename from Source/Filtering/imstkGeometryAlgorithm.h
rename to Source/FilteringCore/imstkGeometryAlgorithm.h
index c7b8a4b196954f3c0e9f583c6d9ee2e15859f6b7..a2bc40ca71e9420420ccc20650265d09a2e1d635 100644
--- a/Source/Filtering/imstkGeometryAlgorithm.h
+++ b/Source/FilteringCore/imstkGeometryAlgorithm.h
@@ -20,6 +20,7 @@
 =========================================================================*/
 #pragma once
 
+#include "imstkLogger.h"
 #include "imstkMacros.h"
 
 #include <memory>
@@ -29,15 +30,64 @@ namespace imstk
 {
 class Geometry;
 
-// Base class for geometry algorithms
+///
+/// \class GeometryAlgorithm
+///
+/// \brief Base abstract class for geometry algorithms. GeometryAlgorithms take N input
+/// geometries and produce N output geometries. Sublcasses should implement requestUpdate
+/// to do algorithm logic. Subclasses may also setInputPortReq to require an input to be
+/// a certain type.
+///
 class GeometryAlgorithm
 {
+public:
+    ///
+    /// \brief Used for type erasure of the port requirements
+    /// \todo: Type names can't be deduced for abstract classes.
+    /// Would be nice to have static type name as well
+    ///
+    class PortReq
+    {
+    public:
+        struct BaseReq
+        {
+            virtual ~BaseReq() = default;
+            virtual bool isValid(std::shared_ptr<Geometry> geom) const = 0;
+            //virtual std::string name() const = 0;
+        };
+
+        template<typename T>
+        struct Requirement : public BaseReq
+        {
+            virtual ~Requirement() override = default;
+            bool isValid(std::shared_ptr<Geometry> geom) const override
+            {
+                return std::dynamic_pointer_cast<T>(geom) != nullptr;
+            }
+
+            //std::string name() const override
+            //{
+            //    T t; // Can't use
+            //    return t.getTypeName();
+            //}
+        };
+
+        std::shared_ptr<BaseReq> req = nullptr;
+
+    public:
+        PortReq() = default;
+
+        template<typename T>
+        PortReq(T*) : req(std::make_shared<Requirement<T>>()) { }
+
+        bool isValid(std::shared_ptr<Geometry> geom) const { return req->isValid(geom); }
+        //std::string validGeomName() const { return req->name(); }
+    };
+
 protected:
     GeometryAlgorithm() = default;
 
 public:
-    GeometryAlgorithm(const GeometryAlgorithm&)  = delete;
-    GeometryAlgorithm(const GeometryAlgorithm&&) = delete;
     virtual ~GeometryAlgorithm() = default;
 
 public:
@@ -74,11 +124,30 @@ protected:
     ///
     void setNumberOfOutputPorts(size_t numPorts);
 
+    ///
+    /// \brief Set a type requirement on the inputs, it will check when running
+    /// the algorithm and warn at runtime
+    ///
+    template<typename T>
+    void setInputPortReq(size_t port)
+    {
+        T* ptr = nullptr;
+        m_inputPortTypeReqs[port] = PortReq(ptr);
+    }
+
 public:
     //void modified() { this->m_modified = true; }
 
+    ///
+    /// \brief Do the actual algorithm
+    ///
     void update()
     {
+        if (!checkInputRequirements(m_inputs, m_inputPortTypeReqs))
+        {
+            LOG(WARNING) << "GeometryAlgorithm failed to run, inputs not satisfied";
+            return;
+        }
         //if (m_modified)
         //{
         requestUpdate();
@@ -87,9 +156,21 @@ public:
     }
 
 protected:
+    ///
+    /// \brief Check inputs are correct
+    /// \return true if all inputs match the requirements, false if not
+    ///
+    virtual bool checkInputRequirements(
+        const std::unordered_map<size_t, std::shared_ptr<Geometry>>& inputs,
+        const std::unordered_map<size_t, PortReq>& inputPortReqs);
+
+    ///
+    /// \brief Users can implement this for the logic to be run
+    ///
     virtual void requestUpdate() = 0;
 
 private:
+    std::unordered_map<size_t, PortReq> m_inputPortTypeReqs; // The desired types of the input
     std::unordered_map<size_t, std::shared_ptr<Geometry>> m_inputs;
     std::unordered_map<size_t, std::shared_ptr<Geometry>> m_outputs;
     //bool m_modified = true;
diff --git a/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp b/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp
index 1cea393266a5cd065a1481bf1e66b03df5fc30af..3e3338bdfc6c8fbbc6d79e9c9f862d9cc84b9afd 100644
--- a/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp
+++ b/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp
@@ -25,16 +25,23 @@
 namespace imstk
 {
 AnalyticalGeometry::AnalyticalGeometry(const std::string& name) : ImplicitGeometry(name),
-    m_position(WORLD_ORIGIN), m_positionPostTransform(WORLD_ORIGIN),
-    m_orientationAxis(UP_VECTOR), m_orientationAxisPostTransform(UP_VECTOR)
+    m_position(Vec3d::Zero()), m_positionPostTransform(Vec3d::Zero()),
+    m_orientation(Quatd::Identity()), m_orientationPostTransform(Quatd::Identity())
 {
 }
 
 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() << ")";
+    LOG(INFO) << "Position: (" <<
+        m_position.x() << ", " <<
+        m_position.y() << ", " <<
+        m_position.z() << ")";
+    LOG(INFO) << "Orientation: (" <<
+        m_orientation.x() << ", " <<
+        m_orientation.y() << ", " <<
+        m_orientation.z() << ", " <<
+        m_orientation.w();
 }
 
 Vec3d
@@ -67,31 +74,28 @@ AnalyticalGeometry::setPosition(const double x, const double y, const double z)
     this->setPosition(Vec3d(x, y, z));
 }
 
-Vec3d
-AnalyticalGeometry::getOrientationAxis(DataType type /* = DataType::PostTransform */)
+Quatd
+AnalyticalGeometry::getOrientation(DataType type)
 {
     if (type == DataType::PostTransform)
     {
         this->updatePostTransformData();
-        return m_orientationAxisPostTransform;
+        return m_orientationPostTransform;
     }
-    return m_orientationAxis;
+    return m_orientation;
 }
 
 void
-AnalyticalGeometry::setOrientationAxis(const Vec3d orientation)
+AnalyticalGeometry::setOrientation(const Quatd r)
 {
-    if (orientation == Vec3d::Zero())
+    // Two quats can represent the same rotation, check coeffs
+    // for true difference
+    if (m_orientation.coeffs() == r.coeffs())
     {
-        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_orientation      = r;
     m_transformApplied = false;
     this->postModified();
 }
@@ -100,14 +104,13 @@ void
 AnalyticalGeometry::applyTransform(const Mat4d& m)
 {
     this->setPosition((m * Vec4d(m_position[0], m_position[1], m_position[2], 1.0)).head<3>());
-    this->setOrientationAxis((m * Vec4d(m_orientationAxis[0], m_orientationAxis[1], m_orientationAxis[2], 0.0)).head<3>());
+    this->setOrientation((m_orientation * Quatd(m.block<3, 3>(0, 0))).normalized());
 }
 
 void
 AnalyticalGeometry::updatePostTransformData() const
 {
-    m_orientationAxisPostTransform = (m_transform * Vec4d(m_orientationAxis[0], m_orientationAxis[1], m_orientationAxis[2], 0.0)).head<3>();
-    m_orientationAxisPostTransform.normalize();
-    m_positionPostTransform = (m_transform * Vec4d(m_position[0], m_position[1], m_position[2], 1.0)).head<3>();
+    m_positionPostTransform    = (m_transform * Vec4d(m_position[0], m_position[1], m_position[2], 1.0)).head<3>();
+    m_orientationPostTransform = (Quatd(getRotation()) * m_orientation).normalized();
 }
 } // imstk
diff --git a/Source/Geometry/Analytic/imstkAnalyticalGeometry.h b/Source/Geometry/Analytic/imstkAnalyticalGeometry.h
index d96f06427628fc8c17d2a6757745b504cb2c7689..1828347b97602d1f9850900df85259e9fdf6e29d 100644
--- a/Source/Geometry/Analytic/imstkAnalyticalGeometry.h
+++ b/Source/Geometry/Analytic/imstkAnalyticalGeometry.h
@@ -44,30 +44,52 @@ public:
     // Accessors
 
     ///
-    /// \brief Get/Set position
+    /// \brief Get the local or global position (post transformed)
     ///
     Vec3d getPosition(DataType type = DataType::PostTransform);
+
+    ///
+    /// \brief Set the local position
+    ///
     void setPosition(const Vec3d p);
     void setPosition(const double x, const double y, const double z);
 
     ///
-    /// \brief Get/Set orientation axis
+    /// \brief Get the local or globa orientation (post transformed)
     ///
-    Vec3d getOrientationAxis(DataType type = DataType::PostTransform);
-    void setOrientationAxis(const Vec3d axis);
+    Quatd getOrientation(DataType type = DataType::PostTransform);
 
+    ///
+    /// \brief Set the local orientation
+    ///
+    void setOrientation(const Quatd r);
+
+    ///
+    /// \brief Returns the implicit function value, this could signed, unsigned distance,
+    /// or some other scalar.
+    /// \param Position in global space
+    /// Note: Called frequently and often in parallel
+    ///
     double getFunctionValue(const Vec3d& imstkNotUsed(pos)) const override { return 0.0; }
 
+    ///
+    /// \brief Apply the global transform to the local parameters producing post
+    /// transformed parameters.
+    ///
+    void updatePostTransformData() const override;
+
 protected:
     AnalyticalGeometry(const std::string& name = std::string(""));
 
+    ///
+    /// \brief Apply a user transform directly to (pre-transformed) parameters producing
+    /// new parameters.
+    ///
     virtual void applyTransform(const Mat4d& m) override;
-    virtual void updatePostTransformData() const override;
-
-    Vec3d m_position;                             ///> position
-    mutable Vec3d m_positionPostTransform;        ///> position once transform applied
 
-    Vec3d m_orientationAxis;                      ///> orientation
-    mutable Vec3d m_orientationAxisPostTransform; ///> orientation once transform applied
+    Vec3d m_position;                         ///> position
+    mutable Vec3d m_positionPostTransform;    ///> position once transform applied
+    Quatd m_orientation;                      ///> orientation
+    mutable Quatd m_orientationPostTransform; ///> orientation once transform is applied
 };
 } //imstk
diff --git a/Source/Geometry/Analytic/imstkCapsule.cpp b/Source/Geometry/Analytic/imstkCapsule.cpp
index 35f5bbbca6c7b7556e414192d7f869a220daedc8..77cf2631b918186df123ff2c53b1028c8e3d6cf6 100644
--- a/Source/Geometry/Analytic/imstkCapsule.cpp
+++ b/Source/Geometry/Analytic/imstkCapsule.cpp
@@ -78,7 +78,8 @@ double
 Capsule::getFunctionValue(const Vec3d& x) const
 {
     // Two lines points
-    const Vec3d a = m_positionPostTransform + 0.5 * m_orientationAxisPostTransform * m_lengthPostTransform;
+    const Vec3d orientationAxes = getRotation().col(1);
+    const Vec3d a = m_positionPostTransform + 0.5 * orientationAxes * m_lengthPostTransform;
     const Vec3d b = 2.0 * m_positionPostTransform - a;
 
     const Vec3d  pa = x - a;
@@ -91,13 +92,12 @@ void
 Capsule::applyTransform(const Mat4d& m)
 {
     AnalyticalGeometry::applyTransform(m);
-    /* const Vec3d s = Vec3d(
-         m.block<3, 1>(0, 0).norm(),
-         m.block<3, 1>(0, 1).norm(),
-         m.block<3, 1>(0, 2).norm());*/
-    const double s0 = m.block<3, 1>(0, 0).norm();
-    this->setRadius(m_radius * s0);
-    this->setLength(m_length * s0);
+    const double s = std::sqrt(Vec3d(
+         m.block<3, 1>(0, 0).squaredNorm(),
+         m.block<3, 1>(0, 1).squaredNorm(),
+         m.block<3, 1>(0, 2).squaredNorm()).maxCoeff());
+    this->setRadius(m_radius * s);
+    this->setLength(m_length * s);
     this->postModified();
 }
 
@@ -109,9 +109,9 @@ Capsule::updatePostTransformData() const
         return;
     }
     AnalyticalGeometry::updatePostTransformData();
-    const double s0 = m_transform.block<3, 1>(0, 0).norm();
-    m_radiusPostTransform = s0 * m_radius;
-    m_lengthPostTransform = s0 * m_length;
+    const double s = getScaling().maxCoeff();
+    m_radiusPostTransform = s * m_radius;
+    m_lengthPostTransform = s * m_length;
     m_transformApplied    = true;
 }
 
@@ -120,7 +120,8 @@ Capsule::computeBoundingBox(Vec3d& min, Vec3d& max, const double imstkNotUsed(pa
 {
     updatePostTransformData();
 
-    const Vec3d l  = (m_lengthPostTransform * 0.5 + m_radiusPostTransform) * m_orientationAxisPostTransform;
+    const Vec3d orientationAxes = getRotation().col(1);
+    const Vec3d l  = (m_lengthPostTransform * 0.5 + m_radiusPostTransform) * orientationAxes;
     const Vec3d p1 = m_positionPostTransform - l;
     const Vec3d p2 = m_positionPostTransform + l;
 
diff --git a/Source/Geometry/Analytic/imstkCapsule.h b/Source/Geometry/Analytic/imstkCapsule.h
index 3ed969530c6a2c7732faeb1f8fb87296388e2a50..1100bdc841b57e9767ebb8c3d32c69c056de67e4 100644
--- a/Source/Geometry/Analytic/imstkCapsule.h
+++ b/Source/Geometry/Analytic/imstkCapsule.h
@@ -28,7 +28,7 @@ namespace imstk
 ///
 /// \class Capsule
 ///
-/// \brief Capsule geometry
+/// \brief Capsule geometry, default configuration is at origin with length running up the y axes
 ///
 class Capsule : public AnalyticalGeometry
 {
@@ -36,7 +36,15 @@ public:
     ///
     /// \brief Constructor
     ///
-    Capsule(const std::string& name = std::string("defaultCapsule")) : AnalyticalGeometry(name) { }
+    Capsule(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double radius = 0.5, const double length = 1.0, const Quatd orientation = Quatd::Identity(),
+            const std::string& name = std::string("defaultCapsule")) :
+        AnalyticalGeometry(name)
+    {
+        setPosition(pos);
+        setOrientation(orientation);
+        setRadius(radius);
+        setLength(length);
+    }
 
     ///
     /// \brief Deconstructor
@@ -89,9 +97,13 @@ public:
     ///
     void computeBoundingBox(Vec3d& min, Vec3d& max, const double paddingPercent);
 
+    ///
+    /// \brief Update the Capsule parameters applying the latest transform
+    ///
+    void updatePostTransformData() const override;
+
 protected:
     void applyTransform(const Mat4d& m) override;
-    void updatePostTransformData() const override;
 
     double m_radius = 1.0;                      ///> Radius of the hemispheres at the end of the capsule
     mutable double m_radiusPostTransform = 1.0; ///> Radius after transform
diff --git a/Source/Geometry/Analytic/imstkCube.cpp b/Source/Geometry/Analytic/imstkCube.cpp
deleted file mode 100644
index 8502421ca76e35c0f0a7bcb109f5af1dacb31b52..0000000000000000000000000000000000000000
--- a/Source/Geometry/Analytic/imstkCube.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*=========================================================================
-
-   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 "imstkCube.h"
-#include "imstkLogger.h"
-
-namespace imstk
-{
-void
-Cube::print() const
-{
-    Geometry::print();
-    LOG(INFO) << "Width: " << m_width;
-}
-
-double
-Cube::getWidth(DataType type /* = DataType::PostTransform */)
-{
-    if (type == DataType::PostTransform)
-    {
-        this->updatePostTransformData();
-        return m_widthPostTransform;
-    }
-    return m_width;
-}
-
-void
-Cube::setWidth(const double w)
-{
-    if (w <= 0)
-    {
-        LOG(WARNING) << "Cube::setWidth error: width should be positive.";
-        return;
-    }
-    if (m_width == w)
-    {
-        return;
-    }
-    m_width = w;
-    m_transformApplied = false;
-    this->postModified();
-}
-
-void
-Cube::applyTransform(const Mat4d& m)
-{
-    AnalyticalGeometry::applyTransform(m);
-    /*Vec3d s = Vec3d(
-        m_transform.block<3, 1>(0, 0).norm(),
-        m_transform.block<3, 1>(0, 1).norm(),
-        m_transform.block<3, 1>(0, 2).norm());*/
-    const double s0 = m.block<3, 1>(0, 0).norm();
-    this->setWidth(m_width * s0);
-    this->postModified();
-}
-
-void
-Cube::updatePostTransformData() const
-{
-    if (m_transformApplied)
-    {
-        return;
-    }
-    AnalyticalGeometry::updatePostTransformData();
-    const double s0 = m_transform.block<3, 1>(0, 0).norm();
-    m_widthPostTransform = s0 * m_width;
-    m_transformApplied   = true;
-}
-
-void
-Cube::computeBoundingBox(Vec3d& min, Vec3d& max, const double imstkNotUsed(paddingPercent))
-{
-    updatePostTransformData();
-
-    const Mat3d r = Quatd::FromTwoVectors(Vec3d(0.0, 1.0, 0.0), m_orientationAxisPostTransform).toRotationMatrix();
-
-    const Vec3d a = r.col(0) * m_widthPostTransform * 0.5;
-    const Vec3d b = r.col(1) * m_widthPostTransform * 0.5;
-    const Vec3d c = r.col(2) * m_widthPostTransform * 0.5;
-
-    Vec3d pts[8];
-    pts[0] = m_positionPostTransform + a + b + c;
-    pts[1] = m_positionPostTransform + a + b - c;
-    pts[2] = m_positionPostTransform + a - b + c;
-    pts[3] = m_positionPostTransform + a - b - c;
-    pts[4] = m_positionPostTransform - a + b + c;
-    pts[5] = m_positionPostTransform - a + b - c;
-    pts[6] = m_positionPostTransform - a - b + c;
-    pts[7] = m_positionPostTransform - a - b - c;
-
-    min = pts[0];
-    max = pts[0];
-    for (int i = 1; i < 8; i++)
-    {
-        min = min.cwiseMin(pts[i]);
-        max = max.cwiseMax(pts[i]);
-    }
-}
-} // imstk
diff --git a/Source/Geometry/Analytic/imstkCylinder.cpp b/Source/Geometry/Analytic/imstkCylinder.cpp
index 24c015083cbf908edb381daab8f5ec2289879d49..55a60bb7d72b61e67b37491235e4963bbc3c1816 100644
--- a/Source/Geometry/Analytic/imstkCylinder.cpp
+++ b/Source/Geometry/Analytic/imstkCylinder.cpp
@@ -57,7 +57,7 @@ Cylinder::getLength(DataType type /* = DataType::PostTransform */)
 void
 Cylinder::setRadius(const double r)
 {
-    CHECK(r > 0) << "Cylinder::setRadius error: radius should be positive.";
+    CHECK(r > 0) << "error: radius should be positive.";
 
     if (m_radius == r)
     {
@@ -74,7 +74,7 @@ Cylinder::setLength(const double l)
 {
     if (l <= 0)
     {
-        LOG(WARNING) << "Cylinder::setLength error: length should be positive.";
+        LOG(WARNING) << "error: length is negative.";
         return;
     }
     if (m_length == l)
@@ -90,13 +90,12 @@ void
 Cylinder::applyTransform(const Mat4d& m)
 {
     AnalyticalGeometry::applyTransform(m);
-    /*const Vec3d s = Vec3d(
-        m.block<3, 1>(0, 0).norm(),
-        m.block<3, 1>(0, 1).norm(),
-        m.block<3, 1>(0, 2).norm());*/
-    const double s0 = m.block<3, 1>(0, 0).norm();
-    this->setRadius(m_radius * s0);
-    this->setLength(m_length * s0);
+    const double s = std::sqrt(Vec3d(
+        m.block<3, 1>(0, 0).squaredNorm(),
+        m.block<3, 1>(0, 1).squaredNorm(),
+        m.block<3, 1>(0, 2).squaredNorm()).maxCoeff());
+    this->setRadius(m_radius * s);
+    this->setLength(m_length * s);
     this->postModified();
 }
 
@@ -108,9 +107,9 @@ Cylinder::updatePostTransformData() const
         return;
     }
     AnalyticalGeometry::updatePostTransformData();
-    const double s0 = m_transform.block<3, 1>(0, 0).norm();
-    m_radiusPostTransform = s0 * m_radius;
-    m_lengthPostTransform = s0 * m_length;
+    const double s = m_transform.block<3, 1>(0, 0).norm();
+    m_radiusPostTransform = s * m_radius;
+    m_lengthPostTransform = s * m_length;
     m_transformApplied    = true;
 }
 
@@ -119,7 +118,8 @@ Cylinder::computeBoundingBox(Vec3d& min, Vec3d& max, const double imstkNotUsed(p
 {
     updatePostTransformData();
 
-    const Vec3d d  = m_orientationAxisPostTransform * m_lengthPostTransform * 0.5;
+    const Vec3d orientationAxes = getRotation().transpose().col(1);
+    const Vec3d d  = orientationAxes * m_lengthPostTransform * 0.5;
     const Vec3d p1 = m_positionPostTransform - d;
     const Vec3d p2 = m_positionPostTransform + d;
 
diff --git a/Source/Geometry/Analytic/imstkCylinder.h b/Source/Geometry/Analytic/imstkCylinder.h
index 61038b1a0ace8a60f78705770cc07be519218fcc..c914abff337f8d18c9c724b11824e01ebecc82c7 100644
--- a/Source/Geometry/Analytic/imstkCylinder.h
+++ b/Source/Geometry/Analytic/imstkCylinder.h
@@ -28,7 +28,7 @@ namespace imstk
 ///
 /// \class Cylinder
 ///
-/// \brief Cylinder geometry
+/// \brief Cylinder geometry, default configuration is at origin with length running up the y axes
 ///
 class Cylinder : public AnalyticalGeometry
 {
@@ -37,11 +37,11 @@ public:
     /// \brief Constructor
     ///
     Cylinder(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double radius = 1.0, const double length = 1.0,
-             const Vec3d& orientationAxis = Vec3d(0.0, 1.0, 0.0), const std::string& name = std::string("defaultCylinder")) :
+             const Quatd& orientation = Quatd::Identity(), const std::string& name = std::string("defaultCylinder")) :
         AnalyticalGeometry(name)
     {
         setPosition(pos);
-        setOrientationAxis(orientationAxis);
+        setOrientation(orientation);
         setRadius(radius);
         setLength(length);
         updatePostTransformData();
@@ -90,12 +90,16 @@ public:
     ///
     void computeBoundingBox(Vec3d& min, Vec3d& max, const double paddingPercent);
 
+    ///
+    /// \brief Update the Cylinder parameters applying the latest transform
+    ///
+    void updatePostTransformData() const override;
+
 protected:
     // Hide these unimplemented functions
     using AnalyticalGeometry::getFunctionValue;
 
     void applyTransform(const Mat4d& m) override;
-    void updatePostTransformData() const override;
 
     double m_radius = 1.0;                      ///> Radius of the cylinder
     double m_length = 1.0;                      ///> Length of the cylinder
diff --git a/Source/Geometry/Analytic/imstkOrientedBox.cpp b/Source/Geometry/Analytic/imstkOrientedBox.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5f59c3dee5c00c7878f49bcb12d55bfc49097b44
--- /dev/null
+++ b/Source/Geometry/Analytic/imstkOrientedBox.cpp
@@ -0,0 +1,182 @@
+/*=========================================================================
+
+   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 "imstkOrientedBox.h"
+#include "imstkLogger.h"
+
+namespace imstk
+{
+void
+OrientedBox::print() const
+{
+    Geometry::print();
+    LOG(INFO) << "Extent0: " << m_extents[0];
+    LOG(INFO) << "Extent1: " << m_extents[1];
+    LOG(INFO) << "Extent2: " << m_extents[2];
+}
+
+Vec3d
+OrientedBox::getExtents(DataType type /* = DataType::PostTransform */)
+{
+    if (type == DataType::PostTransform)
+    {
+        this->updatePostTransformData();
+        return m_extentsPostTransform;
+    }
+    return m_extents;
+}
+
+void
+OrientedBox::setExtents(const Vec3d extents)
+{
+    if (extents[0] <= 0.0 || extents[1] <= 0.0 || extents[2] <= 0.0)
+    {
+        LOG(WARNING) << "error: extents should be positive.";
+        return;
+    }
+    if (m_extents == extents)
+    {
+        return;
+    }
+    m_extents = extents;
+    m_transformApplied = false;
+    this->postModified();
+}
+
+void
+OrientedBox::applyTransform(const Mat4d& m)
+{
+    AnalyticalGeometry::applyTransform(m);
+    Vec3d s = Vec3d(
+        m.block<3, 1>(0, 0).norm(),
+        m.block<3, 1>(0, 1).norm(),
+        m.block<3, 1>(0, 2).norm());
+    this->setExtents(m_extents.cwiseProduct(s));
+    this->postModified();
+}
+
+void
+OrientedBox::updatePostTransformData() const
+{
+    if (m_transformApplied)
+    {
+        return;
+    }
+    AnalyticalGeometry::updatePostTransformData();
+    const Vec3d s = getScaling();
+    m_extentsPostTransform = m_extents.cwiseProduct(s);
+    m_transformApplied     = true;
+}
+
+double
+OrientedBox::getFunctionValue(const Vec3d& pos) const
+{
+    const Mat3d  rot     = m_orientationPostTransform.toRotationMatrix();
+    const Vec3d& extents = m_extentsPostTransform;
+
+    const Vec3d diff   = (pos - m_positionPostTransform);
+    const Mat3d rotInv = rot.transpose();
+    const Vec3d proj   = rotInv * diff; // dot product/project onto each axes
+
+    bool inside[3] =
+    {
+        (std::abs(proj[0]) < extents[0]),
+        (std::abs(proj[1]) < extents[1]),
+        (std::abs(proj[2]) < extents[2])
+    };
+    bool isInsideCube = inside[0] && inside[1] && inside[2];
+
+    double signedDist = 0.0;
+    if (isInsideCube)
+    {
+        // If inside, find closest face, that is the signed distance
+        signedDist = std::numeric_limits<double>::lowest();
+        for (int i = 0; i < 3; i++)
+        {
+            double dist = proj[i];
+            if (dist < extents[i] && dist >= 0.0)
+            {
+                const double unsignedDistToSide = (extents[i] - dist);
+                if (-unsignedDistToSide > signedDist)
+                {
+                    signedDist = -unsignedDistToSide;
+                }
+            }
+            else if (dist > -extents[i] && dist < 0.0)
+            {
+                const double unsignedDistToSide = (extents[i] + dist);
+                if (-unsignedDistToSide > signedDist)
+                {
+                    signedDist = -unsignedDistToSide;
+                }
+            }
+        }
+    }
+    else
+    {
+        // If outside we need to also consider diagonal distance to corners and edges
+        // Compute nearest point
+        Vec3d closestPt = Vec3d::Zero();
+        Vec3d axialSignedDists = Vec3d::Zero();
+        for (int i = 0; i < 3; i++)
+        {
+            double dist = proj[i];
+
+            // If distance farther than the box extents, clamp to the box
+            if (dist >= extents[i] || dist <= -extents[i])
+            {
+                axialSignedDists[i] = std::abs(dist) - extents[i];
+            }
+        }
+        signedDist = axialSignedDists.norm();
+    }
+    return signedDist;
+}
+
+void
+OrientedBox::computeBoundingBox(Vec3d& min, Vec3d& max, const double imstkNotUsed(paddingPercent))
+{
+    updatePostTransformData();
+
+    const Mat3d r = m_orientationPostTransform.toRotationMatrix();
+    const Vec3d a = r.col(0) * m_extentsPostTransform[0];
+    const Vec3d b = r.col(1) * m_extentsPostTransform[1];
+    const Vec3d c = r.col(2) * m_extentsPostTransform[2];
+
+    Vec3d pts[8];
+    pts[0] = m_positionPostTransform + a + b + c;
+    pts[1] = m_positionPostTransform + a + b - c;
+    pts[2] = m_positionPostTransform + a - b + c;
+    pts[3] = m_positionPostTransform + a - b - c;
+    pts[4] = m_positionPostTransform - a + b + c;
+    pts[5] = m_positionPostTransform - a + b - c;
+    pts[6] = m_positionPostTransform - a - b + c;
+    pts[7] = m_positionPostTransform - a - b - c;
+
+    min = pts[0];
+    max = pts[0];
+    for (int i = 1; i < 8; i++)
+    {
+        min = min.cwiseMin(pts[i]);
+        max = max.cwiseMax(pts[i]);
+    }
+}
+} // imstk
diff --git a/Source/Geometry/Analytic/imstkCube.h b/Source/Geometry/Analytic/imstkOrientedBox.h
similarity index 51%
rename from Source/Geometry/Analytic/imstkCube.h
rename to Source/Geometry/Analytic/imstkOrientedBox.h
index 5edd398dfccc9ac3e1a4254822d3e02d2444f72b..af9737dec04224db9df21f3eb6b09694f0c67faa 100644
--- a/Source/Geometry/Analytic/imstkCube.h
+++ b/Source/Geometry/Analytic/imstkOrientedBox.h
@@ -25,30 +25,28 @@
 
 namespace imstk
 {
-class Cube;
-
 ///
-/// \class Cube
+/// \class OrientedBox
 ///
-/// \brief Cube geometry
+/// \brief OrientedBox geometry, specified with extents (half lengths)
 ///
-class Cube : public AnalyticalGeometry
+class OrientedBox : public AnalyticalGeometry
 {
 public:
-    Cube(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double width = 1.0, const Vec3d& orientationAxis = Vec3d(0.0, 1.0, 0.0),
-         const std::string& name = std::string("defaultCube")) : AnalyticalGeometry(name)
+    OrientedBox(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const Vec3d extents = Vec3d(0.5, 0.5, 0.5), const Quatd& orientation = Quatd::Identity(),
+                const std::string& name = std::string("defaultOrientedBox")) : AnalyticalGeometry(name)
     {
         setPosition(pos);
-        setOrientationAxis(orientationAxis);
-        setWidth(width);
+        setOrientation(orientation);
+        setExtents(extents);
     }
 
-    virtual ~Cube() override = default;
+    virtual ~OrientedBox() override = default;
 
     ///
     /// \brief Returns the string representing the type name of the geometry
     ///
-    virtual const std::string getTypeName() const override { return "Cube"; }
+    virtual const std::string getTypeName() const override { return "OrientedBox"; }
 
 public:
     ///
@@ -59,46 +57,42 @@ public:
     ///
     /// \brief Returns the volume of the cube
     ///
-    double getVolume() override { return m_width * m_width * m_width; }
+    virtual double getVolume() override { return m_extents[0] * m_extents[1] * m_extents[2] * 8.0; }
+
+    ///
+    /// \brief Returns the extents of the cube
+    ///
+    Vec3d getExtents(DataType type = DataType::PostTransform);
 
     ///
-    /// \brief Returns the width of the cube
+    /// \brief Sets the extents of the cube (half dimensions)
     ///
-    double getWidth(DataType type = DataType::PostTransform);
+    void setExtents(const Vec3d extents);
 
     ///
-    /// \brief Sets the width of the cube
+    /// \brief Sets the width of the cube (half dimensions)
     ///
-    void setWidth(const double w);
+    void setExtents(const double x, const double y, const double z) { setExtents(Vec3d(x, y, z)); }
 
     ///
     /// \brief Returns signed distance to surface at pos
-    /// \todo Doesn't support orientation yet
     ///
-    double getFunctionValue(const Vec3d& pos) const override
-    {
-        // Unrotate the point and cube to axes align the cube
-        const Mat3d r      = Quatd::FromTwoVectors(m_orientationAxisPostTransform, Vec3d(0.0, 1.0, 0.0)).toRotationMatrix();
-        const Vec3d p      = r * pos;
-        const Vec3d center = r * m_positionPostTransform;
-
-        // Then test
-        const Vec3d dmin = p - center - Vec3d(m_widthPostTransform, m_widthPostTransform, m_widthPostTransform) * 0.5;
-        const Vec3d dmax = center - p - Vec3d(m_widthPostTransform, m_widthPostTransform, m_widthPostTransform) * 0.5;
-        const Vec3d d    = dmin.cwiseMax(dmax);
-        return std::max(std::max(d[0], d[1]), d[2]);
-    }
+    double getFunctionValue(const Vec3d& pos) const override;
 
     ///
     /// \brief Get the min, max of the AABB around the cube
     ///
     void computeBoundingBox(Vec3d& min, Vec3d& max, const double paddingPercent = 0.0) override;
 
+    ///
+    /// \brief Update the Cube parameters applying the latest transform
+    ///
+    void updatePostTransformData() const override;
+
 protected:
     void applyTransform(const Mat4d& m) override;
-    void updatePostTransformData() const override;
 
-    double m_width = 1.0;                      ///> Width of the cube
-    mutable double m_widthPostTransform = 1.0; ///> Width of the cube once transform applied
+    Vec3d m_extents = Vec3d(0.5, 0.5, 0.5);                      // Half dimensions of the oriented box
+    mutable Vec3d m_extentsPostTransform = Vec3d(0.5, 0.5, 0.5); ///> Half dimensions of the oriented box once transform applied
 };
 }
diff --git a/Source/Geometry/Analytic/imstkPlane.cpp b/Source/Geometry/Analytic/imstkPlane.cpp
index 7172c191999fe9cf4233c0feb4bb14368f0b1c3b..697b49582e2c833f3d03cb53758cdf5b41ed241c 100644
--- a/Source/Geometry/Analytic/imstkPlane.cpp
+++ b/Source/Geometry/Analytic/imstkPlane.cpp
@@ -24,69 +24,58 @@
 
 namespace imstk
 {
-void
-Plane::print() const
-{
-    AnalyticalGeometry::print();
-    LOG(INFO) << "Width: " << m_width;
-}
-
 Vec3d
 Plane::getNormal(DataType type /* = DataType::PostTransform */)
 {
-    return this->getOrientationAxis(type);
+    if (type == DataType::PostTransform)
+    {
+        this->updatePostTransformData();
+        return m_normalPostTransform;
+    }
+    return m_normal;
 }
 
 void
 Plane::setNormal(const Vec3d n)
 {
-    this->setOrientationAxis(n);
+    // A normal with no direction would destroy the basis
+    // of the transform
+    if (m_normal == n || n.norm() == 0.0)
+    {
+        return;
+    }
+    m_normal = n.normalized();
+    m_transformApplied = false;
+    this->postModified();
 }
 
 void
-Plane::setNormal(double x, double y, double z)
+Plane::setNormal(const double x, const double y, const double z)
 {
     this->setNormal(Vec3d(x, y, z));
 }
 
 double
-Plane::getWidth(DataType type /* = DataType::PostTransform */)
+Plane::getWidth()
 {
-    if (type == DataType::PostTransform)
-    {
-        this->updatePostTransformData();
-        return m_widthPostTransform;
-    }
-    return m_width;
+    const Vec3d s = Vec3d(
+        m_transform.block<3, 1>(0, 0).squaredNorm(),
+        m_transform.block<3, 1>(0, 1).squaredNorm(),
+        m_transform.block<3, 1>(0, 2).squaredNorm());
+    double t = s.cwiseAbs().maxCoeff();
+    return std::sqrt(t);
 }
 
 void
 Plane::setWidth(const double w)
 {
-    if (w <= 0)
-    {
-        LOG(WARNING) << "Plane::setWidth error: width should be positive.";
-        return;
-    }
-    if (m_width == w)
-    {
-        return;
-    }
-    m_width = w;
-    m_transformApplied = false;
-    this->postModified();
+    setScaling(Vec3d(w, w, w));
 }
 
 void
 Plane::applyTransform(const Mat4d& m)
 {
     AnalyticalGeometry::applyTransform(m);
-    /* const Vec3d s = Vec3d(
-         m_transform.block<3, 1>(0, 0).norm(),
-         m_transform.block<3, 1>(0, 1).norm(),
-         m_transform.block<3, 1>(0, 2).norm());*/
-    const double s0 = m.block<3, 1>(0, 0).norm();
-    this->setWidth(m_width * s0);
     this->postModified();
 }
 
@@ -98,23 +87,24 @@ Plane::updatePostTransformData() const
         return;
     }
     AnalyticalGeometry::updatePostTransformData();
-    const double s0 = m_transform.block<3, 1>(0, 0).norm();
-    m_widthPostTransform = s0 * m_width;
-    m_transformApplied   = true;
+    m_normalPostTransform = m_orientation._transformVector(m_normal);
+    m_transformApplied    = true;
 }
 
 void
 Plane::computeBoundingBox(Vec3d& min, Vec3d& max, const double imstkNotUsed(paddingPercent))
 {
     updatePostTransformData();
-    const Quatd r = Quatd::FromTwoVectors(Vec3d(0.0, 1.0, 0.0), m_orientationAxisPostTransform);
-    const Vec3d i = r._transformVector(Vec3d(1.0, 0.0, 0.0));
-    const Vec3d j = r._transformVector(Vec3d(0.0, 0.0, 1.0));
-
-    const Vec3d p1 = m_positionPostTransform + m_widthPostTransform * (i + j);
-    const Vec3d p2 = m_positionPostTransform + m_widthPostTransform * (i - j);
-    const Vec3d p3 = m_positionPostTransform + m_widthPostTransform * (-i + j);
-    const Vec3d p4 = m_positionPostTransform + m_widthPostTransform * (-i - j);
+
+    Vec3d p1 = m_position + Vec3d(0.5, 0.0, 0.5);
+    Vec3d p2 = m_position + Vec3d(0.5, 0.0, -0.5);
+    Vec3d p3 = m_position + Vec3d(-0.5, 0.0, 0.5);
+    Vec3d p4 = m_position + Vec3d(-0.5, 0.0, -0.5);
+
+    p1 = (m_transform * Vec4d(p1[0], p1[1], p1[2], 1.0)).head<3>();
+    p2 = (m_transform * Vec4d(p2[0], p2[1], p2[2], 1.0)).head<3>();
+    p3 = (m_transform * Vec4d(p3[0], p3[1], p3[2], 1.0)).head<3>();
+    p4 = (m_transform * Vec4d(p4[0], p4[1], p4[2], 1.0)).head<3>();
 
     min = p1.cwiseMin(p2);
     min = min.cwiseMin(p3);
diff --git a/Source/Geometry/Analytic/imstkPlane.h b/Source/Geometry/Analytic/imstkPlane.h
index d0b6966e18bd0dbfd81a551d3b251ff6f0543d86..ac7b95b9a99585943efa0afd33203c2e7893b38a 100644
--- a/Source/Geometry/Analytic/imstkPlane.h
+++ b/Source/Geometry/Analytic/imstkPlane.h
@@ -56,11 +56,6 @@ public:
     virtual const std::string getTypeName() const override { return "Plane"; }
 
 public:
-    ///
-    /// \brief Print the plane info
-    ///
-    void print() const override;
-
     ///
     /// \brief Returns the normal of the plane
     ///
@@ -70,12 +65,12 @@ public:
     /// \brief Sets the normal to the plane
     ///
     void setNormal(const Vec3d n);
-    void setNormal(double x, double y, double z);
+    void setNormal(const double x, const double y, const double z);
 
     ///
-    /// \brief Returns the width of the plane
+    /// \brief Returns the width of the plane after transform
     ///
-    double getWidth(DataType type = DataType::PostTransform);
+    double getWidth();
 
     ///
     /// \brief Sets the width of the plane
@@ -85,18 +80,23 @@ public:
     ///
     /// \brief Returns signed distance to surface at pos
     ///
-    double getFunctionValue(const Vec3d& pos) const override { return m_orientationAxisPostTransform.dot(pos - m_positionPostTransform); }
+    double getFunctionValue(const Vec3d& pos) const override { return m_normalPostTransform.dot(pos - m_positionPostTransform); }
 
     ///
     /// \brief Get the min, max of the AABB around the plane
     ///
     void computeBoundingBox(Vec3d& min, Vec3d& max, const double paddingPercent = 0.0) override;
 
+    ///
+    /// \brief Update the Plane parameters applying the latest transform
+    ///
+    void updatePostTransformData() const override;
+
 protected:
     void applyTransform(const Mat4d& m) override;
-    void updatePostTransformData() const override;
 
-    double m_width = 1.0;                      ///> Width of the plane
-    mutable double m_widthPostTransform = 1.0; ///> Width of the plane once transform applied
+protected:
+    Vec3d m_normal;
+    mutable Vec3d m_normalPostTransform;
 };
 } // imstk
diff --git a/Source/Geometry/Analytic/imstkSphere.cpp b/Source/Geometry/Analytic/imstkSphere.cpp
index c24a30f61d2ea16c055ead9b50b438cc11666148..0ddd7b274a019318bb01d04b4eaa6b668e5f42e9 100644
--- a/Source/Geometry/Analytic/imstkSphere.cpp
+++ b/Source/Geometry/Analytic/imstkSphere.cpp
@@ -47,7 +47,7 @@ Sphere::setRadius(const double r)
 {
     if (r <= 0)
     {
-        LOG(WARNING) << "Sphere::setRadius error: radius should be positive.";
+        LOG(WARNING) << "error: radius supplied is negative";
         return;
     }
     if (std::abs(m_radius - r) < 1e-20)
diff --git a/Source/Geometry/Analytic/imstkSphere.h b/Source/Geometry/Analytic/imstkSphere.h
index a39a113e4661ca99faf597bc1ae99c435b7f7231..de22ad328d40aeed94474c174b18d7a2a1f07883 100644
--- a/Source/Geometry/Analytic/imstkSphere.h
+++ b/Source/Geometry/Analytic/imstkSphere.h
@@ -79,11 +79,15 @@ public:
     ///
     /// \brief Returns signed distance to surface given position
     ///
-    double getFunctionValue(const Vec3d& pos) const override { return (pos - m_position).norm() - m_radius; }
+    double getFunctionValue(const Vec3d& pos) const override { return (pos - m_positionPostTransform).norm() - m_radiusPostTransform; }
+
+    ///
+    /// \brief Update the Sphere parameters applying the latest transform
+    ///
+    void updatePostTransformData() const override;
 
 protected:
     void applyTransform(const Mat4d& m) override;
-    void updatePostTransformData() const override;
 
     double m_radius = 1.0;                      ///> Radius of the sphere
     mutable double m_radiusPostTransform = 1.0; ///> Radius of the sphere once transform applied
diff --git a/Source/Geometry/CMakeLists.txt b/Source/Geometry/CMakeLists.txt
index 08fd2950ae190bed849b024f7eb7be26193137cc..c545551dd9f9aeef9351b4453ed827ffbb944304 100644
--- a/Source/Geometry/CMakeLists.txt
+++ b/Source/Geometry/CMakeLists.txt
@@ -7,10 +7,13 @@ imstk_add_library( Geometry
     Common
     ${VTK_LIBRARIES})
 
+target_compile_options(Geometry PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/bigobj>)
+
 #-----------------------------------------------------------------------------
 # Testing
 #-----------------------------------------------------------------------------
 if( ${PROJECT_NAME}_BUILD_TESTING )
   include(imstkAddTest)
   imstk_add_test( Geometry )
+  target_compile_options(imstk_geometry_test_driver PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/bigobj>)
 endif()
diff --git a/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h
index 6dd2b3362094dfb9bfc0ba9b1cefb9ca0c7fe082..6c28aef182d8bbb222ecf19d369f4aa233266aab 100644
--- a/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h
+++ b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h
@@ -70,7 +70,11 @@ public:
     /// \param geometry to use
     /// \param boolean function type to use
     ///
-    void addImplicitGeometry(std::shared_ptr<ImplicitGeometry> geometry, const GeometryBoolType type) { geometries.push_back(GeometryBoolPair(geometry, type)); }
+    void addImplicitGeometry(std::shared_ptr<ImplicitGeometry> geometry, const GeometryBoolType type)
+    {
+        geometry->updatePostTransformData();
+        geometries.push_back(GeometryBoolPair(geometry, type));
+    }
 
 protected:
     std::list<GeometryBoolPair> geometries;
diff --git a/Source/Geometry/Implicit/imstkImplicitFunctionFiniteDifferenceFunctor.h b/Source/Geometry/Implicit/imstkImplicitFunctionFiniteDifferenceFunctor.h
index dd294b2b427004c7bd09d8ef502ffdab4dd26121..1545901a2e9c854cb48b780e29a659850f6ec04f 100644
--- a/Source/Geometry/Implicit/imstkImplicitFunctionFiniteDifferenceFunctor.h
+++ b/Source/Geometry/Implicit/imstkImplicitFunctionFiniteDifferenceFunctor.h
@@ -43,6 +43,7 @@ struct ImplicitFunctionGradient
         const Vec3d& getDx() const { return m_dx; }
 
         void setFunction(std::shared_ptr<ImplicitGeometry> func) { this->m_func = func; }
+        std::shared_ptr<ImplicitGeometry> getFunction() const { return m_func; }
 
     protected:
         std::shared_ptr<ImplicitGeometry> m_func;
diff --git a/Source/Geometry/Mesh/imstkHexahedralMesh.cpp b/Source/Geometry/Mesh/imstkHexahedralMesh.cpp
index bfd5ea366619202076e306400083039482509e1f..dca5df7156c4a78fb6f3a62a616e63f14d2ec5fd 100644
--- a/Source/Geometry/Mesh/imstkHexahedralMesh.cpp
+++ b/Source/Geometry/Mesh/imstkHexahedralMesh.cpp
@@ -33,16 +33,10 @@ HexahedralMesh::HexahedralMesh(const std::string& name) : VolumetricMesh(name),
 
 void
 HexahedralMesh::initialize(std::shared_ptr<VecDataArray<double, 3>> vertices,
-                           std::shared_ptr<VecDataArray<int, 8>> hexahedra,
-                           bool computeAttachedSurfaceMesh)
+                           std::shared_ptr<VecDataArray<int, 8>> hexahedra)
 {
     PointSet::initialize(vertices);
     this->setHexahedraIndices(hexahedra);
-
-    if (computeAttachedSurfaceMesh)
-    {
-        this->computeAttachedSurfaceMesh();
-    }
 }
 
 void
@@ -115,21 +109,11 @@ HexahedralMesh::getVolume()
     return volume / 6.0;
 }
 
-void
-HexahedralMesh::computeAttachedSurfaceMesh()
-{
-    this->m_attachedSurfaceMesh = std::make_shared<imstk::SurfaceMesh>();
-    if (!this->extractSurfaceMesh(this->m_attachedSurfaceMesh))
-    {
-        LOG(FATAL) << "HexahedralMesh::computeAttachedSurfaceMesh error: surface mesh was not extracted.";
-    }
-}
-
-bool
-HexahedralMesh::extractSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh)
+std::shared_ptr<SurfaceMesh>
+HexahedralMesh::extractSurfaceMesh()
 {
-    LOG(FATAL) << "HexahedralMesh::extractSurfaceMesh error: not implemented.";
-    return false;
+    LOG(WARNING) << "error: not implemented.";
+    return nullptr;
 }
 
 const Vec8i&
@@ -138,7 +122,7 @@ HexahedralMesh::getHexahedronIndices(const int hexaNum) const
     return (*m_hexahedraIndices)[hexaNum];
 }
 
-size_t
+int
 HexahedralMesh::getNumHexahedra() const
 {
     return m_hexahedraIndices->size();
diff --git a/Source/Geometry/Mesh/imstkHexahedralMesh.h b/Source/Geometry/Mesh/imstkHexahedralMesh.h
index 3c0c091ac7df9c6b3eca9d71b6b1acf66ed8900b..9c8f2eae8a0c84728b4ccffa49b616705a182420 100644
--- a/Source/Geometry/Mesh/imstkHexahedralMesh.h
+++ b/Source/Geometry/Mesh/imstkHexahedralMesh.h
@@ -54,8 +54,7 @@ public:
     ///  hexahedra connectivity
     ///
     void initialize(std::shared_ptr<VecDataArray<double, 3>> vertices,
-                    std::shared_ptr<VecDataArray<int, 8>> hexahedra,
-                    bool computeAttachedSurfaceMesh = false);
+                    std::shared_ptr<VecDataArray<int, 8>> hexahedra);
 
     ///
     /// \brief Clear all the mesh data
@@ -67,14 +66,9 @@ public:
     ///
     void print() const override;
 
-    ///
-    /// \brief Compute and set the attached surface mesh
-    ///
-    void computeAttachedSurfaceMesh() override;
-
     ///
     /// \brief Extract surface Mesh
-    bool extractSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh);
+    std::shared_ptr<SurfaceMesh> extractSurfaceMesh() override;
 
     ///
     /// \brief Returns true if the geometry is a mesh, else returns false
@@ -97,7 +91,7 @@ public:
     ///
     /// \brief Returns the number of hexahedra
     ///
-    size_t getNumHexahedra() const;
+    int getNumHexahedra() const;
 
     ///
     /// \brief Compute and return the volume of the hexahedral mesh
diff --git a/Source/Geometry/Mesh/imstkImageData.cpp b/Source/Geometry/Mesh/imstkImageData.cpp
index 91e35b1ee5f451871c7063a0c17d568e0538b7f5..5d51bb88eba9273897af87a8449a32e3235e3ea6 100644
--- a/Source/Geometry/Mesh/imstkImageData.cpp
+++ b/Source/Geometry/Mesh/imstkImageData.cpp
@@ -25,36 +25,6 @@
 
 namespace imstk
 {
-template<typename FROM_TYPE, typename TO_TYPE>
-static void
-castArray(std::shared_ptr<DataArray<FROM_TYPE>> fromArray, std::shared_ptr<DataArray<TO_TYPE>> toArray)
-{
-    const DataArray<FROM_TYPE>& fromArrayRef = *fromArray;
-    DataArray<TO_TYPE>&         toArrayRef   = *toArray;
-    const size_t                numVals      = fromArray->size();
-    for (size_t i = 0; i < numVals; i++)
-    {
-        toArrayRef[i] = static_cast<TO_TYPE>(fromArrayRef[i]);
-    }
-}
-
-template<typename FROM_TYPE>
-static void
-castImage(std::shared_ptr<AbstractDataArray> fromScalars, std::shared_ptr<ImageData> toImage)
-{
-    const ScalarType toType = toImage->getScalars()->getScalarType();
-    switch (toType)
-    {
-        TemplateMacro(castArray(
-            std::dynamic_pointer_cast<DataArray<FROM_TYPE>>(fromScalars),
-            std::dynamic_pointer_cast<DataArray<IMSTK_TT>>(toImage->getScalars())); );
-    default:
-        LOG(WARNING) << "Unknown scalar type";
-        break;
-    }
-    ;
-}
-
 ImageData::ImageData(const std::string& name)
     : PointSet(name),
     m_scalarArray(nullptr)
@@ -95,15 +65,9 @@ ImageData::cast(ScalarType toType)
 {
     // Create image of new type
     std::shared_ptr<ImageData> results = std::make_shared<ImageData>();
-    results->allocate(toType, m_numComps, m_dims, m_spacing, m_origin);
-    switch (m_scalarArray->getScalarType())
-    {
-        TemplateMacro(castImage<IMSTK_TT>(m_scalarArray, results); );
-    default:
-        LOG(WARNING) << "Unknown scalar type";
-        break;
-    }
-    ;
+    results->setOrigin(m_origin);
+    results->setSpacing(m_spacing);
+    results->setScalars(getScalars()->cast(toType), m_numComps, m_dims.data());
     return results;
 }
 
diff --git a/Source/Geometry/Mesh/imstkLineMesh.cpp b/Source/Geometry/Mesh/imstkLineMesh.cpp
index 0cb29668c2f29a51864676a9ddcc7bcae05ea418..97d2f82c0640cf0532ed20f2c3d8f45cd1cccf2e 100644
--- a/Source/Geometry/Mesh/imstkLineMesh.cpp
+++ b/Source/Geometry/Mesh/imstkLineMesh.cpp
@@ -63,7 +63,7 @@ LineMesh::print() const
     }
 }
 
-size_t
+int
 LineMesh::getNumLines() const
 {
     return m_segmentIndices->size();
diff --git a/Source/Geometry/Mesh/imstkLineMesh.h b/Source/Geometry/Mesh/imstkLineMesh.h
index f1be32b32742543c3c1f3c0d5d2dddcc32c12205..9e80dfd5d41f35a389ea0bc986da977f175537d4 100644
--- a/Source/Geometry/Mesh/imstkLineMesh.h
+++ b/Source/Geometry/Mesh/imstkLineMesh.h
@@ -79,7 +79,7 @@ public:
     ///
     /// \brief Get the number of segments/cells
     ///
-    size_t getNumLines() const;
+    int getNumLines() const;
 
     ///
     /// \brief Set the connectivity of the segments
diff --git a/Source/Geometry/Mesh/imstkPointSet.cpp b/Source/Geometry/Mesh/imstkPointSet.cpp
index a0f3926c8fc44d7e8324965ad07119fcab27d335..ced1539635fd3b02fba3f30fe4346ef927a359fe 100644
--- a/Source/Geometry/Mesh/imstkPointSet.cpp
+++ b/Source/Geometry/Mesh/imstkPointSet.cpp
@@ -153,7 +153,7 @@ PointSet::getVertexPosition(const size_t vertNum, DataType type)
     return (*this->getVertexPositions(type))[vertNum];
 }
 
-size_t
+int
 PointSet::getNumVertices() const
 {
     return m_vertexPositions->size();
@@ -271,7 +271,7 @@ PointSet::setVertexNormals(const std::string& arrayName)
 {
     if (hasVertexAttribute(arrayName))
     {
-        m_activeVertexNormals = arrayName;
+        setActiveVertexAttribute(m_activeVertexNormals, arrayName, 3, IMSTK_DOUBLE);
     }
 }
 
@@ -300,7 +300,7 @@ PointSet::setVertexTangents(const std::string& arrayName)
 {
     if (hasVertexAttribute(arrayName))
     {
-        m_activeVertexTangents = arrayName;
+        setActiveVertexAttribute(m_activeVertexTangents, arrayName, 3, IMSTK_FLOAT);
     }
 }
 
@@ -329,7 +329,7 @@ PointSet::setVertexTCoords(const std::string& arrayName)
 {
     if (hasVertexAttribute(arrayName))
     {
-        m_activeVertexTCoords = arrayName;
+        setActiveVertexAttribute(m_activeVertexTCoords, arrayName, 2, IMSTK_FLOAT);
     }
 }
 
@@ -345,4 +345,26 @@ PointSet::getVertexTCoords() const
         return nullptr;
     }
 }
-} // imstk
+
+void
+PointSet::setActiveVertexAttribute(std::string& activeAttributeName, std::string attributeName,
+                                   const int expectedNumComponents, const ScalarType expectedScalarType)
+{
+    std::shared_ptr<AbstractDataArray> attribute = m_vertexAttributes[attributeName];
+    if (attribute->getNumberOfComponents() != expectedNumComponents)
+    {
+        LOG(WARNING) << "Failed to set vertex attribute on " << getName() << " with "
+                     << attribute->getNumberOfComponents() << " components. Expected " <<
+            expectedNumComponents << " components.";
+        return;
+    }
+    else if (attribute->getScalarType() != expectedScalarType)
+    {
+        LOG(INFO) << "Tried to set vertex attribute on " << getName() << " with scalar type "
+                  << static_cast<int>(attribute->getScalarType()) << ". Casting to "
+                  << static_cast<int>(expectedScalarType) << " scalar type";
+        m_vertexAttributes[attributeName] = attribute->cast(expectedScalarType);
+    }
+    activeAttributeName = attributeName;
+}
+} // imstk
\ No newline at end of file
diff --git a/Source/Geometry/Mesh/imstkPointSet.h b/Source/Geometry/Mesh/imstkPointSet.h
index f13005850f23a47f72172541da46c047849ca6e9..c7d0765ba48e965c9018bd7461da29ce0bf81cfd 100644
--- a/Source/Geometry/Mesh/imstkPointSet.h
+++ b/Source/Geometry/Mesh/imstkPointSet.h
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "imstkGeometry.h"
+#include "imstkTypes.h"
 
 #include <unordered_map>
 
@@ -116,7 +117,7 @@ public:
     ///
     /// \brief Returns the number of total vertices in the mesh
     ///
-    size_t getNumVertices() const;
+    int getNumVertices() const;
 
     ///
     /// \brief Set load factor
@@ -128,7 +129,7 @@ public:
     ///
     /// \brief Get the maximum number of vertices
     ///
-    size_t getMaxNumVertices() const { return m_maxNumVertices; }
+    int getMaxNumVertices() const { return m_maxNumVertices; }
 
 // Attributes
 public:
@@ -200,6 +201,13 @@ protected:
     ///
     void applyTransform(const Mat4d& m) override;
 
+    ///
+    /// \brief Sets the active vertex attribute name as long as the # components is satisfied.
+    /// Throws message and casts if incorrect scalar type is provided.
+    ///
+    void setActiveVertexAttribute(std::string& activeAttributeName, const std::string attributeName,
+                                  const int expectedNumComponents, const ScalarType expectedScalarType);
+
     std::shared_ptr<VecDataArray<double, 3>> m_initialVertexPositions;
     std::shared_ptr<VecDataArray<double, 3>> m_vertexPositions;
 
@@ -210,7 +218,7 @@ protected:
     std::string m_activeVertexTCoords  = "";
 
     double m_loadFactor          = 2.0;
-    size_t m_maxNumVertices      = 0;
-    size_t m_originalNumVertices = 0;
+    int    m_maxNumVertices      = 0;
+    int    m_originalNumVertices = 0;
 };
 } // imstk
diff --git a/Source/Geometry/Mesh/imstkSurfaceMesh.cpp b/Source/Geometry/Mesh/imstkSurfaceMesh.cpp
index 728df2f7abd852420727984e423f7b57af198b3d..0103061dbf384422efb319b313c1514a9239c980 100644
--- a/Source/Geometry/Mesh/imstkSurfaceMesh.cpp
+++ b/Source/Geometry/Mesh/imstkSurfaceMesh.cpp
@@ -175,7 +175,7 @@ SurfaceMesh::computeTrianglesNormals()
     {
         if (m_triangleIndices->size() != triangleNormalsPtr->size())
         {
-            triangleNormalsPtr->resize(static_cast<int>(m_triangleIndices->size()));
+            triangleNormalsPtr->resize(m_triangleIndices->size());
         }
     }
     VecDataArray<double, 3>& triangleNormals = *triangleNormalsPtr;
@@ -210,7 +210,7 @@ SurfaceMesh::computeTriangleTangents()
         {
             if (m_triangleIndices->size() != triangleTangentsPtr->size())
             {
-                triangleTangentsPtr->resize(static_cast<int>(m_triangleIndices->size()));
+                triangleTangentsPtr->resize(m_triangleIndices->size());
             }
         }
         VecDataArray<double, 3>& triangleTangents = *triangleTangentsPtr;
@@ -471,7 +471,7 @@ SurfaceMesh::optimizeForDataLocality()
     this->initialize(optimallyOrderedNodalPos, optConnectivityRenumbered);
 }
 
-size_t
+int
 SurfaceMesh::getNumTriangles() const
 {
     return m_triangleIndices->size();
@@ -621,7 +621,7 @@ SurfaceMesh::computeUVSeamVertexGroups()
 void
 SurfaceMesh::deepCopy(std::shared_ptr<SurfaceMesh> srcMesh)
 {
-    // todo: Add deep copies to all geometry classes
+    // \todo: Add deep copies to all geometry classes
     // SurfaceMesh members
     this->m_triangleIndices = std::make_shared<VecDataArray<int, 3>>(*srcMesh->m_triangleIndices);
     this->m_vertexNeighborTriangles = srcMesh->m_vertexNeighborTriangles;
@@ -630,7 +630,7 @@ SurfaceMesh::deepCopy(std::shared_ptr<SurfaceMesh> srcMesh)
     {
         this->m_UVSeamVertexGroups[i.first] = std::make_shared<std::vector<size_t>>(*i.second);
     }
-    // todo: abstract DataArray's can't be copied
+    // \todo: abstract DataArray's can't be copied currently
     for (auto i : srcMesh->m_cellAttributes)
     {
         this->m_cellAttributes[i.first] = i.second;
@@ -644,7 +644,7 @@ SurfaceMesh::deepCopy(std::shared_ptr<SurfaceMesh> srcMesh)
     // PointSet members
     this->m_initialVertexPositions = std::make_shared<VecDataArray<double, 3>>(*srcMesh->m_initialVertexPositions);
     this->m_vertexPositions = std::make_shared<VecDataArray<double, 3>>(*srcMesh->m_vertexPositions);
-    // todo: abstract DataArray's can't be copied
+    // \todo: abstract DataArray's can't be copied currently
     for (auto i : srcMesh->m_vertexAttributes)
     {
         this->m_vertexAttributes[i.first] = i.second;
@@ -747,7 +747,7 @@ SurfaceMesh::setCellNormals(const std::string& arrayName)
 {
     if (hasCellAttribute(arrayName))
     {
-        m_activeCellNormals = arrayName;
+        setCellActiveAttribute(m_activeCellNormals, arrayName, 3, IMSTK_DOUBLE);
     }
 }
 
@@ -776,7 +776,7 @@ SurfaceMesh::setCellTangents(const std::string& arrayName)
 {
     if (hasCellAttribute(arrayName))
     {
-        m_activeCellTangents = arrayName;
+        setCellActiveAttribute(m_activeCellTangents, arrayName, 3, IMSTK_DOUBLE);
     }
 }
 
@@ -792,4 +792,26 @@ SurfaceMesh::getCellTangents() const
         return nullptr;
     }
 }
+
+void
+SurfaceMesh::setCellActiveAttribute(std::string& activeAttributeName, std::string attributeName,
+                                    const int expectedNumComponents, const ScalarType expectedScalarType)
+{
+    std::shared_ptr<AbstractDataArray> attribute = m_cellAttributes[attributeName];
+    if (attribute->getNumberOfComponents() != expectedNumComponents)
+    {
+        LOG(WARNING) << "Failed to set cell attribute on " << getName() << " with "
+                     << attribute->getNumberOfComponents() << " components. Expected " <<
+            expectedNumComponents << " components.";
+        return;
+    }
+    else if (attribute->getScalarType() != expectedScalarType)
+    {
+        LOG(INFO) << "Tried to set cell attribute on " << getName() << " with scalar type "
+                  << static_cast<int>(attribute->getScalarType()) << ". Casting to "
+                  << static_cast<int>(expectedScalarType) << " scalar type";
+        m_cellAttributes[attributeName] = attribute->cast(expectedScalarType);
+    }
+    activeAttributeName = attributeName;
+}
 }  // namespace imstk
diff --git a/Source/Geometry/Mesh/imstkSurfaceMesh.h b/Source/Geometry/Mesh/imstkSurfaceMesh.h
index bd51b227697a6aa4d159a05546bc002072e72cab..e5242a6453061f042707d8417606b6c0f6ae9a19 100644
--- a/Source/Geometry/Mesh/imstkSurfaceMesh.h
+++ b/Source/Geometry/Mesh/imstkSurfaceMesh.h
@@ -201,12 +201,12 @@ public:
     ///
     /// \brief Returns the number of triangles
     ///
-    size_t getNumTriangles() const;
+    int getNumTriangles() const;
 
     ///
     /// \brief Get the maximum number of triangles
     ///
-    size_t getMaxNumTriangles() const { return m_maxNumTriangles; }
+    int getMaxNumTriangles() const { return m_maxNumTriangles; }
 
     ///
     /// \brief Get the volume enclosed by the surface mesh
@@ -264,6 +264,10 @@ public:
     std::string getActiveCellTangents() const { return m_activeCellTangents; }
     std::shared_ptr<VecDataArray<double, 3>> getCellTangents() const;
 
+protected:
+    void setCellActiveAttribute(std::string& activeAttributeName, std::string attributeName,
+                                const int expectedNumComponents, const ScalarType expectedScalarType);
+
 protected:
     std::shared_ptr<VecDataArray<int, 3>> m_triangleIndices;
     std::vector<NeighborsType> m_vertexNeighborTriangles; ///> Neighbor triangles to vertices
@@ -276,7 +280,7 @@ protected:
     std::string m_activeCellTangents = "";
     std::string m_activeCellScalars  = "";
 
-    size_t m_originalNumTriangles = 0;
-    size_t m_maxNumTriangles      = 0;
+    int m_originalNumTriangles = 0;
+    int m_maxNumTriangles      = 0;
 };
 } // imstk
diff --git a/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp b/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp
index 08677ed5a4dc3fc3fca59fc821759822565439c1..6c2854593c49b05b54abdd1f28a6a950666c9136 100644
--- a/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp
+++ b/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp
@@ -33,17 +33,11 @@ TetrahedralMesh::TetrahedralMesh(const std::string& name) : VolumetricMesh(name)
 
 void
 TetrahedralMesh::initialize(std::shared_ptr<VecDataArray<double, 3>> vertices,
-                            std::shared_ptr<VecDataArray<int, 4>> tetrahedra,
-                            bool computeAttachedSurfaceMesh)
+                            std::shared_ptr<VecDataArray<int, 4>> tetrahedra)
 {
     PointSet::initialize(vertices);
     this->setTetrahedraIndices(tetrahedra);
 
-    if (computeAttachedSurfaceMesh)
-    {
-        this->computeAttachedSurfaceMesh();
-    }
-
     m_removedMeshElems.resize(tetrahedra->size(), false);
 }
 
@@ -70,66 +64,50 @@ TetrahedralMesh::print() const
 double
 TetrahedralMesh::getVolume()
 {
-    Vec3d                          v[4];
-    Mat4d                          A;
     double                         volume   = 0.0;
     const VecDataArray<double, 3>& vertices = *m_vertexPositions;
-    for (const Vec4i& tetIndices : *m_tetrahedraIndices)
+    for (const Vec4i& tet : *m_tetrahedraIndices)
     {
-        for (int i = 0; i < 4; ++i)
-        {
-            v[i] = vertices[tetIndices[i]];
-        }
-
-        A << v[0][0], v[0][1], v[0][2], 1, v[1][0], v[1][1], v[1][2], 1, v[2][0], v[2][1], v[2][2], 1, v[3][0], v[3][1], v[3][2], 1;
-
-        const double det = A.determinant();
-        if (det < 0)
+        const double tetVol = tetVolume(vertices[tet[0]], vertices[tet[1]], vertices[tet[2]], vertices[tet[3]]);
+        if (tetVol < 0.0)
         {
             LOG(WARNING) << "Tetrahedron is inverted, has negative volume!";
         }
-
-        volume += std::abs(det) / 6;
+        volume += tetVol;
     }
 
     return volume;
 }
 
-void
-TetrahedralMesh::computeAttachedSurfaceMesh()
-{
-    this->m_attachedSurfaceMesh = std::make_shared<SurfaceMesh>();
-
-    CHECK(this->extractSurfaceMesh(this->m_attachedSurfaceMesh))
-        << "TetrahedralMesh::computeAttachedSurfaceMesh error: surface mesh was not extracted.";
-}
-
-bool
-TetrahedralMesh::extractSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh,
-                                    const bool                   enforceWindingConsistency /* = false*/)
+std::shared_ptr<SurfaceMesh>
+TetrahedralMesh::extractSurfaceMesh()
 {
-    CHECK(surfaceMesh != nullptr)
-        << "TetrahedralMesh::extractSurfaceMesh error: the surface mesh provided is not instantiated.";
-
-    const std::vector<Vec3i> facePattern = {
+    const std::array<Vec3i, 4> facePattern = {
         Vec3i(0, 1, 2), Vec3i(0, 1, 3), Vec3i(0, 2, 3), Vec3i(1, 2, 3)
     };
+    const std::array<int, 4>   unusedVert = { 3, 2, 1, 0 };
 
     // Find and store the tetrahedral faces that are unique
-    const VecDataArray<int, 4>&           tetraIndices    = *this->getTetrahedraIndices();
-    std::shared_ptr<VecDataArray<int, 3>> triangleIndices = std::make_shared<VecDataArray<int, 3>>();
-    VecDataArray<int, 3>&                 surfaceTri      = *triangleIndices;
-    std::vector<size_t>                   surfaceTriTet;
-    std::vector<size_t>                   tetRemainingVert;
-    bool                                  unique;
-    int                                   foundAt, tetId = 0;
-    int                                   a, b, c;
+    const VecDataArray<int, 4>&              tetraIndices   = *this->getTetrahedraIndices();
+    std::shared_ptr<VecDataArray<double, 3>> tetVerticesPtr = getVertexPositions();
+    const VecDataArray<double, 3>&           tetVertices    = *tetVerticesPtr;
+    std::shared_ptr<VecDataArray<int, 3>>    triIndicesPtr  = std::make_shared<VecDataArray<int, 3>>();
+    VecDataArray<int, 3>&                    triIndices     = *triIndicesPtr;
+    //std::vector<size_t>                   surfaceTriTet;
+
+    // Gives surfaceTri id/faceid -> index of unused vert for face (4 verts per tet, one will be unused)
+    std::vector<size_t> tetRemainingVert;
 
+    bool unique;
+    int  foundAt;
+    int  a, b, c;
+
+    // For every tetrahedron
     for (int i = 0; i < tetraIndices.size(); i++)
     {
         const Vec4i& tet = tetraIndices[i];
-        // std::cout << "tet: " << tetId << std::endl;
 
+        // For every triangle face of the tetrahedron
         for (int t = 0; t < 4; ++t)
         {
             unique  = true;
@@ -138,10 +116,11 @@ TetrahedralMesh::extractSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh,
             b       = tet[facePattern[t][1]];
             c       = tet[facePattern[t][2]];
 
-            // search in reverse
-            for (int j = surfaceTri.size() - 1; j != -1; j--)
+            // Search in reverse for matching face (consider using hash/unordered or ordered binary tree instead)
+            for (int j = triIndices.size() - 1; j != -1; j--)
             {
-                const Vec3i& tri = surfaceTri[j];
+                const Vec3i& tri = triIndices[j];
+                // Checks all equivalence permutations
                 if (((tri[0] == a)
                      && ((tri[1] == b && tri[2] == c) || (tri[1] == c && tri[2] == b)))
                     || ((tri[1] == a)
@@ -155,78 +134,105 @@ TetrahedralMesh::extractSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh,
                 }
             }
 
+            // If not found yet, insert as potentially unique face
             if (unique)
             {
-                surfaceTri.push_back(Vec3i(a, b, c));
-                surfaceTriTet.push_back(tetId);
-                tetRemainingVert.push_back(static_cast<size_t>(3 - t));
+                triIndices.push_back(Vec3i(a, b, c));
+                //surfaceTriTet.push_back(tetId);
+                tetRemainingVert.push_back(tet[unusedVert[t]]);
             }
+            // If found, erase face, it is not unique anymore
             else
             {
-                surfaceTri.erase(foundAt);
+                triIndices.erase(foundAt);
+                tetRemainingVert.erase(tetRemainingVert.begin() + foundAt);
             }
         }
-        tetId++;
     }
+    // Finally we end up with a set of unique faces, surfaceTri
 
-    // Arrange the surface triangle faces found in order
-    Vec3d v0, v1, v2;
-    Vec3d centroid;
-    Vec3d normal;
-    for (size_t faceId = 0; faceId < surfaceTri.size(); ++faceId)
+    // Ensure all faces are have correct windings (such that interior vertex of the tet is inside)
+    for (int i = 0; i < triIndices.size(); i++)
     {
-        v0 = this->getVertexPosition(surfaceTri[faceId][0]);
-        v1 = this->getVertexPosition(surfaceTri[faceId][1]);
-        v2 = this->getVertexPosition(surfaceTri[faceId][2]);
-
-        centroid = (v0 + v1 + v2) / 3;
+        const Vec3d& v0       = tetVertices[triIndices[i][0]];
+        const Vec3d& v1       = tetVertices[triIndices[i][1]];
+        const Vec3d& v2       = tetVertices[triIndices[i][2]];
+        const Vec3d  normal   = ((v1 - v0).cross(v2 - v0));
+        const Vec3d  centroid = (v0 + v1 + v2) / 3.0;
 
-        normal = ((v0 - v1).cross(v0 - v2));
+        // Vertex that does not contribute to the face
+        const Vec3d unusedVertex = tetVertices[tetRemainingVert.at(i)];
 
-        if (normal.dot(centroid - this->getVertexPosition(tetRemainingVert.at(faceId))) > 0)
+        // If the normal is correct, it should be pointing in the same direction as the (face centroid-unusedVertex)
+        if (normal.dot(centroid - unusedVertex) < 0)
         {
-            std::swap(surfaceTri[faceId][2], surfaceTri[faceId][1]);
+            std::swap(triIndices[i][2], triIndices[i][1]);
         }
     }
 
-    // Renumber the vertices
-    std::list<int> uniqueVertIdList;
-    for (const auto& face : surfaceTri)
-    {
-        uniqueVertIdList.push_back(face[0]);
-        uniqueVertIdList.push_back(face[1]);
-        uniqueVertIdList.push_back(face[2]);
-    }
-    uniqueVertIdList.sort();
-    uniqueVertIdList.unique();
+    // All the existing triangles are still pointing to the old vertex buffer
+    // we need to reindex and make a new vertex buffer
 
-    int                                      vertId;
-    std::list<int>::iterator                 it;
-    std::shared_ptr<VecDataArray<double, 3>> vertPositions = std::make_shared<VecDataArray<double, 3>>();
-    for (vertId = 0, it = uniqueVertIdList.begin(); it != uniqueVertIdList.end(); ++vertId, it++)
+    // Create a map of old to new indices
+    std::unordered_map<int, int> oldToNewVertId;
+    for (int i = 0; i < triIndices.size(); i++)
     {
-        vertPositions->push_back(this->getVertexPosition(static_cast<size_t>(*it)));
-        for (auto& face : surfaceTri)
+        Vec3i& face = triIndices[i];
+
+        // If the vertex hasn't been reassigned
+        if (oldToNewVertId.count(face[0]) == 0)
         {
-            for (size_t i = 0; i < 3; ++i)
-            {
-                if (face[i] == *it)
-                {
-                    face[i] = vertId;
-                }
-            }
+            // Use size as new index
+            const int newVertexId = oldToNewVertId.size();
+            oldToNewVertId[face[0]] = newVertexId;
+            face[0] = newVertexId; // Relabel the old one
+        }
+        // If the vertex has already been reassigned
+        else
+        {
+            face[0] = oldToNewVertId[face[0]];
+        }
+
+        if (oldToNewVertId.count(face[1]) == 0)
+        {
+            const int newVertexId = oldToNewVertId.size();
+            oldToNewVertId[face[1]] = newVertexId;
+            face[1] = newVertexId;
+        }
+        else
+        {
+            face[1] = oldToNewVertId[face[1]];
+        }
+
+        if (oldToNewVertId.count(face[2]) == 0)
+        {
+            const int newVertexId = oldToNewVertId.size();
+            oldToNewVertId[face[2]] = newVertexId;
+            face[2] = newVertexId;
+        }
+        else
+        {
+            face[2] = oldToNewVertId[face[2]];
         }
     }
 
-    // Create and attach surface mesh
-    surfaceMesh->initialize(vertPositions, triangleIndices);
+    auto                     triVerticesPtr = std::make_shared<VecDataArray<double, 3>>(oldToNewVertId.size());
+    VecDataArray<double, 3>& triVertices    = *triVerticesPtr;
 
-    if (enforceWindingConsistency)
+    for (auto vertIndexPair : oldToNewVertId)
     {
-        surfaceMesh->correctWindingOrder();
+        const int tetVertId = vertIndexPair.first;
+        const int triVertId = vertIndexPair.second;
+        // Copy the vertex over
+        triVertices[triVertId] = tetVertices[tetVertId];
     }
 
-    return true;
+    // \todo: Copy over attributes (can't be done yet as type copying of data arrays is not possible)
+
+    // Create and attach surface mesh
+    auto surfMesh = std::make_shared<SurfaceMesh>();
+    surfMesh->initialize(triVerticesPtr, triIndicesPtr);
+    return surfMesh;
 }
 
 void
@@ -293,7 +299,7 @@ TetrahedralMesh::getTetrahedronIndices(const size_t tetId)
     return (*m_tetrahedraIndices)[tetId];
 }
 
-size_t
+int
 TetrahedralMesh::getNumTetrahedra() const
 {
     return m_tetrahedraIndices->size();
diff --git a/Source/Geometry/Mesh/imstkTetrahedralMesh.h b/Source/Geometry/Mesh/imstkTetrahedralMesh.h
index c21c0ec398d30a03d9a727a4aecf2dc3a7970119..16dab901ddb8a0a747c6c23e04e7a2dac8f858f4 100644
--- a/Source/Geometry/Mesh/imstkTetrahedralMesh.h
+++ b/Source/Geometry/Mesh/imstkTetrahedralMesh.h
@@ -61,8 +61,7 @@ public:
     ///  tetrahedra connectivity
     ///
     void initialize(std::shared_ptr<VecDataArray<double, 3>> vertices,
-                    std::shared_ptr<VecDataArray<int, 4>> tetrahedra,
-                    bool computeAttachedSurfaceMesh = false);
+                    std::shared_ptr<VecDataArray<int, 4>> tetrahedra);
 
     ///
     /// \brief Clear all the mesh data
@@ -75,18 +74,9 @@ public:
     void print() const override;
 
     ///
-    /// \brief Compute and set the attached surface mesh
+    /// \brief This method extracts the conforming triangular mesh from the tetrahedral mesh
     ///
-    void computeAttachedSurfaceMesh() override;
-
-    ///
-    /// \brief This method
-    /// (a) Extracts the confirming triangular mesh from the tetrahedral mesh
-    /// (b) Checks and flips the triangle connectivity order if it is not consistent
-    /// (c) Renumbers the vertices
-    /// (d) optionally enforces the consistency of winding of resulting surface triangles
-    ///
-    bool extractSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh, const bool enforceWindingConsistency = false);
+    std::shared_ptr<SurfaceMesh> extractSurfaceMesh() override;
 
     ///
     /// \brief compute the barycentric weights of a given point in 3D space for a given the tetrahedra
@@ -124,7 +114,7 @@ public:
     ///
     /// \brief Returns the number of tetrahedra
     ///
-    size_t getNumTetrahedra() const;
+    int getNumTetrahedra() const;
 
     ///
     /// \brief Get/set method for removed elements from the mesh
diff --git a/Source/Geometry/Mesh/imstkVolumetricMesh.cpp b/Source/Geometry/Mesh/imstkVolumetricMesh.cpp
deleted file mode 100644
index 163a29305ec95a0533992378bd313a2c08c1d339..0000000000000000000000000000000000000000
--- a/Source/Geometry/Mesh/imstkVolumetricMesh.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*=========================================================================
-
-   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 "imstkVolumetricMesh.h"
-#include "imstkLogger.h"
-
-namespace imstk
-{
-std::shared_ptr<SurfaceMesh>
-VolumetricMesh::getAttachedSurfaceMesh()
-{
-    if (m_attachedSurfaceMesh == nullptr)
-    {
-        LOG(WARNING) << "VolumetricMesh::getAttachedSurfaceMesh warning: attachedSurfaceMesh not set.\n"
-                     << "Extract a surface mesh to attach using computeAttachedSurfaceMesh().";
-    }
-    return m_attachedSurfaceMesh;
-}
-
-void
-VolumetricMesh::setAttachedSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh)
-{
-    m_attachedSurfaceMesh = surfaceMesh;
-}
-} // imstk
\ No newline at end of file
diff --git a/Source/Geometry/Mesh/imstkVolumetricMesh.h b/Source/Geometry/Mesh/imstkVolumetricMesh.h
index 4b9deb669851ae1f070b2154f6ff6bc60dad3445..1e663b78a7c855d64a08acdddb3722b243bb8451 100644
--- a/Source/Geometry/Mesh/imstkVolumetricMesh.h
+++ b/Source/Geometry/Mesh/imstkVolumetricMesh.h
@@ -42,23 +42,11 @@ public:
 
 public:
     ///
-    /// \brief Computes the attached surface mesh
+    /// \brief Compute the conforming surface mesh
     ///
-    virtual void computeAttachedSurfaceMesh() = 0;
-
-    ///
-    /// \brief Returns the attached surface mesh
-    ///
-    std::shared_ptr<SurfaceMesh> getAttachedSurfaceMesh();
-
-    ///
-    /// \brief Sets the surface mesh that is attached
-    ///
-    void setAttachedSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh);
+    virtual std::shared_ptr<SurfaceMesh> extractSurfaceMesh() { return nullptr; }
 
 protected:
     VolumetricMesh(const std::string& name = std::string("")) : PointSet(name) {}
-
-    std::shared_ptr<SurfaceMesh> m_attachedSurfaceMesh;          ///> Attached surface mesh
 };
 } // imstk
diff --git a/Source/Geometry/Testing/imstkCubeTest.cpp b/Source/Geometry/Testing/imstkCubeTest.cpp
deleted file mode 100644
index 8c0c8c2b45a10b88ef60c834fbbb30a796d16b5a..0000000000000000000000000000000000000000
--- a/Source/Geometry/Testing/imstkCubeTest.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*=========================================================================
-
-   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 "imstkCube.h"
-
-#include <gtest/gtest.h>
-
-using namespace imstk;
-
-class imstkCubeTest : public ::testing::Test
-{
-protected:
-    Cube m_cube;
-};
-
-///
-/// \brief TODO
-///
-TEST_F(imstkCubeTest, SetGetWidth)
-{
-    m_cube.setWidth(2);
-    EXPECT_EQ(m_cube.getWidth(), 2);
-
-    m_cube.setWidth(0.003);
-    EXPECT_EQ(m_cube.getWidth(), 0.003);
-
-    m_cube.setWidth(400000000);
-    EXPECT_EQ(m_cube.getWidth(), 400000000);
-
-    m_cube.setWidth(0);
-    EXPECT_GT(m_cube.getWidth(), 0);
-
-    m_cube.setWidth(-5);
-    EXPECT_GT(m_cube.getWidth(), 0);
-}
-
-///
-/// \brief TODO
-///
-TEST_F(imstkCubeTest, GetVolume)
-{
-    m_cube.setWidth(2);
-    EXPECT_EQ(m_cube.getVolume(), 8);
-
-    m_cube.setWidth(0.003);
-    EXPECT_EQ(m_cube.getVolume(), 0.003 * 0.003 * 0.003);
-
-    double w = 400000000;
-    m_cube.setWidth(400000000);
-    EXPECT_EQ(m_cube.getVolume(), w * w * w);
-}
-
-///
-/// \brief TODO
-///
-int
-imstkCubeTest(int argc, char* argv[])
-{
-    // Init Google Test & Mock
-    ::testing::InitGoogleTest(&argc, argv);
-
-    // Run tests with gtest
-    return RUN_ALL_TESTS();
-}
diff --git a/Source/Geometry/Testing/imstkImageDataTest.cpp b/Source/Geometry/Testing/imstkImageDataTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..59aa486cd7e49b4234f6ad7e2427df351454aadd
--- /dev/null
+++ b/Source/Geometry/Testing/imstkImageDataTest.cpp
@@ -0,0 +1,78 @@
+/*=========================================================================
+
+   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 "gtest/gtest.h"
+
+#include <memory>
+
+#include "imstkImageData.h"
+#include "imstkVecDataArray.h"
+#include "imstkMath.h"
+
+using namespace imstk;
+namespace
+{
+VecDataArray<double, 3> doubleArray = {
+    Vec3d{ 0, 0, 0 },
+    Vec3d{ 1, 1, 1 },
+    Vec3d{ 2, 2, 2 },
+    Vec3d{ 3, 3, 3 }
+};
+
+DataArray<int>    intScalars    = { 1, 2, 3, 4 };
+DataArray<double> doubleScalars = { 1.0, 2.0, 3.0, 4.0 };
+}
+
+TEST(imstkImageDataTest, Cast)
+{
+    Vec3i     dim     = { 2, 2, 0 };
+    Vec3d     spacing = { 1.0, 2.0, 3.0 };
+    Vec3d     origin  = { 4.0, 5.0, 6.0 };
+    ImageData img;
+    img.setScalars(std::make_shared<DataArray<int>>(intScalars), 1, dim.data());
+    img.setSpacing(spacing);
+    img.setOrigin(origin);
+    EXPECT_EQ(IMSTK_INT, img.getScalarType());
+
+    auto castImg    = img.cast(IMSTK_DOUBLE);
+    auto newScalars = castImg->getScalars();
+    EXPECT_EQ(IMSTK_DOUBLE, newScalars->getScalarType());
+    auto actualScalars = std::dynamic_pointer_cast<DataArray<double>>(newScalars);
+    EXPECT_TRUE(actualScalars != nullptr);
+    EXPECT_TRUE(dim.isApprox(castImg->getDimensions()));
+    EXPECT_TRUE(spacing.isApprox(castImg->getSpacing()));
+    EXPECT_TRUE(origin.isApprox(castImg->getOrigin()));
+
+    for (int i = 0; i < actualScalars->size(); ++i)
+    {
+        EXPECT_DOUBLE_EQ(static_cast<double>(intScalars[i]), (*actualScalars)[i]);
+    }
+}
+
+int
+imstkImageDataTest(int argc, char* argv[])
+{
+    // Init Google Test & Mock
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // Run tests with gtest
+    return RUN_ALL_TESTS();
+}
diff --git a/Source/Geometry/Testing/imstkOrientedBoxTest.cpp b/Source/Geometry/Testing/imstkOrientedBoxTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..90b3588fe31e23c3faf62ada4425faafa7600aef
--- /dev/null
+++ b/Source/Geometry/Testing/imstkOrientedBoxTest.cpp
@@ -0,0 +1,87 @@
+/*=========================================================================
+
+   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 "imstkOrientedBox.h"
+
+#include <gtest/gtest.h>
+
+using namespace imstk;
+
+class imstkOrientedBoxTest : public ::testing::Test
+{
+protected:
+    OrientedBox m_box;
+};
+
+///
+/// \brief TODO
+///
+TEST_F(imstkOrientedBoxTest, SetGetWidth)
+{
+    m_box.setExtents(1.0, 1.0, 1.0);
+    const Vec3d extents = m_box.getExtents();
+    EXPECT_DOUBLE_EQ(1.0, extents[0]);
+    EXPECT_DOUBLE_EQ(1.0, extents[1]);
+    EXPECT_DOUBLE_EQ(1.0, extents[2]);
+}
+
+///
+/// \brief TODO
+///
+TEST_F(imstkOrientedBoxTest, GetVolume)
+{
+    m_box.setExtents(1.0, 1.0, 1.0);
+    EXPECT_DOUBLE_EQ(8, m_box.getVolume());
+}
+
+///
+/// \brief test the cube SDF evaluator
+///
+TEST_F(imstkOrientedBoxTest, GetFunctionValue)
+{
+    m_box.setExtents(1.0, 1.0, 2.0);
+    m_box.updatePostTransformData();
+
+    EXPECT_DOUBLE_EQ(-1., m_box.getFunctionValue(Vec3d(0.0, 0.0, 0.0)));
+    EXPECT_DOUBLE_EQ(-0.5, m_box.getFunctionValue(Vec3d(0.5, 0.0, 0.0)));
+    EXPECT_DOUBLE_EQ(0.0, m_box.getFunctionValue(Vec3d(1.0, 1.0, 2.0)));
+    EXPECT_DOUBLE_EQ(9.0, m_box.getFunctionValue(Vec3d(0.0, -10.0, 0.0)));
+
+    m_box.rotate(Vec3d(1.0, 0.0, 0.0), 0.5 * PI);
+    m_box.updatePostTransformData();
+
+    EXPECT_DOUBLE_EQ(-1.0, m_box.getFunctionValue(Vec3d(0.0, 0.0, 0.0)));
+    EXPECT_DOUBLE_EQ(-0.5, m_box.getFunctionValue(Vec3d(0.5, 0.0, 0.0)));
+    EXPECT_DOUBLE_EQ(-0.5, m_box.getFunctionValue(Vec3d(0.0, -1.5, 0.0)));
+}
+
+///
+/// \brief TODO
+///
+int
+imstkOrientedBoxTest(int argc, char* argv[])
+{
+    // Init Google Test & Mock
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // Run tests with gtest
+    return RUN_ALL_TESTS();
+}
diff --git a/Source/Geometry/Testing/imstkPlaneTest.cpp b/Source/Geometry/Testing/imstkPlaneTest.cpp
index 579de4a2a641496671b715dc5a445961645e8630..779178e72c4edaeaf1ab642bf90745e8c4a2726c 100644
--- a/Source/Geometry/Testing/imstkPlaneTest.cpp
+++ b/Source/Geometry/Testing/imstkPlaneTest.cpp
@@ -40,19 +40,20 @@ protected:
 TEST_F(imstkPlaneTest, SetGetWidth)
 {
     m_plane.setWidth(2);
-    EXPECT_EQ(m_plane.getWidth(), 2);
+    EXPECT_DOUBLE_EQ(2, m_plane.getWidth());
 
     m_plane.setWidth(0.003);
-    EXPECT_EQ(m_plane.getWidth(), 0.003);
+    EXPECT_DOUBLE_EQ(0.003, m_plane.getWidth());
 
     m_plane.setWidth(400000000);
-    EXPECT_EQ(m_plane.getWidth(), 400000000);
+    EXPECT_DOUBLE_EQ(400000000.0, m_plane.getWidth());
 
-    m_plane.setWidth(0);
-    EXPECT_GT(m_plane.getWidth(), 0);
+    // Should not apply
+    m_plane.setWidth(0.0);
+    EXPECT_DOUBLE_EQ(400000000.0, m_plane.getWidth());
 
-    m_plane.setWidth(-5);
-    EXPECT_GT(m_plane.getWidth(), 0);
+    m_plane.setWidth(-5.0);
+    EXPECT_LT(-5.0, m_plane.getWidth());
 }
 
 ///
@@ -73,8 +74,8 @@ TEST_F(imstkPlaneTest, SetGetNormal)
     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)));
+    m_plane.setNormal(Vec3d::Zero());
+    EXPECT_FALSE(m_plane.getNormal().isApprox(Vec3d::Zero()));
 }
 
 ///
@@ -82,7 +83,30 @@ TEST_F(imstkPlaneTest, SetGetNormal)
 ///
 TEST_F(imstkPlaneTest, GetVolume)
 {
-    EXPECT_EQ(m_plane.getVolume(), 0);
+    EXPECT_DOUBLE_EQ(0, m_plane.getVolume());
+}
+
+///
+/// \brief test the plane SDF evaluator
+///
+TEST_F(imstkPlaneTest, GetFunctionValue)
+{
+    m_plane.setNormal(Vec3d(0., 1., 0.));
+    m_plane.updatePostTransformData();
+
+    EXPECT_DOUBLE_EQ(0., m_plane.getFunctionValue(Vec3d(0., 0., 0.)), );
+    EXPECT_DOUBLE_EQ(0., m_plane.getFunctionValue(Vec3d(0.5, 0., 0.)));
+    EXPECT_DOUBLE_EQ(1., m_plane.getFunctionValue(Vec3d(1., 1., 1.)));
+    EXPECT_DOUBLE_EQ(-10., m_plane.getFunctionValue(Vec3d(0., -10., 0.)));
+
+    m_plane.setPosition(Vec3d(1., 1., 1.));
+    m_plane.setNormal(Vec3d(1., 1., 1.));
+    m_plane.updatePostTransformData();
+
+    EXPECT_DOUBLE_EQ(-std::sqrt(3.0), m_plane.getFunctionValue(Vec3d(0., 0., 0.)));
+    EXPECT_DOUBLE_EQ(0.0, m_plane.getFunctionValue(Vec3d(1., 1., 1.)));
+    EXPECT_DOUBLE_EQ(-2.0 / std::sqrt(3.0), m_plane.getFunctionValue(Vec3d(1., 0., 0.)));
+    EXPECT_DOUBLE_EQ(-13.0 / std::sqrt(3.0), m_plane.getFunctionValue(Vec3d(0., -10., 0.)));
 }
 
 ///
diff --git a/Source/Geometry/Testing/imstkPointSetTest.cpp b/Source/Geometry/Testing/imstkPointSetTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7e9cf004f7887021e48d481b41ce657f717db3df
--- /dev/null
+++ b/Source/Geometry/Testing/imstkPointSetTest.cpp
@@ -0,0 +1,139 @@
+/*=========================================================================
+
+   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 "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+#include "imstkPointSet.h"
+#include "imstkVecDataArray.h"
+#include "imstkMath.h"
+
+using namespace imstk;
+
+namespace
+{
+auto floatArray3 = std::make_shared<VecDataArray<float, 3>>(VecDataArray<float, 3>({
+        Vec3f{ 0.0f, 0.1f, 0.2f },
+        Vec3f{ 1.0f, 1.1f, 1.2f },
+        Vec3f{ 2.0f, 2.1f, 2.2f },
+}));
+
+auto doubleArray3 = std::make_shared<VecDataArray<double, 3>>(VecDataArray<double, 3>({
+        Vec3d{ 0.0, 0.1, 0.2 },
+        Vec3d{ 1.0, 1.1, 1.2 },
+        Vec3d{ 2.0, 2.1, 2.2 },
+        Vec3d{ 3.0, 3.1, 3.2 },
+ }));
+
+auto floatArray2 = std::make_shared<VecDataArray<float, 2>>(VecDataArray<float, 2>({
+        Vec2f{ 0.0f, 0.1f },
+        Vec2f{ 1.0f, 1.1f },
+        Vec2f{ 2.0f, 2.1f },
+    }));
+
+auto doubleArray2 = std::make_shared<VecDataArray<double, 2>>(VecDataArray<double, 2>({
+        Vec2d{ 0.0, 0.1 },
+        Vec2d{ 1.0, 1.1 },
+        Vec2d{ 2.0, 2.1 },
+    }));
+
+std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>> attributes = {
+    { "float3", floatArray3 }, { "double3", doubleArray3 },
+    { "float2", floatArray2 }, { "double2", doubleArray2 }
+};
+}
+
+TEST(imstkPointSetTest, VertexNormalAttributes)
+{
+    PointSet p;
+    p.setVertexAttributes(attributes);
+    p.setVertexNormals("double3");
+    EXPECT_EQ(doubleArray3, p.getVertexNormals());
+
+    // Normals want doubles, test with floats
+    p.setVertexNormals("float3");
+    auto normals = p.getVertexNormals();
+    ASSERT_NE(nullptr, normals);
+    EXPECT_NE(floatArray3->getVoidPointer(), normals->getVoidPointer());
+    EXPECT_EQ(3, normals->size());
+    for (int i = 0; i < normals->size(); ++i)
+    {
+        EXPECT_TRUE((*floatArray3)[i].cast<double>().isApprox((*normals)[i]));
+    }
+
+    // This could work we'd need to make the DataArray a little bit more standards compliant
+    // EXPECT_THAT(*normals, ElementsAreArray(doubleArray3->begin(), doubleArray3->end()));
+    // HS 2021-apr-04 Death tests don't work with the current infrastructure
+    //ASSERT_DEATH(p.setVertexNormals("float2"), ".*");
+}
+
+TEST(imstkPointSetTest, VertexTangentAttributes)
+{
+    PointSet p;
+    p.setVertexAttributes(attributes);
+    p.setVertexTangents("float3");
+    EXPECT_EQ(floatArray3, p.getVertexTangents());
+
+    // Tangents want floats, test with doubles
+    p.setVertexTangents("double3");
+    auto tangents = p.getVertexTangents();
+    ASSERT_NE(nullptr, tangents);
+    EXPECT_NE(doubleArray3->getVoidPointer(), tangents->getVoidPointer());
+    EXPECT_EQ(4, tangents->size());
+    for (int i = 0; i < tangents->size(); ++i)
+    {
+        EXPECT_TRUE((*doubleArray3)[i].cast<float>().isApprox((*tangents)[i]));
+    }
+
+    // HS 2021-apr-04 Death tests don't work with the current infrastructure
+    //ASSERT_DEATH(p.setVertexTangents("float2"), ".*");
+}
+
+TEST(imstkPointSetTest, VertexTexCoordAttributes)
+{
+    PointSet p;
+    p.setVertexAttributes(attributes);
+    p.setVertexTCoords("float2");
+    EXPECT_EQ(floatArray2, p.getVertexTCoords());
+
+    // TexCoords wants floats, test with doubles
+    p.setVertexTCoords("double2");
+    auto tcoords = p.getVertexTCoords();
+    ASSERT_NE(nullptr, tcoords);
+    EXPECT_NE(doubleArray2->getVoidPointer(), tcoords->getVoidPointer());
+    for (int i = 0; i < tcoords->size(); ++i)
+    {
+        EXPECT_TRUE((*doubleArray2)[i].cast<float>().isApprox((*tcoords)[i]));
+    }
+
+    // HS 2021-apr-04 Death tests don't work with the current infrastructure
+    //ASSERT_DEATH(p.setVertexTangents("float2"), ".*");
+}
+
+int
+imstkPointSetTest(int argc, char* argv[])
+{
+    // Init Google Test & Mock
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // Run tests with gtest
+    return RUN_ALL_TESTS();
+}
diff --git a/Source/Geometry/Testing/imstkSphereTest.cpp b/Source/Geometry/Testing/imstkSphereTest.cpp
index 48de88d1dec9241842a6b3a584ba1b038e96999a..eca65ac7727b3f4c7d0b35786fb454dd42d9958e 100644
--- a/Source/Geometry/Testing/imstkSphereTest.cpp
+++ b/Source/Geometry/Testing/imstkSphereTest.cpp
@@ -40,32 +40,56 @@ protected:
 TEST_F(imstkSphereTest, SetGetRadius)
 {
     m_sphere.setRadius(2);
-    EXPECT_EQ(m_sphere.getRadius(), 2);
+    EXPECT_DOUBLE_EQ(2, m_sphere.getRadius());
 
     m_sphere.setRadius(0.003);
-    EXPECT_EQ(m_sphere.getRadius(), 0.003);
+    EXPECT_DOUBLE_EQ(0.003, m_sphere.getRadius());
 
     m_sphere.setRadius(400000000);
-    EXPECT_EQ(m_sphere.getRadius(), 400000000);
+    EXPECT_DOUBLE_EQ(400000000, m_sphere.getRadius());
 
     m_sphere.setRadius(0);
-    EXPECT_GT(m_sphere.getRadius(), 0);
+    EXPECT_LT(0, m_sphere.getRadius());
 
     m_sphere.setRadius(-5);
-    EXPECT_GT(m_sphere.getRadius(), 0);
+    EXPECT_LT(0, m_sphere.getRadius());
 }
 
 TEST_F(imstkSphereTest, GetVolume)
 {
     m_sphere.setRadius(2);
-    EXPECT_EQ(m_sphere.getVolume(), 4.0 / 3.0 * 8 * PI);
+    EXPECT_DOUBLE_EQ(4.0 / 3.0 * 8 * PI, m_sphere.getVolume());
 
     m_sphere.setRadius(0.003);
-    EXPECT_EQ(m_sphere.getVolume(), 4.0 / 3.0 * PI * 0.003 * 0.003 * 0.003);
+    EXPECT_DOUBLE_EQ(4.0 / 3.0 * PI * 0.003 * 0.003 * 0.003, m_sphere.getVolume());
 
     double r = 400000000;
     m_sphere.setRadius(400000000);
-    EXPECT_EQ(m_sphere.getVolume(), 4.0 / 3.0 * PI * r * r * r);
+    EXPECT_DOUBLE_EQ(4.0 / 3.0 * PI * r * r * r, m_sphere.getVolume());
+}
+
+///
+/// \brief test the sphere SDF evaluator
+///
+TEST_F(imstkSphereTest, GetFunctionValue)
+{
+    m_sphere.setRadius(20.);
+    m_sphere.updatePostTransformData();
+
+    EXPECT_DOUBLE_EQ(-20.0, m_sphere.getFunctionValue(Vec3d(0.0, 0.0, 0.0)));
+    EXPECT_DOUBLE_EQ(-15.0, m_sphere.getFunctionValue(Vec3d(5.0, 0.0, 0.0)));
+    EXPECT_DOUBLE_EQ(-20.0 + std::sqrt(3), m_sphere.getFunctionValue(Vec3d(1.0, 1.0, 1.0)));
+    EXPECT_DOUBLE_EQ(0.0, m_sphere.getFunctionValue(Vec3d(0.0, 20.0, 0.0)));
+    EXPECT_DOUBLE_EQ(30.0, m_sphere.getFunctionValue(Vec3d(0.0, 0.0, 50.0)));
+
+    m_sphere.rotate(Vec3d(1.0, 1.0, 0.0), 0.1 * PI);
+    m_sphere.updatePostTransformData();
+
+    EXPECT_DOUBLE_EQ(-20.0, m_sphere.getFunctionValue(Vec3d(0.0, 0.0, 0.0)));
+    EXPECT_DOUBLE_EQ(-15.0, m_sphere.getFunctionValue(Vec3d(5.0, 0.0, 0.0)));
+    EXPECT_DOUBLE_EQ(-20.0 + std::sqrt(3), m_sphere.getFunctionValue(Vec3d(1.0, 1.0, 1.0)));
+    EXPECT_NEAR(0., m_sphere.getFunctionValue(Vec3d(0.0, 20., 0.0)), 1.0e-10);
+    EXPECT_DOUBLE_EQ(30.0, m_sphere.getFunctionValue(Vec3d(0.0, 0.0, 50.0)));
 }
 
 ///
diff --git a/Source/Geometry/Testing/imstkSurfaceMeshTest.cpp b/Source/Geometry/Testing/imstkSurfaceMeshTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ad1e9ce1a74743e0f959885cba453f9230ff6925
--- /dev/null
+++ b/Source/Geometry/Testing/imstkSurfaceMeshTest.cpp
@@ -0,0 +1,201 @@
+/*=========================================================================
+
+   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 "imstkOrientedBox.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkMath.h"
+#include "imstkPointSet.h"
+#include "imstkSurfaceMesh.h"
+#include "imstkVecDataArray.h"
+
+#include <gtest/gtest.h>
+
+using namespace imstk;
+
+namespace
+{
+auto floatArray3 = std::make_shared<VecDataArray<float, 3>>(VecDataArray<float, 3>({
+        Vec3f{ 0.0f, 0.1f, 0.2f },
+        Vec3f{ 1.0f, 1.1f, 1.2f },
+        Vec3f{ 2.0f, 2.1f, 2.2f },
+    }));
+
+auto doubleArray3 = std::make_shared<VecDataArray<double, 3>>(VecDataArray<double, 3>({
+        Vec3d{ 0.0, 0.1, 0.2 },
+        Vec3d{ 1.0, 1.1, 1.2 },
+        Vec3d{ 2.0, 2.1, 2.2 },
+        Vec3d{ 3.0, 3.1, 3.2 },
+    }));
+
+auto floatArray2 = std::make_shared<VecDataArray<float, 2>>(VecDataArray<float, 2>({
+        Vec2f{ 0.0f, 0.1f },
+        Vec2f{ 1.0f, 1.1f },
+        Vec2f{ 2.0f, 2.1f },
+    }));
+
+auto doubleArray2 = std::make_shared<VecDataArray<double, 2>>(VecDataArray<double, 2>({
+        Vec2d{ 0.0, 0.1 },
+        Vec2d{ 1.0, 1.1 },
+        Vec2d{ 2.0, 2.1 },
+    }));
+
+std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>> attributes = {
+    { "float3", floatArray3 }, { "double3", doubleArray3 },
+    { "float2", floatArray2 }, { "double2", doubleArray2 }
+};
+}
+
+///
+/// \brief TODO
+///
+class imstkSurfaceMeshTest : public ::testing::Test
+{
+protected:
+    SurfaceMesh m_surfMesh;
+};
+
+TEST_F(imstkSurfaceMeshTest, CellNormalAttributes)
+{
+    m_surfMesh.setCellAttributes(attributes);
+    m_surfMesh.setCellNormals("double3");
+    EXPECT_EQ(doubleArray3, m_surfMesh.getCellNormals());
+
+    // Normals want doubles, test with floats
+    m_surfMesh.setCellNormals("float3");
+    auto normals = m_surfMesh.getCellNormals();
+    ASSERT_NE(nullptr, normals);
+    EXPECT_NE(floatArray3->getVoidPointer(), normals->getVoidPointer());
+    EXPECT_EQ(3, normals->size());
+    for (int i = 0; i < normals->size(); ++i)
+    {
+        EXPECT_TRUE((*floatArray3)[i].cast<double>().isApprox((*normals)[i]));
+    }
+
+    // This could work we'd need to make the DataArray a little bit more standards compliant
+    // EXPECT_THAT(*normals, ElementsAreArray(doubleArray3->begin(), doubleArray3->end()));
+    // HS 2021-apr-04 Death tests don't work with the current infrastructure
+    //ASSERT_DEATH(p.setVertexNormals("float2"), ".*");
+}
+
+TEST_F(imstkSurfaceMeshTest, CellTangentAttributes)
+{
+    m_surfMesh.setCellAttributes(attributes);
+    m_surfMesh.setCellTangents("double3");
+    EXPECT_EQ(doubleArray3, m_surfMesh.getCellTangents());
+
+    // Tangents want floats, test with doubles
+    m_surfMesh.setCellTangents("float3");
+    auto tangents = m_surfMesh.getCellTangents();
+    ASSERT_NE(nullptr, tangents);
+    EXPECT_NE(floatArray3->getVoidPointer(), tangents->getVoidPointer());
+    EXPECT_EQ(3, tangents->size());
+    for (int i = 0; i < tangents->size(); ++i)
+    {
+        EXPECT_TRUE((*floatArray3)[i].cast<double>().isApprox((*tangents)[i]));
+    }
+
+    // HS 2021-apr-04 Death tests don't work with the current infrastructure
+    //ASSERT_DEATH(p.setVertexTangents("float2"), ".*");
+}
+
+///
+/// \brief Tests the correct computation of face normals
+///
+TEST_F(imstkSurfaceMeshTest, ComputeTriangleNormals)
+{
+    // This is counter clockwise, when looking down on y, so normal should be directly up
+    // opengl coordinate system with -z going "out" from identity view
+    auto verticesPtr = std::make_shared<VecDataArray<double, 3>>(3);
+    (*verticesPtr)[0] = Vec3d(0.5, 0.0, -0.5);
+    (*verticesPtr)[1] = Vec3d(-0.5, 0.0, -0.5);
+    (*verticesPtr)[2] = Vec3d(0.0, 0.0, 0.5);
+
+    auto indicesPtr = std::make_shared<VecDataArray<int, 3>>(1);
+    (*indicesPtr)[0] = Vec3i(0, 1, 2);
+    m_surfMesh.initialize(verticesPtr, indicesPtr);
+
+    m_surfMesh.computeTrianglesNormals();
+    auto normalsPtr = m_surfMesh.getCellNormals();
+
+    EXPECT_NE(nullptr, normalsPtr);
+    EXPECT_EQ(1, normalsPtr->size());
+    EXPECT_EQ(Vec3d(0.0, 1.0, 0.0), (*normalsPtr)[0]);
+}
+
+TEST_F(imstkSurfaceMeshTest, ComputeVertexNormals)
+{
+    //
+    //   /|\
+    //  / | \
+    // //   \\
+    //
+    // Tests two triangles that share an edge
+    auto verticesPtr = std::make_shared<VecDataArray<double, 3>>(4);
+    (*verticesPtr)[0] = Vec3d(0.0, 0.0, -1.0);
+    (*verticesPtr)[1] = Vec3d(0.0, 0.0, 1.0);
+    (*verticesPtr)[2] = Vec3d(1.0, -1.0, 0.0);
+    (*verticesPtr)[3] = Vec3d(-1.0, -1.0, 0.0);
+
+    auto indicesPtr = std::make_shared<VecDataArray<int, 3>>(2);
+    (*indicesPtr)[0] = Vec3i(0, 1, 2);
+    (*indicesPtr)[1] = Vec3i(0, 3, 1);
+    m_surfMesh.initialize(verticesPtr, indicesPtr);
+
+    // Should make 45 degrees 1, 1 edge
+    m_surfMesh.computeVertexNormals();
+    auto normalsPtr = m_surfMesh.getVertexNormals();
+
+    const Vec3d results1 = Vec3d(1.0, 1.0, 0.0).normalized();
+    const Vec3d results2 = Vec3d(-1.0, 1.0, 0.0).normalized();
+
+    // Check the endpoint normals (these are summed to the face)
+    EXPECT_NEAR(results1[0], (*normalsPtr)[2][0], 0.00000001);
+    EXPECT_NEAR(results1[1], (*normalsPtr)[2][1], 0.00000001);
+    EXPECT_NEAR(results1[2], (*normalsPtr)[2][2], 0.00000001);
+
+    EXPECT_NEAR(results2[0], (*normalsPtr)[3][0], 0.00000001);
+    EXPECT_NEAR(results2[1], (*normalsPtr)[3][1], 0.00000001);
+    EXPECT_NEAR(results2[2], (*normalsPtr)[3][2], 0.00000001);
+
+    // Check the shared vertex normals which should point straight up
+    EXPECT_EQ(Vec3d(0.0, 1.0, 0.0), (*normalsPtr)[0]);
+    EXPECT_EQ(Vec3d(0.0, 1.0, 0.0), (*normalsPtr)[1]);
+}
+
+///
+/// \brief Tests the correct computation of volume
+///
+TEST_F(imstkSurfaceMeshTest, GetVolume)
+{
+    std::shared_ptr<SurfaceMesh> cubeSurfMesh =
+        GeometryUtils::toSurfaceMesh(std::make_shared<OrientedBox>());
+    EXPECT_NEAR(1.0, cubeSurfMesh->getVolume(), 0.0000000000001);
+}
+
+int
+imstkSurfaceMeshTest(int argc, char* argv[])
+{
+    // Init Google Test & Mock
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // Run tests with gtest
+    return RUN_ALL_TESTS();
+}
diff --git a/Source/Geometry/Testing/imstkTetrahedralMeshTest.cpp b/Source/Geometry/Testing/imstkTetrahedralMeshTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..13b323586a591e0d162b1f758ac46a80ef11d513
--- /dev/null
+++ b/Source/Geometry/Testing/imstkTetrahedralMeshTest.cpp
@@ -0,0 +1,139 @@
+/*=========================================================================
+
+   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 "imstkSurfaceMesh.h"
+#include "imstkTetrahedralMesh.h"
+#include "imstkVecDataArray.h"
+
+#include <gtest/gtest.h>
+
+using namespace imstk;
+
+///
+/// \brief TODO
+///
+class imstkTetrahedralMeshTest : public ::testing::Test
+{
+protected:
+    TetrahedralMesh m_tetMesh;
+};
+
+///
+/// \brief Test the mesh extraction of a cube
+///
+TEST_F(imstkTetrahedralMeshTest, ExtractSurfaceMesh)
+{
+    // Setup a cube
+    //    0-------1
+    //   /|      /|
+    //  / |     / |
+    // 3--|----2  |
+    // |  4----|--5    +y +z
+    // | /     | /     | /
+    // 7-------6       |/__+x
+    {
+        auto verticesPtr = std::make_shared<VecDataArray<double, 3>>(8);
+        auto indicesPtr  = std::make_shared<VecDataArray<int, 4>>(5);
+
+        VecDataArray<double, 3>& vertices = *verticesPtr;
+        VecDataArray<int, 4>&    indices  = *indicesPtr;
+
+        vertices[0] = Vec3d(-0.5, 0.5, 0.5);
+        vertices[1] = Vec3d(0.5, 0.5, 0.5);
+        vertices[2] = Vec3d(0.5, 0.5, -0.5);
+        vertices[3] = Vec3d(-0.5, 0.5, -0.5);
+        vertices[4] = Vec3d(-0.5, -0.5, 0.5);
+        vertices[5] = Vec3d(0.5, -0.5, 0.5);
+        vertices[6] = Vec3d(0.5, -0.5, -0.5);
+        vertices[7] = Vec3d(-0.5, -0.5, -0.5);
+
+        indices[0] = Vec4i(0, 7, 5, 4);
+        indices[1] = Vec4i(3, 7, 2, 0);
+        indices[2] = Vec4i(2, 7, 5, 0);
+        indices[3] = Vec4i(1, 2, 0, 5);
+        indices[4] = Vec4i(2, 6, 7, 5);
+
+        m_tetMesh.initialize(verticesPtr, indicesPtr);
+    }
+
+    // Extract the surface
+    std::shared_ptr<SurfaceMesh>             surfMesh = m_tetMesh.extractSurfaceMesh();
+    std::shared_ptr<VecDataArray<double, 3>> surfVerticesPtr = surfMesh->getVertexPositions();
+    std::shared_ptr<VecDataArray<int, 3>>    surfIndicesPtr  = surfMesh->getTriangleIndices();
+    VecDataArray<double, 3>&                 surfVertices    = *surfVerticesPtr;
+    VecDataArray<int, 3>&                    surfIndices     = *surfIndicesPtr;
+
+    // There should be 12 faces and 8 verts of the cube
+    ASSERT_EQ(12, surfIndices.size());
+    ASSERT_EQ(8, surfVertices.size());
+
+    // To test the winding direction of the faces we'll use the normals
+    for (int i = 0; i < surfIndices.size(); i++)
+    {
+        const Vec3i& face     = surfIndices[i];
+        const Vec3d  centroid = (surfVertices[face[0]] + surfVertices[face[1]] + surfVertices[face[2]]) / 3.0;
+        const Vec3d  n = ((surfVertices[face[1]] - surfVertices[face[0]]).cross(surfVertices[face[2]] - surfVertices[face[0]])).normalized();
+
+        // Project the centroid (of the centered 0,0,0 cube) onto the face normal
+        // It should be positive when facing outwards (the correct direction)
+        const double val = centroid.dot(n);
+        ASSERT_GT(val, 0.0) << "face: " << i;
+    }
+}
+
+///
+/// \brief Test the computation of volume
+///
+TEST_F(imstkTetrahedralMeshTest, GetVolume)
+{
+    // We use a regular tetrahedron with edge lengths 2
+    // V = (edge length)^3/(6sqrt(2))
+    const double edgeLenth      = 2.0;
+    const double expectedVolume = std::pow(edgeLenth, 3.0) / (6.0 * std::sqrt(2.0));
+
+    auto                     verticesPtr = std::make_shared<VecDataArray<double, 3>>(4);
+    auto                     indicesPtr  = std::make_shared<VecDataArray<int, 4>>(1);
+    VecDataArray<double, 3>& vertices    = *verticesPtr;
+    VecDataArray<int, 4>&    indices     = *indicesPtr;
+
+    vertices[0] = Vec3d(1.0, 0.0, -1.0 / std::sqrt(2.0));
+    vertices[1] = Vec3d(-1.0, 0.0, -1.0 / std::sqrt(2.0));
+    vertices[2] = Vec3d(0.0, 1.0, 1.0 / std::sqrt(2.0));
+    vertices[3] = Vec3d(0.0, -1.0, 1.0 / std::sqrt(2.0));
+
+    indices[0] = Vec4i(0, 1, 2, 3);
+
+    m_tetMesh.initialize(verticesPtr, indicesPtr);
+    EXPECT_NEAR(expectedVolume, m_tetMesh.getVolume(), 0.000001);
+}
+
+///
+/// \brief TODO
+///
+int
+imstkTetrahedralMeshTest(int argc, char* argv[])
+{
+    // Init Google Test & Mock
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // Run tests with gtest
+    return RUN_ALL_TESTS();
+}
diff --git a/Source/Geometry/imstkGeometry.cpp b/Source/Geometry/imstkGeometry.cpp
index 72a404455aebf993db6bc8819db0a564fb17205d..d0ec3cbaf1ed81b9be4ba9a4a55ea9cdae8a497d 100644
--- a/Source/Geometry/imstkGeometry.cpp
+++ b/Source/Geometry/imstkGeometry.cpp
@@ -87,7 +87,7 @@ Geometry::rotate(const Quatd& q, TransformType type)
 void
 Geometry::rotate(const Vec3d& axis, double radians, TransformType type)
 {
-    this->rotate(Rotd(radians, axis).toRotationMatrix(), type);
+    this->rotate(Rotd(radians, axis.normalized()).toRotationMatrix(), type);
 }
 
 void
@@ -175,6 +175,12 @@ Geometry::setRotation(const Vec3d& axis, const double angle)
 void
 Geometry::setScaling(const Vec3d& s)
 {
+    // Applying 0 scales will destroy the basis, would need another transform
+    if (s == Vec3d::Zero())
+    {
+        LOG(WARNING) << "Cannot apply 0 scales";
+        return;
+    }
     m_transform.block<3, 1>(0, 0) = m_transform.block<3, 1>(0, 0).normalized() * s[0];
     m_transform.block<3, 1>(0, 1) = m_transform.block<3, 1>(0, 1).normalized() * s[1];
     m_transform.block<3, 1>(0, 2) = m_transform.block<3, 1>(0, 2).normalized() * s[2];
@@ -184,10 +190,7 @@ Geometry::setScaling(const Vec3d& s)
 void
 Geometry::setScaling(const double s)
 {
-    m_transform.block<3, 1>(0, 0) = m_transform.block<3, 1>(0, 0).normalized() * s;
-    m_transform.block<3, 1>(0, 1) = m_transform.block<3, 1>(0, 1).normalized() * s;
-    m_transform.block<3, 1>(0, 2) = m_transform.block<3, 1>(0, 2).normalized() * s;
-    m_transformApplied = false;
+    setScaling(Vec3d(s, s, s));
 }
 
 Mat3d
diff --git a/Source/Geometry/imstkGeometry.h b/Source/Geometry/imstkGeometry.h
index 340857b21666d6f2ebf536bc621318f79e92002b..5a19b2487da06ed999ee1b763c8c7b271a62ac57 100644
--- a/Source/Geometry/imstkGeometry.h
+++ b/Source/Geometry/imstkGeometry.h
@@ -82,8 +82,9 @@ public:
     virtual const std::string getTypeName() const = 0;
 
 public:
-    SIGNAL(Geometry,modified);
-
+    // *INDENT-OFF*
+    SIGNAL(Geometry, modified);
+    // *INDENT-ON*
 public:
     ///
     /// \brief Print
@@ -99,48 +100,48 @@ public:
     /// \brief Compute the bounding box for the geometry
     /// \todo Padding should not be here
     ///
-    virtual void computeBoundingBox(Vec3d& lowerCorner,Vec3d& upperCorner,const double paddingPercent = 0.0);
+    virtual void computeBoundingBox(Vec3d& lowerCorner, Vec3d& upperCorner, const double paddingPercent = 0.0);
 
     ///
     /// \brief Returns the bounding box center
     ///
     virtual Vec3d getCenter()
     {
-        Vec3d min,max;
-        computeBoundingBox(min,max);
+        Vec3d min, max;
+        computeBoundingBox(min, max);
         return (min + max) * 0.5;
     }
 
     ///
     /// \brief Translate the geometry in Cartesian space
     ///
-    void translate(const Vec3d& t,TransformType type = TransformType::ConcatenateToTransform);
-    void translate(double x,double y,double z,TransformType type = TransformType::ConcatenateToTransform);
+    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& q,TransformType type = TransformType::ConcatenateToTransform);
-    void rotate(const Mat3d& m,TransformType type = TransformType::ConcatenateToTransform);
-    void rotate(const Vec3d& axis,double radians,TransformType type = TransformType::ConcatenateToTransform);
+    void rotate(const Quatd& q, TransformType type = TransformType::ConcatenateToTransform);
+    void rotate(const Mat3d& m, TransformType type = TransformType::ConcatenateToTransform);
+    void rotate(const Vec3d& axis, double radians, TransformType type = TransformType::ConcatenateToTransform);
 
     ///
     /// \brief Scale in Cartesian directions
     ///
-    void scale(const Vec3d& scaling,TransformType type = TransformType::ConcatenateToTransform);
-    void scale(const double scaling,TransformType type = TransformType::ConcatenateToTransform);
+    void scale(const Vec3d& scaling, TransformType type = TransformType::ConcatenateToTransform);
+    void scale(const double scaling, TransformType type = TransformType::ConcatenateToTransform);
 
     ///
     /// \brief Applies a rigid transform to the geometry
     ///
-    void transform(const Mat4d& T,TransformType type = TransformType::ConcatenateToTransform);
+    void transform(const Mat4d& T, TransformType type = TransformType::ConcatenateToTransform);
 
     ///
     /// \brief Get/Set translation
     ///
     Vec3d getTranslation() const;
     void setTranslation(const Vec3d& t);
-    void setTranslation(const double x,const double y,const double z);
+    void setTranslation(const double x, const double y, const double z);
 
     ///
     /// \brief Get/Set rotation
@@ -148,7 +149,7 @@ public:
     Mat3d getRotation() const;
     void setRotation(const Mat3d& m);
     void setRotation(const Quatd& q);
-    void setRotation(const Vec3d& axis,const double angle);
+    void setRotation(const Vec3d& axis, const double angle);
 
     ///
     /// \brief Get/Set scaling
@@ -160,7 +161,7 @@ public:
     ///
     /// \brief Get/Set the transform
     ///
-    const Mat4d& getTransform() { return m_transform; }
+    const Mat4d& getTransform() const { return m_transform; }
     void setTransform(const Mat4d& m)
     {
         m_transform = m;
@@ -170,12 +171,12 @@ public:
     ///
     /// \brief Get name of the geometry
     ///
-    const std::string& getName() const{ return m_name; }
+    const std::string& getName() const { return m_name; }
 
     ///
     /// \brief Get the global (unique) index of the geometry
     ///
-    uint32_t getGlobalIndex() const{ return m_geometryIndex; }
+    uint32_t getGlobalIndex() const { return m_geometryIndex; }
 
     ///
     /// \brief Get a pointer to geometry that has been registered globally
@@ -185,14 +186,14 @@ public:
     ///
     /// \brief Returns true if the geometry is a mesh, else returns false
     ///
-    virtual bool isMesh() const{ return false; }
+    virtual bool isMesh() const { return false; }
 
     ///
     /// \brief Post modified event
     ///
     void postModified() { this->postEvent(Event(Geometry::modified())); }
 
-    virtual void updatePostTransformData() const{ }
+    virtual void updatePostTransformData() const { }
 
 protected:
     ///
diff --git a/Source/Geometry/imstkGeometryUtilities.cpp b/Source/Geometry/imstkGeometryUtilities.cpp
index 59f0cfb9b7c3aebe805432537817faa23d894f37..ef39a13bb7d404baead5706e7f89a960bb8718cb 100644
--- a/Source/Geometry/imstkGeometryUtilities.cpp
+++ b/Source/Geometry/imstkGeometryUtilities.cpp
@@ -20,11 +20,11 @@
 =========================================================================*/
 
 #include "imstkGeometryUtilities.h"
-#include "imstkCube.h"
 #include "imstkHexahedralMesh.h"
 #include "imstkImageData.h"
 #include "imstkLineMesh.h"
 #include "imstkLogger.h"
+#include "imstkOrientedBox.h"
 #include "imstkParallelUtils.h"
 #include "imstkPlane.h"
 #include "imstkSphere.h"
@@ -255,10 +255,22 @@ GeometryUtils::copyToPointSet(vtkSmartPointer<vtkPointSet> vtkMesh)
         vtkDataArray* tCoords   = pointData->GetTCoords();
         vtkDataArray* scalars   = pointData->GetScalars();
         vtkDataArray* tangents  = pointData->GetTangents();
-        mesh->setVertexNormals((normals == nullptr || normals->GetName() == nullptr) ? "" : std::string(normals->GetName()));
-        mesh->setVertexTCoords((tCoords == nullptr || tCoords->GetName() == nullptr) ? "" : std::string(tCoords->GetName()));
-        mesh->setVertexScalars((scalars == nullptr || scalars->GetName() == nullptr) ? "" : std::string(scalars->GetName()));
-        mesh->setVertexTangents((tangents == nullptr || tangents->GetName() == nullptr) ? "" : std::string(tangents->GetName()));
+        if (normals != nullptr)
+        {
+            mesh->setVertexNormals(std::string(normals->GetName()));
+        }
+        if (tCoords != nullptr)
+        {
+            mesh->setVertexTCoords(std::string(tCoords->GetName()));
+        }
+        if (scalars != nullptr)
+        {
+            mesh->setVertexScalars(std::string(scalars->GetName()));
+        }
+        if (tangents != nullptr)
+        {
+            mesh->setVertexTangents(std::string(tangents->GetName()));
+        }
     }
 
     return mesh;
@@ -286,10 +298,22 @@ GeometryUtils::copyToSurfaceMesh(vtkSmartPointer<vtkPolyData> vtkMesh)
         vtkDataArray* tCoords   = pointData->GetTCoords();
         vtkDataArray* scalars   = pointData->GetScalars();
         vtkDataArray* tangents  = pointData->GetTangents();
-        mesh->setVertexNormals((normals == nullptr || normals->GetName() == nullptr) ? "" : std::string(normals->GetName()));
-        mesh->setVertexTCoords((tCoords == nullptr || tCoords->GetName() == nullptr) ? "" : std::string(tCoords->GetName()));
-        mesh->setVertexScalars((scalars == nullptr || scalars->GetName() == nullptr) ? "" : std::string(scalars->GetName()));
-        mesh->setVertexTangents((tangents == nullptr || tangents->GetName() == nullptr) ? "" : std::string(tangents->GetName()));
+        if (normals != nullptr)
+        {
+            mesh->setVertexNormals(std::string(normals->GetName()));
+        }
+        if (tCoords != nullptr)
+        {
+            mesh->setVertexTCoords(std::string(tCoords->GetName()));
+        }
+        if (scalars != nullptr)
+        {
+            mesh->setVertexScalars(std::string(scalars->GetName()));
+        }
+        if (tangents != nullptr)
+        {
+            mesh->setVertexTangents(std::string(tangents->GetName()));
+        }
     }
 
     // Cell Data
@@ -302,9 +326,18 @@ GeometryUtils::copyToSurfaceMesh(vtkSmartPointer<vtkPolyData> vtkMesh)
         vtkDataArray* normals  = cellData->GetNormals();
         vtkDataArray* scalars  = cellData->GetScalars();
         vtkDataArray* tangents = cellData->GetTangents();
-        mesh->setCellNormals((normals == nullptr || normals->GetName() == nullptr) ? "" : std::string(normals->GetName()));
-        mesh->setCellScalars((scalars == nullptr || scalars->GetName() == nullptr) ? "" : std::string(scalars->GetName()));
-        mesh->setCellTangents((tangents == nullptr || tangents->GetName() == nullptr) ? "" : std::string(tangents->GetName()));
+        if (normals != nullptr)
+        {
+            mesh->setCellNormals(std::string(normals->GetName()));
+        }
+        if (scalars != nullptr)
+        {
+            mesh->setCellScalars(std::string(scalars->GetName()));
+        }
+        if (tangents != nullptr)
+        {
+            mesh->setCellTangents(std::string(tangents->GetName()));
+        }
     }
 
     // Active Texture
@@ -327,6 +360,12 @@ GeometryUtils::copyToLineMesh(vtkSmartPointer<vtkPolyData> vtkMesh)
     std::shared_ptr<VecDataArray<double, 3>> vertices = copyToVecDataArray(vtkMesh->GetPoints());
     std::shared_ptr<VecDataArray<int, 2>>    cells    = copyToVecDataArray<2>(vtkMesh->GetPolys());
 
+    // If polys is empty use lines instead
+    if (cells->size() == 0)
+    {
+        cells = copyToVecDataArray<2>(vtkMesh->GetLines());
+    }
+
     auto mesh = std::make_unique<LineMesh>();
     mesh->initialize(vertices, cells);
 
@@ -341,10 +380,22 @@ GeometryUtils::copyToLineMesh(vtkSmartPointer<vtkPolyData> vtkMesh)
         vtkDataArray* tCoords   = pointData->GetTCoords();
         vtkDataArray* scalars   = pointData->GetScalars();
         vtkDataArray* tangents  = pointData->GetTangents();
-        mesh->setVertexNormals((normals == nullptr || normals->GetName() == nullptr) ? "" : std::string(normals->GetName()));
-        mesh->setVertexTCoords((tCoords == nullptr || tCoords->GetName() == nullptr) ? "" : std::string(tCoords->GetName()));
-        mesh->setVertexScalars((scalars == nullptr || scalars->GetName() == nullptr) ? "" : std::string(scalars->GetName()));
-        mesh->setVertexTangents((tangents == nullptr || tangents->GetName() == nullptr) ? "" : std::string(tangents->GetName()));
+        if (normals != nullptr)
+        {
+            mesh->setVertexNormals(std::string(normals->GetName()));
+        }
+        if (tCoords != nullptr)
+        {
+            mesh->setVertexTCoords(std::string(tCoords->GetName()));
+        }
+        if (scalars != nullptr)
+        {
+            mesh->setVertexScalars(std::string(scalars->GetName()));
+        }
+        if (tangents != nullptr)
+        {
+            mesh->setVertexTangents(std::string(tangents->GetName()));
+        }
     }
 
     return mesh;
@@ -365,7 +416,7 @@ GeometryUtils::copyToVolumetricMesh(vtkSmartPointer<vtkUnstructuredGrid> vtkMesh
 
         std::shared_ptr<TetrahedralMesh> mesh = std::make_unique<TetrahedralMesh>();
         vMesh = mesh;
-        mesh->initialize(vertices, cells, false);
+        mesh->initialize(vertices, cells);
     }
     else if (cellType == VTK_HEXAHEDRON)
     {
@@ -373,7 +424,7 @@ GeometryUtils::copyToVolumetricMesh(vtkSmartPointer<vtkUnstructuredGrid> vtkMesh
 
         std::shared_ptr<HexahedralMesh> mesh = std::make_unique<HexahedralMesh>();
         vMesh = mesh;
-        mesh->initialize(vertices, cells, false);
+        mesh->initialize(vertices, cells);
     }
     else
     {
@@ -392,10 +443,22 @@ GeometryUtils::copyToVolumetricMesh(vtkSmartPointer<vtkUnstructuredGrid> vtkMesh
         vtkDataArray* tCoords   = pointData->GetTCoords();
         vtkDataArray* scalars   = pointData->GetScalars();
         vtkDataArray* tangents  = pointData->GetTangents();
-        vMesh->setVertexNormals((normals == nullptr || normals->GetName() == nullptr) ? "" : std::string(normals->GetName()));
-        vMesh->setVertexTCoords((tCoords == nullptr || tCoords->GetName() == nullptr) ? "" : std::string(tCoords->GetName()));
-        vMesh->setVertexScalars((scalars == nullptr || scalars->GetName() == nullptr) ? "" : std::string(scalars->GetName()));
-        vMesh->setVertexTangents((tangents == nullptr || tangents->GetName() == nullptr) ? "" : std::string(tangents->GetName()));
+        if (normals != nullptr)
+        {
+            vMesh->setVertexNormals(std::string(normals->GetName()));
+        }
+        if (tCoords != nullptr)
+        {
+            vMesh->setVertexTCoords(std::string(tCoords->GetName()));
+        }
+        if (scalars != nullptr)
+        {
+            vMesh->setVertexScalars(std::string(scalars->GetName()));
+        }
+        if (tangents != nullptr)
+        {
+            vMesh->setVertexTangents(std::string(tangents->GetName()));
+        }
     }
 
     // Cell Data
@@ -668,17 +731,28 @@ GeometryUtils::copyToVecDataArray(vtkCellArray* vtkCells)
 }
 
 void
-GeometryUtils::copyToDataMap(vtkDataSetAttributes* const dataAttributes, std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>>& dataMap)
+GeometryUtils::copyToDataMap(vtkDataSetAttributes* dataAttributes, std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>>& dataMap)
 {
     CHECK(dataAttributes != nullptr) << "No point data provided!";
 
     for (int i = 0; i < dataAttributes->GetNumberOfArrays(); ++i)
     {
         vtkDataArray* array = dataAttributes->GetArray(i);
-        std::string   name  = "";
-        if (array->GetName() != NULL)
+        std::string   name  = "unnamed";
+        if (array->GetName() == NULL)
         {
-            name = array->GetName();
+            int iter = 0;
+            // If name already exists, iterate key
+            while (dataMap.count(name + std::to_string(iter)) != 0)
+            {
+                iter++;
+            }
+            name = name + std::to_string(iter);
+            array->SetName(name.c_str());
+        }
+        else
+        {
+            name = std::string(array->GetName());
         }
         dataMap[name] = copyToDataArray(array);
     }
@@ -700,36 +774,6 @@ GeometryUtils::copyToVtkDataAttributes(vtkDataSetAttributes* pointData, const st
     }
 }
 
-std::shared_ptr<SurfaceMesh>
-GeometryUtils::toCubeSurfaceMesh(std::shared_ptr<Cube> cube)
-{
-    vtkNew<vtkCubeSource> cubeSource;
-    cubeSource->SetCenter(cube->getPosition(Geometry::DataType::PreTransform).data());
-    cubeSource->SetXLength(cube->getWidth());
-    cubeSource->SetYLength(cube->getWidth());
-    cubeSource->SetZLength(cube->getWidth());
-    cubeSource->Update();
-
-    Mat4d mat;
-    mat.setIdentity();
-    mat.block<3, 3>(0, 0) = cube->getRotation();
-
-    vtkNew<vtkTransform> transform;
-    transform->SetMatrix(mat.data());
-
-    vtkNew<vtkTransformFilter> transformCube;
-    transformCube->SetInputData(cubeSource->GetOutput());
-    transformCube->SetTransform(transform);
-    transformCube->Update();
-    vtkNew<vtkTriangleFilter> triangulate;
-    triangulate->SetInputData(transformCube->GetOutput());
-    triangulate->Update();
-    vtkNew<vtkCleanPolyData> cleanData;
-    cleanData->SetInputData(triangulate->GetOutput());
-    cleanData->Update();
-    return copyToSurfaceMesh(cleanData->GetOutput());
-}
-
 std::shared_ptr<SurfaceMesh>
 GeometryUtils::toUVSphereSurfaceMesh(std::shared_ptr<Sphere> sphere,
                                      const unsigned int phiDivisions, const unsigned int thetaDivisions)
@@ -759,25 +803,59 @@ GeometryUtils::toUVSphereSurfaceMesh(std::shared_ptr<Sphere> sphere,
 }
 
 std::shared_ptr<SurfaceMesh>
-GeometryUtils::toQuadSurfaceMesh(std::shared_ptr<Plane> plane)
+GeometryUtils::toSurfaceMesh(std::shared_ptr<AnalyticalGeometry> geom)
 {
-    const Quatd r = Quatd::FromTwoVectors(Vec3d(0.0, 1.0, 0.0), plane->getOrientationAxis());
-    const Vec3d i = r._transformVector(Vec3d(1.0, 0.0, 0.0));
-    const Vec3d j = r._transformVector(Vec3d(0.0, 0.0, 1.0));
-
-    //Vec3d p1 = plane->getPosition() + plane->getWidth() * (i + j);
-    Vec3d p2 = plane->getPosition() + plane->getWidth() * (i - j);
-    Vec3d p3 = plane->getPosition() + plane->getWidth() * (-i + j);
-    Vec3d p4 = plane->getPosition() + plane->getWidth() * (-i - j);
-
-    vtkNew<vtkPlaneSource> planeSource;
-    planeSource->SetOrigin(p4.data());
-    planeSource->SetPoint1(p3.data());
-    planeSource->SetPoint2(p2.data());
-    planeSource->Update();
+    vtkSmartPointer<vtkPointSet> results = nullptr;
+    if (auto plane = std::dynamic_pointer_cast<Plane>(geom))
+    {
+        const Quatd r = Quatd(plane->getRotation());
+        const Vec3d i = r._transformVector(Vec3d(1.0, 0.0, 0.0));
+        const Vec3d j = r._transformVector(Vec3d(0.0, 0.0, 1.0));
+
+        //Vec3d p1 = plane->getPosition() + plane->getWidth() * (i + j);
+        Vec3d p2 = plane->getPosition() + plane->getWidth() * (i - j);
+        Vec3d p3 = plane->getPosition() + plane->getWidth() * (-i + j);
+        Vec3d p4 = plane->getPosition() + plane->getWidth() * (-i - j);
+
+        vtkNew<vtkPlaneSource> planeSource;
+        planeSource->SetOrigin(p4.data());
+        planeSource->SetPoint1(p3.data());
+        planeSource->SetPoint2(p2.data());
+        planeSource->Update();
+        results = planeSource->GetOutput();
+    }
+    else if (auto orientedBox = std::dynamic_pointer_cast<OrientedBox>(geom))
+    {
+        vtkNew<vtkCubeSource> cubeSource;
+        cubeSource->SetCenter(orientedBox->getPosition(Geometry::DataType::PreTransform).data());
+        Vec3d extents = orientedBox->getExtents();
+        cubeSource->SetXLength(extents[0] * 2.0);
+        cubeSource->SetYLength(extents[1] * 2.0);
+        cubeSource->SetZLength(extents[2] * 2.0);
+        cubeSource->Update();
+
+        Mat4d mat;
+        mat.setIdentity();
+        mat.block<3, 3>(0, 0) = orientedBox->getRotation();
+
+        vtkNew<vtkTransform> transform;
+        transform->SetMatrix(mat.data());
+
+        vtkNew<vtkTransformFilter> transformCube;
+        transformCube->SetInputData(cubeSource->GetOutput());
+        transformCube->SetTransform(transform);
+        transformCube->Update();
+        results = transformCube->GetOutput();
+    }
+    else
+    {
+        LOG(WARNING) << "Failed to produce SurfaceMesh from provided AnalyticalGeometry";
+        return nullptr;
+    }
 
+    // Triangulate, mesh could have quads or other primitives
     vtkNew<vtkTriangleFilter> triangulate;
-    triangulate->SetInputData(planeSource->GetOutput());
+    triangulate->SetInputData(results);
     triangulate->Update();
     vtkNew<vtkCleanPolyData> cleanData;
     cleanData->SetInputConnection(triangulate->GetOutputPort());
diff --git a/Source/Geometry/imstkGeometryUtilities.h b/Source/Geometry/imstkGeometryUtilities.h
index 256b82f832eab453a36b1f1a5a52eb4931095605..901eb312f608b0be1f1578199a29c839ee748175 100644
--- a/Source/Geometry/imstkGeometryUtilities.h
+++ b/Source/Geometry/imstkGeometryUtilities.h
@@ -48,6 +48,7 @@ class vtkDataSetAttributes;
 namespace imstk
 {
 class AbstractDataArray;
+class AnalyticalGeometry;
 class ImageData;
 class HexahedralMesh;
 class LineMesh;
@@ -56,7 +57,7 @@ class SurfaceMesh;
 class TetrahedralMesh;
 class VolumetricMesh;
 
-class Cube;
+class OrientedBox;
 class Sphere;
 class Plane;
 
@@ -185,7 +186,7 @@ std::shared_ptr<VecDataArray<int, dim>> copyToVecDataArray(vtkCellArray* vtkCell
 ///
 /// \brief Copy vtkPointData to a data map
 ///
-void copyToDataMap(vtkDataSetAttributes* const pointData, std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>>& dataMap);
+void copyToDataMap(vtkDataSetAttributes* pointData, std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>>& dataMap);
 
 ///
 /// \brief Copy from a data map to vtkDataAttributes (used for vtkCellData and vtkPointData)
@@ -193,11 +194,6 @@ void copyToDataMap(vtkDataSetAttributes* const pointData, std::unordered_map<std
 ///
 void copyToVtkDataAttributes(vtkDataSetAttributes* pointData, const std::unordered_map<std::string, std::shared_ptr<AbstractDataArray>>& dataMap);
 
-///
-/// \brief Produces SurfaceMesh cube from imstkCube
-///
-std::shared_ptr<SurfaceMesh> toCubeSurfaceMesh(std::shared_ptr<Cube> cube);
-
 ///
 /// \brief UV sphere from imstkSphere
 ///
@@ -205,9 +201,9 @@ std::shared_ptr<SurfaceMesh> toUVSphereSurfaceMesh(std::shared_ptr<Sphere> spher
                                                    const unsigned int phiDivisions, const unsigned int thetaDivisions);
 
 ///
-/// \brief Produces SurfaceMesh cube from imstkPlane
+/// \brief Produces SurfaceMesh from an analytical geometry
 ///
-std::shared_ptr<SurfaceMesh> toQuadSurfaceMesh(std::shared_ptr<Plane> plane);
+std::shared_ptr<SurfaceMesh> toSurfaceMesh(std::shared_ptr<AnalyticalGeometry> geom);
 
 ///
 /// \brief Returns the number of open edges, use to tell if manifold (==0)
diff --git a/Source/GeometryMappers/imstkOneToOneMap.cpp b/Source/GeometryMappers/imstkOneToOneMap.cpp
index bacb9c27bc4331c24a5c25fac3dcda7e39e4dd05..376991b0ebc671c23be8cd34dd700bdbd18840ba 100644
--- a/Source/GeometryMappers/imstkOneToOneMap.cpp
+++ b/Source/GeometryMappers/imstkOneToOneMap.cpp
@@ -1,22 +1,16 @@
 /*=========================================================================
-
    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 "imstkOneToOneMap.h"
@@ -39,50 +33,44 @@ OneToOneMap::compute()
     m_oneToOneMap.clear();
     ParallelUtils::SpinLock lock;
 
-    bool bValid = true;
+    std::shared_ptr<VecDataArray<double, 3>> masterVerticesPtr = meshMaster->getInitialVertexPositions();
+    const VecDataArray<double, 3>&           masterVertices    = *masterVerticesPtr;
+    std::shared_ptr<VecDataArray<double, 3>> slaveVerticesPtr  = meshSlave->getInitialVertexPositions();
+    const VecDataArray<double, 3>&           slaveVertices     = *slaveVerticesPtr;
+
+    // For every vertex on the slave, find corresponding one on the master
     ParallelUtils::parallelFor(meshSlave->getNumVertices(),
         [&](const size_t nodeId)
         {
-            if (!bValid) // If map is invalid, no need to check further
-            {
-                return;
-            }
             // Find the enclosing or closest tetrahedron
             size_t matchingNodeId;
-            if (!findMatchingVertex(meshMaster, meshSlave->getVertexPosition(nodeId), matchingNodeId))
+            if (!findMatchingVertex(masterVertices, slaveVertices[nodeId], matchingNodeId))
             {
-                LOG(WARNING) << "Could not find matching node for the node " << nodeId;
-                bValid = false;
                 return;
             }
 
             // Add to the map
             // Note: This replaces the map if one with <nodeId> already exists
             lock.lock();
-            m_oneToOneMap[nodeId] = matchingNodeId;
+            m_oneToOneMap[nodeId] = matchingNodeId; // slave index -> master index
             lock.unlock();
         });
 
-    if (!bValid)
-    {
-        m_oneToOneMap.clear();
-        return;
-    }
-
     // Copy data from map to vector for parallel processing
     m_oneToOneMapVector.resize(0);
-    for (auto kv: m_oneToOneMap)
+    for (auto kv : m_oneToOneMap)
     {
         m_oneToOneMapVector.push_back({ kv.first, kv.second });
     }
 }
 
 bool
-OneToOneMap::findMatchingVertex(const std::shared_ptr<PointSet>& masterMesh, const Vec3d& p, size_t& nodeId)
+OneToOneMap::findMatchingVertex(const VecDataArray<double, 3>& masterVertices, const Vec3d& p, size_t& nodeId)
 {
-    for (size_t idx = 0; idx < masterMesh->getNumVertices(); ++idx)
+    const double eps2 = m_epsilon * m_epsilon;
+    for (size_t idx = 0; idx < masterVertices.size(); ++idx)
     {
-        if (masterMesh->getInitialVertexPosition(idx) == p)
+        if ((masterVertices[idx] - p).squaredNorm() < eps2)
         {
             nodeId = idx;
             return true;
@@ -94,55 +82,7 @@ OneToOneMap::findMatchingVertex(const std::shared_ptr<PointSet>& masterMesh, con
 bool
 OneToOneMap::isValid() const
 {
-    auto meshMaster = std::dynamic_pointer_cast<PointSet>(m_master);
-    auto meshSlave  = std::dynamic_pointer_cast<PointSet>(m_slave);
-
-#if defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG)
-    CHECK(dynamic_cast<PointSet*>(m_master.get()) && dynamic_cast<PointSet*>(m_slave.get())) <<
-        "Failed to cast from geometry to pointset";
-#endif
-
-    const size_t numVertMaster = meshMaster->getNumVertices();
-    const size_t numVertSlave  = meshSlave->getNumVertices();
-
-    bool valid = true;
-    ParallelUtils::parallelFor(m_oneToOneMapVector.size(),
-        [&](const size_t idx) {
-            if (!valid) // If map is invalid, no need to check further
-            {
-                return;
-            }
-            const auto& mapValue = m_oneToOneMapVector[idx];
-            if (mapValue.first >= numVertSlave
-                && mapValue.second >= numVertMaster)
-            {
-                valid = false;
-            }
-        });
-
-    // check conformity
-    if (valid)
-    {
-        ParallelUtils::parallelFor(meshSlave->getNumVertices(), [&](const size_t nodeId)
-            {
-                const Vec3d& p  = meshSlave->getVertexPosition(nodeId);
-                bool matchFound = false;
-                for (size_t idx = 0; idx < meshMaster->getNumVertices(); ++idx)
-                {
-                    if (meshMaster->getInitialVertexPosition(idx) == p)
-                    {
-                        matchFound = true;
-                        break;
-                    }
-                }
-                if (!matchFound)
-                {
-                    valid = false;
-                }
-        });
-    }
-
-    return valid;
+    return true;
 }
 
 void
@@ -152,7 +92,7 @@ OneToOneMap::setMap(const std::map<size_t, size_t>& sourceMap)
 
     // Copy data from map to vector for parallel processing
     m_oneToOneMapVector.resize(0);
-    for (auto kv: m_oneToOneMap)
+    for (auto kv : m_oneToOneMap)
     {
         m_oneToOneMapVector.push_back({ kv.first, kv.second });
     }
@@ -236,4 +176,4 @@ OneToOneMap::getMapIdx(const size_t& idx)
 #endif
     return m_oneToOneMap[idx];
 }
-} // imstk
+} // imstk
\ No newline at end of file
diff --git a/Source/GeometryMappers/imstkOneToOneMap.h b/Source/GeometryMappers/imstkOneToOneMap.h
index 74bfb216f6e1dc6c4c26e44b465497be0a1f73a9..c8cba6a6dbcb0787ebb68d3e65c712aa7a6f79ab 100644
--- a/Source/GeometryMappers/imstkOneToOneMap.h
+++ b/Source/GeometryMappers/imstkOneToOneMap.h
@@ -1,30 +1,26 @@
 /*=========================================================================
-
    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.
-
 =========================================================================*/
 
 #pragma once
 
 #include "imstkGeometryMap.h"
+#include "imstkTypes.h"
 
 namespace imstk
 {
+template<typename T, int N> class VecDataArray;
 class PointSet;
 
 ///
@@ -56,6 +52,7 @@ public:
     ///
     virtual ~OneToOneMap() override = default;
 
+public:
     ///
     /// \brief Compute the tetra-triangle mesh map
     ///
@@ -92,20 +89,31 @@ public:
     void setSlave(std::shared_ptr<Geometry> slave) override;
 
     ///
-    /// \brief
+    /// \brief Get the corresponding master index, given a slave index
+    /// \param index on the slave geometry
     ///
     size_t getMapIdx(const size_t& idx) override;
 
+    ///
+    /// \brief Set the tolerance, that is the distance to consider
+    /// two points equivalent/corresponding
+    ///
+    void setTolerance(const double tolerance) { m_epsilon = tolerance; }
+
+    double getTolerance() const { return m_epsilon; }
+
 protected:
 
     ///
     /// \brief Returns the first matching vertex
     ///
-    bool findMatchingVertex(const std::shared_ptr<PointSet>& masterMesh, const Vec3d& p, size_t& nodeId);
+    bool findMatchingVertex(const VecDataArray<double, 3>& masterMesh, const Vec3d& p, size_t& nodeId);
 
     std::map<size_t, size_t> m_oneToOneMap;   ///> One to one mapping data
 
     // This vector is for parallel processing, it should contain identical data as m_oneToOneMap
-    std::vector<std::pair<size_t, size_t>> m_oneToOneMapVector;   ///> One to one mapping data
+    std::vector<std::pair<size_t, size_t>> m_oneToOneMapVector; ///> One to one mapping data
+
+    double m_epsilon = IMSTK_DOUBLE_EPS;                        // Tolerance for considering two points equivalent
 };
-} // imstk
+} // imstk
\ No newline at end of file
diff --git a/Source/MeshIO/CMakeLists.txt b/Source/MeshIO/CMakeLists.txt
index d26bc6ff931da03f666ca371b26bb0379ee7d391..b29c22be02b460f0b0688b24ab4a02dba518c187 100644
--- a/Source/MeshIO/CMakeLists.txt
+++ b/Source/MeshIO/CMakeLists.txt
@@ -11,6 +11,8 @@ imstk_add_library( MeshIO
     VegaFEM::volumetricMesh
     ${VTK_LIBRARIES}
   )
+  
+target_compile_options(MeshIO PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/bigobj>)
 
 #-----------------------------------------------------------------------------
 # Testing
diff --git a/Source/MeshIO/imstkAssimpMeshIO.cpp b/Source/MeshIO/imstkAssimpMeshIO.cpp
index 0a355a167a104885d4570eb732fceddf53e8cb8d..962a41393abb58ffcc0c15cbb1796721925836f9 100644
--- a/Source/MeshIO/imstkAssimpMeshIO.cpp
+++ b/Source/MeshIO/imstkAssimpMeshIO.cpp
@@ -46,7 +46,7 @@ AssimpMeshIO::read(
         return AssimpMeshIO::readMeshData(filePath);
         break;
     default:
-        LOG(WARNING) << "AssimpMeshIO::read error: file type not supported";
+        LOG(WARNING) << "Error: file type not supported for input " << filePath;
         return nullptr;
         break;
     }
@@ -60,12 +60,18 @@ AssimpMeshIO::readMeshData(const std::string& filePath)
     auto             scene = importer.ReadFile(filePath, AssimpMeshIO::getDefaultPostProcessSteps());
 
     // Check if there is actually a mesh or if the file can be read
-    CHECK(scene != nullptr && scene->HasMeshes()) << "AssimpMeshIO::readMeshData error: could not read with reader.";
+    CHECK(scene != nullptr && scene->HasMeshes()) << "Error: could not read with Assimp reader for input " << filePath;
 
     // Get first mesh
     auto importedMesh = scene->mMeshes[0];
 
-    return AssimpMeshIO::convertAssimpMesh(importedMesh);
+    auto surfMesh = AssimpMeshIO::convertAssimpMesh(importedMesh);
+    if (!surfMesh)
+    {
+        LOG(WARNING) << "Error: Invalid surface mesh. Input: " << filePath;
+    }
+
+    return surfMesh;
 }
 
 std::shared_ptr<SurfaceMesh>
@@ -80,7 +86,7 @@ AssimpMeshIO::convertAssimpMesh(aiMesh* importedMesh)
 
     if (numVertices == 0)
     {
-        LOG(WARNING) << "AssimpMeshIO::readMeshData error: mesh has no vertices.";
+        LOG(WARNING) << "Error: mesh has no vertices.";
         return nullptr;
     }
 
diff --git a/Source/MeshIO/imstkMSHMeshIO.cpp b/Source/MeshIO/imstkMSHMeshIO.cpp
index dbab1a0532134c7a6d79c1f3dc75b62ec9a0f77c..52ac5c31caf148bc75068ea699db18924cb7b8f6 100644
--- a/Source/MeshIO/imstkMSHMeshIO.cpp
+++ b/Source/MeshIO/imstkMSHMeshIO.cpp
@@ -32,7 +32,7 @@ namespace imstk
 std::shared_ptr<imstk::VolumetricMesh>
 MSHMeshIO::read(const std::string& filePath, const MeshFileType meshType)
 {
-    CHECK(meshType == MeshFileType::MSH) << "MSHMeshIO::read error: file type not supported";
+    CHECK(meshType == MeshFileType::MSH) << "Error: file type other than .msh not supported for input " << filePath;
 
     // based on the format provided on
     // http://www.manpagez.com/info/gmsh/gmsh-2.2.6/gmsh_63.php
@@ -56,7 +56,7 @@ MSHMeshIO::read(const std::string& filePath, const MeshFileType meshType)
     // Open the file
     std::ifstream mshStream(filePath);
 
-    CHECK(mshStream.is_open()) << "Failed to open the input .msh file";
+    CHECK(mshStream.is_open()) << "Error: Failed to open the input file" << filePath;
 
     // Look for "$MeshFormat"
     while (getline(mshStream, mshLine))
@@ -98,7 +98,7 @@ MSHMeshIO::read(const std::string& filePath, const MeshFileType meshType)
     }
     if (mshStream.eof())
     {
-        LOG(WARNING) << "MSHMeshIO::read error : Elements not defined in the file";
+        LOG(WARNING) << "Error: Elements not defined in the file for input file " << filePath;
         return nullptr;
     }
 
@@ -115,7 +115,7 @@ MSHMeshIO::read(const std::string& filePath, const MeshFileType meshType)
             break;
         }
     }
-    LOG(INFO) << "The MSH mesh comprises of: \n" << '\t' << "Number of NODES: " << nNodes;
+    LOG(INFO) << "MSH mesh comprises of: \n" << '\t' << "Number of NODES: " << nNodes;
 
     // Get the node IDs and the node coordinates
     nodeIDs.resize(nNodes);
@@ -150,8 +150,8 @@ MSHMeshIO::read(const std::string& filePath, const MeshFileType meshType)
     // Check to the $Nodes field is in the correct format in .msh file
     if (nodes_count != nNodes)
     {
-        LOG(WARNING) << " MSHMeshIO::read error: number of nodes read (" << nodes_count << ") "
-                     << "inconsistent with number of nodes defined in file (" << nNodes << ").";
+        LOG(WARNING) << "Error: number of nodes read (" << nodes_count << ") "
+                     << "inconsistent with number of nodes defined in file (" << nNodes << "). Input file: " << filePath;
         return nullptr;
     }
 
@@ -174,7 +174,7 @@ MSHMeshIO::read(const std::string& filePath, const MeshFileType meshType)
     }
     if (mshStream.eof())
     {
-        LOG(WARNING) << "MSHMeshIO::read error : Elements not defined in the file";
+        LOG(WARNING) << "Error: Elements not defined in the file " << filePath;
         return nullptr;
     }
 
@@ -215,9 +215,9 @@ MSHMeshIO::read(const std::string& filePath, const MeshFileType meshType)
             // To avoid out of range casting, and to check validity of the .msh file
             if (elemType < ElemType::line || elemType > ElemType::tetrahedronFifthOrder)
             {
-                LOG(FATAL) << "MSHMeshIO::read error : elm-type ( " << elemType << " ) "
+                LOG(FATAL) << "Error : elm-type ( " << elemType << " ) "
                            << "is not in the range" << "(" << ElemType::line << " to "
-                           << ElemType::tetrahedronFifthOrder << "), so is not a valid element type.";
+                           << ElemType::tetrahedronFifthOrder << "), so is not a valid element type. Input: " << filePath;
                 return nullptr;
             }
             ++elemCountMap[ElemType(elemType)];
@@ -234,16 +234,58 @@ MSHMeshIO::read(const std::string& filePath, const MeshFileType meshType)
     // Set the stream back to the elem field
     if (!(nElements == totalElem))
     {
-        LOG(WARNING) << "MSHMeshIO::read error: number of elements read (" << nElements << ") "
-                     << "inconsistent with number of elements defined in file (" << totalElem << ").";
+        LOG(WARNING) << "Error: number of elements read (" << nElements << ") "
+                     << "inconsistent with number of elements defined in file (" << totalElem << "). Input: " << filePath;
         return nullptr;
     }
     if (elemCountMap[ElemType::tetrahedron] == 0 && elemCountMap[ElemType::hexahedron] == 0)
     {
-        LOG(WARNING) << "MSHMeshIO::read error: No tet or hex elements present in the mesh!";
+        LOG(WARNING) << "Error: No tet or hex elements present in the mesh! Input: " << filePath;
         return nullptr;
     }
 
+    // Lambda to determine number of nodes per element of given type
+    auto numElemNodes = [&filePath](const ElemType& elType) -> size_t
+                        {
+                            switch (elType)
+                            {
+                            case ElemType::line:                            return 2;
+                            case ElemType::triangle:                        return 3;
+                            case ElemType::quadrangle:                      return 4;
+                            case ElemType::tetrahedron:                     return 4;
+                            case ElemType::hexahedron:                      return 8;
+                            case ElemType::prism:                           return 6;
+                            case ElemType::pyramid:                         return 5;
+                            case ElemType::lineSecondOrder:                 return 3;
+                            case ElemType::triangleSecondOrder:             return 6;
+                            case ElemType::quadrangleSecondOrderType1:      return 9;
+                            case ElemType::tetrahedronSecondOrder:          return 10;
+                            case ElemType::hexahedronSecondOrderType1:      return 27;
+                            case ElemType::prismSecondOrderType1:           return 18;
+                            case ElemType::pyramidSecondOrderType1:         return 14;
+                            case ElemType::point:                           return 1;
+                            case ElemType::quadrangleSecondOrderType2:      return 8;
+                            case ElemType::hexahedronSecondOrderType2:      return 20;
+                            case ElemType::prismSecondOrderType2:           return 15;
+                            case ElemType::pyramidSecondOrderType2:         return 13;
+                            case ElemType::triangleThirdOrderIncomplete:    return 9;
+                            case ElemType::triangleThirdOrder:              return 10;
+                            case ElemType::triangleFourthOrderIncomplete:   return 12;
+                            case ElemType::triangleFourthOrder:             return 15;
+                            case ElemType::triangleFifthOrderIncomplete:    return 15;
+                            case ElemType::triangleFifthOrder:              return 21;
+                            case ElemType::edgeThirdOrder:                  return 4;
+                            case ElemType::edgeFourthOrder:                 return 5;
+                            case ElemType::edgeFifthOrder:                  return 6;
+                            case ElemType::tetrahedronThirdOrder:           return 20;
+                            case ElemType::tetrahedronFourthOrder:          return 35;
+                            case ElemType::tetrahedronFifthOrder:           return 56;
+                            default:
+                                LOG(FATAL) << "Error: Unknown element type to compute number of nodes. Input: " << filePath;
+                                return 0;
+                            }
+                        };
+
     // Read the tet and hex (if any) elements IDs and connectivity in the $Element field in the .msh file
     tetrahedronIDs.resize(elemCountMap[ElemType::tetrahedron]);
     hexahedronIDs.resize(elemCountMap[ElemType::hexahedron]);
@@ -347,7 +389,7 @@ MSHMeshIO::read(const std::string& filePath, const MeshFileType meshType)
         }
 
         auto volMesh = std::make_shared<TetrahedralMesh>();
-        volMesh->initialize(vertices, cellsPtr, false);
+        volMesh->initialize(vertices, cellsPtr);
         return volMesh;
     }
     else if (elemCountMap[ElemType::hexahedron] != 0)
@@ -363,55 +405,13 @@ MSHMeshIO::read(const std::string& filePath, const MeshFileType meshType)
             cells.push_back(hexahedronConnectivity[iHex]);
         }
         auto volMesh = std::make_shared<HexahedralMesh>();
-        volMesh->initialize(vertices, cellsPtr, false);
+        volMesh->initialize(vertices, cellsPtr);
         return volMesh;
     }
     else
     {
-        LOG(FATAL) << "This volume type is not supported in iMSTK";
+        LOG(FATAL) << "Error: Element types other than tetrahedron and hexahedron not supported! Input: " << filePath;
         return nullptr;
     }
 }
-
-size_t
-MSHMeshIO::numElemNodes(const ElemType& elType)
-{
-    switch (elType)
-    {
-    case ElemType::line:                            return 2;
-    case ElemType::triangle:                        return 3;
-    case ElemType::quadrangle:                      return 4;
-    case ElemType::tetrahedron:                     return 4;
-    case ElemType::hexahedron:                      return 8;
-    case ElemType::prism:                           return 6;
-    case ElemType::pyramid:                         return 5;
-    case ElemType::lineSecondOrder:                 return 3;
-    case ElemType::triangleSecondOrder:             return 6;
-    case ElemType::quadrangleSecondOrderType1:      return 9;
-    case ElemType::tetrahedronSecondOrder:          return 10;
-    case ElemType::hexahedronSecondOrderType1:      return 27;
-    case ElemType::prismSecondOrderType1:           return 18;
-    case ElemType::pyramidSecondOrderType1:         return 14;
-    case ElemType::point:                           return 1;
-    case ElemType::quadrangleSecondOrderType2:      return 8;
-    case ElemType::hexahedronSecondOrderType2:      return 20;
-    case ElemType::prismSecondOrderType2:           return 15;
-    case ElemType::pyramidSecondOrderType2:         return 13;
-    case ElemType::triangleThirdOrderIncomplete:    return 9;
-    case ElemType::triangleThirdOrder:              return 10;
-    case ElemType::triangleFourthOrderIncomplete:   return 12;
-    case ElemType::triangleFourthOrder:             return 15;
-    case ElemType::triangleFifthOrderIncomplete:    return 15;
-    case ElemType::triangleFifthOrder:              return 21;
-    case ElemType::edgeThirdOrder:                  return 4;
-    case ElemType::edgeFourthOrder:                 return 5;
-    case ElemType::edgeFifthOrder:                  return 6;
-    case ElemType::tetrahedronThirdOrder:           return 20;
-    case ElemType::tetrahedronFourthOrder:          return 35;
-    case ElemType::tetrahedronFifthOrder:           return 56;
-    default:
-        LOG(FATAL) << "MSHMeshIO::numElemNodes: Unknown element type";
-        return 0;
-    }
-}
 } // iMSTK
\ No newline at end of file
diff --git a/Source/MeshIO/imstkMeshIO.cpp b/Source/MeshIO/imstkMeshIO.cpp
index 196c3c89bcec2e8d637d46dbd96a1a46904a48ed..a01895d8d2e764b18c2777aaf8e942de89300f11 100644
--- a/Source/MeshIO/imstkMeshIO.cpp
+++ b/Source/MeshIO/imstkMeshIO.cpp
@@ -101,8 +101,7 @@ MeshIO::read(const std::string& filePath)
     default:
         break;
     }
-
-    LOG(FATAL) << "MeshIO::read error: file type not supported";
+    LOG(FATAL) << "Error: file type not supported for input " << filePath;
     return nullptr;
 }
 
@@ -133,7 +132,7 @@ MeshIO::getFileType(const std::string& filePath)
 {
     std::string extString = filePath.substr(filePath.find_last_of(".") + 1);
 
-    CHECK(!extString.empty()) << "MeshIO::getFileType error: invalid file name";
+    CHECK(!extString.empty()) << "Error: invalid file name " << filePath;
 
     // To lowercase
     std::transform(extString.begin(), extString.end(), extString.begin(),
@@ -141,7 +140,7 @@ MeshIO::getFileType(const std::string& filePath)
 
     if (extToType.count(extString) == 0)
     {
-        LOG(FATAL) << "MeshIO::getFileType error: unknown file extension";
+        LOG(FATAL) << "Error: unknown file extension " << extString;
     }
 
     return extToType[extString];
@@ -152,7 +151,7 @@ MeshIO::write(const std::shared_ptr<imstk::PointSet> imstkMesh, const std::strin
 {
     if (imstkMesh == nullptr)
     {
-        LOG(WARNING) << "MeshIO::write error: Mesh nullptr";
+        LOG(WARNING) << "Error: Mesh object supplied is not valid!";
         return false;
     }
 
@@ -180,7 +179,7 @@ MeshIO::write(const std::shared_ptr<imstk::PointSet> imstkMesh, const std::strin
         break;
     }
 
-    LOG(FATAL) << "MeshIO::write error: file type not supported";
+    LOG(FATAL) << "Error: file type not supported for input " << filePath;
     return false;
 }
 } // imstk
diff --git a/Source/MeshIO/imstkVTKMeshIO.cpp b/Source/MeshIO/imstkVTKMeshIO.cpp
index f8f2509c66cee316b4423d7ba1e1d7f8b341ef58..8261d375d2ed38ff4e591c34537c49233dee3a94 100644
--- a/Source/MeshIO/imstkVTKMeshIO.cpp
+++ b/Source/MeshIO/imstkVTKMeshIO.cpp
@@ -117,7 +117,7 @@ VTKMeshIO::read(const std::string& filePath, MeshFileType meshType)
     }
     default:
     {
-        LOG(FATAL) << "VTKMeshIO::read error: file type not supported";
+        LOG(FATAL) << "Error: file type not supported for input " << filePath;
         return nullptr;
     }
     }
@@ -151,7 +151,7 @@ VTKMeshIO::write(const std::shared_ptr<PointSet> imstkMesh, const std::string& f
             return VTKMeshIO::writeVtkImageData<vtkBMPWriter>(imgMesh, filePath);
         }
         default:
-            LOG(WARNING) << "VTKMeshIO::write error: file type not supported for volumetric mesh.";
+            LOG(WARNING) << "Error: file type not supported for volumetric mesh. Target path supplied:" << filePath;
             return false;
         }
     }
@@ -188,7 +188,7 @@ VTKMeshIO::write(const std::shared_ptr<PointSet> imstkMesh, const std::string& f
             }
 
         default:
-            LOG(WARNING) << "VTKMeshIO::write error: file type not supported for volumetric mesh.";
+            LOG(WARNING) << "Error: file type not supported for volumetric mesh. Target path supplied:" << filePath;
             return false;
         }
     }
@@ -205,7 +205,7 @@ VTKMeshIO::write(const std::shared_ptr<PointSet> imstkMesh, const std::string& f
         case MeshFileType::VTK:
             return VTKMeshIO::writeVtkPolyData<vtkPolyDataWriter>(sMesh, filePath);
         default:
-            LOG(WARNING) << "VTKMeshIO::write error: file type not supported for surface mesh.";
+            LOG(WARNING) << "Error: file type not supported for surface mesh. Target path supplied:" << filePath;
             return false;
         }
     }
@@ -218,7 +218,7 @@ VTKMeshIO::write(const std::shared_ptr<PointSet> imstkMesh, const std::string& f
         case MeshFileType::VTP:
             return VTKMeshIO::writeVtkPolyData<vtkXMLPolyDataWriter>(lMesh, filePath);
         default:
-            LOG(WARNING) << "vtkMeshIO::write error: file type not supported for line mesh.";
+            LOG(WARNING) << "Error: file type not supported for line mesh. Target path supplied:" << filePath;
             return false;
         }
     }
@@ -229,13 +229,13 @@ VTKMeshIO::write(const std::shared_ptr<PointSet> imstkMesh, const std::string& f
         case MeshFileType::VTK:
             return VTKMeshIO::writeVtkPointSet<vtkGenericDataObjectWriter>(ptMesh, filePath);
         default:
-            LOG(WARNING) << "vtkMeshIO::write error: file type not supported for point mesh.";
+            LOG(WARNING) << "Error: file type not supported for point mesh. Target path supplied:" << filePath;
             return false;
         }
     }
     else
     {
-        LOG(WARNING) << "VTKMeshIO::write error: the provided mesh is not a surface or volumetric mesh.";
+        LOG(WARNING) << "Error: the provided mesh is not a surface or volumetric mesh. Target path supplied:" << filePath;
         return false;
     }
 }
@@ -250,7 +250,18 @@ VTKMeshIO::readVtkGenericFormatData(const std::string& filePath)
 
     if (vtkSmartPointer<vtkPolyData> vtkMesh = reader->GetPolyDataOutput())
     {
-        return GeometryUtils::copyToSurfaceMesh(vtkMesh);
+        // Try to convert to surface mesh, if no elements exist try reading as a line mesh
+        std::shared_ptr<SurfaceMesh> surfMesh = GeometryUtils::copyToSurfaceMesh(vtkMesh);
+        if (surfMesh->getNumTriangles() > 0)
+        {
+            return surfMesh;
+        }
+        std::shared_ptr<LineMesh> lineMesh = GeometryUtils::copyToLineMesh(vtkMesh);
+        if (lineMesh->getNumLines() > 0)
+        {
+            return lineMesh;
+        }
+        return GeometryUtils::copyToPointSet(vtkMesh);
     }
 
     if (vtkUnstructuredGrid* vtkMesh = reader->GetUnstructuredGridOutput())
@@ -258,7 +269,7 @@ VTKMeshIO::readVtkGenericFormatData(const std::string& filePath)
         return GeometryUtils::copyToVolumetricMesh(vtkMesh);
     }
 
-    LOG(FATAL) << "VTKMeshIO::readVtkGenericFormatData error: could not read with VTK reader.";
+    LOG(FATAL) << "Error: could not read with VTK reader for input " << filePath;
     return nullptr;
 }
 
@@ -288,7 +299,6 @@ VTKMeshIO::writeVtkImageData(const std::shared_ptr<ImageData> imstkMesh, const s
         return false;
     }
 
-    int* dim    = vtkMesh->GetDimensions();
     auto writer = vtkSmartPointer<WriterType>::New();
     if (vtkMesh->GetDimensions()[2] == 1)
     {
@@ -376,7 +386,7 @@ VTKMeshIO::readVtkImageDataDICOM(const std::string& filePath)
 {
     bool isDirectory;
 
-    CHECK(MeshIO::fileExists(filePath, isDirectory)) << "VTKMeshIO::read error: file not found: " << filePath;
+    CHECK(MeshIO::fileExists(filePath, isDirectory)) << "Error: file " << filePath << " not found!";
 
     if (!isDirectory)
     {
@@ -400,7 +410,7 @@ VTKMeshIO::writeVtkUnstructuredGrid(std::shared_ptr<TetrahedralMesh> tetMesh, co
 
     if (!vtkMesh)
     {
-        LOG(WARNING) << "VTKMeshIO::writeVtkUnstructuredGrid error: conversion unsuccessful";
+        LOG(WARNING) << "Error: conversion unsuccessful. Target path supplied:" << filePath;
         return false;
     }
 
@@ -420,7 +430,7 @@ VTKMeshIO::writeVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> hMesh, const
 
     if (!vtkMesh)
     {
-        LOG(WARNING) << "VTKMeshIO::writeVtkUnstructuredGrid error: conversion unsuccessful";
+        LOG(WARNING) << "Error: conversion unsuccessful. Target path supplied:" << filePath;
         return false;
     }
 
@@ -463,7 +473,7 @@ VTKMeshIO::writeVtkImageDataNIFTI(std::shared_ptr<ImageData> imageData, const st
     auto vtkMesh = GeometryUtils::copyToVtkImageData(imageData);
     if (!vtkMesh)
     {
-        LOG(WARNING) << "VTKMeshIO::writeVtkImageDataNIFTI error: conversion unsuccessful";
+        LOG(WARNING) << "Error: conversion unsuccessful. Target path supplied:" << filePath;
         return false;
     }
 
@@ -485,14 +495,15 @@ VTKMeshIO::writeVtkImageDataNIFTI(std::shared_ptr<ImageData> imageData, const st
 bool
 VTKMeshIO::writeMetaImageData(std::shared_ptr<ImageData> imageData, const std::string& filePath)
 {
-    vtkSmartPointer<vtkImageData> vtkMesh = GeometryUtils::copyToVtkImageData(imageData);
-    if (!vtkMesh)
+    vtkSmartPointer<vtkImageData> vtkImage = GeometryUtils::copyToVtkImageData(imageData);
+    if (!vtkImage)
     {
+        LOG(WARNING) << "Error: conversion unsuccessful. Target path supplied:" << filePath;
         return false;
     }
 
     auto writer = vtkSmartPointer<vtkMetaImageWriter>::New();
-    if (vtkMesh->GetDimensions()[2] == 1)
+    if (vtkImage->GetDimensions()[2] == 1)
     {
         writer->SetFileDimensionality(2);
     }
@@ -500,7 +511,7 @@ VTKMeshIO::writeMetaImageData(std::shared_ptr<ImageData> imageData, const std::s
     {
         writer->SetFileDimensionality(3);
     }
-    writer->SetInputData(vtkMesh);
+    writer->SetInputData(vtkImage);
     writer->SetFileName(filePath.c_str());
     writer->SetRAWFileName((filePath + ".raw").c_str());
     writer->Write();
diff --git a/Source/MeshIO/imstkVegaMeshIO.cpp b/Source/MeshIO/imstkVegaMeshIO.cpp
index b2def6c513f560c51fa7b4719967b26a6b264b66..643e94f517dd1dd7bff7c9a958225d3730b5969c 100644
--- a/Source/MeshIO/imstkVegaMeshIO.cpp
+++ b/Source/MeshIO/imstkVegaMeshIO.cpp
@@ -33,7 +33,7 @@ namespace imstk
 std::shared_ptr<VolumetricMesh>
 VegaMeshIO::read(const std::string& filePath, MeshFileType meshType)
 {
-    CHECK(meshType == MeshFileType::VEG) << "VegaMeshIO::read error: file type not supported";
+    CHECK(meshType == MeshFileType::VEG) << "@VegaMeshIO::read error: input file type is not veg for input " << filePath;
 
     // Read Vega Mesh
     std::shared_ptr<vega::VolumetricMesh> vegaMesh = VegaMeshIO::readVegaMesh(filePath);
@@ -45,29 +45,30 @@ VegaMeshIO::read(const std::string& filePath, MeshFileType meshType)
 bool
 VegaMeshIO::write(const std::shared_ptr<imstk::PointSet> imstkMesh, const std::string& filePath, const MeshFileType meshType)
 {
-    CHECK(meshType == MeshFileType::VEG) << "VegaMeshIO::write error: file type is not veg";
+    CHECK(meshType == MeshFileType::VEG) << "@VegaMeshIO::write error: file type is not veg for input " << filePath;
 
     // extract volumetric mesh
     const auto imstkVolMesh = std::dynamic_pointer_cast<imstk::VolumetricMesh>(imstkMesh);
 
-    CHECK(imstkVolMesh != nullptr) << "VegaMeshIO::write error: imstk::Mesh is not a volumetric mesh";
+    CHECK(imstkVolMesh != nullptr) << "@VegaMeshIO::write error: imstk::PointSet object supplied is not a imstk::VolumetricMesh type for input" << filePath;
 
     const std::string geometryType = imstkVolMesh->getTypeName();
     if (geometryType == "TetrahedralMesh" || geometryType == "HexahedralMesh")
     {
         auto vegaMesh = convertVolumetricMeshToVegaMesh(imstkVolMesh);
 
-        CHECK(vegaMesh != nullptr) << "VegaMeshIO::write error: failed to convert volumetric mesh to vega mesh";
+        CHECK(vegaMesh != nullptr) << "@VegaMeshIO::write error: failed to convert volumetric mesh to vega mesh for input" << filePath;
 
         const auto fileName     = const_cast<char*>(filePath.c_str());
         const int  write_status = vegaMesh->save(fileName);
 
-        CHECK(write_status == 0) << "VegaMeshIO::write error: failed to write .veg file";
+        CHECK(write_status == 0) << "@VegaMeshIO::write error: failed (vega fail code " << write_status <<
+            ". Check vega::VolumetricMesh::save for documentation)to write .veg file for input" << filePath;
 
         return true;
     }
 
-    LOG(WARNING) << "VegaMeshIO::write error: this element type not supported in vega";
+    LOG(WARNING) << "Error: Unknown element type (only tetrahedral and hexahedral elements supported) for input " << filePath;
     return false;
 }
 
@@ -96,7 +97,7 @@ VegaMeshIO::convertVegaMeshToVolumetricMesh(std::shared_ptr<vega::VolumetricMesh
         VegaMeshIO::copyCells<4>(vegaMesh, cells);
 
         auto tetMesh = std::make_shared<TetrahedralMesh>();
-        tetMesh->initialize(vertices, cellsPtr, false);
+        tetMesh->initialize(vertices, cellsPtr);
         mesh = tetMesh;
     }
     else if (cellType == vega::VolumetricMesh::CUBIC)
@@ -106,13 +107,13 @@ VegaMeshIO::convertVegaMeshToVolumetricMesh(std::shared_ptr<vega::VolumetricMesh
         VegaMeshIO::copyCells<8>(vegaMesh, cells);
 
         auto hexMesh = std::make_shared<HexahedralMesh>();
-        hexMesh->initialize(vertices, cellsPtr, false);
+        hexMesh->initialize(vertices, cellsPtr);
         mesh = hexMesh;
     }
     else
     {
         vegaMesh.reset();
-        LOG(WARNING) << "VegaMeshIO::read error: invalid cell type.";
+        LOG(WARNING) << "Error: invalid cell type";
         return nullptr;
     }
     return mesh;
@@ -151,11 +152,6 @@ VegaMeshIO::convertVolumetricMeshToVegaMesh(const std::shared_ptr<imstk::Volumet
     // as of now, only works for TET elements
     if (imstkVolMesh->getTypeName() == "TetrahedralMesh")
     {
-        // Using default material properties to append to the .veg file
-        const double E       = 1E7;
-        const double nu      = 0.4;
-        const double density = 1000.0;
-
         auto imstkVolTetMesh = std::dynamic_pointer_cast<imstk::TetrahedralMesh>(imstkVolMesh);
 
         auto                vertexArray = *imstkVolMesh->getVertexPositions();
@@ -177,16 +173,23 @@ VegaMeshIO::convertVolumetricMeshToVegaMesh(const std::shared_ptr<imstk::Volumet
             elements.emplace_back(int(tet[3]));
         }
 
-        std::shared_ptr<vega::TetMesh> vegaMesh = std::make_shared<vega::TetMesh>(int(imstkVolTetMesh->getNumVertices()), &vertices[0],
-            int(imstkVolTetMesh->getNumTetrahedra()), &elements[0], E, nu, density);
+        // Using default material properties to append to the .veg file
+        auto vegaMesh = std::make_shared<vega::TetMesh>(int(imstkVolTetMesh->getNumVertices()),
+            &vertices[0],
+            int(imstkVolTetMesh->getNumTetrahedra()),
+            &elements[0],
+            1E7, /* Young's modulus */
+            0.4, /* Poisson's ratio */
+            1000.0 /* density */);
 
-        CHECK(vegaMesh != nullptr) << "VegaMeshIO::convertVolumetricMeshToVegaMesh error: Failed to create vega mesh";
+        CHECK(vegaMesh != nullptr) << "@VegaMeshIO::convertVolumetricMeshToVegaMesh error: Failed to create vega mesh. "
+                                   << "Check vega::TetMesh::TetMesh() for clues";
 
         return vegaMesh;
     }
     else
     {
-        LOG(WARNING) << "VegaMeshIO::convertVolumetricMeshToVegaMesh error: Geometry type not supported";
+        LOG(WARNING) << "Error: Geometry type other than tetrahedral mesh not supported";
         return nullptr;
     }
 }
diff --git a/Source/Pulse/CMakeLists.txt b/Source/Pulse/CMakeLists.txt
deleted file mode 100644
index d180f45dafea057baeb310c0f56fb22f856c4cee..0000000000000000000000000000000000000000
--- a/Source/Pulse/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-#-----------------------------------------------------------------------------
-# Create target
-#-----------------------------------------------------------------------------
-if(iMSTK_USE_Pulse)
-  include(imstkAddLibrary)
-  imstk_add_library( Pulse
-    DEPENDS
-      Scene
-      Pulse::CommonPulseModels)
-endif()
\ No newline at end of file
diff --git a/Source/Pulse/imstkHemorrhageAction.cpp b/Source/Pulse/imstkHemorrhageAction.cpp
deleted file mode 100644
index a95059e69748df0d0ecf9fe937d339c3ea676a69..0000000000000000000000000000000000000000
--- a/Source/Pulse/imstkHemorrhageAction.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*=========================================================================
-
-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 "imstkHemorrhageAction.h"
-
-#include "PulsePhysiologyEngine.h"
-#include "CommonDataModel.h"
-#include "engine/SEEngineTracker.h"
-#include "engine/SEDataRequest.h"
-#include "engine/SEDataRequestManager.h"
-#include "engine/SEAction.h"
-#include "utils/DataTrack.h"
-#include "patient/actions/SEHemorrhage.h"
-#include "properties/SEScalarVolumePerTime.h"
-#include "compartment/SECompartmentManager.h"
-
-#include "properties/SEScalarTime.h"
-#include "engine/SEEngineTracker.h"
-#include "compartment/SECompartmentManager.h"
-#include "patient/actions/SESubstanceCompoundInfusion.h"
-#include "system/physiology/SEBloodChemistrySystem.h"
-#include "system/physiology/SECardiovascularSystem.h"
-#include "system/physiology/SEEnergySystem.h"
-#include "system/physiology/SERespiratorySystem.h"
-#include "substance/SESubstanceManager.h"
-#include "substance/SESubstanceCompound.h"
-#include "properties/SEScalar0To1.h"
-#include "properties/SEScalarFrequency.h"
-#include "properties/SEScalarMass.h"
-#include "properties/SEScalarMassPerVolume.h"
-#include "properties/SEScalarPressure.h"
-#include "properties/SEScalarTemperature.h"
-#include "properties/SEScalarTime.h"
-#include "properties/SEScalarVolume.h"
-#include "properties/SEScalarVolumePerTime.h"
-#include "properties/SEScalarVolumePerTimeArea.h"
-#include "compartment/fluid/SELiquidCompartmentGraph.h"
-
-namespace imstk
-{
-HemorrhageAction::HemorrhageAction(const Type t, const std::string& name)
-{
-    m_hemorrhage = std::make_shared<SEHemorrhage>();
-    this->setType(t);
-    this->SetCompartment("pulse::" + name);
-}
-
-void
-HemorrhageAction::setRate(double val /*in milliLiters/sec*/)
-{
-    m_hemorrhage->GetRate().SetValue(val, VolumePerTimeUnit::mL_Per_s);
-}
-
-void
-HemorrhageAction::setType(const Type t)
-{
-    (t == Type::External) ? m_hemorrhage->SetType(eHemorrhage_Type::External) :
-    m_hemorrhage->SetType(eHemorrhage_Type::External);
-}
-
-void
-HemorrhageAction::SetCompartment(const std::string& name)
-{
-    m_hemorrhage->SetCompartment(name);
-}
-
-double
-HemorrhageAction::getRate() const
-{
-    return m_hemorrhage->GetRate().GetValue(VolumePerTimeUnit::mL_Per_s);
-}
-
-std::shared_ptr<SEPatientAction>
-HemorrhageAction::getAction()
-{
-    return std::dynamic_pointer_cast<SEPatientAction>(m_hemorrhage);
-}
-}
\ No newline at end of file
diff --git a/Source/Pulse/imstkHemorrhageAction.h b/Source/Pulse/imstkHemorrhageAction.h
deleted file mode 100644
index 67aac34aab683d107e3ee5304d828931e45d2352..0000000000000000000000000000000000000000
--- a/Source/Pulse/imstkHemorrhageAction.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*=========================================================================
-
-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.
-
-=========================================================================*/
-
-#pragma once
-
-#include "imstkPhysiologyModel.h"
-
-class SEHemorrhage;
-
-namespace imstk
-{
-class HemorrhageAction : public PhysiologyAction
-{
-public:
-    enum class Type { External = 0, Internal };
-
-    HemorrhageAction(const Type t, const std::string& name);
-
-public:
-    ///
-    /// \brief Set the rate of hemorrhage
-    ///
-    void setRate(double val /*in milliLiters/sec*/);
-
-    ///
-    /// \brief Set the rate of hemorrhage
-    ///
-    void setType(const Type t);
-
-    ///
-    /// \brief Set the vascular compartment for hemorrhage
-    /// The string is expected to be pulse::VascularCompartment::<name_of_compartment>
-    /// (Refer: PulsePhysiologyEngine.h)
-    ///
-    void SetCompartment(const std::string& name);
-
-    ///
-    /// \brief Get the rate of hemorrhage in milliLiters/sec
-    ///
-    double getRate() const;
-
-    ///
-    /// \brief
-    ///
-    std::shared_ptr<SEPatientAction> getAction();
-
-protected:
-    std::shared_ptr<SEHemorrhage> m_hemorrhage;
-};
-}
\ No newline at end of file
diff --git a/Source/Pulse/imstkPhysiologyModel.cpp b/Source/Pulse/imstkPhysiologyModel.cpp
deleted file mode 100644
index 4215155d5ac89572ff9b61fdeed163251928d821..0000000000000000000000000000000000000000
--- a/Source/Pulse/imstkPhysiologyModel.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*=========================================================================
-
-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 "imstkPhysiologyModel.h"
-#include "imstkLogger.h"
-#include "imstkTaskGraph.h"
-
-// Pulse
-#include <PulsePhysiologyEngine.h>
-#include <engine/SEEngineTracker.h>
-#include <engine/SEDataRequestManager.h>
-#include <patient/actions/SEHemorrhage.h>
-#include <compartment/SECompartmentManager.h>
-
-namespace imstk
-{
-PhysiologyModel::PhysiologyModel() : AbstractDynamicalModel(DynamicalModelType::Physiology)
-{
-    m_solveNode = m_taskGraph->addFunction("PhysiologyModel_Solve", std::bind(&PhysiologyModel::solve, this));
-}
-
-bool
-PhysiologyModel::initialize()
-{
-    // Create the engine and load the patient
-    m_pulseObj = CreatePulseEngine();
-    m_pulseObj->GetLogger()->LogToConsole(m_config->m_enableLogging);
-
-    std::string patientFile;
-    switch (m_config->m_basePatient)
-    {
-    case PatientPhysiology::StandardMale:
-        patientFile = iMSTK_DATA_ROOT "/PhysiologyState/StandardMale@0s.pbb";
-        break;
-    case PatientPhysiology::StandardFemale:
-        patientFile = iMSTK_DATA_ROOT "/PhysiologyState/StandardFemale.json";
-        break;
-    default:
-        LOG(WARNING) << "Could not find the patient. Initializing to StandardMale";
-        patientFile = iMSTK_DATA_ROOT "/PhysiologyStates/StandardMale.json";
-    }
-
-    CHECK(m_pulseObj->SerializeFromFile(patientFile)) << "Could not load Pulse state file.";
-
-    // Submit data requests
-    for (auto dataPair : m_dataPairs)
-    {
-        m_pulseObj->GetEngineTracker()->GetDataRequestManager().CreatePhysiologyDataRequest(dataPair.first, dataPair.second);
-    }
-
-    return true;
-}
-
-void
-PhysiologyModel::addDataRequest(const std::string& property, SEDecimalFormat* dfault /*= nullptr*/)
-{
-    m_dataPairs.push_back(PhysiologyDataRequestPair(property, dfault));
-}
-
-const SECompartment*
-PhysiologyModel::getCompartment(const PhysiologyCompartmentType type, const std::string& compartmentName) const
-{
-    switch (type)
-    {
-    case PhysiologyCompartmentType::Gas:
-        return (SECompartment*)m_pulseObj->GetCompartments().GetGasCompartment(compartmentName);
-        break;
-    case PhysiologyCompartmentType::Liquid:
-        return (SECompartment*)m_pulseObj->GetCompartments().GetLiquidCompartment(compartmentName);
-        break;
-    case PhysiologyCompartmentType::Thermal:
-        return (SECompartment*)m_pulseObj->GetCompartments().GetThermalCompartment(compartmentName);
-        break;
-    case PhysiologyCompartmentType::Tissue:
-        return (SECompartment*)m_pulseObj->GetCompartments().GetTissueCompartment(compartmentName);
-        break;
-    default:
-        LOG(WARNING) << "Could not find the compartment type";
-        return nullptr;
-    }
-}
-
-void
-PhysiologyModel::solve()
-{
-    // Process all actions that are currently stored
-    for (auto i : m_actions)
-    {
-        m_pulseObj->ProcessAction(*i.second->getAction().get());
-    }
-
-    // Advance physiology model in time
-    m_pulseObj->AdvanceModelTime(m_config->m_timeStep, TimeUnit::s);
-
-    m_currentTime += m_config->m_timeStep;
-}
-
-void
-PhysiologyModel::initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink)
-{
-    // Setup graph connectivity
-    m_taskGraph->addEdge(source, m_solveNode);
-    m_taskGraph->addEdge(m_solveNode, sink);
-}
-}// imstk
diff --git a/Source/Pulse/imstkPhysiologyModel.h b/Source/Pulse/imstkPhysiologyModel.h
deleted file mode 100644
index 47156a177ff19d451907d7311e6c007fe5136cb2..0000000000000000000000000000000000000000
--- a/Source/Pulse/imstkPhysiologyModel.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*=========================================================================
-
-   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.
-
-=========================================================================*/
-
-#pragma once
-
-#include <unordered_map>
-
-#include "imstkAbstractDynamicalModel.h"/*
-#include "properties/SEScalarVolumePerTime.h"
-#include "compartment/fluid/SELiquidCompartment.h"*/
-
-class PhysiologyEngine;
-class SELiquidCompartment;
-class SEDecimalFormat;
-class SEPatientAction;
-class VolumePerTimeUnit;
-class SECompartment;
-
-namespace imstk
-{
-using PhysiologyDataRequestPair = std::pair<std::string, SEDecimalFormat*>;
-
-enum class PatientPhysiology
-{
-    StandardMale=0,
-    StandardFemale
-};
-
-enum class PhysiologyCompartmentType
-{
-    Gas = 0,
-    Liquid,
-    Thermal,
-    Tissue
-};
-
-class PhysiologyAction
-{
-public:
-    virtual std::shared_ptr<SEPatientAction> getAction() = 0;
-};
-
-///
-/// \struct PhysiologyModelConfig
-/// \brief Contains physiology model settings
-///
-struct PhysiologyModelConfig
-{
-    PatientPhysiology m_basePatient = PatientPhysiology::StandardMale;
-
-    double m_timeStep    = 0.02;  ///< Pulse time step
-    bool m_enableLogging = false; ///< Enable Pulse engine logging
-};
-
-///
-/// \class PhysiologyModel
-/// \brief Human physiology dynamical model
-///
-class PhysiologyModel : public AbstractDynamicalModel
-{
-public:
-    ///
-    /// \brief Constructor
-    ///
-    PhysiologyModel();
-
-    ///
-    /// \brief Destructor
-    ///
-    virtual ~PhysiologyModel() override = default;
-
-    ///
-    /// \brief Set simulation parameters
-    ///
-    void configure(const std::shared_ptr<PhysiologyModelConfig>& params) { m_config = params; }
-
-    ///
-    /// \brief Initialize the dynamical model
-    ///
-    virtual bool initialize() override;
-
-    ///
-    /// \brief Get the solver task node
-    ///
-    std::shared_ptr<TaskNode> getSolveNode() const { return m_solveNode; }
-
-    ///
-    /// \brief Update states
-    ///
-    virtual void updateBodyStates(const Vectord&, const StateUpdateType) override {}
-
-    ///
-    /// \brief Set the default time step size,
-    /// valid only if using a fixed time step for integration
-    ///
-    void setDefaultTimeStep(const Real) {}
-
-    ///
-    /// \brief Reset the physiology model to the initial state
-    ///
-    virtual void resetToInitialState() override {};
-
-    ///
-    /// \brief Add a data request that to output vitals to CSV files
-    ///
-    void addDataRequest(const std::string& property, SEDecimalFormat* dfault = nullptr);
-
-    ///
-    /// \brief Returns the time step size
-    ///
-    virtual double getTimeStep() const override { return m_config->m_timeStep; }
-
-    ///
-    /// \brief Set the time step of the pulse solver
-    ///
-    virtual void setTimeStep(const double t) override { m_config->m_timeStep = t; }
-
-    ///
-    /// \brief Add a new action
-    ///
-    void addAction(std::string name, std::shared_ptr<PhysiologyAction> action) { m_actions[name] = action; };
-
-    std::shared_ptr<PhysiologyAction> getAction(std::string name) const { return (m_actions.count(name) == 0) ? nullptr : m_actions.at(name); }
-
-    ///
-    /// \brief Clear all actions
-    ///
-    void clearActions() { m_actions.clear(); }
-
-    ///
-    /// \brief Set the name of the file to write out the data requests
-    ///
-    void setDataWriteOutFileName(const std::string& filename) { m_dataWriteOutFile = filename; }
-
-    ///
-    /// \brief Get the physiology compartment model of the body
-    ///
-    const SECompartment* getCompartment(const PhysiologyCompartmentType type, const std::string& compartmentName) const;
-
-protected:
-    ///
-    /// \brief Setup physiology compute graph connectivity
-    ///
-    virtual void initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink) override;
-
-    ///
-    /// \brief Advance one time step of the pulse engine solver
-    ///
-    void solve();
-
-    std::shared_ptr<TaskNode> m_solveNode = nullptr;
-
-    std::unordered_map<std::string, std::shared_ptr<PhysiologyAction>> m_actions; ///< container for all the actions
-    std::vector<PhysiologyDataRequestPair> m_dataPairs;                           ///< container for data requests
-
-private:
-    // main pulse object
-    std::unique_ptr<PhysiologyEngine> m_pulseObj = nullptr;
-
-    double m_currentTime = 0.;    ///< Current total time (incremented every solve)
-
-    std::string m_dataWriteOutFile = "pulseVitals.csv";
-
-    // Physiology Model parameters (must be set before simulation)
-    // empty for now but can be set if  needed
-    std::shared_ptr<PhysiologyModelConfig> m_config;
-};
-} // end namespace imstk
diff --git a/Source/Pulse/imstkPhysiologyObject.cpp b/Source/Pulse/imstkPhysiologyObject.cpp
deleted file mode 100644
index b792a785ae53254a0fadc155cc0cc2449ded1cd1..0000000000000000000000000000000000000000
--- a/Source/Pulse/imstkPhysiologyObject.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*=========================================================================
-
-   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 "imstkPhysiologyObject.h"
-#include "imstkLogger.h"
-#include "imstkPhysiologyModel.h"
-
-namespace imstk
-{
-PhysiologyObject::PhysiologyObject(const std::string& name) : DynamicObject(name)
-{
-    this->m_type = Type::Physiology;
-}
-
-std::shared_ptr<PhysiologyModel>
-PhysiologyObject::getPhysiologyModel()
-{
-    m_PhysiologyModel = std::dynamic_pointer_cast<PhysiologyModel>(m_dynamicalModel);
-    return m_PhysiologyModel;
-};
-
-bool
-PhysiologyObject::initialize()
-{
-    m_PhysiologyModel = std::dynamic_pointer_cast<PhysiologyModel>(m_dynamicalModel);
-    if (m_PhysiologyModel == nullptr)
-    {
-        LOG(FATAL) << "Dynamics pointer cast failure in SPHObject::initialize()";
-        return false;
-    }
-
-    DynamicObject::initialize();
-    m_PhysiologyModel->initialize();
-
-    return true;
-}
-} // end namespace imstk
diff --git a/Source/Pulse/imstkPhysiologyObject.h b/Source/Pulse/imstkPhysiologyObject.h
deleted file mode 100644
index 5fa31e1feb9cf94dfe52648310357ad7ccf0522c..0000000000000000000000000000000000000000
--- a/Source/Pulse/imstkPhysiologyObject.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*=========================================================================
-
-   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.
-
-=========================================================================*/
-
-#pragma once
-
-#include "imstkDynamicObject.h"
-
-namespace imstk
-{
-class PhysiologyModel;
-
-///
-/// \class PhysiologyObject
-///
-/// \brief Base class for Physiology objects
-///
-class PhysiologyObject : public DynamicObject
-{
-public:
-    explicit PhysiologyObject(const std::string& name);
-
-    virtual ~PhysiologyObject() override = default;
-
-public:
-    ///
-    /// \brief Initialize the Physiology scene object
-    ///
-    bool initialize() override;
-
-    std::shared_ptr<PhysiologyModel> getPhysiologyModel();
-
-protected:
-    std::shared_ptr<PhysiologyModel> m_PhysiologyModel = nullptr;
-};
-} // end namespace imstk
diff --git a/Source/Pulse/imstkSPHPhysiologyInteraction.cpp b/Source/Pulse/imstkSPHPhysiologyInteraction.cpp
deleted file mode 100644
index c008c2473f404afd76f665104edefaf07d2612cb..0000000000000000000000000000000000000000
--- a/Source/Pulse/imstkSPHPhysiologyInteraction.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*=========================================================================
-
-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 "imstkSPHPhysiologyInteraction.h"
-#include "imstkHemorrhageAction.h"
-#include "imstkPhysiologyObject.h"
-#include "imstkSPHModel.h"
-#include "imstkSPHObject.h"
-#include "imstkTaskGraph.h"
-
-// Pulse
-#include <PulsePhysiologyEngine.h>
-#include <compartment/fluid/SELiquidCompartmentGraph.h>
-
-namespace imstk
-{
-SPHPhysiologyObjectInteractionPair::SPHPhysiologyObjectInteractionPair(
-    std::shared_ptr<SPHObject>        obj1,
-    std::shared_ptr<PhysiologyObject> obj2) :
-    ObjectInteractionPair(obj1, obj2)
-{
-    m_sphModel = obj1->getDynamicalSPHModel();
-    m_physiologyModel = obj2->getPhysiologyModel();
-
-    // Define where the boundary condition happens
-    m_bcNode = std::make_shared<TaskNode>([&]() { computeInteraction(); },
-      obj1->getName() + "_vs_" + obj2->getName() + "_boundaryCondition", true);
-
-    // Define where solver interaction happens
-    m_solveNodeInputs.first.push_back(m_sphModel->getTaskGraph()->getSource());
-    m_solveNodeInputs.second.push_back(m_physiologyModel->getTaskGraph()->getSource());
-
-    m_solveNodeOutputs.first.push_back(m_sphModel->getFindParticleNeighborsNode());
-    m_solveNodeOutputs.second.push_back(m_physiologyModel->getSolveNode());
-}
-
-void
-SPHPhysiologyObjectInteractionPair::computeInteraction()
-{
-    std::shared_ptr<SPHHemorrhage> hemorrhageModel = m_sphModel->getHemorrhageModel();
-    const SELiquidCompartment*     compartment     = (SELiquidCompartment*)m_physiologyModel->getCompartment(m_compartmentType, m_compartmentName);
-
-    // check if the hemorrhage is being used in SPH
-    if (hemorrhageModel != nullptr && m_hemorrhageAction != nullptr && compartment != nullptr)
-    {
-        // compute the hemorrhage flow rate
-        const double hemorrhageRate = m_sphModel->getHemorrhageModel()->getHemorrhageRate();
-
-        // set the hemorrhage flow rate in Pulse
-        m_hemorrhageAction->setRate(hemorrhageRate);
-
-        // compute the femoral flow rate from Pulse
-        const double flowRate = compartment->GetInFlow(VolumePerTimeUnit::mL_Per_s);
-
-        // set the femoral flow rate as an SPH inlet boundary condition
-        m_sphModel->getBoundaryConditions()->setInletVelocity(flowRate);
-
-        // set how much time to run Pulse for
-        m_physiologyModel->setTimeStep(m_sphModel->getTimeStep());
-    }
-}
-
-void
-SPHPhysiologyObjectInteractionPair::apply()
-{
-    // Add the SPH physiology interaction node to the task graph
-    m_objects.first->getTaskGraph()->addNode(m_bcNode);
-    m_objects.second->getTaskGraph()->addNode(m_bcNode);
-
-    // Add the edges to the task graph
-    for (size_t i = 0; i < m_solveNodeInputs.first.size(); i++)
-    {
-        m_objects.first->getTaskGraph()->addEdge(m_solveNodeInputs.first[i], m_bcNode);
-    }
-    for (size_t i = 0; i < m_solveNodeInputs.second.size(); i++)
-    {
-        m_objects.second->getTaskGraph()->addEdge(m_solveNodeInputs.second[i], m_bcNode);
-    }
-
-    for (size_t i = 0; i < m_solveNodeOutputs.first.size(); i++)
-    {
-        m_objects.first->getTaskGraph()->addEdge(m_bcNode, m_solveNodeOutputs.first[i]);
-    }
-    for (size_t i = 0; i < m_solveNodeOutputs.second.size(); i++)
-    {
-        m_objects.second->getTaskGraph()->addEdge(m_bcNode, m_solveNodeOutputs.second[i]);
-    }
-}
-}
\ No newline at end of file
diff --git a/Source/Pulse/imstkSPHPhysiologyInteraction.h b/Source/Pulse/imstkSPHPhysiologyInteraction.h
deleted file mode 100644
index 7faa274b56d415577166163296fc702ece8b8208..0000000000000000000000000000000000000000
--- a/Source/Pulse/imstkSPHPhysiologyInteraction.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*=========================================================================
-
-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.
-
-=========================================================================*/
-
-#pragma once
-
-#include "imstkCollisionPair.h"
-#include "imstkPhysiologyModel.h"
-
-namespace imstk
-{
-class SPHObject;
-class PhysiologyObject;
-class SPHModel;
-class HemorrhageAction;
-
-///
-/// \class SPHPhysiologyObjectInteractionPair
-///
-/// \brief This class defines an interaction between SPH and physiology (Pulse)
-///
-class SPHPhysiologyObjectInteractionPair : public ObjectInteractionPair
-{
-public:
-    SPHPhysiologyObjectInteractionPair(std::shared_ptr<SPHObject> obj1, std::shared_ptr<PhysiologyObject> obj2);
-
-    virtual ~SPHPhysiologyObjectInteractionPair() override = default;
-
-public:
-    void apply() override;
-
-    ///
-    /// \brief Computes hemorrhage interaction between SPH and physiology (Pulse)
-    ///
-    void computeInteraction();
-
-    ///
-    /// \brief Set the Pulse hemorrhage action that should be connected to the SPH hemorrhage model
-    ///
-    void setHemorrhageAction(std::shared_ptr<HemorrhageAction> hemorrhageAction) { m_hemorrhageAction = hemorrhageAction; }
-
-    ///
-    /// \brief Set the pulse compartment of the body where the hemorrhage is happening
-    ///
-    void setCompartment(const PhysiologyCompartmentType type, const std::string& compartmentName)
-    {
-        m_compartmentType = type;
-        m_compartmentName = compartmentName;
-    }
-
-private:
-    Inputs  m_solveNodeInputs;
-    Outputs m_solveNodeOutputs;
-    std::shared_ptr<SPHModel> m_sphModel = nullptr;
-    std::shared_ptr<PhysiologyModel> m_physiologyModel = nullptr;
-    std::shared_ptr<TaskNode> m_bcNode = nullptr;
-
-    std::shared_ptr<HemorrhageAction> m_hemorrhageAction;
-
-    PhysiologyCompartmentType m_compartmentType;
-    std::string m_compartmentName;
-};
-}
\ No newline at end of file
diff --git a/Source/Rendering/CMakeLists.txt b/Source/Rendering/CMakeLists.txt
index 865e59e49e2f9f86f9a6dc90b8369cd4d38178e0..5855c4ed7ccc57302092826c3037d8fe9e846477 100644
--- a/Source/Rendering/CMakeLists.txt
+++ b/Source/Rendering/CMakeLists.txt
@@ -5,7 +5,7 @@
 set(VTK_H_FILES
     VTKRenderer/imstkVTKRenderer.h
     VTKRenderer/imstkVTKTextureDelegate.h
-    VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h
+    VTKRenderer/RenderDelegate/imstkVTKOrientedBoxRenderDelegate.h
     VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h
     VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h
     VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h
@@ -13,6 +13,7 @@ set(VTK_H_FILES
     VTKRenderer/RenderDelegate/imstkVTKImageDataRenderDelegate.h
     VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h
     VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h
+    VTKRenderer/RenderDelegate/imstkVTKSurfaceNormalRenderDelegate.h
     VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h
     VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h
     VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h
@@ -27,13 +28,14 @@ set(VTK_H_FILES
 set(VTK_CPP_FILES
     VTKRenderer/imstkVTKRenderer.cpp
     VTKRenderer/imstkVTKTextureDelegate.cpp
-    VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
+    VTKRenderer/RenderDelegate/imstkVTKOrientedBoxRenderDelegate.cpp
     VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp
     VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
     VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp
     VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
     VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
     VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp
+    VTKRenderer/RenderDelegate/imstkVTKSurfaceNormalRenderDelegate.cpp
     VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp
     VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp
     VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
diff --git a/Source/Rendering/Materials/imstkRenderMaterial.cpp b/Source/Rendering/Materials/imstkRenderMaterial.cpp
index 3f7974c09facddc4457fedfc7f4c44e4a271accf..f925b643867ddab3f9e47ba5b5dff3387708a80c 100644
--- a/Source/Rendering/Materials/imstkRenderMaterial.cpp
+++ b/Source/Rendering/Materials/imstkRenderMaterial.cpp
@@ -54,7 +54,7 @@ RenderMaterial::setTessellated(const bool tessellated)
 }
 
 void
-RenderMaterial::setLineWidth(const float width)
+RenderMaterial::setLineWidth(const double width)
 {
     if (width != m_lineWidth)
     {
@@ -64,7 +64,7 @@ RenderMaterial::setLineWidth(const float width)
 }
 
 void
-RenderMaterial::setPointSize(const float size)
+RenderMaterial::setPointSize(const double size)
 {
     if (size != m_pointSize)
     {
@@ -132,7 +132,7 @@ RenderMaterial::setAmbientColor(const Color& color)
 }
 
 void
-RenderMaterial::setMetalness(const float metalness)
+RenderMaterial::setMetalness(const double metalness)
 {
     if (m_metalness != metalness)
     {
@@ -142,7 +142,7 @@ RenderMaterial::setMetalness(const float metalness)
 }
 
 void
-RenderMaterial::setRoughness(const float roughness)
+RenderMaterial::setRoughness(const double roughness)
 {
     if (roughness != m_roughness)
     {
@@ -152,7 +152,7 @@ RenderMaterial::setRoughness(const float roughness)
 }
 
 void
-RenderMaterial::setEmissivity(const float emissivity)
+RenderMaterial::setEmissivity(const double emissivity)
 {
     if (m_emissivity != emissivity)
     {
@@ -166,7 +166,7 @@ RenderMaterial::getTexture(Texture::Type type)
 {
     if (type >= Texture::Type::None)
     {
-        LOG(WARNING) << "RenderMaterial::getTexture error: Invalid texture format";
+        LOG(WARNING) << "error: Invalid texture format";
         return nullptr;
     }
     return m_textures[(unsigned int)type];
@@ -177,7 +177,7 @@ RenderMaterial::addTexture(std::shared_ptr<Texture> texture)
 {
     if (texture->getType() >= Texture::Type::None)
     {
-        LOG(WARNING) << "RenderMaterial::addTexture: Invalid texture format";
+        LOG(WARNING) << "Invalid texture format";
         return;
     }
     m_textures[static_cast<size_t>(texture->getType())] = texture;
@@ -251,7 +251,7 @@ RenderMaterial::setShadingModel(const ShadingModel& model)
 }
 
 void
-RenderMaterial::setOcclusionStrength(const float occlusionStrength)
+RenderMaterial::setOcclusionStrength(const double occlusionStrength)
 {
     if (occlusionStrength != m_occlusionStrength)
     {
@@ -261,7 +261,7 @@ RenderMaterial::setOcclusionStrength(const float occlusionStrength)
 }
 
 void
-RenderMaterial::setNormalStrength(const float normalStrength)
+RenderMaterial::setNormalStrength(const double normalStrength)
 {
     if (normalStrength != m_normalStrength)
     {
@@ -271,7 +271,7 @@ RenderMaterial::setNormalStrength(const float normalStrength)
 }
 
 void
-RenderMaterial::setIndexOfRefraction(const float indexOfRefraction)
+RenderMaterial::setIndexOfRefraction(const double indexOfRefraction)
 {
     if (indexOfRefraction == m_indexOfRefraction)
     {
@@ -301,7 +301,7 @@ RenderMaterial::setVertexColor(const Color& color)
 }
 
 void
-RenderMaterial::setOpacity(const float opacity)
+RenderMaterial::setOpacity(const double opacity)
 {
     if (m_opacity != opacity)
     {
diff --git a/Source/Rendering/Materials/imstkRenderMaterial.h b/Source/Rendering/Materials/imstkRenderMaterial.h
index caa3dfb6afc6768947422f66fefc397d6dfb35b2..2f03f213ce09132c0b9c8d86ac4300b496fd25bb 100644
--- a/Source/Rendering/Materials/imstkRenderMaterial.h
+++ b/Source/Rendering/Materials/imstkRenderMaterial.h
@@ -49,7 +49,8 @@ public:
         WireframeSurface,
         VolumeRendering,
         Fluid,               ///< Renders a set of points using a screen-space fluid renderer
-        Image
+        Image,
+        SurfaceNormals
     };
 
     /// surface shading model. Defaults to Phong
@@ -75,51 +76,53 @@ public:
     virtual ~RenderMaterial() = default;
 
 public:
+    // *INDENT-OFF*
     ///
     /// \brief Posted when material parameters are modified
     ///
-    SIGNAL(RenderMaterial,modified);
+    SIGNAL(RenderMaterial, modified);
 
     ///
     /// \brief Posted when textures are modified
     ///
-    SIGNAL(RenderMaterial,texturesModified);
+    SIGNAL(RenderMaterial, texturesModified);
+    // *INDENT-ON*
 
 public:
     ///
     /// \brief Get/Set the material name
     ///
-    const std::string& getName() const{ return m_name; }
+    const std::string& getName() const { return m_name; }
     void setName(std::string name) { m_name = name; }
 
     ///
     /// \brief Get/Set display mode
     ///
-    const DisplayMode getDisplayMode() const{ return m_displayMode; }
+    const DisplayMode getDisplayMode() const { return m_displayMode; }
     void setDisplayMode(const DisplayMode displayMode);
 
     ///
     /// \brief Get/Set tessellated
     ///
-    const bool getTessellated() const{ return m_tessellated; }
+    const bool getTessellated() const { return m_tessellated; }
     void setTessellated(const bool tessellated);
 
     ///
     /// \brief Get/Set line width or the wireframe
     ///
-    const float getLineWidth() const{ return m_lineWidth; }
-    void setLineWidth(const float width);
+    const double getLineWidth() const { return m_lineWidth; }
+    void setLineWidth(const double width);
 
     ///
     /// \brief Get/Set point radius
     ///
-    const float getPointSize() const{ return m_pointSize; }
-    void setPointSize(const float size);
+    const double getPointSize() const { return m_pointSize; }
+    void setPointSize(const double size);
 
     ///
     /// \brief Backface culling on/off
     ///
-    const bool getBackFaceCulling() const{ return m_backfaceCulling; }
+    const bool getBackFaceCulling() const { return m_backfaceCulling; }
     void setBackFaceCulling(const bool culling);
     void backfaceCullingOn();
     void backfaceCullingOff();
@@ -128,64 +131,64 @@ public:
     /// \brief Get/Set the color. This affects the diffuse color directly, but
     /// it affects the specular color in the case of metals.
     ///
-    const Color& getDiffuseColor() const{ return m_diffuseColor; }
+    const Color& getDiffuseColor() const { return m_diffuseColor; }
     void setDiffuseColor(const Color& color);
-    const Color& getColor() const{ return this->getDiffuseColor(); }
+    const Color& getColor() const { return this->getDiffuseColor(); }
     void setColor(const Color& color);
 
     ///
     /// \brief Get/Set the specular color
     ///
-    const Color& getSpecularColor() const{ return m_specularColor; }
+    const Color& getSpecularColor() const { return m_specularColor; }
     void setSpecularColor(const Color& color);
 
     ///
     /// \brief Get/Set the specular amount
     ///
-    float getSpecular() const{ return m_specular; }
-    void setSpecular(float specular) { m_specular = specular; }
+    double getSpecular() const { return m_specular; }
+    void setSpecular(double specular) { m_specular = specular; }
 
     ///
     /// \brief Get/Set the ambient color
     ///
-    const Color& getAmbientColor() const{ return m_ambientColor; }
+    const Color& getAmbientColor() const { return m_ambientColor; }
     void setAmbientColor(const Color& color);
 
     ///
     /// \brief Get/Set the metalness
     ///
-    const float getMetalness() const{ return m_metalness; }
-    void setMetalness(const float metalness);
+    const double getMetalness() const { return m_metalness; }
+    void setMetalness(const double metalness);
 
     ///
     /// \brief Get/Set ambient light coefficient
     ///
-    const float getAmbient() const{ return m_ambient; };
-    void setAmbient(float ambient) { m_ambient = ambient; }
+    const double getAmbient() const { return m_ambient; };
+    void setAmbient(double ambient) { m_ambient = ambient; }
 
     ///
     /// \brief Get/Set diffuse light coefficient
     ///
-    const float getDiffuse() const{ return m_diffuse; }
-    void setDiffuse(float diffuse) { m_diffuse = diffuse; }
+    const double getDiffuse() const { return m_diffuse; }
+    void setDiffuse(double diffuse) { m_diffuse = diffuse; }
 
     ///
     /// \brief Get/Set ambient light coefficient
     ///
-    const float getSpecularPower() const{ return m_specularPower; }
-    void setSpecularPower(const float p) { m_specularPower = p; }
+    const double getSpecularPower() const { return m_specularPower; }
+    void setSpecularPower(const double p) { m_specularPower = p; }
 
     ///
     /// \brief Get/Set the roughness
     ///
-    const float getRoughness() const{ return m_roughness; }
-    void setRoughness(const float roughness);
+    const double getRoughness() const { return m_roughness; }
+    void setRoughness(const double roughness);
 
     ///
     /// \brief Get/Set emissivity
     ///
-    const float getEmissivity() const{ return m_emissivity; }
-    void setEmissivity(const float emissivity);
+    const double getEmissivity() const { return m_emissivity; }
+    void setEmissivity(const double emissivity);
 
     ///
     /// \brief Add/Remove/Get texture
@@ -199,19 +202,19 @@ public:
     /// \brief Get/Set shadow receiving ability
     ///
     void setReceivesShadows(const bool receivesShadows);
-    bool getReceivesShadows() const{ return m_receivesShadows; }
+    bool getReceivesShadows() const { return m_receivesShadows; }
 
     ///
     /// \brief Get/Set shadow cast status
     ///
     void setCastsShadows(const bool castsShadows);
-    bool getCastsShadows() const{ return m_castsShadows; }
+    bool getCastsShadows() const { return m_castsShadows; }
 
     ///
     /// \brief Get/Set edge visibility
     ///
     void setEdgeVisibility(const bool visibility) { m_edgeVisibility = visibility; };
-    bool getEdgeVisibility() const{ return m_edgeVisibility; };
+    bool getEdgeVisibility() const { return m_edgeVisibility; };
 
     ///
     /// \brief Get/Set blend mode
@@ -219,50 +222,50 @@ public:
     /// and the MAXIMUM_INTENSITY and MINIMUM_INTENSITY blend modes are only available for volumes
     ///
     virtual void setBlendMode(const BlendMode blendMode);
-    const BlendMode getBlendMode() const{ return m_blendMode; }
+    const BlendMode getBlendMode() const { return m_blendMode; }
 
     ///
     /// \brief Checks if the material must be handled uniquely
     ///
-    bool isDecal() const{ return m_isDecal; }
-    bool isParticle() const{ return m_isParticle; }
-    bool isLineMesh() const{ return m_isLineMesh; }
+    bool isDecal() const { return m_isDecal; }
+    bool isParticle() const { return m_isParticle; }
+    bool isLineMesh() const { return m_isLineMesh; }
 
-    const DisplayMode getRenderMode() const{ return m_displayMode; }
-    const ShadingModel getShadingModel() const{ return m_shadingModel; }
+    const DisplayMode getRenderMode() const { return m_displayMode; }
+    const ShadingModel getShadingModel() const { return m_shadingModel; }
     void setShadingModel(const ShadingModel& model);
 
-    float getOcclusionStrength() const{ return m_occlusionStrength; }
-    void setOcclusionStrength(const float o);
+    double getOcclusionStrength() const { return m_occlusionStrength; }
+    void setOcclusionStrength(const double o);
 
-    float getNormalStrength() const{ return m_normalStrength; }
-    void setNormalStrength(const float n);
+    double getNormalStrength() const { return m_normalStrength; }
+    void setNormalStrength(const double n);
 
-    float getIndexOfRefraction() const{ return m_indexOfRefraction; }
-    void setIndexOfRefraction(const float n);
+    double getIndexOfRefraction() const { return m_indexOfRefraction; }
+    void setIndexOfRefraction(const double n);
 
-    const Color& getEdgeColor() const{ return m_edgeColor; }
+    const Color& getEdgeColor() const { return m_edgeColor; }
     void setEdgeColor(const Color& color);
 
-    const Color& getVertexColor() const{ return m_vertexColor; }
+    const Color& getVertexColor() const { return m_vertexColor; }
     void setVertexColor(const Color& color);
 
-    const double getOpacity() const{ return m_opacity; }
-    void setOpacity(const float opacity);
+    const double getOpacity() const { return m_opacity; }
+    void setOpacity(const double opacity);
 
-    const bool getBackfaceCulling() const{ return m_backfaceCulling; }
+    const bool getBackfaceCulling() const { return m_backfaceCulling; }
     void setBackfaceCulling(const bool c);
 
-    std::shared_ptr<ColorFunction> getColorLookupTable() const{ return m_lookupTable; }
+    std::shared_ptr<ColorFunction> getColorLookupTable() const { return m_lookupTable; }
     void setColorLookupTable(std::shared_ptr<ColorFunction> lut);
 
-    const bool getScalarVisibility() const{ return m_scalarVisibility; }
+    const bool getScalarVisibility() const { return m_scalarVisibility; }
     void setScalarVisibility(const bool scalarVisibility);
 
-    const bool getRecomputeVertexNormals() const{ return m_recomputeVertexNormals; }
+    const bool getRecomputeVertexNormals() const { return m_recomputeVertexNormals; }
     void setRecomputeVertexNormals(const bool recomputeVertexNormals) { m_recomputeVertexNormals = recomputeVertexNormals; }
 
-    const bool getRenderPointsAsSpheres() const{ return m_renderPointsAsSpheres; }
+    const bool getRenderPointsAsSpheres() const { return m_renderPointsAsSpheres; }
     void setRenderPointsAsSpheres(const bool renderPointsAsSpheres) { m_renderPointsAsSpheres = renderPointsAsSpheres; }
 
     void postModified() { this->postEvent(Event(RenderMaterial::modified())); }
@@ -284,35 +287,35 @@ protected:
     BlendMode m_blendMode = BlendMode::Alpha;
 
     ///-------------------Common properties---------------------
-    float m_diffuse      = 1.0f;
-    Color m_diffuseColor = Color::LightGray;
+    double m_diffuse      = 1.0;
+    Color  m_diffuseColor = Color::LightGray;
 
-    float m_specularPower = 100.0f;
-    float m_specular      = 0.0f;
-    Color m_specularColor = Color::Red;
+    double m_specularPower = 100.0;
+    double m_specular      = 0.0;
+    Color  m_specularColor = Color::Red;
 
-    float m_ambient      = 0.1f;
-    Color m_ambientColor = Color::White;
+    double m_ambient      = 0.1;
+    Color  m_ambientColor = Color::White;
 
-    float m_opacity = 1.0f;
+    double m_opacity = 1.0;
 
     ///-------------Wireframe specific properties----------------
-    float m_lineWidth        = 1.f;
-    float m_pointSize        = 2.f;
-    Color m_edgeColor        = Color::Marigold;
-    Color m_vertexColor      = Color::Teal;
-    bool  m_edgeVisibility   = true; ///< \note not used (vtk backend)
-    bool  m_vertexVisibility = true; ///< \note not used (vtk backend)
+    double m_lineWidth        = 1.0;
+    double m_pointSize        = 2.0;
+    Color  m_edgeColor        = Color::Marigold;
+    Color  m_vertexColor      = Color::Teal;
+    bool   m_edgeVisibility   = true; ///< \note not used (vtk backend)
+    bool   m_vertexVisibility = true; ///< \note not used (vtk backend)
 
     ///----------------PBR specific properties-------------------
-    float m_emissivity    = 0.f;
-    Color m_emmisiveColor = Color::White;
-
-    float m_metalness = 1.0f; ///< Value for metalness with range: [0.0, 1.0]
-    float m_roughness = 1.0f; ///< Value for roughness with range: [0.0, 1.0]
-    float m_occlusionStrength = 1.0f;
-    float m_normalStrength    = 1.0f;
-    float m_indexOfRefraction = 1.0f;
+    double m_emissivity    = 0.0;
+    Color  m_emmisiveColor = Color::White;
+
+    double m_metalness = 1.0; ///< Value for metalness with range: [0.0, 1.0]
+    double m_roughness = 1.0; ///< Value for roughness with range: [0.0, 1.0]
+    double m_occlusionStrength = 1.0;
+    double m_normalStrength    = 1.0;
+    double m_indexOfRefraction = 1.0;
 
     ///---------------------Global states------------------------
     bool m_imageBasedLighting = false;
diff --git a/Source/Rendering/Materials/imstkTexture.h b/Source/Rendering/Materials/imstkTexture.h
index 1d22478bd895c782ca097d9f31d6178daa19d130..d61989605f291d5afdeafeabc2c98b67b0a655dc 100644
--- a/Source/Rendering/Materials/imstkTexture.h
+++ b/Source/Rendering/Materials/imstkTexture.h
@@ -91,7 +91,9 @@ public:
     virtual ~Texture() = default;
 
 public:
-    SIGNAL(Texture,modified);
+    // *INDENT-OFF*
+    SIGNAL(Texture, modified);
+    // *INDENT-ON*
 
     void postModified() { this->postEvent(Event(modified())); }
 
@@ -114,7 +116,7 @@ public:
     ///
     /// \brief Get path
     ///
-    const std::string& getPath() const{ return m_path; }
+    const std::string& getPath() const { return m_path; }
 
     ///
     /// \brief Get file extension
@@ -124,22 +126,22 @@ public:
     ///
     /// \brief Get if mipmaps are enabled
     ///
-    const bool getMipmapsEnabled() const{ return m_mipmapsEnabled; }
+    const bool getMipmapsEnabled() const { return m_mipmapsEnabled; }
 
     ///
     /// \brief Get if repeat is enabled, if off it clamps
     ///
-    const bool getRepeating() const{ return m_repeating; }
+    const bool getRepeating() const { return m_repeating; }
 
     ///
     /// \brief Get if anisotropic filtering is enabled
     ///
-    const bool isAnisotropyEnabled() const{ return m_anisotropyEnabled; }
+    const bool isAnisotropyEnabled() const { return m_anisotropyEnabled; }
 
     ///
     /// \brief Get anisotropy factor
     ///
-    const double getAnisotropyFactor() const{ return m_anisotropyFactor; }
+    const double getAnisotropyFactor() const { return m_anisotropyFactor; }
 
     ///
     /// \brief Set the input image data, not required (paths to files can be used instead)
@@ -149,7 +151,7 @@ public:
     ///
     /// \brief Get the input image data for the texture, not required (paths to files can be used instead)
     ///
-    std::shared_ptr<ImageData> getImageData() const{ return imageTexture; }
+    std::shared_ptr<ImageData> getImageData() const { return imageTexture; }
 
 protected:
     std::shared_ptr<ImageData> imageTexture = nullptr;
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
index e992620a458505d6a6b20c354adc55bd20b504ba..257b5e93eae774d9ca2eee97a78b46546f487766 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp
@@ -30,17 +30,21 @@
 
 namespace imstk
 {
-VTKCapsuleRenderDelegate::VTKCapsuleRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel)
+VTKCapsuleRenderDelegate::VTKCapsuleRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel),
+    m_capsuleSource(vtkSmartPointer<vtkCapsuleSource>::New())
 {
-    auto geometry = std::static_pointer_cast<Capsule>(visualModel->getGeometry());
+    auto geometry = std::dynamic_pointer_cast<Capsule>(visualModel->getGeometry());
 
-    m_capsuleSource = vtkSmartPointer<vtkCapsuleSource>::New();
-    m_capsuleSource->SetRadius(geometry->getRadius());
-    m_capsuleSource->SetCylinderLength(geometry->getLength());
+    m_capsuleSource->SetCenter(0.0, 0.0, 0.0);
+    m_capsuleSource->SetRadius(geometry->getRadius(Geometry::DataType::PreTransform));
+    m_capsuleSource->SetCylinderLength(geometry->getLength(Geometry::DataType::PreTransform));
     m_capsuleSource->SetLatLongTessellation(20);
     m_capsuleSource->SetPhiResolution(20);
     m_capsuleSource->SetThetaResolution(20);
 
+    const Mat4d& transform = geometry->getTransform().transpose();
+    m_transform->SetMatrix(transform.data());
+
     // Setup mapper
     {
         vtkNew<vtkPolyDataMapper> mapper;
@@ -62,17 +66,17 @@ VTKCapsuleRenderDelegate::processEvents()
     VTKRenderDelegate::processEvents();
 
     // Don't use events for primitives, just always update
-    auto geometry = std::static_pointer_cast<Capsule>(m_visualModel->getGeometry());
+    auto geometry = std::dynamic_pointer_cast<Capsule>(m_visualModel->getGeometry());
 
-    m_capsuleSource->SetRadius(geometry->getRadius());
-    m_capsuleSource->SetCylinderLength(geometry->getLength());
+    m_capsuleSource->SetRadius(geometry->getRadius(Geometry::DataType::PreTransform));
+    m_capsuleSource->SetCylinderLength(geometry->getLength(Geometry::DataType::PreTransform));
+    m_capsuleSource->Modified();
 
     AffineTransform3d T = AffineTransform3d::Identity();
     T.translate(geometry->getPosition(Geometry::DataType::PostTransform));
-    T.rotate(Quatd::FromTwoVectors(UP_VECTOR, geometry->getOrientationAxis(Geometry::DataType::PostTransform)));
-    T.scale(1.0);
+    T.rotate(geometry->getOrientation(Geometry::DataType::PostTransform));
+    T.scale(geometry->getScaling());
     T.matrix().transposeInPlace();
-
     m_transform->SetMatrix(T.data());
 }
 } // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
index b11ede104c564222cca1677a973798f31db72b73..bdc02c7d4a4cdf51a04f97c063b2cfa1520e967b 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp
@@ -31,16 +31,19 @@
 
 namespace imstk
 {
-VTKCylinderRenderDelegate::VTKCylinderRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel)
+VTKCylinderRenderDelegate::VTKCylinderRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel),
+    m_cylinderSource(vtkSmartPointer<vtkCylinderSource>::New())
 {
-    auto geometry = std::static_pointer_cast<Cylinder>(visualModel->getGeometry());
+    auto geometry = std::dynamic_pointer_cast<Cylinder>(visualModel->getGeometry());
 
-    m_cylinderSource = vtkSmartPointer<vtkCylinderSource>::New();
     m_cylinderSource->SetCenter(0.0, 0.0, 0.0);
-    m_cylinderSource->SetRadius(1.0);
-    m_cylinderSource->SetHeight(geometry->getLength());
+    m_cylinderSource->SetRadius(geometry->getRadius(Geometry::DataType::PreTransform));
+    m_cylinderSource->SetHeight(geometry->getLength(Geometry::DataType::PreTransform));
     m_cylinderSource->SetResolution(100);
 
+    const Mat4d& transform = geometry->getTransform().transpose();
+    m_transform->SetMatrix(transform.data());
+
     // Setup mapper
     {
         vtkNew<vtkPolyDataMapper> mapper;
@@ -61,17 +64,17 @@ VTKCylinderRenderDelegate::processEvents()
 {
     VTKRenderDelegate::processEvents();
 
-    auto geometry = std::static_pointer_cast<Cylinder>(m_visualModel->getGeometry());
+    auto geometry = std::dynamic_pointer_cast<Cylinder>(m_visualModel->getGeometry());
 
-    m_cylinderSource->SetRadius(geometry->getRadius());
-    m_cylinderSource->SetHeight(geometry->getLength());
+    m_cylinderSource->SetRadius(geometry->getRadius(Geometry::DataType::PreTransform));
+    m_cylinderSource->SetHeight(geometry->getLength(Geometry::DataType::PreTransform));
+    m_cylinderSource->Modified();
 
     AffineTransform3d T = AffineTransform3d::Identity();
     T.translate(geometry->getPosition(Geometry::DataType::PostTransform));
-    T.rotate(Quatd::FromTwoVectors(UP_VECTOR, geometry->getOrientationAxis(Geometry::DataType::PostTransform)));
-    T.scale(1.0);
+    T.rotate(geometry->getOrientation(Geometry::DataType::PostTransform));
+    T.scale(geometry->getScaling());
     T.matrix().transposeInPlace();
-
     m_transform->SetMatrix(T.data());
 }
 } // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKOrientedBoxRenderDelegate.cpp
similarity index 53%
rename from Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKOrientedBoxRenderDelegate.cpp
index 39ff30de2aad8b3ded86a454c44ee3877e6b928e..e6352f0aeef5b1cb5b9d581436ed4c7ce487eaa5 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKOrientedBoxRenderDelegate.cpp
@@ -19,8 +19,8 @@
 
 =========================================================================*/
 
-#include "imstkVTKCubeRenderDelegate.h"
-#include "imstkCube.h"
+#include "imstkVTKOrientedBoxRenderDelegate.h"
+#include "imstkOrientedBox.h"
 #include "imstkVisualModel.h"
 
 #include <vtkActor.h>
@@ -30,20 +30,24 @@
 
 namespace imstk
 {
-VTKCubeRenderDelegate::VTKCubeRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel)
+VTKOrientedCubeRenderDelegate::VTKOrientedCubeRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel),
+    m_cubeSource(vtkSmartPointer<vtkCubeSource>::New())
 {
-    //auto geometry = std::static_pointer_cast<Cube>(visualModel->getGeometry());
+    auto geometry = std::dynamic_pointer_cast<OrientedBox>(visualModel->getGeometry());
 
-    vtkNew<vtkCubeSource> cubeSource;
-    cubeSource->SetCenter(0, 0, 0);
-    cubeSource->SetXLength(1.0);
-    cubeSource->SetYLength(1.0);
-    cubeSource->SetZLength(1.0);
+    const Vec3d& extents = geometry->getExtents(Geometry::DataType::PreTransform);
+    m_cubeSource->SetCenter(0.0, 0.0, 0.0);
+    m_cubeSource->SetXLength(extents[0] * 2.0);
+    m_cubeSource->SetYLength(extents[1] * 2.0);
+    m_cubeSource->SetZLength(extents[2] * 2.0);
+
+    const Mat4d& transform = geometry->getTransform().transpose();
+    m_transform->SetMatrix(transform.data());
 
     // Setup mapper
     {
         vtkNew<vtkPolyDataMapper> mapper;
-        mapper->SetInputConnection(cubeSource->GetOutputPort());
+        mapper->SetInputConnection(m_cubeSource->GetOutputPort());
         vtkNew<vtkActor> actor;
         actor->SetMapper(mapper);
         actor->SetUserTransform(m_transform);
@@ -56,19 +60,24 @@ VTKCubeRenderDelegate::VTKCubeRenderDelegate(std::shared_ptr<VisualModel> visual
 }
 
 void
-VTKCubeRenderDelegate::processEvents()
+VTKOrientedCubeRenderDelegate::processEvents()
 {
     VTKRenderDelegate::processEvents();
 
-    // Don't use events for primitives, just always update
-    auto geometry = std::static_pointer_cast<Cube>(m_visualModel->getGeometry());
+    // Events aren't used for primitives, always update
+    auto geometry = std::dynamic_pointer_cast<OrientedBox>(m_visualModel->getGeometry());
+
+    const Vec3d& extents = geometry->getExtents(Geometry::DataType::PreTransform);
+    m_cubeSource->SetXLength(extents[0] * 2.0);
+    m_cubeSource->SetYLength(extents[1] * 2.0);
+    m_cubeSource->SetZLength(extents[2] * 2.0);
+    m_cubeSource->Modified();
 
     AffineTransform3d T = AffineTransform3d::Identity();
     T.translate(geometry->getPosition(Geometry::DataType::PostTransform));
-    T.rotate(Quatd::FromTwoVectors(UP_VECTOR, geometry->getOrientationAxis(Geometry::DataType::PostTransform)));
-    T.scale(geometry->getWidth(Geometry::DataType::PostTransform));
+    T.rotate(geometry->getOrientation(Geometry::DataType::PostTransform));
+    T.scale(geometry->getScaling());
     T.matrix().transposeInPlace();
-
     m_transform->SetMatrix(T.data());
 }
 } // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKOrientedBoxRenderDelegate.h
similarity index 74%
rename from Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h
rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKOrientedBoxRenderDelegate.h
index 4518656b5c1e11ee91fa4ea2fd2f8e44ad0b58f7..c8776ea0f4b7f60778e8fa64c050d3d1e4fb72e6 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKOrientedBoxRenderDelegate.h
@@ -23,29 +23,34 @@
 
 #include "imstkVTKPolyDataRenderDelegate.h"
 
+class vtkCubeSource;
+
 namespace imstk
 {
 ///
-/// \class VTKCubeRenderDelegate
+/// \class VTKOrientedCubeRenderDelegate
 ///
-/// \brief Cube render delegate with VTK backend
+/// \brief Oriented box render delegate with VTK backend
 ///
-class VTKCubeRenderDelegate : public VTKPolyDataRenderDelegate
+class VTKOrientedCubeRenderDelegate : public VTKPolyDataRenderDelegate
 {
 public:
     ///
     /// \brief Constructor
     ///
-    VTKCubeRenderDelegate(std::shared_ptr<VisualModel> visualModel);
+    VTKOrientedCubeRenderDelegate(std::shared_ptr<VisualModel> visualModel);
 
     ///
     /// \brief Destructor
     ///
-    virtual ~VTKCubeRenderDelegate() override = default;
+    virtual ~VTKOrientedCubeRenderDelegate() override = default;
 
     ///
     /// \brief Update cube source based on the cube geometry
     ///
     void processEvents() override;
+
+protected:
+    vtkSmartPointer<vtkCubeSource> m_cubeSource;
 };
 } // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
index 9575792dfbd3b9d24e640683cfb37faf7c839bf1..978293c4973286a9144b208b0978cb273be5a51c 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp
@@ -30,18 +30,22 @@
 
 namespace imstk
 {
-VTKPlaneRenderDelegate::VTKPlaneRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel)
+VTKPlaneRenderDelegate::VTKPlaneRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel),
+    m_planeSource(vtkSmartPointer<vtkPlaneSource>::New())
 {
-    //auto geometry = std::static_pointer_cast<Plane>(m_visualModel->getGeometry());
+    auto geometry = std::dynamic_pointer_cast<Plane>(m_visualModel->getGeometry());
 
-    vtkNew<vtkPlaneSource> planeSource;
-    planeSource->SetCenter(0.0, 0.0, 0.0);
-    planeSource->SetNormal(0.0, 1.0, 0.0);
+    m_planeSource = vtkSmartPointer<vtkPlaneSource>::New();
+    m_planeSource->SetCenter(0.0, 0.0, 0.0);
+    m_planeSource->SetNormal(geometry->getNormal(Geometry::DataType::PreTransform).data());
+
+    const Mat4d& transform = geometry->getTransform().transpose();
+    m_transform->SetMatrix(transform.data());
 
     // Setup mapper
     {
         vtkNew<vtkPolyDataMapper> mapper;
-        mapper->SetInputConnection(planeSource->GetOutputPort());
+        mapper->SetInputConnection(m_planeSource->GetOutputPort());
         vtkNew<vtkActor> actor;
         actor->SetMapper(mapper);
         actor->SetUserTransform(m_transform);
@@ -58,14 +62,17 @@ VTKPlaneRenderDelegate::processEvents()
 {
     VTKRenderDelegate::processEvents();
 
-    auto geometry = std::static_pointer_cast<Plane>(m_visualModel->getGeometry());
+    // Events aren't used for primitives, always update
+    auto geometry = std::dynamic_pointer_cast<Plane>(m_visualModel->getGeometry());
+
+    m_planeSource->SetNormal(geometry->getNormal(Geometry::DataType::PreTransform).data());
+    m_planeSource->Modified();
 
     AffineTransform3d T = AffineTransform3d::Identity();
     T.translate(geometry->getPosition(Geometry::DataType::PostTransform));
-    T.rotate(Quatd::FromTwoVectors(UP_VECTOR, geometry->getNormal(Geometry::DataType::PostTransform)));
-    T.scale(geometry->getWidth(Geometry::DataType::PostTransform));
+    T.rotate(geometry->getOrientation(Geometry::DataType::PostTransform));
+    T.scale(geometry->getScaling().maxCoeff());
     T.matrix().transposeInPlace();
-
     m_transform->SetMatrix(T.data());
 }
 } // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h
index 40c5f83d632e364dc274b2774442cc649f43b10c..1f7da42c8a7bd64b55970c5ec7d6f1f6db89aae3 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h
@@ -23,6 +23,8 @@
 
 #include "imstkVTKPolyDataRenderDelegate.h"
 
+class vtkPlaneSource;
+
 namespace imstk
 {
 ///
@@ -47,5 +49,8 @@ public:
     /// \brief Update plane source based on the plane geometry
     ///
     void processEvents() override;
+
+protected:
+    vtkSmartPointer<vtkPlaneSource> m_planeSource;
 };
 } // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp
index b8bb91de7bc5f2028894836d3502ff94b64a813a..56e00828d1b1605904a4456206e4ef02bd7e1d02 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp
@@ -33,16 +33,17 @@
 
 // VTK render delegates
 #include "imstkVTKCapsuleRenderDelegate.h"
-#include "imstkVTKCubeRenderDelegate.h"
 #include "imstkVTKCylinderRenderDelegate.h"
 #include "imstkVTKFluidRenderDelegate.h"
 #include "imstkVTKHexahedralMeshRenderDelegate.h"
 #include "imstkVTKImageDataRenderDelegate.h"
 #include "imstkVTKLineMeshRenderDelegate.h"
+#include "imstkVTKOrientedBoxRenderDelegate.h"
 #include "imstkVTKPlaneRenderDelegate.h"
 #include "imstkVTKPointSetRenderDelegate.h"
 #include "imstkVTKSphereRenderDelegate.h"
 #include "imstkVTKSurfaceMeshRenderDelegate.h"
+#include "imstkVTKSurfaceNormalRenderDelegate.h"
 #include "imstkVTKTetrahedralMeshRenderDelegate.h"
 
 #include <vtkActor.h>
@@ -73,6 +74,7 @@ VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
 {
     const std::string geomType = visualModel->getGeometry()->getTypeName();
 
+    // Two edge cases
     if (visualModel->getRenderMaterial()->getDisplayMode() == RenderMaterial::DisplayMode::Fluid)
     {
         if (std::dynamic_pointer_cast<PointSet>(visualModel->getGeometry()) != nullptr)
@@ -80,14 +82,17 @@ VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
             return std::make_shared<VTKFluidRenderDelegate>(visualModel);
         }
     }
-
-    if (visualModel->getGeometry()->isMesh())
+    if (visualModel->getRenderMaterial()->getDisplayMode() == RenderMaterial::DisplayMode::SurfaceNormals)
     {
-        if (geomType == "PointSet")
+        if (std::dynamic_pointer_cast<PointSet>(visualModel->getGeometry()) != nullptr)
         {
-            return std::make_shared<VTKPointSetRenderDelegate>(visualModel);
+            return std::make_shared<VTKSurfaceNormalRenderDelegate>(visualModel);
         }
-        else if (geomType == "SurfaceMesh")
+    }
+
+    if (visualModel->getGeometry()->isMesh())
+    {
+        if (geomType == "SurfaceMesh")
         {
             return std::make_shared<VTKSurfaceMeshRenderDelegate>(visualModel);
         }
@@ -106,7 +111,11 @@ VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
     }
     else
     {
-        if (geomType == "Plane")
+        if (geomType == "PointSet")
+        {
+            return std::make_shared<VTKPointSetRenderDelegate>(visualModel);
+        }
+        else if (geomType == "Plane")
         {
             return std::make_shared<VTKPlaneRenderDelegate>(visualModel);
         }
@@ -118,9 +127,9 @@ VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
         {
             return std::make_shared<VTKCapsuleRenderDelegate>(visualModel);
         }
-        else if (geomType == "Cube")
+        else if (geomType == "OrientedBox")
         {
-            return std::make_shared<VTKCubeRenderDelegate>(visualModel);
+            return std::make_shared<VTKOrientedCubeRenderDelegate>(visualModel);
         }
         else if (geomType == "Cylinder")
         {
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
index 4793b51f2658e53fd0aa9c1e28ed25d1e03f10c0..0c9dbff4587db9bbe962ea93a0075da6b0438da6 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp
@@ -30,18 +30,23 @@
 
 namespace imstk
 {
-VTKSphereRenderDelegate::VTKSphereRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel)
+VTKSphereRenderDelegate::VTKSphereRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel),
+    m_sphereSource(vtkSmartPointer<vtkSphereSource>::New())
 {
-    vtkNew<vtkSphereSource> sphereSource;
-    sphereSource->SetCenter(0.0, 0.0, 0.0);
-    sphereSource->SetRadius(1.0);
-    sphereSource->SetPhiResolution(20);
-    sphereSource->SetThetaResolution(20);
+    auto geometry = std::dynamic_pointer_cast<Sphere>(visualModel->getGeometry());
+
+    m_sphereSource->SetCenter(0.0, 0.0, 0.0);
+    m_sphereSource->SetRadius(geometry->getRadius(Geometry::DataType::PreTransform));
+    m_sphereSource->SetPhiResolution(20);
+    m_sphereSource->SetThetaResolution(20);
+
+    const Mat4d& transform = geometry->getTransform().transpose();
+    m_transform->SetMatrix(transform.data());
 
     // Setup mapper
     {
         vtkNew<vtkPolyDataMapper> mapper;
-        mapper->SetInputConnection(sphereSource->GetOutputPort());
+        mapper->SetInputConnection(m_sphereSource->GetOutputPort());
         vtkNew<vtkActor> actor;
         actor->SetMapper(mapper);
         actor->SetUserTransform(m_transform);
@@ -58,14 +63,16 @@ VTKSphereRenderDelegate::processEvents()
 {
     VTKRenderDelegate::processEvents();
 
-    auto geometry = std::static_pointer_cast<Sphere>(m_visualModel->getGeometry());
+    auto geometry = std::dynamic_pointer_cast<Sphere>(m_visualModel->getGeometry());
+
+    m_sphereSource->SetRadius(geometry->getRadius(Geometry::DataType::PreTransform));
+    m_sphereSource->Modified();
 
     AffineTransform3d T = AffineTransform3d::Identity();
     T.translate(geometry->getPosition(Geometry::DataType::PostTransform));
-    T.rotate(Quatd::FromTwoVectors(UP_VECTOR, geometry->getOrientationAxis(Geometry::DataType::PostTransform)));
-    T.scale(geometry->getRadius(Geometry::DataType::PostTransform));
+    T.rotate(geometry->getOrientation(Geometry::DataType::PostTransform));
+    T.scale(geometry->getScaling().maxCoeff());
     T.matrix().transposeInPlace();
-
     m_transform->SetMatrix(T.data());
 }
 } // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h
index d791b3c82197833f108809c5c7dfc447fac191cc..424bdca3d3a5ac006dc4312bf5ee020390e14885 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h
@@ -23,10 +23,10 @@
 
 #include "imstkVTKPolyDataRenderDelegate.h"
 
+class vtkSphereSource;
+
 namespace imstk
 {
-class VisualModel;
-
 ///
 /// \class VTKSphereRenderDelegate
 ///
@@ -49,5 +49,8 @@ public:
     /// \brief Update sphere source based on the sphere geometry
     ///
     void processEvents() override;
+
+protected:
+    vtkSmartPointer<vtkSphereSource> m_sphereSource;
 };
 } // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceNormalRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceNormalRenderDelegate.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c8bc1855ef0713e54d4acd99ab2502fbefc3dd82
--- /dev/null
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceNormalRenderDelegate.cpp
@@ -0,0 +1,217 @@
+/*=========================================================================
+
+   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 "imstkVTKSurfaceNormalRenderDelegate.h"
+#include "imstkPointSet.h"
+#include "imstkVisualModel.h"
+#include "imstkGeometryUtilities.h"
+#include "imstkRenderMaterial.h"
+#include "imstkLogger.h"
+#include "imstkSurfaceMesh.h"
+
+#include <vtkActor.h>
+#include <vtkDataArray.h>
+#include <vtkPointData.h>
+#include <vtkTransform.h>
+#include <vtkArrowSource.h>
+#include <vtkOpenGLGlyph3DMapper.h>
+
+namespace imstk
+{
+VTKSurfaceNormalRenderDelegate::VTKSurfaceNormalRenderDelegate(std::shared_ptr<VisualModel> visualModel) : VTKPolyDataRenderDelegate(visualModel),
+    m_polydata(vtkSmartPointer<vtkPolyData>::New())
+{
+    auto surfMesh = std::static_pointer_cast<SurfaceMesh>(visualModel->getGeometry());
+    m_surfMeshVertices = surfMesh->getVertexPositions();
+    m_surfMeshIndices  = surfMesh->getTriangleIndices();
+
+    // Compute the centers of the triangle
+    m_triangleCenterVertices = computeTriangleCenters(m_surfMeshVertices, m_surfMeshIndices);
+    m_triangleNormals = computeTriangleNormals(m_surfMeshVertices, m_surfMeshIndices);
+
+    // Map vertices to VTK point data
+    if (m_surfMeshVertices != nullptr)
+    {
+        m_mappedVertexArray = GeometryUtils::coupleVtkDataArray(m_triangleCenterVertices);
+        auto points = vtkSmartPointer<vtkPoints>::New();
+        points->SetNumberOfPoints(m_triangleCenterVertices->size());
+        points->SetData(m_mappedVertexArray);
+        m_polydata->SetPoints(points);
+    }
+
+    m_mappedNormalsArray = GeometryUtils::coupleVtkDataArray(m_triangleNormals);
+    m_mappedNormalsArray->SetName("ImageScalars");
+    m_polydata->GetPointData()->SetVectors(m_mappedNormalsArray);
+
+    // When geometry is modified, update data source, mostly for when an entirely new array/buffer was set
+    queueConnect<Event>(surfMesh, &Geometry::modified, this, &VTKSurfaceNormalRenderDelegate::geometryModified);
+
+    // When the vertex buffer internals are modified, ie: a single or N elements
+    queueConnect<Event>(m_surfMeshVertices, &AbstractDataArray::modified, this, &VTKSurfaceNormalRenderDelegate::vertexDataModified);
+
+    // Setup mapper
+    {
+        vtkNew<vtkArrowSource> arrowSource;
+        arrowSource->Update();
+        m_glyphPolyData = arrowSource->GetOutput();
+        vtkNew<vtkOpenGLGlyph3DMapper> mapper;
+        mapper->OrientOn();
+        mapper->SetInputData(m_polydata);
+        mapper->SetSourceData(m_glyphPolyData);
+        mapper->SetOrientationArray(m_mappedNormalsArray->GetName());
+        mapper->ScalingOn();
+        mapper->SetScaleFactor(visualModel->getRenderMaterial()->getPointSize());
+        mapper->Update();
+        vtkNew<vtkActor> actor;
+        actor->SetMapper(mapper);
+        actor->SetUserTransform(m_transform);
+        m_mapper = mapper;
+        m_actor  = actor;
+    }
+
+    update();
+    updateRenderProperties();
+}
+
+void
+VTKSurfaceNormalRenderDelegate::processEvents()
+{
+    // Custom handling of events
+    std::shared_ptr<PointSet>                geom     = std::dynamic_pointer_cast<PointSet>(m_visualModel->getGeometry());
+    std::shared_ptr<VecDataArray<double, 3>> vertices = geom->getVertexPositions();
+
+    // Only use the most recent event from respective sender
+    std::list<Command> cmds;
+    bool               contains[4] = { false, false, false, false };
+    rforeachEvent([&](Command cmd)
+        {
+            if (cmd.m_event->m_sender == m_visualModel.get() && !contains[0])
+            {
+                cmds.push_back(cmd);
+                contains[0] = true;
+            }
+            else if (cmd.m_event->m_sender == m_material.get() && !contains[1])
+            {
+                cmds.push_back(cmd);
+                contains[1] = true;
+            }
+            else if (cmd.m_event->m_sender == geom.get() && !contains[2])
+            {
+                cmds.push_back(cmd);
+                contains[2] = true;
+            }
+            else if (cmd.m_event->m_sender == vertices.get() && !contains[3])
+            {
+                cmds.push_back(cmd);
+                contains[3] = true;
+            }
+        });
+
+    // Now do each event in order recieved
+    for (std::list<Command>::reverse_iterator i = cmds.rbegin(); i != cmds.rend(); i++)
+    {
+        i->invoke();
+    }
+}
+
+void
+VTKSurfaceNormalRenderDelegate::vertexDataModified(Event* imstkNotUsed(e))
+{
+    auto geometry = std::static_pointer_cast<SurfaceMesh>(m_visualModel->getGeometry());
+    m_surfMeshVertices = geometry->getVertexPositions();
+
+    // Compute the centers of the triangle
+    m_triangleCenterVertices = computeTriangleCenters(m_surfMeshVertices, m_surfMeshIndices);
+    m_triangleNormals = computeTriangleNormals(m_surfMeshVertices, m_surfMeshIndices);
+
+    m_mappedVertexArray->SetNumberOfComponents(3);
+    m_mappedVertexArray->SetVoidArray(reinterpret_cast<double*>(m_triangleCenterVertices->getPointer()), m_triangleCenterVertices->size() * 3, 1);
+    m_mappedVertexArray->Modified();
+
+    m_mappedNormalsArray->SetNumberOfComponents(3);
+    m_mappedNormalsArray->SetVoidArray(reinterpret_cast<double*>(m_triangleNormals->getPointer()), m_triangleNormals->size() * 3, 1);
+    m_mappedNormalsArray->Modified();
+}
+
+void
+VTKSurfaceNormalRenderDelegate::geometryModified(Event* imstkNotUsed(e))
+{
+    // Called when the geometry posts modified
+    auto geometry = std::static_pointer_cast<PointSet>(m_visualModel->getGeometry());
+
+    // Test if the vertex buffer changed
+    //if (m_surfMeshVertices != geometry->getVertexPositions())
+    {
+        vertexDataModified(nullptr);
+    }
+}
+
+void
+VTKSurfaceNormalRenderDelegate::updateRenderProperties()
+{
+    VTKPolyDataRenderDelegate::updateRenderProperties();
+
+    vtkOpenGLGlyph3DMapper::SafeDownCast(m_mapper)->SetScaleFactor(m_visualModel->getRenderMaterial()->getPointSize());
+}
+
+std::shared_ptr<VecDataArray<double, 3>>
+VTKSurfaceNormalRenderDelegate::computeTriangleCenters(
+    std::shared_ptr<VecDataArray<double, 3>> verticesPtr,
+    std::shared_ptr<VecDataArray<int, 3>> indicesPtr)
+{
+    auto                     newVerticesPtr = std::make_shared<VecDataArray<double, 3>>(indicesPtr->size());
+    VecDataArray<double, 3>& newVertices    = *newVerticesPtr;
+
+    VecDataArray<double, 3>& vertices = *verticesPtr;
+    VecDataArray<int, 3>&    indices  = *indicesPtr;
+    const double             ratio    = 1.0 / 3.0;
+    for (int i = 0; i < indices.size(); i++)
+    {
+        const Vec3d& a = vertices[indices[i][0]];
+        const Vec3d& b = vertices[indices[i][1]];
+        const Vec3d& c = vertices[indices[i][2]];
+
+        newVertices[i] = (a + b + c) * ratio;
+    }
+    return newVerticesPtr;
+}
+
+std::shared_ptr<VecDataArray<double, 3>>
+VTKSurfaceNormalRenderDelegate::computeTriangleNormals(
+    std::shared_ptr<VecDataArray<double, 3>> verticesPtr,
+    std::shared_ptr<VecDataArray<int, 3>> indicesPtr)
+{
+    auto                     orientationsPtr = std::make_shared<VecDataArray<double, 3>>(indicesPtr->size());
+    VecDataArray<double, 3>& orientations    = *orientationsPtr;
+
+    VecDataArray<double, 3>& vertices = *verticesPtr;
+    VecDataArray<int, 3>&    indices  = *indicesPtr;
+    for (int i = 0; i < indices.size(); i++)
+    {
+        const Vec3d& a = vertices[indices[i][0]];
+        const Vec3d& b = vertices[indices[i][1]];
+        const Vec3d& c = vertices[indices[i][2]];
+
+        orientations[i] = (c - a).cross(c - b).normalized();
+    }
+    return orientationsPtr;
+}
+} // imstk
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceNormalRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceNormalRenderDelegate.h
new file mode 100644
index 0000000000000000000000000000000000000000..4dec41a235b1ea6163c00760b38d61145710fbe4
--- /dev/null
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceNormalRenderDelegate.h
@@ -0,0 +1,97 @@
+/*=========================================================================
+
+   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.
+
+=========================================================================*/
+
+#pragma once
+
+#include "imstkVTKPolyDataRenderDelegate.h"
+
+class vtkDataArray;
+class vtkPolyData;
+
+namespace imstk
+{
+class PointSet;
+template<typename T, int N> class VecDataArray;
+
+///
+/// \class VTKSurfaceNormalRenderDelegate
+///
+/// \brief Renders normals as vectors from a surface mesh
+///
+class VTKSurfaceNormalRenderDelegate : public VTKPolyDataRenderDelegate
+{
+public:
+    ///
+    /// \brief Constructor
+    ///
+    VTKSurfaceNormalRenderDelegate(std::shared_ptr<VisualModel> visualModel);
+
+    ///
+    /// \brief Destructor
+    ///
+    virtual ~VTKSurfaceNormalRenderDelegate() override = default;
+
+    ///
+    /// \brief Update polydata source based on the mesh geometry
+    ///
+    void processEvents() override;
+
+protected:
+    ///
+    /// \brief Callback for when vertex data changes
+    ///
+    void vertexDataModified(Event* e);
+
+    ///
+    /// \brief Callback for when geometry changes
+    ///
+    void geometryModified(Event* e);
+
+    ///
+    /// \brief Updates the actor and mapper properties from the currently set VisualModel
+    ///
+    virtual void updateRenderProperties() override;
+
+    ///
+    /// \brief Computes triangle centers from the current geometry
+    ///
+    std::shared_ptr<VecDataArray<double, 3>> computeTriangleCenters(
+        std::shared_ptr<VecDataArray<double, 3>> verticesPtr,
+        std::shared_ptr<VecDataArray<int, 3>> indicesPtr);
+
+    std::shared_ptr<VecDataArray<double, 3>> computeTriangleNormals(
+        std::shared_ptr<VecDataArray<double, 3>> verticesPtr,
+        std::shared_ptr<VecDataArray<int, 3>> indicesPtr);
+
+protected:
+    std::shared_ptr<VecDataArray<double, 3>> m_surfMeshVertices;
+    std::shared_ptr<VecDataArray<int, 3>>    m_surfMeshIndices;
+
+    std::shared_ptr<VecDataArray<double, 3>> m_triangleCenterVertices;
+    std::shared_ptr<VecDataArray<double, 3>> m_triangleNormals;
+
+    vtkSmartPointer<vtkPolyData> m_polydata;
+    vtkSmartPointer<vtkPolyData> m_glyphPolyData;
+
+    vtkSmartPointer<vtkDataArray> m_mappedVertexArray;  ///> Mapped array of vertices
+    vtkSmartPointer<vtkDataArray> m_mappedNormalsArray; ///> Mapped array of orientations
+};
+}
diff --git a/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp b/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp
index 4086b2c7629a54c4addfcf390309c2f9acc0ccc8..7135f5d6ce5fd3de62ee0b814c406601f0208930 100644
--- a/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp
+++ b/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp
@@ -456,7 +456,7 @@ VTKRenderer::addVisualModel(std::shared_ptr<SceneObject> sceneObject, std::share
     auto renderDelegate = m_renderDelegates[visualModel] = VTKRenderDelegate::makeDelegate(visualModel);
     if (renderDelegate == nullptr)
     {
-        LOG(WARNING) << "Renderer::Renderer error: Could not create render delegate for '"
+        LOG(WARNING) << "error: Could not create render delegate for '"
                      << sceneObject->getName() << "'.";
         return;
     }
@@ -536,7 +536,7 @@ VTKRenderer::sceneModifed(Event* imstkNotUsed(e))
             auto delegate = VTKRenderDelegate::makeDebugDelegate(dbgVizModel);
             if (delegate == nullptr)
             {
-                LOG(WARNING) << "Renderer::Renderer error: Could not create render delegate for '"
+                LOG(WARNING) << "error: Could not create render delegate for '"
                              << geom->getName() << "'.";
                 continue;
             }
diff --git a/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp b/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp
index 9d43fe4b70f07877743e53d716b4e4e498c4ebdb..db9e5c80363770e272f3ec068cdff984e6067fe9 100644
--- a/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp
@@ -29,6 +29,7 @@
 #include <vtkImageReader2Factory.h>
 #include <vtkPNGReader.h>
 #include <vtkTexture.h>
+#include <vtksys/SystemTools.hxx>
 
 namespace imstk
 {
@@ -41,6 +42,9 @@ VTKTextureDelegate::VTKTextureDelegate(std::shared_ptr<Texture> texture) : m_vtk
     std::shared_ptr<ImageData> imstkImgData = texture->getImageData();
     if (imstkImgData == nullptr)
     {
+        CHECK(vtksys::SystemTools::FileExists(tFileName.c_str()))
+            << "Error: texture file \"" << tFileName << "\" does not exist";
+
         // Load by file name
         vtkNew<vtkImageReader2Factory> readerFactory;
         if (texture->getType() == Texture::Type::Cubemap)
@@ -57,7 +61,7 @@ VTKTextureDelegate::VTKTextureDelegate(std::shared_ptr<Texture> texture) : m_vtk
 
                 vtkImageReader2* imgReader = readerFactory->CreateImageReader2(sideName.c_str());
 
-                CHECK(imgReader != nullptr) << "VTKTextureDelegate::loadTexture error: could not find reader for "
+                CHECK(imgReader != nullptr) << "Error: could not find reader for "
                                             << sideName;
 
                 auto imageFlip = vtkSmartPointer<vtkImageFlip>::New();
@@ -72,7 +76,7 @@ VTKTextureDelegate::VTKTextureDelegate(std::shared_ptr<Texture> texture) : m_vtk
         {
             vtkImageReader2* imgReader = readerFactory->CreateImageReader2(tFileName.c_str());
 
-            CHECK(imgReader != nullptr) << "VTKTextureDelegate::loadTexture error: could not find reader for "
+            CHECK(imgReader != nullptr) << "Error: could not find reader for "
                                         << tFileName;
 
             imgReader->SetFileName(tFileName.c_str());
diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp
index 0545484a7a1a0839034cc785e5d441c2c9e64bdf..891c0b967d1f57ca2e560f1084214c0676a03798 100644
--- a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp
+++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp
@@ -100,9 +100,6 @@ VulkanRenderDelegate::make_delegate(std::shared_ptr<VisualModel> visualModel,
     }
     case Geometry::Type::HexahedralMesh:
     {
-        /*LOG(WARNING) << "RenderDelegate::make_delegate error: HexahedralMeshRenderDelegate not yet implemented";
-        return nullptr;*/
-
         LOG(FATAL) << "No support for HexahedralMesh rendering with Vulkan backend!";
     }
     case Geometry::Type::DecalPool:
@@ -115,7 +112,7 @@ VulkanRenderDelegate::make_delegate(std::shared_ptr<VisualModel> visualModel,
     }
     default:
     {
-        LOG(WARNING) << "RenderDelegate::make_delegate error: Geometry type incorrect.";
+        LOG(WARNING) << "error: Geometry type incorrect.";
         visualModel->m_renderDelegateCreated = false;
         return nullptr;
     }
diff --git a/Source/Scene/imstkCollisionPair.cpp b/Source/Scene/imstkCollisionPair.cpp
index 7ebfa9f27802b5ea664d0a33a0777644dc70956a..a5cdf98516d5828e1ab31dd1a447b8ca10db8fd8 100644
--- a/Source/Scene/imstkCollisionPair.cpp
+++ b/Source/Scene/imstkCollisionPair.cpp
@@ -144,7 +144,7 @@ CollisionPair::apply()
         // Connect inputB's->CD
         for (size_t i = 0; i < m_taskNodeInputs.second.size(); i++)
         {
-            computeGraphA->addEdge(m_taskNodeInputs.second[i], m_collisionDetectionNode);
+            computeGraphB->addEdge(m_taskNodeInputs.second[i], m_collisionDetectionNode);
         }
     }
 
diff --git a/Source/Scene/imstkRigidObjectCollidingCollisionPair.cpp b/Source/Scene/imstkRigidObjectCollidingCollisionPair.cpp
index 5b61f1e31a435ab0b088671c527e755fd8cc137e..9a2ca570cd702fe249a6328e8ada2b58e7c43df1 100644
--- a/Source/Scene/imstkRigidObjectCollidingCollisionPair.cpp
+++ b/Source/Scene/imstkRigidObjectCollidingCollisionPair.cpp
@@ -29,8 +29,6 @@ limitations under the License.
 
 namespace imstk
 {
-namespace expiremental
-{
 RigidObjectCollidingCollisionPair::RigidObjectCollidingCollisionPair(
     std::shared_ptr<RigidObject2> obj1, std::shared_ptr<CollidingObject> obj2,
     CollisionDetection::Type cdType, const double stiffness, const double frictionalCoefficient) :
@@ -58,5 +56,4 @@ RigidObjectCollidingCollisionPair::RigidObjectCollidingCollisionPair(
     // Setup the handlers for each side
     setCollisionHandlingA(std::make_shared<RigidBodyCH>(CollisionHandling::Side::A, m_colData, obj1, nullptr, stiffness, frictionalCoefficient));
 }
-}
 }
\ No newline at end of file
diff --git a/Source/Scene/imstkRigidObjectCollidingCollisionPair.h b/Source/Scene/imstkRigidObjectCollidingCollisionPair.h
index 5c61116f33092e17aefc0df68fa80d1beff2ef7d..283feae12b6892618668d698c94cb7cbb415436e 100644
--- a/Source/Scene/imstkRigidObjectCollidingCollisionPair.h
+++ b/Source/Scene/imstkRigidObjectCollidingCollisionPair.h
@@ -26,8 +26,6 @@ limitations under the License.
 
 namespace imstk
 {
-namespace expiremental
-{
 class RigidObject2;
 
 ///
@@ -43,5 +41,4 @@ public:
 
     virtual ~RigidObjectCollidingCollisionPair() override = default;
 };
-}
 }
\ No newline at end of file
diff --git a/Source/Scene/imstkRigidObjectCollisionPair.cpp b/Source/Scene/imstkRigidObjectCollisionPair.cpp
index 9a049432df890fc3daebde5f9a38b4cc8a0101cf..0bb493f5066f459428f4b4c51eddc16483402289 100644
--- a/Source/Scene/imstkRigidObjectCollisionPair.cpp
+++ b/Source/Scene/imstkRigidObjectCollisionPair.cpp
@@ -30,8 +30,6 @@ limitations under the License.
 
 namespace imstk
 {
-namespace expiremental
-{
 RigidObjectCollisionPair::RigidObjectCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<RigidObject2> obj2,
                                                    CollisionDetection::Type cdType) : CollisionPair(obj1, obj2)
 {
@@ -92,8 +90,8 @@ RigidObjectCollisionPair::apply()
         // 1.) Copy the vertices at the start of the frame
         obj1->getTaskGraph()->insertBefore(obj1->getRigidBodyModel2()->getComputeTentativeVelocitiesNode(),
             std::make_shared<TaskNode>([ = ]()
-                {
-                    copyVertsToPrevious();
+            {
+                copyVertsToPrevious();
                 }, "CopyVertsToPrevious"));
 
         // If you were to update to tentative, you'd do it here, then compute displacements
@@ -101,8 +99,8 @@ RigidObjectCollisionPair::apply()
         // 2.) Compute the displacements after updating geometry
         obj1->getTaskGraph()->insertAfter(obj1->getUpdateGeometryNode(),
             std::make_shared<TaskNode>([ = ]()
-                {
-                    measureDisplacementFromPrevious();
+            {
+                measureDisplacementFromPrevious();
                 }, "ComputeDisplacements"));
     }
 }
@@ -145,10 +143,9 @@ RigidObjectCollisionPair::measureDisplacementFromPrevious()
 
         ParallelUtils::parallelFor(displacements->size(),
             [&](const int i)
-                {
-                    displacementsArr[i] = vertices[i] - prevVertices[i];
+            {
+                displacementsArr[i] = vertices[i] - prevVertices[i];
             });
     }
 }
-}
 }
\ No newline at end of file
diff --git a/Source/Scene/imstkRigidObjectCollisionPair.h b/Source/Scene/imstkRigidObjectCollisionPair.h
index 3be8b0db3db3f8f75612499c6b74b37c83880a51..2baeedce1e65f4b49751245d875ae9d5d5eaab07 100644
--- a/Source/Scene/imstkRigidObjectCollisionPair.h
+++ b/Source/Scene/imstkRigidObjectCollisionPair.h
@@ -28,8 +28,6 @@ namespace imstk
 {
 template<typename T, int N> class VecDataArray;
 
-namespace expiremental
-{
 class RigidObject2;
 
 ///
@@ -57,5 +55,4 @@ public:
 public:
     std::shared_ptr<VecDataArray<double, 3>> m_prevVertices;
 };
-}
 }
\ No newline at end of file
diff --git a/Source/Scene/imstkRigidObjectLevelSetCollisionPair.cpp b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.cpp
index a841971a67bff2ec7662e5f39476a411a060754b..3fb2e7d63ee793144c66c4c761399089a4a2a979 100644
--- a/Source/Scene/imstkRigidObjectLevelSetCollisionPair.cpp
+++ b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.cpp
@@ -36,8 +36,6 @@ limitations under the License.
 
 namespace imstk
 {
-namespace expiremental
-{
 RigidObjectLevelSetCollisionPair::RigidObjectLevelSetCollisionPair(std::shared_ptr<RigidObject2> obj1, std::shared_ptr<LevelSetDeformableObject> obj2) :
     CollisionPair(obj1, obj2), m_prevVertices(std::make_shared<VecDataArray<double, 3>>())
 {
@@ -93,8 +91,8 @@ RigidObjectLevelSetCollisionPair::apply()
         // 1.) Copy the vertices at the start of the frame
         obj1->getTaskGraph()->insertBefore(obj1->getRigidBodyModel2()->getComputeTentativeVelocitiesNode(),
             std::make_shared<TaskNode>([ = ]()
-                {
-                    copyVertsToPrevious();
+            {
+                copyVertsToPrevious();
                 }, "CopyVertsToPrevious"));
 
         // If you were to update to tentative, you'd do it here, then compute displacements
@@ -145,10 +143,9 @@ RigidObjectLevelSetCollisionPair::measureDisplacementFromPrevious()
 
         ParallelUtils::parallelFor(displacements->size(),
             [&](const int i)
-                {
-                    displacementsArr[i] = vertices[i] - prevVertices[i];
+            {
+                displacementsArr[i] = vertices[i] - prevVertices[i];
             });
     }
 }
-}
 }
\ No newline at end of file
diff --git a/Source/Scene/imstkRigidObjectLevelSetCollisionPair.h b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.h
index a43acdd11a828479ddc5257e70a26b5621640f90..c6b90a734b96fefd34ccb7dd84dbb291db4a8af3 100644
--- a/Source/Scene/imstkRigidObjectLevelSetCollisionPair.h
+++ b/Source/Scene/imstkRigidObjectLevelSetCollisionPair.h
@@ -29,8 +29,6 @@ namespace imstk
 class LevelSetDeformableObject;
 template<typename T, int N> class VecDataArray;
 
-namespace expiremental
-{
 class RigidObject2;
 
 ///
@@ -54,5 +52,4 @@ public:
 public:
     std::shared_ptr<VecDataArray<double, 3>> m_prevVertices;
 };
-}
 }
\ No newline at end of file
diff --git a/Source/Scene/imstkScene.h b/Source/Scene/imstkScene.h
index 945e5c64f201ecc7cb665cf246a7e15057b184a3..5434020bad186272c5cd5c9bca6d38cf8de43ab2 100644
--- a/Source/Scene/imstkScene.h
+++ b/Source/Scene/imstkScene.h
@@ -91,15 +91,17 @@ using NamedMap = std::unordered_map<std::string, std::shared_ptr<T>>;
 
 public:
     Scene(const std::string& name, std::shared_ptr<SceneConfig> config = std::make_shared<SceneConfig>());
-    virtual ~Scene() override= default;
+    virtual ~Scene() override = default;
 
 public:
-    SIGNAL(Scene,configureTaskGraph);
+    // *INDENT-OFF*
+    SIGNAL(Scene, configureTaskGraph);
     ///
     /// \brief Called when scene is modified, when scene objects
     /// or interactions are added/removed
     ///
-    SIGNAL(Scene,modified);
+    SIGNAL(Scene, modified);
+    // *INDENT-ON*
 
 public:
     ///
@@ -146,7 +148,7 @@ public:
     ///
     /// \brief Return the SceneObjects of the scene
     ///
-    const std::unordered_set<std::shared_ptr<SceneObject>>& getSceneObjects() const{ return m_sceneObjects; }
+    const std::unordered_set<std::shared_ptr<SceneObject>>& getSceneObjects() const { return m_sceneObjects; }
 
     ///
     /// \brief Return a vector of shared pointers to the scene objects
@@ -157,7 +159,7 @@ public:
     ///
     /// \brief Get the scene object controllers
     ///
-    const std::vector<std::shared_ptr<TrackingDeviceControl>> getControllers() const{ return m_trackingControllers; }
+    const std::vector<std::shared_ptr<TrackingDeviceControl>> getControllers() const { return m_trackingControllers; }
 
     ///
     /// \brief Get SceneObject by name, returns nullptr if doesn't exist
@@ -209,7 +211,7 @@ public:
     ///
     std::shared_ptr<Light> getLight(const std::string& lightName) const;
 
-    const NamedMap<Camera>& getCameras() const{ return m_cameras; }
+    const NamedMap<Camera>& getCameras() const { return m_cameras; }
 
     ///
     /// \brief Add/remove lights from the scene
@@ -226,24 +228,24 @@ public:
     ///
     /// \brief Get the name of the scene
     ///
-    const std::string& getName() const{ return m_name; }
+    const std::string& getName() const { return m_name; }
 
     ///
     /// \brief Get the computational graph of the scene
     ///
-    std::shared_ptr<TaskGraph> getTaskGraph() const{ return m_taskGraph; }
+    std::shared_ptr<TaskGraph> getTaskGraph() const { return m_taskGraph; }
 
     ///
     /// \brief Get the camera for the scene
     ///
-    std::shared_ptr<Camera> getActiveCamera() const{ return m_activeCamera; }
+    std::shared_ptr<Camera> getActiveCamera() const { return m_activeCamera; }
 
     ///
     /// \brief Get the name of the camera, if it exists
     ///
     std::string getCameraName(std::shared_ptr<Camera> cam) const
     {
-        auto i = std::find_if(m_cameras.begin(),m_cameras.end(),
+        auto i = std::find_if(m_cameras.begin(), m_cameras.end(),
             [&cam](const NamedMap<Camera>::value_type& j) { return j.second == cam; });
         if (i != m_cameras.end())
         {
@@ -274,7 +276,7 @@ public:
     ///
     /// \brief Set the camera for the scene
     ///
-    void addCamera(std::string name,std::shared_ptr<Camera> cam) { m_cameras[name] = cam; }
+    void addCamera(std::string name, std::shared_ptr<Camera> cam) { m_cameras[name] = cam; }
 
     ///
     /// \brief Set the active camera by name
@@ -291,7 +293,7 @@ public:
     ///
     /// \brief Return the collision graph
     ///
-    std::shared_ptr<CollisionGraph> getCollisionGraph() const{ return m_collisionGraph; }
+    std::shared_ptr<CollisionGraph> getCollisionGraph() const { return m_collisionGraph; }
 
     ///
     /// \brief Add objects controllers
@@ -301,12 +303,12 @@ public:
     ///
     /// \brief Set/Get the FPS
     ///
-    double getFPS() const{ return m_fps; }
+    double getFPS() const { return m_fps; }
 
     ///
     /// \brief Get the map of elapsed times
     ///
-    const std::unordered_map<std::string,double>& getTaskComputeTimes() const{ return m_nodeComputeTimes; }
+    const std::unordered_map<std::string, double>& getTaskComputeTimes() const { return m_nodeComputeTimes; }
 
     ///
     /// \brief Lock the compute times resource
@@ -321,7 +323,7 @@ public:
     ///
     /// \brief Get the configuration
     ///
-    std::shared_ptr<SceneConfig> getConfig() const{ return m_config; };
+    std::shared_ptr<SceneConfig> getConfig() const { return m_config; };
 
 protected:
     std::shared_ptr<SceneConfig> m_config;
@@ -343,7 +345,7 @@ protected:
     std::function<void(Scene*)> m_postTaskGraphConfigureCallback = nullptr;
 
     std::shared_ptr<ParallelUtils::SpinLock> m_computeTimesLock;
-    std::unordered_map<std::string,double>   m_nodeComputeTimes; ///> Map of ComputeNode names to elapsed times for benchmarking
+    std::unordered_map<std::string, double>  m_nodeComputeTimes; ///> Map of ComputeNode names to elapsed times for benchmarking
 
     double m_fps = 0.0;
 
diff --git a/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp b/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp
index 0f7bc8ce51764612d8fa5831638901e1688a6009..cb489a0e712a60e14427671a8ae5f3dbb570818e 100644
--- a/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp
+++ b/Source/SceneEntities/Loader/imstkVisualObjectImporter.cpp
@@ -78,7 +78,7 @@ ObjectIO::importSceneObject(
         && type != MeshFileType::FBX
         && type != MeshFileType::DAE)
     {
-        LOG(FATAL) << "File type not supported";
+        LOG(FATAL) << "Error: File type not supported! Input model file path: " << modelFilePath;
         return nullptr;
     }
 
@@ -89,7 +89,7 @@ ObjectIO::importSceneObject(
     const aiScene*   scene = importer.ReadFile(modelFilePath, AssimpMeshIO::getDefaultPostProcessSteps());
 
     // Check if there is actually a mesh or if the file can be read
-    CHECK(scene != nullptr && scene->HasMeshes()) << "AssimpMeshIO::readMeshData error: could not read with reader: "
+    CHECK(scene != nullptr && scene->HasMeshes()) << "Error: could not read model with Assimp reader! Input model file path: "
                                                   << modelFilePath;
 
     // Iterate over each material
diff --git a/Source/SceneEntities/Objects/imstkRigidObject2.cpp b/Source/SceneEntities/Objects/imstkRigidObject2.cpp
index 526e830dc098ebd6fc7be2babee1dcef9e125b67..8cd412cdaf99698722a7f28267fa6844b2581f28 100644
--- a/Source/SceneEntities/Objects/imstkRigidObject2.cpp
+++ b/Source/SceneEntities/Objects/imstkRigidObject2.cpp
@@ -26,8 +26,6 @@
 
 namespace imstk
 {
-namespace expiremental
-{
 bool
 RigidObject2::initialize()
 {
@@ -72,5 +70,4 @@ RigidObject2::updatePhysicsGeometry()
 
     DynamicObject::updatePhysicsGeometry();
 }
-}
-} // imstk
+} // imstk
\ No newline at end of file
diff --git a/Source/SceneEntities/Objects/imstkRigidObject2.h b/Source/SceneEntities/Objects/imstkRigidObject2.h
index 1a913e365d1746819e318fa4c5af4fc7ab298772..2dbc0928c12fa473b1dccc75f84e310effb5c67c 100644
--- a/Source/SceneEntities/Objects/imstkRigidObject2.h
+++ b/Source/SceneEntities/Objects/imstkRigidObject2.h
@@ -26,9 +26,6 @@
 namespace imstk
 {
 class PointSet;
-
-namespace expiremental
-{
 class RigidBodyModel2;
 struct RigidBody;
 
@@ -79,5 +76,4 @@ protected:
     std::shared_ptr<RigidBodyModel2> m_rigidBodyModel2;
     std::shared_ptr<RigidBody>       m_rigidBody; ///> Gives the actual body within the model
 };
-}
 } // imstk
\ No newline at end of file
diff --git a/Source/SceneEntities/Objects/imstkSceneObject.h b/Source/SceneEntities/Objects/imstkSceneObject.h
index 051a7d0e15e753ad16e64ab5f9f0998fe3d8fbbe..87d7d94a60586cb2f944a57327dcc2161e07c020 100644
--- a/Source/SceneEntities/Objects/imstkSceneObject.h
+++ b/Source/SceneEntities/Objects/imstkSceneObject.h
@@ -44,26 +44,28 @@ class SceneObject : public SceneEntity
 {
 public:
     SceneObject(const std::string& name);
-    virtual ~SceneObject() override= default;
+    virtual ~SceneObject() override = default;
 
 public:
-    SIGNAL(SceneObject,modified);
+    // *INDENT-OFF*
+    SIGNAL(SceneObject, modified);
+    // *INDENT-ON*
 
 public:
     ///
     /// \brief Get the type of the object
     ///
-    virtual const std::string getTypeName() const{ return "SceneObject"; }
+    virtual const std::string getTypeName() const { return "SceneObject"; }
 
     ///
     /// \brief Get the computational graph
     ///
-    std::shared_ptr<TaskGraph> getTaskGraph() const{ return m_taskGraph; }
+    std::shared_ptr<TaskGraph> getTaskGraph() const { return m_taskGraph; }
 
     ///
     /// \brief Get/Set the custom name of the scene object
     ///
-    const std::string& getName() const{ return m_name; }
+    const std::string& getName() const { return m_name; }
     void setName(const std::string& name) { m_name = name; }
 
     ///
@@ -84,7 +86,7 @@ public:
 
     void removeVisualModel(std::shared_ptr<VisualModel> visualModel)
     {
-        auto iter = std::find(m_visualModels.begin(),m_visualModels.end(),visualModel);
+        auto iter = std::find(m_visualModels.begin(), m_visualModels.end(), visualModel);
         if (iter != m_visualModels.end())
         {
             m_visualModels.erase(iter);
@@ -105,17 +107,17 @@ public:
     ///
     /// \brief Get the master geometry
     ///
-    virtual std::shared_ptr<Geometry> getMasterGeometry() const{ return this->getVisualGeometry(); }
+    virtual std::shared_ptr<Geometry> getMasterGeometry() const { return this->getVisualGeometry(); }
 
     ///
     /// \brief Returns the computational node for updating
     ///
-    std::shared_ptr<TaskNode> getUpdateNode() const{ return m_updateNode; }
+    std::shared_ptr<TaskNode> getUpdateNode() const { return m_updateNode; }
 
     ///
     /// \brief Returns the computational node for updating geometry
     ///
-    std::shared_ptr<TaskNode> getUpdateGeometryNode() const{ return m_updateGeometryNode; }
+    std::shared_ptr<TaskNode> getUpdateGeometryNode() const { return m_updateGeometryNode; }
 
     ///
     /// \brief Update the SceneObject, called during scene update
@@ -151,7 +153,7 @@ protected:
     ///
     /// \brief Setup connectivity of the compute graph
     ///
-    virtual void initGraphEdges(std::shared_ptr<TaskNode> source,std::shared_ptr<TaskNode> sink);
+    virtual void initGraphEdges(std::shared_ptr<TaskNode> source, std::shared_ptr<TaskNode> sink);
 
 protected:
     std::string m_name;                                       ///> Custom name of the scene object
diff --git a/Source/SceneEntities/Objects/imstkVisualModel.cpp b/Source/SceneEntities/Objects/imstkVisualModel.cpp
index 58ec909dd309c4f1931ba3e32891f743402d9e3d..1b3f017a333c77d85f83065fc6951493d91c713f 100644
--- a/Source/SceneEntities/Objects/imstkVisualModel.cpp
+++ b/Source/SceneEntities/Objects/imstkVisualModel.cpp
@@ -46,6 +46,10 @@ VisualModel::VisualModel(std::shared_ptr<DebugRenderGeometry> geometry,
 {
 }
 
+VisualModel::VisualModel() : m_renderMaterial(std::make_shared<RenderMaterial>())
+{
+}
+
 bool
 VisualModel::getRenderDelegateCreated(Renderer* ren)
 {
diff --git a/Source/SceneEntities/Objects/imstkVisualModel.h b/Source/SceneEntities/Objects/imstkVisualModel.h
index 1b45cbd1d5f3a32dde210c0194e0974886e74a99..a36e95a9ffa8b5f09780a4f9c13a5a379c6545e8 100644
--- a/Source/SceneEntities/Objects/imstkVisualModel.h
+++ b/Source/SceneEntities/Objects/imstkVisualModel.h
@@ -51,17 +51,19 @@ public:
     VisualModel(std::shared_ptr<DebugRenderGeometry> geometry);
     VisualModel(std::shared_ptr<DebugRenderGeometry> geometry,
                 std::shared_ptr<RenderMaterial>      renderMaterial);
-    VisualModel() = default;
-    virtual ~VisualModel() override= default;
+    VisualModel();
+    virtual ~VisualModel() override = default;
 
 public:
-    SIGNAL(VisualModel,modified);
+    // *INDENT-OFF*
+    SIGNAL(VisualModel, modified);
+    // *INDENT-ON*
 
 public:
     ///
     /// \brief Get/set geometry
     ///
-    std::shared_ptr<Geometry> getGeometry() const{ return m_geometry; }
+    std::shared_ptr<Geometry> getGeometry() const { return m_geometry; }
     void setGeometry(std::shared_ptr<Geometry> geometry) { m_geometry = geometry; }
 
     ///
@@ -73,7 +75,7 @@ public:
     ///
     /// \brief Get/set geometry
     ///
-    std::shared_ptr<DebugRenderGeometry> getDebugGeometry() const{ return m_DbgGeometry; }
+    std::shared_ptr<DebugRenderGeometry> getDebugGeometry() const { return m_DbgGeometry; }
     void setDebugGeometry(std::shared_ptr<DebugRenderGeometry> geometry) { m_DbgGeometry = geometry; }
 
     ///
@@ -85,14 +87,14 @@ public:
         this->postModified();
     }
 
-    std::shared_ptr<RenderMaterial> getRenderMaterial() const{ return m_renderMaterial; }
+    std::shared_ptr<RenderMaterial> getRenderMaterial() const { return m_renderMaterial; }
 
     ///
     /// \brief Visibility functions
     ///
     void show() { setIsVisible(true); }
     void hide() { setIsVisible(false); }
-    bool isVisible() const{ return m_isVisible; }
+    bool isVisible() const { return m_isVisible; }
     void setIsVisible(const bool visible)
     {
         m_isVisible = visible;
@@ -103,7 +105,7 @@ public:
     /// \brief Get/Set whether the delegate has been created
     ///
     bool getRenderDelegateCreated(Renderer* ren);
-    void setRenderDelegateCreated(Renderer* ren,bool created) { m_renderDelegateCreated[ren] = created; }
+    void setRenderDelegateCreated(Renderer* ren, bool created) { m_renderDelegateCreated[ren] = created; }
 
     void postModified() { this->postEvent(Event(VisualModel::modified())); }
 
@@ -118,6 +120,6 @@ protected:
     std::shared_ptr<RenderMaterial>      m_renderMaterial;
 
     bool m_isVisible = true;              ///< true if mesh is shown, false if mesh is hidden
-    std::unordered_map<Renderer*,bool> m_renderDelegateCreated;
+    std::unordered_map<Renderer*, bool> m_renderDelegateCreated;
 };
 }
diff --git a/Source/SimulationManager/imstkSimulationManager.h b/Source/SimulationManager/imstkSimulationManager.h
index b8a1a364a545e6e2bf3a3bc892a1c05bab7e1f1a..a9835c1d0db4bb51fdb5a82f9b461192b2d28fc5 100644
--- a/Source/SimulationManager/imstkSimulationManager.h
+++ b/Source/SimulationManager/imstkSimulationManager.h
@@ -53,18 +53,20 @@ public:
     };
 
 public:
-    virtual ~SimulationManager() override= default;
+    virtual ~SimulationManager() override = default;
 
 public:
+    // *INDENT-OFF*
     ///
     /// \brief Called after initialization but before starting the loop
     ///
-    SIGNAL(SimulationManager,starting);
+    SIGNAL(SimulationManager, starting);
 
     ///
     /// \brief Called after ending, but before un initialization
     ///
-    SIGNAL(SimulationManager,ending);
+    SIGNAL(SimulationManager, ending);
+    // *INDENT-ON*
 
 public:
     void start() override;
@@ -114,7 +116,7 @@ protected:
 protected:
     std::vector<std::shared_ptr<Viewer>> m_viewers;
 
-    std::unordered_map<Module*,bool> m_running;
+    std::unordered_map<Module*, bool> m_running;
 
     std::vector<std::shared_ptr<Module>> m_syncModules;      ///> Modules called once per update
     std::vector<std::shared_ptr<Module>> m_asyncModules;     ///> Modules that run on completely other threads without restraint
diff --git a/Source/Solvers/imstkConjugateGradient.cpp b/Source/Solvers/imstkConjugateGradient.cpp
index e9a575683310686a7f186761e7e4ebdb1d4e661b..ea173b1f4c8a7fb9acf6a416dfdf0c8338295f9b 100644
--- a/Source/Solvers/imstkConjugateGradient.cpp
+++ b/Source/Solvers/imstkConjugateGradient.cpp
@@ -61,7 +61,7 @@ ConjugateGradient::solve(Vectord& x)
 {
     if (!m_linearSystem)
     {
-        LOG(WARNING) << "ConjugateGradient::solve: Linear system is not supplied for CG solver!";
+        LOG(WARNING) << "Linear system is not supplied for CG solver!";
         return;
     }
 
@@ -127,7 +127,7 @@ ConjugateGradient::modifiedCGSolve(Vectord& x)
         }
         else
         {
-            LOG(WARNING) << "ConjugateGradient::modifiedCGSolve: deniminator zero. Terminating MCG iteation!";
+            LOG(WARNING) << "Warning: denominator zero. Terminating MCG iteration!";
             return;
         }
         x   += alpha * c;
diff --git a/Source/Solvers/imstkIterativeLinearSolver.cpp b/Source/Solvers/imstkIterativeLinearSolver.cpp
index eb8e6883655375631dcb28be1e70a0e75d56a2d1..0ad3e5f2924ac217b8027957cd772971b37975ff 100644
--- a/Source/Solvers/imstkIterativeLinearSolver.cpp
+++ b/Source/Solvers/imstkIterativeLinearSolver.cpp
@@ -73,7 +73,7 @@ IterativeLinearSolver::solve(Vectord& imstkNotUsed(x))
     /*
     if (!m_linearSystem)
     {
-        LOG(WARNING) << "IterativeLinearSolver::solve: The linear system should be assigned before solving!";
+        LOG(WARNING) << "The linear system should be assigned before solving!";
         return;
     }
 
diff --git a/Source/apiUtilities/imstkAPIUtilities.cpp b/Source/apiUtilities/imstkAPIUtilities.cpp
index 95620bb43f7adfba8f78b60fcfddf009c928be46..df74d14c90630918d064e8484a2d681d9efb485e 100644
--- a/Source/apiUtilities/imstkAPIUtilities.cpp
+++ b/Source/apiUtilities/imstkAPIUtilities.cpp
@@ -32,7 +32,7 @@
 
 // Geometry
 #include "imstkCapsule.h"
-#include "imstkCube.h"
+#include "imstkOrientedBox.h"
 #include "imstkImageData.h"
 #include "imstkMeshIO.h"
 #include "imstkPlane.h"
@@ -48,7 +48,7 @@ std::unordered_map<std::string, std::function<std::shared_ptr<Geometry>()>> geom
 {
     { "Sphere", []() { return std::make_shared<Sphere>(); } },
     { "Plane", []() { return std::make_shared<Sphere>(); } },
-    { "Cube", []() { return std::make_shared<Sphere>(); } },
+    { "OrientedBox", []() { return std::make_shared<OrientedBox>(); } },
     { "Capsule", []() { return std::make_shared<Sphere>(); } },
     { "Cylinder", []() { return std::make_shared<Sphere>(); } }
 };
@@ -63,12 +63,12 @@ createVisualAnalyticalSceneObject(std::string            type,
                                   const Vec3d            scale /* = 1.*/,
                                   const Vec3d            t /*= Vec3d(0., 0., 0.)*/)
 {
-    CHECK(scene != nullptr) << "createVisualAnalyticalSceneObject: Scene is not valid!";
-    CHECK(!objName.empty()) << "createVisualAnalyticalSceneObject: Name is empty!";
+    CHECK(scene != nullptr) << "Error: Scene object is not valid!";
+    CHECK(!objName.empty()) << "Error: Name is empty!";
 
     if (geomMakeFunctions.count(type) == 0)
     {
-        LOG(WARNING) << "createVisualAnalyticalSceneObject: Scene object geometry type is not analytical!";
+        LOG(WARNING) << "Scene object geometry type " << type << " is not analytical!";
         return nullptr;
     }
     std::shared_ptr<Geometry> geom = geomMakeFunctions[type]();
@@ -93,12 +93,12 @@ createCollidingAnalyticalSceneObject(std::string            type,
                                      const Vec3d            scale /*= 1.*/,
                                      const Vec3d            t /*= Vec3d(0., 0., 0.)*/)
 {
-    CHECK(scene != nullptr) << "createCollidingSphereSceneObject: Scene is not valid!";
-    CHECK(!objName.empty()) << "createCollidingAnalyticalSceneObject: Name is empty!";
+    CHECK(scene != nullptr) << "Scene is not valid!";
+    CHECK(!objName.empty()) << "Name is empty!";
 
     if (geomMakeFunctions.count(type) == 0)
     {
-        LOG(WARNING) << "createCollidingAnalyticalSceneObject: Scene object geometry type is not analytical!";
+        LOG(WARNING) << "Scene object geometry type " << type << " is not analytical!";
         return nullptr;
     }
     std::shared_ptr<Geometry> geom = geomMakeFunctions[type]();
@@ -122,8 +122,8 @@ createAndAddVisualSceneObject(std::shared_ptr<Scene> scene,
                               const std::string&     fileName,
                               const std::string&     objectName)
 {
-    CHECK(scene != nullptr) << "createAndAddVisualSceneObject: Scene is not valid!";
-    CHECK(!fileName.empty()) << "createAndAddVisualSceneObject: Name is empty!";
+    CHECK(scene != nullptr) << "Error: Scene object supplied is not valid!";
+    CHECK(!fileName.empty()) << "Error: Name is empty!";
 
     auto mesh = MeshIO::read(fileName);
     auto SurfaceMesh = std::dynamic_pointer_cast<imstk::SurfaceMesh>(mesh);
@@ -143,7 +143,7 @@ createAndAddVisualSceneObject(std::shared_ptr<Scene> scene,
 std::shared_ptr<NonLinearSystem<SparseMatrixd>>
 createNonLinearSystem(std::shared_ptr<FEMDeformableBodyModel> dynaModel)
 {
-    CHECK(dynaModel != nullptr) << "createNonLinearSystem: Dynamic model is not valid!";
+    CHECK(dynaModel != nullptr) << "Dynamic model object supplied is not valid!";
 
     auto nlSystem = std::make_shared<NonLinearSystem<SparseMatrixd>>(
                 dynaModel->getFunction(),
@@ -164,7 +164,7 @@ createNonLinearSystem(std::shared_ptr<FEMDeformableBodyModel> dynaModel)
 std::shared_ptr<Graph>
 getMeshGraph(std::shared_ptr<PointSet> m)
 {
-    LOG(WARNING) << "The graph of a point set has no edges";
+    LOG(WARNING) << "Note: The graph of a point set has no edges";
 
     return std::make_shared<Graph>(m->getNumVertices());
 }