diff --git a/Examples/PBDCutting/PBDCuttingExample.cpp b/Examples/PBDCutting/PBDCuttingExample.cpp index 92f9430fcfac7e86de39b7efcebcb5554aa36ea3..a5da83d370f39481149cbb142f948f4e0e18356b 100644 --- a/Examples/PBDCutting/PBDCuttingExample.cpp +++ b/Examples/PBDCutting/PBDCuttingExample.cpp @@ -48,6 +48,7 @@ // Collisions and Models #include "imstkPbdModel.h" +#include "imstkPbdObjectCuttingPair.h" #include "imstkPbdSolver.h" #include "imstkRenderMaterial.h" #include "imstkVisualModel.h" @@ -201,6 +202,8 @@ main() scene->addSceneObject(clothObj); // Add interaction pair for pbd cutting + imstkNew<PbdObjectCuttingPair> cuttingPair(clothObj, cutObj); + /* // Device Server imstkNew<HapticDeviceManager> server; @@ -251,34 +254,12 @@ main() } // Queue keypress to be called after scene thread - queueConnect<KeyEvent>(viewer->getKeyboardDevice(), EventType::KeyEvent, sceneManager, [&](KeyEvent* e) + queueConnect<KeyEvent>(viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress, sceneManager, [&](KeyEvent* e) { // When i is pressed replace the PBD cloth with a cut one if (e->m_key == 'i' && e->m_keyPressType == KEY_PRESS) { - // This has a number of issues that make it not physically realistic - // - Mass is not conservative when interpolated from subdivide - // - Constraint resting lengths are not correctly reinited - std::shared_ptr<SurfaceMesh> clothMesh = std::dynamic_pointer_cast<SurfaceMesh>(clothObj->getPhysicsGeometry()); - imstkNew<SurfaceMeshCut> surfCut; - surfCut->setInputMesh(clothMesh); - surfCut->setCutGeometry(cutGeom); - surfCut->update(); - std::shared_ptr<SurfaceMesh> newClothMesh = surfCut->getOutputMesh(); - - // RenderDelegates cannot visually have entire geometries swapped yet, so even though we could just set the geometry - // on the model, you would not visually see it. Instead we replace the vertex and index buffers of the existing one - clothMesh->setInitialVertexPositions(std::make_shared<VecDataArray<double, 3>>(*newClothMesh->getInitialVertexPositions())); - clothMesh->setVertexPositions(std::make_shared<VecDataArray<double, 3>>(*newClothMesh->getVertexPositions())); - clothMesh->setTriangleIndices(std::make_shared<VecDataArray<int, 3>>(*newClothMesh->getTriangleIndices())); - clothMesh->modified(); - - // Re-initialize states, vertices, masses and constraints on the object - clothObj->getPbdModel()->initState(); - clothObj->getPbdModel()->removeConstraints(surfCut->getRemoveConstraintVertices()); - clothObj->getPbdModel()->addConstraints(surfCut->getAddConstraintVertices()); - clothObj->getPbdModel()->getSolver()->setInvMasses(clothObj->getPbdModel()->getInvMasses()); - clothObj->getPbdModel()->getSolver()->setPositions(clothObj->getPbdModel()->getCurrentState()->getPositions()); + cuttingPair->apply(); } }); diff --git a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp index 53f0744e12c37fcb6bd7ef767d95d17754972fd2..fd14a7c8eb8dd0ea0b1307ff79e05118d3484b93 100644 --- a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp +++ b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp @@ -609,7 +609,7 @@ void PbdModel::addConstraints(std::shared_ptr<std::unordered_set<size_t>> vertices) { // check if constraint type matches the mesh type - CHECK(m_mesh->getType() == Geometry::Type::SurfaceMesh) + CHECK(m_mesh->getTypeName() == "SurfaceMesh") << "Add element constraints does not support current mesh type."; const auto& triMesh = std::static_pointer_cast<SurfaceMesh>(m_mesh); diff --git a/Source/Scene/CMakeLists.txt b/Source/Scene/CMakeLists.txt index 114253e60cc34d7e2dac0f43841a29db2d0920f5..5d1a4640b5f69e59067630d2063dab2976020dd0 100644 --- a/Source/Scene/CMakeLists.txt +++ b/Source/Scene/CMakeLists.txt @@ -9,6 +9,7 @@ imstk_add_library( Scene CollisionHandling SceneEntities Controllers + Filtering ) #----------------------------------------------------------------------------- diff --git a/Source/Scene/imstkPbdObjectCuttingPair.cpp b/Source/Scene/imstkPbdObjectCuttingPair.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62dd5f8431a536886bf3ca2c6a0f498c9f65d566 --- /dev/null +++ b/Source/Scene/imstkPbdObjectCuttingPair.cpp @@ -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. + +=========================================================================*/ + +#include "imstkPbdObjectCuttingPair.h" + +#include "imstkAnalyticalGeometry.h" +#include "imstkCollidingObject.h" +#include "imstkLogger.h" +#include "imstkNew.h" +#include "imstkPbdModel.h" +#include "imstkPbdObject.h" +#include "imstkPbdSolver.h" +#include "imstkSurfaceMesh.h" +#include "imstkSurfaceMeshCut.h" + +namespace imstk +{ +PbdObjectCuttingPair::PbdObjectCuttingPair(std::shared_ptr<PbdObject> pbdObj, std::shared_ptr<CollidingObject> cutObj) : ObjectInteractionPair(pbdObj, cutObj) +{ + // check whether pbd object is a surfacemesh + if (std::dynamic_pointer_cast<SurfaceMesh>(pbdObj->getPhysicsGeometry()) == nullptr) + { + LOG(WARNING) << "PbdObj is not a SurfaceMesh, could not create cutting pair"; + return; + } + + // check whether cut object is valid + if (std::dynamic_pointer_cast<SurfaceMesh>(cutObj->getCollidingGeometry()) == nullptr + && std::dynamic_pointer_cast<AnalyticalGeometry>(cutObj->getCollidingGeometry()) == nullptr) + { + LOG(WARNING) << "CutObj is neither a SurfaceMesh nor an AnalyticalGeometry, could not create cutting pair"; + return; + } +} + +void +PbdObjectCuttingPair::apply() +{ + auto pbdObj = std::static_pointer_cast<PbdObject>(m_objects.first); + auto cutObj = std::static_pointer_cast<CollidingObject>(m_objects.second); + auto pbdMesh = std::static_pointer_cast<SurfaceMesh>(pbdObj->getPhysicsGeometry()); + auto pbdModel = pbdObj->getPbdModel(); + + // perform cutting + imstkNew<SurfaceMeshCut> surfCut; + surfCut->setInputMesh(pbdMesh); + surfCut->setCutGeometry(cutObj->getCollidingGeometry()); + surfCut->update(); + auto newPbdMesh = surfCut->getOutputMesh(); + + // update pbd mesh + pbdMesh->setInitialVertexPositions(std::make_shared<VecDataArray<double, 3>>(*newPbdMesh->getInitialVertexPositions())); + pbdMesh->setVertexPositions(std::make_shared<VecDataArray<double, 3>>(*newPbdMesh->getVertexPositions())); + pbdMesh->setTriangleIndices(std::make_shared<VecDataArray<int, 3>>(*newPbdMesh->getTriangleIndices())); + pbdMesh->modified(); + + // update pbd states, constraints and solver + pbdModel->initState(); + pbdModel->removeConstraints(surfCut->getRemoveConstraintVertices()); + pbdModel->addConstraints(surfCut->getAddConstraintVertices()); + pbdModel->getSolver()->setInvMasses(pbdModel->getInvMasses()); + pbdModel->getSolver()->setPositions(pbdModel->getCurrentState()->getPositions()); +} +} \ No newline at end of file diff --git a/Source/Scene/imstkPbdObjectCuttingPair.h b/Source/Scene/imstkPbdObjectCuttingPair.h new file mode 100644 index 0000000000000000000000000000000000000000..7fe35f62f394dad7f4e43ec88b0dfce744bed46f --- /dev/null +++ b/Source/Scene/imstkPbdObjectCuttingPair.h @@ -0,0 +1,46 @@ +/*========================================================================= + +Library: iMSTK + +Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, +& Imaging in Medicine, Rensselaer Polytechnic Institute. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0.txt + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +=========================================================================*/ + +#pragma once + +#include "imstkObjectInteractionPair.h" + +namespace imstk +{ +class PbdObject; +class CollidingObject; + +/// +/// \class PbdObjectCuttingPair +/// +/// \brief This class defines a cutting pair between a PbdObject and a CollidingObject +/// +class PbdObjectCuttingPair : public ObjectInteractionPair +{ +public: + PbdObjectCuttingPair(std::shared_ptr<PbdObject> pbdObj, std::shared_ptr<CollidingObject> cutObj); + virtual ~PbdObjectCuttingPair() override = default; + + void apply(); + +protected: +}; +} \ No newline at end of file