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