diff --git a/Modules/Simulation/Resources/Interactions/Simulation.xml b/Modules/Simulation/Resources/Interactions/Simulation.xml index 2018c2c7ef..c0bad251b8 100644 --- a/Modules/Simulation/Resources/Interactions/Simulation.xml +++ b/Modules/Simulation/Resources/Interactions/Simulation.xml @@ -1,23 +1,45 @@ + - + + + + + - - + + - - + + + + + + + + + + + - - + + - - + + + + + + + + + + \ No newline at end of file diff --git a/Modules/Simulation/Resources/Interactions/SimulationConfig.xml b/Modules/Simulation/Resources/Interactions/SimulationConfig.xml index 4be2b1b2de..224f082a55 100644 --- a/Modules/Simulation/Resources/Interactions/SimulationConfig.xml +++ b/Modules/Simulation/Resources/Interactions/SimulationConfig.xml @@ -1,20 +1,40 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Modules/Simulation/mitkSimulationInteractor.cpp b/Modules/Simulation/mitkSimulationInteractor.cpp index 307ebd03b8..1b989d4f0c 100644 --- a/Modules/Simulation/mitkSimulationInteractor.cpp +++ b/Modules/Simulation/mitkSimulationInteractor.cpp @@ -1,510 +1,526 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include +#include #include #include #include #include #include #include #include #include #include #include #include "mitkSimulation.h" #include "mitkSimulationInteractor.h" +using sofa::component::collision::AttachBodyPerformer; using sofa::component::collision::BaseRayContact; using sofa::component::collision::BodyPicked; using sofa::component::collision::ComponentMouseInteraction; using sofa::component::collision::FixParticlePerformerConfiguration; using sofa::component::collision::InteractionPerformer; using sofa::component::collision::Ray; using sofa::component::collision::RayModel; using sofa::component::container::MechanicalObject; using sofa::core::behavior::BaseMechanicalState; using sofa::core::collision::DetectionOutput; using sofa::core::collision::Pipeline; using sofa::core::objectmodel::BaseContext; using sofa::core::CollisionElementIterator; using sofa::core::ExecParams; using sofa::core::MechanicalParams; using sofa::core::VecCoordId; using sofa::defaulttype::dot; using sofa::defaulttype::Vec3d; using sofa::defaulttype::Vec3Types; using sofa::helper::vector; using sofa::simulation::CollisionVisitor; using sofa::simulation::DeleteVisitor; using sofa::simulation::MechanicalPickParticlesVisitor; using sofa::simulation::MechanicalPropagatePositionVisitor; using sofa::simulation::Node; namespace mitk { class SimulationInteractor::Impl { public: Impl(); ~Impl(); void Initialize(Node::SPtr rootNode); void Uninitialize(); void AttachMouseNode(); void DetachMouseNode(); - bool IsMouseNodeAttached() const; - void UpdatePickRay(const InteractionPositionEvent* event); + bool IsInteractionPerformerNotNull() const; + void UpdatePickRay(InteractionPositionEvent* event); void FindCollision(); void AttachCompatibleInteraction(); void DetachInteraction(bool setNull); - void StartInteraction(); + void StartInteraction(const std::string& type); void ExecuteInteraction(); void StopInteraction(); private: Impl(const Impl&); Impl& operator=(const Impl&); BodyPicked FindCollisionUsingPipeline(); BodyPicked FindCollisionUsingBruteForce(); void ConfigureInteractionPerformer(); Node::SPtr m_RootNode; Node::SPtr m_MouseNode; MechanicalObject::SPtr m_PickRayContainer; RayModel::SPtr m_PickRayModel; std::vector m_InteractionComponents; ComponentMouseInteraction* m_Interaction; std::auto_ptr m_InteractionPerformer; bool m_IsMouseNodeAttached; bool m_UseCollisionPipeline; BodyPicked m_LastBodyPicked; }; } mitk::SimulationInteractor::Impl::Impl() : m_Interaction(NULL), m_IsMouseNodeAttached(false), m_UseCollisionPipeline(true) { } mitk::SimulationInteractor::Impl::~Impl() { this->Uninitialize(); } void mitk::SimulationInteractor::Impl::Initialize(const Node::SPtr rootNode) { this->Uninitialize(); m_RootNode = rootNode; m_PickRayContainer = sofa::core::objectmodel::New >(); m_PickRayContainer->setName("MousePosition"); m_PickRayContainer->resize(1); m_PickRayModel = sofa::core::objectmodel::New(); m_PickRayModel->setName("MouseCollisionModel"); m_PickRayModel->setNbRay(1); m_MouseNode = rootNode->createChild("Mouse"); m_MouseNode->addObject(m_PickRayContainer); m_MouseNode->addObject(m_PickRayModel); m_MouseNode->init(ExecParams::defaultInstance()); m_PickRayContainer->init(); m_PickRayModel->init(); typedef ComponentMouseInteraction::ComponentMouseInteractionFactory Factory; const Factory* factory = Factory::getInstance(); for (Factory::const_iterator it = factory->begin(); it != factory->end(); ++it) m_InteractionComponents.push_back(it->second->createInstance(NULL)); m_MouseNode->detachFromGraph(); Pipeline* collisionPipeline; rootNode->getContext()->get(collisionPipeline, BaseContext::SearchRoot); m_UseCollisionPipeline = collisionPipeline != NULL; } void mitk::SimulationInteractor::Impl::Uninitialize() { this->DetachMouseNode(); if (!m_InteractionComponents.empty()) { for (std::vector::iterator it = m_InteractionComponents.begin(); it != m_InteractionComponents.end(); ++it) delete *it; m_InteractionComponents.clear(); m_Interaction = NULL; } if (m_MouseNode) { m_MouseNode->execute(ExecParams::defaultInstance()); m_PickRayModel.reset(); m_PickRayContainer.reset(); m_MouseNode.reset(); m_RootNode.reset(); } } void mitk::SimulationInteractor::Impl::AttachMouseNode() { if (!m_IsMouseNodeAttached) { m_RootNode->addChild(m_MouseNode); m_IsMouseNodeAttached = true; } } void mitk::SimulationInteractor::Impl::DetachMouseNode() { if (m_IsMouseNodeAttached) { this->DetachInteraction(false); m_MouseNode->detachFromGraph(); m_IsMouseNodeAttached = false; } } -bool mitk::SimulationInteractor::Impl::IsMouseNodeAttached() const +bool mitk::SimulationInteractor::Impl::IsInteractionPerformerNotNull() const { - return m_IsMouseNodeAttached; + return m_InteractionPerformer.get() != NULL; } -void mitk::SimulationInteractor::Impl::UpdatePickRay(const InteractionPositionEvent* event) +void mitk::SimulationInteractor::Impl::UpdatePickRay(InteractionPositionEvent* event) { if (!m_IsMouseNodeAttached) return; vtkCamera* camera = event->GetSender()->GetVtkRenderer()->GetActiveCamera(); Vec3d cameraOrigin(camera->GetPosition()); Vec3d pickedPosition(event->GetPositionInWorld().GetDataPointer()); Vec3d pickRayDirection(pickedPosition - cameraOrigin); Vec3d focalPoint(camera->GetFocalPoint()); Vec3d cameraDirection(focalPoint - cameraOrigin); cameraDirection.normalize(); std::pair clippingRange; camera->GetClippingRange(clippingRange.first, clippingRange.second); double dotProduct = dot(cameraDirection, pickRayDirection); double norm = pickRayDirection.norm(); clippingRange.first = clippingRange.first / dotProduct * norm; clippingRange.second = clippingRange.second / dotProduct * norm; pickRayDirection.normalize(); Ray pickRay = m_PickRayModel->getRay(0); pickRay.setOrigin(cameraOrigin + pickRayDirection * clippingRange.first); pickRay.setDirection(pickRayDirection); pickRay.setL(clippingRange.second - clippingRange.first); MechanicalPropagatePositionVisitor(MechanicalParams::defaultInstance(), 0, VecCoordId::position(), true) .execute(m_PickRayModel->getContext()); MechanicalPropagatePositionVisitor(MechanicalParams::defaultInstance(), 0, VecCoordId::freePosition(), true) .execute(m_PickRayModel->getContext()); } void mitk::SimulationInteractor::Impl::FindCollision() { CollisionVisitor(ExecParams::defaultInstance()).execute(m_RootNode->getContext()); if (m_UseCollisionPipeline) { - MITK_INFO << "FindCollisionUsingPipeline()"; m_LastBodyPicked = this->FindCollisionUsingPipeline(); if (m_LastBodyPicked.body != NULL) return; } - MITK_INFO << "FindCollisionUsingBruteForce()"; m_LastBodyPicked = this->FindCollisionUsingBruteForce(); - - if (m_LastBodyPicked.body == NULL && m_LastBodyPicked.mstate == NULL) - MITK_WARN << "No body picked!"; } BodyPicked mitk::SimulationInteractor::Impl::FindCollisionUsingPipeline() { BodyPicked bodyPicked; Ray ray = m_PickRayModel->getRay(0); const Vec3d& origin = ray.origin(); const Vec3d& direction = ray.direction(); const double length = ray.l(); const std::set& contacts = m_PickRayModel->getContacts(); - if (contacts.empty()) - MITK_WARN << "No picking contacts!"; - for (std::set::const_iterator contact = contacts.begin(); contact != contacts.end(); ++contact) { const vector& detectionOutputs = (*contact)->getDetectionOutputs(); for (vector::const_iterator detectionOutput = detectionOutputs.begin(); detectionOutput != detectionOutputs.end(); ++detectionOutput) { CollisionElementIterator collisionElement; int pointIndex; if ((*detectionOutput)->elem.first.getCollisionModel() == m_PickRayModel) { collisionElement = (*detectionOutput)->elem.second; pointIndex = 1; } else if ((*detectionOutput)->elem.second.getCollisionModel() == m_PickRayModel) { collisionElement = (*detectionOutput)->elem.first; pointIndex = 0; } else { continue; } if (!collisionElement.getCollisionModel()->isSimulated()) continue; const double t = ((*detectionOutput)->point[pointIndex] - origin) * direction; if (t < 0.0 || t > length) continue; if (bodyPicked.body == NULL || t < bodyPicked.rayLength) { bodyPicked.body = collisionElement.getCollisionModel(); bodyPicked.indexCollisionElement = collisionElement.getIndex(); bodyPicked.point = (*detectionOutput)->point[pointIndex]; bodyPicked.dist = ((*detectionOutput)->point[1] - (*detectionOutput)->point[0]).norm(); bodyPicked.rayLength = t; } } } return bodyPicked; } BodyPicked mitk::SimulationInteractor::Impl::FindCollisionUsingBruteForce() { BodyPicked bodyPicked; Ray ray = m_PickRayModel->getRay(0); const Vec3d& origin = ray.origin(); const Vec3d& direction = ray.direction(); const double length = ray.l(); MechanicalPickParticlesVisitor pickVisitor(ExecParams::defaultInstance(), origin, direction, length); pickVisitor.execute(m_RootNode->getContext()); if (!pickVisitor.particles.empty()) { bodyPicked.mstate = pickVisitor.particles.begin()->second.first; bodyPicked.indexCollisionElement = pickVisitor.particles.begin()->second.second; bodyPicked.point[0] = bodyPicked.mstate->getPX(bodyPicked.indexCollisionElement); bodyPicked.point[1] = bodyPicked.mstate->getPY(bodyPicked.indexCollisionElement); bodyPicked.point[2] = bodyPicked.mstate->getPZ(bodyPicked.indexCollisionElement); bodyPicked.dist = 0; bodyPicked.rayLength = (bodyPicked.point - origin) * direction; } - else - { - MITK_WARN << "No particles picked!"; - } return bodyPicked; } void mitk::SimulationInteractor::Impl::AttachCompatibleInteraction() { BaseContext* context; if (m_LastBodyPicked.body == NULL) { context = m_LastBodyPicked.mstate != NULL ? m_LastBodyPicked.mstate->getContext() : NULL; } else { context = m_LastBodyPicked.body->getContext(); } if (context != NULL) { if (m_Interaction == NULL || !m_Interaction->isCompatible(context)) { bool foundCompatibleInteractor = false; for (std::vector::const_iterator it = m_InteractionComponents.begin(); it != m_InteractionComponents.end(); ++it) { if (*it != m_Interaction && (*it)->isCompatible(context)) { this->DetachInteraction(false); m_Interaction = *it; m_Interaction->attach(m_MouseNode.get()); foundCompatibleInteractor = true; break; } } if (!foundCompatibleInteractor) this->DetachInteraction(true); } } else { this->DetachInteraction(true); } if (m_Interaction != NULL) { m_Interaction->mouseInteractor->setMouseRayModel(m_PickRayModel.get()); m_Interaction->mouseInteractor->setBodyPicked(m_LastBodyPicked); } } void mitk::SimulationInteractor::Impl::DetachInteraction(bool setNull) { if (m_Interaction != NULL) { m_Interaction->detach(); if (setNull) m_Interaction = NULL; } } -void mitk::SimulationInteractor::Impl::StartInteraction() +void mitk::SimulationInteractor::Impl::StartInteraction(const std::string& type) { if (m_Interaction == NULL) return; InteractionPerformer::InteractionPerformerFactory* factory = InteractionPerformer::InteractionPerformerFactory::getInstance(); - m_InteractionPerformer.reset(factory->createObject("FixParticle", m_Interaction->mouseInteractor.get())); + m_InteractionPerformer.reset(factory->createObject(type, m_Interaction->mouseInteractor.get())); if (m_InteractionPerformer.get() != NULL) { this->ConfigureInteractionPerformer(); m_Interaction->mouseInteractor->addInteractionPerformer(m_InteractionPerformer.get()); m_InteractionPerformer->start(); } } void mitk::SimulationInteractor::Impl::ConfigureInteractionPerformer() { - FixParticlePerformerConfiguration* configuration = dynamic_cast(m_InteractionPerformer.get()); + AttachBodyPerformer* attachBodyPerformer = dynamic_cast*>(m_InteractionPerformer.get()); + + if (attachBodyPerformer != NULL) + { + attachBodyPerformer->setStiffness(1000); + attachBodyPerformer->setArrowSize(0); + attachBodyPerformer->setShowFactorSize(1); + return; + } - if (configuration != NULL) - configuration->setStiffness(10000); + FixParticlePerformerConfiguration* fixParticlePerformer = dynamic_cast(m_InteractionPerformer.get()); + + if (fixParticlePerformer != NULL) + fixParticlePerformer->setStiffness(10000); } void mitk::SimulationInteractor::Impl::ExecuteInteraction() { if (m_InteractionPerformer.get() == NULL) return; m_InteractionPerformer->execute(); } void mitk::SimulationInteractor::Impl::StopInteraction() { if (m_InteractionPerformer.get() == NULL) return; + AttachBodyPerformer* attachBodyPerformer = dynamic_cast*>(m_InteractionPerformer.get()); + + if (attachBodyPerformer != NULL) + attachBodyPerformer->clear(); + m_Interaction->mouseInteractor->removeInteractionPerformer(m_InteractionPerformer.get()); m_InteractionPerformer.release(); } mitk::SimulationInteractor::SimulationInteractor() : m_Impl(new Impl) { } mitk::SimulationInteractor::~SimulationInteractor() { } void mitk::SimulationInteractor::ConnectActionsAndFunctions() { - CONNECT_FUNCTION("attachMouseNode", AttachMouseNode); - CONNECT_FUNCTION("detachMouseNode", DetachMouseNode); - CONNECT_FUNCTION("moveMouse", MoveMouse); - CONNECT_CONDITION("isMouseNodeAttached", IsMouseNodeAttached); + CONNECT_FUNCTION("startPrimaryInteraction", StartPrimaryInteraction); + CONNECT_FUNCTION("startSecondaryInteraction", StartSecondaryInteraction); + CONNECT_FUNCTION("stopInteraction", StopInteraction); + CONNECT_FUNCTION("executeInteraction", ExecuteInteraction); + CONNECT_CONDITION("isInteractionPerformerNotNull", IsInteractionPerformerNotNull); } void mitk::SimulationInteractor::DataNodeChanged() { this->ResetToStartState(); NodeType dataNode = this->GetDataNode(); if (dataNode.IsNotNull()) { Simulation::Pointer simulation = dynamic_cast(dataNode->GetData()); if (simulation.IsNotNull()) { m_Impl->Initialize(simulation->GetRootNode()); return; } } m_Impl->Uninitialize(); } -bool mitk::SimulationInteractor::AttachMouseNode(StateMachineAction*, InteractionEvent* event) +void mitk::SimulationInteractor::StartInteraction(const std::string& type, InteractionPositionEvent* event) { m_Impl->AttachMouseNode(); - m_Impl->UpdatePickRay(dynamic_cast(event)); + m_Impl->UpdatePickRay(event); m_Impl->FindCollision(); m_Impl->AttachCompatibleInteraction(); - m_Impl->StartInteraction(); + m_Impl->StartInteraction(type); +} +bool mitk::SimulationInteractor::StartPrimaryInteraction(StateMachineAction*, InteractionEvent* event) +{ + this->StartInteraction("AttachBody", dynamic_cast(event)); + return true; +} + +bool mitk::SimulationInteractor::StartSecondaryInteraction(StateMachineAction*, InteractionEvent* event) +{ + this->StartInteraction("FixParticle", dynamic_cast(event)); return true; } -bool mitk::SimulationInteractor::DetachMouseNode(StateMachineAction*, InteractionEvent*) +bool mitk::SimulationInteractor::StopInteraction(StateMachineAction*, InteractionEvent*) { m_Impl->StopInteraction(); m_Impl->DetachMouseNode(); return true; } -bool mitk::SimulationInteractor::MoveMouse(StateMachineAction*, InteractionEvent* event) +bool mitk::SimulationInteractor::ExecuteInteraction(StateMachineAction*, InteractionEvent* event) { - m_Impl->UpdatePickRay(dynamic_cast(event)); + m_Impl->UpdatePickRay(dynamic_cast(event)); m_Impl->ExecuteInteraction(); return true; } -bool mitk::SimulationInteractor::IsMouseNodeAttached(const InteractionEvent*) +bool mitk::SimulationInteractor::IsInteractionPerformerNotNull(const InteractionEvent*) { - return m_Impl->IsMouseNodeAttached(); + return m_Impl->IsInteractionPerformerNotNull(); } diff --git a/Modules/Simulation/mitkSimulationInteractor.h b/Modules/Simulation/mitkSimulationInteractor.h index 55757c3c89..6e838d86f7 100644 --- a/Modules/Simulation/mitkSimulationInteractor.h +++ b/Modules/Simulation/mitkSimulationInteractor.h @@ -1,50 +1,54 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkSimulationInteractor_h #define mitkSimulationInteractor_h #include #include namespace mitk { + class InteractionPositionEvent; + class MitkSimulation_EXPORT SimulationInteractor : public DataInteractor { public: mitkClassMacro(SimulationInteractor, DataInteractor); itkFactorylessNewMacro(Self); itkCloneMacro(Self); protected: void ConnectActionsAndFunctions(); void DataNodeChanged(); private: SimulationInteractor(); ~SimulationInteractor(); - bool AttachMouseNode(StateMachineAction* action, InteractionEvent* event); - bool DetachMouseNode(StateMachineAction* action, InteractionEvent* event); - bool MoveMouse(StateMachineAction* action, InteractionEvent* event); - bool IsMouseNodeAttached(const InteractionEvent* event); + void StartInteraction(const std::string& type, InteractionPositionEvent* event); + bool StartPrimaryInteraction(StateMachineAction* action, InteractionEvent* event); + bool StartSecondaryInteraction(StateMachineAction* action, InteractionEvent* event); + bool ExecuteInteraction(StateMachineAction* action, InteractionEvent* event); + bool StopInteraction(StateMachineAction* action, InteractionEvent* event); + bool IsInteractionPerformerNotNull(const InteractionEvent* event); class Impl; std::auto_ptr m_Impl; }; } #endif