diff --git a/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.cpp b/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.cpp index 4b2422cc23..5cc584f098 100644 --- a/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.cpp +++ b/Modules/IGT/Algorithms/mitkIGTLMessageToNavigationDataFilter.cpp @@ -1,439 +1,439 @@ /*=================================================================== 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 "mitkIGTLMessageToNavigationDataFilter.h" #include "igtlTrackingDataMessage.h" #include "igtlQuaternionTrackingDataMessage.h" #include "igtlTransformMessage.h" #include "mitkQuaternion.h" #include mitk::IGTLMessageToNavigationDataFilter::IGTLMessageToNavigationDataFilter() : mitk::NavigationDataSource() { mitk::NavigationData::Pointer output = mitk::NavigationData::New(); this->SetNumberOfRequiredOutputs(1); this->SetNthOutput(0, output.GetPointer()); } mitk::IGTLMessageToNavigationDataFilter::~IGTLMessageToNavigationDataFilter() { } void mitk::IGTLMessageToNavigationDataFilter::SetInput(const IGTLMessage* msg) { this->SetInput(0, msg); } void mitk::IGTLMessageToNavigationDataFilter::SetInput(unsigned int idx, const IGTLMessage* msg) { if (msg == nullptr) // if an input is set to nullptr, remove it { this->RemoveInput(idx); } else { // ProcessObject is not const-correct so a const_cast is required here this->ProcessObject::SetNthInput(idx, const_cast(msg)); } this->CreateOutputsForAllInputs(); } const mitk::IGTLMessage* mitk::IGTLMessageToNavigationDataFilter::GetInput(void) const { if (this->GetNumberOfInputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetInput(0)); } const mitk::IGTLMessage* mitk::IGTLMessageToNavigationDataFilter::GetInput(unsigned int idx) const { if (this->GetNumberOfInputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetInput(idx)); } const mitk::IGTLMessage* mitk::IGTLMessageToNavigationDataFilter::GetInput(std::string messageName) const { const DataObjectPointerArray& inputs = const_cast(this)->GetInputs(); for (DataObjectPointerArray::const_iterator it = inputs.begin(); it != inputs.end(); ++it) { if (std::string(messageName) == (static_cast(it->GetPointer()))->GetName()) { return static_cast(it->GetPointer()); } } return nullptr; } itk::ProcessObject::DataObjectPointerArraySizeType mitk::IGTLMessageToNavigationDataFilter::GetInputIndex(std::string messageName) { DataObjectPointerArray outputs = this->GetInputs(); for (DataObjectPointerArray::size_type i = 0; i < outputs.size(); ++i) { if (messageName == (static_cast(outputs.at(i).GetPointer()))->GetName()) { return i; } } throw std::invalid_argument("output name does not exist"); } void mitk::IGTLMessageToNavigationDataFilter::ConnectTo( mitk::IGTLMessageSource* UpstreamFilter) { for (DataObjectPointerArraySizeType i = 0; i < UpstreamFilter->GetNumberOfOutputs(); i++) { this->SetInput(i, UpstreamFilter->GetOutput(i)); } } void mitk::IGTLMessageToNavigationDataFilter::SetNumberOfExpectedOutputs( unsigned int numOutputs) { this->SetNumberOfIndexedOutputs(numOutputs); this->CreateOutputsForAllInputs(); } void mitk::IGTLMessageToNavigationDataFilter::CreateOutputsForAllInputs() { // create outputs for all inputs // this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); bool isModified = false; for (unsigned int idx = 0; idx < this->GetNumberOfIndexedOutputs(); ++idx) { if (this->GetOutput(idx) == nullptr) { mitk::NavigationData::Pointer newOutput = mitk::NavigationData::New(); this->SetNthOutput(idx, newOutput); isModified = true; } } if (isModified) this->Modified(); } void mitk::IGTLMessageToNavigationDataFilter::GenerateTransformData() { const mitk::IGTLMessage* input = this->GetInput(0); assert(input); //cast the input message into the proper type igtl::TransformMessage* tMsg = (igtl::TransformMessage*)(input->GetMessage().GetPointer()); //check if cast was successful if (!tMsg) { mitkThrow() << "Cast from igtl::MessageBase to igtl::TransformMessage " << "failed! Please check the message."; } /* update outputs with tracking data from tools */ for (unsigned int i = 0; i < this->GetNumberOfOutputs(); ++i) { mitk::NavigationData* output = this->GetOutput(i); assert(output); if (input->IsDataValid() == false) { output->SetDataValid(false); continue; } //get the transformation matrix and convert it into an affinetransformation igtl::Matrix4x4 transformation_; tMsg->GetMatrix(transformation_); mitk::AffineTransform3D::Pointer affineTransformation = mitk::AffineTransform3D::New(); mitk::Matrix3D transformation; mitk::Vector3D offset; for (unsigned int r = 0; r < 3; r++) { for (unsigned int c = 0; c < 3; c++) { transformation.GetVnlMatrix().set(r, c, transformation_[r][c]); } offset.SetElement(r, transformation_[r][3]); } //convert the igtl matrix here and set it in the affine transformation affineTransformation->SetMatrix(transformation); affineTransformation->SetOffset(offset); //create a new navigation data here, there is a neat constructor for //affine transformations that sets the orientation, position according to //the affine transformation. The other values are initialized with standard //values mitk::NavigationData::Pointer nd = mitk::NavigationData::New(affineTransformation, true); //set the time stamp nd->SetIGTTimeStamp(input->GetTimeStamp()); //set the name nd->SetName(input->GetName()); output->Graft(nd); } } void mitk::IGTLMessageToNavigationDataFilter::GenerateTrackingDataData() { const mitk::IGTLMessage* input = this->GetInput(0); assert(input); //cast the input message into the proper type igtl::TrackingDataMessage* tdMsg = (igtl::TrackingDataMessage*)(input->GetMessage().GetPointer()); //check if cast was successful if (!tdMsg) { mitkThrow() << "Cast from igtl::MessageBase to igtl::TrackingDataMessage " << "failed! Please check the message."; } //get the number of tracking data elements unsigned int numTrackingDataElements = tdMsg->GetNumberOfTrackingDataElements(); if (!numTrackingDataElements) { MITK_ERROR("IGTLMsgToNavDataFilter") << "There are no tracking data " "elements in this message"; } /* update outputs with tracking data from tools */ for (unsigned int i = 0; i < this->GetNumberOfOutputs(); ++i) { mitk::NavigationData* output = this->GetOutput(i); assert(output); //invalidate the output output->SetDataValid(false); //check if the current index, all outputs that have no corresponding input //tracking element stay invalidated, the others are validated according to //the tracking element if (input->IsDataValid() == false || i >= numTrackingDataElements) { continue; } output->SetDataValid(true); //get the tracking data element which holds all the data igtl::TrackingDataElement::Pointer td; tdMsg->GetTrackingDataElement(i, td); //get the transformation matrix and convert it into an affinetransformation igtl::Matrix4x4 transformation_; td->GetMatrix(transformation_); mitk::AffineTransform3D::Pointer affineTransformation = mitk::AffineTransform3D::New(); mitk::Matrix3D transformation; mitk::Vector3D offset; for (unsigned int r = 0; r < 3; r++) { for (unsigned int c = 0; c < 3; c++) { transformation.GetVnlMatrix().set(r, c, transformation_[r][c]); } offset.SetElement(r, transformation_[r][3]); } //convert the igtl matrix here and set it in the affine transformation affineTransformation->SetMatrix(transformation); affineTransformation->SetOffset(offset); mitk::NavigationData::Pointer nd; //check the rotation matrix vnl_matrix_fixed rotationMatrix = affineTransformation->GetMatrix().GetVnlMatrix(); vnl_matrix_fixed rotationMatrixTransposed = rotationMatrix.transpose(); // a quadratic matrix is a rotation matrix exactly when determinant is 1 // and transposed is inverse if (!Equal(1.0, vnl_det(rotationMatrix), 0.1) || !((rotationMatrix*rotationMatrixTransposed).is_identity(0.1))) { MITK_ERROR("IGTLMsgToNavDataFilter") << "tried to initialize NavData " << "with non-rotation matrix :" << rotationMatrix << " (Does your " "AffineTransform3D object include spacing? This is not " "supported by NavigationData objects!)"; nd = mitk::NavigationData::New(); } else { //create a new navigation data here, there is a neat constructor for //affine transformations that sets the orientation, position according to //the affine transformation. The other values are initialized with standard //values nd = mitk::NavigationData::New(affineTransformation, true); } //set the time stamp nd->SetIGTTimeStamp(input->GetIGTTimeStamp()); //set the name - nd->SetName(td->GetName()); + nd->SetName(input->GetName()); output->Graft(nd); } } void mitk::IGTLMessageToNavigationDataFilter::GenerateQuaternionTrackingDataData() { const mitk::IGTLMessage* input = this->GetInput(0); assert(input); //cast the input message into the proper type igtl::QuaternionTrackingDataMessage* tdMsg = (igtl::QuaternionTrackingDataMessage*)(input->GetMessage().GetPointer()); //check if cast was successful if (!tdMsg) { mitkThrow() << "Cast from igtl::MessageBase to igtl::TrackingDataMessage " << "failed! Please check the message."; } //get the number of tracking data elements unsigned int numTrackingDataElements = tdMsg->GetNumberOfQuaternionTrackingDataElements(); if (!numTrackingDataElements) { MITK_ERROR("IGTLMsgToNavDataFilter") << "There are no tracking data " "elements in this message"; } /* update outputs with tracking data from tools */ for (unsigned int i = 0; i < this->GetNumberOfOutputs(); ++i) { mitk::NavigationData* output = this->GetOutput(i); assert(output); //invalidate the output output->SetDataValid(false); //check if the current index, all outputs that have no corresponding input //tracking element stay invalidated, the others are validated according to //the tracking element if (input->IsDataValid() == false || i >= numTrackingDataElements) { continue; } output->SetDataValid(true); //get the tracking data element which holds all the data igtl::QuaternionTrackingDataElement::Pointer td; tdMsg->GetQuaternionTrackingDataElement(i, td); //get the quaternion and set it float quaternion_[4]; //igtl quat type td->GetQuaternion(quaternion_); mitk::Quaternion quaternion; quaternion.put(0, quaternion_[0]); quaternion.put(1, quaternion_[1]); quaternion.put(2, quaternion_[2]); quaternion.put(3, quaternion_[3]); output->SetOrientation(quaternion); output->SetHasOrientation(true); //get the position and set it float position_[3]; //igtl position type td->GetPosition(position_); mitk::NavigationData::PositionType position; //mitk position type position.SetElement(0, position_[0]); position.SetElement(1, position_[1]); position.SetElement(2, position_[2]); output->SetPosition(position); output->SetHasPosition(true); //set the time stamp output->SetIGTTimeStamp(input->GetTimeStamp()); //set the name output->SetName(td->GetName()); //there is no explicit covarience matrix output->SetCovErrorMatrix(mitk::NavigationData::CovarianceMatrixType()); } } void mitk::IGTLMessageToNavigationDataFilter::GenerateData() { //get the IGTLMessage from the previous filter const mitk::IGTLMessage* input = this->GetInput(0); assert(input); //check if the message is valid, if it is not valid we do not generate new //outputs if (!input->IsDataValid()) { MITK_DEBUG("IGTLMessageToNavigationDataFilter") << "Input data is invalid."; return; } //get the message type const char* msgType = input->GetIGTLMessageType(); //check if the IGTL message has the proper type if (strcmp(msgType, "TRANSFORM") == 0) { this->GenerateTransformData(); } else if (strcmp(msgType, "TDATA") == 0) { this->GenerateTrackingDataData(); } else if (strcmp(msgType, "QTDATA") == 0) { this->GenerateQuaternionTrackingDataData(); } else { //the message has another type //ignore MITK_INFO("IGTLMessageToNavigationDataFilter") << "The input has a unknown " << "message type: " << msgType; } } void mitk::IGTLMessageToNavigationDataFilter::GenerateOutputInformation() { // Superclass::GenerateOutputInformation(); // mitk::NavigationData* output = this->GetOutput(0); // assert(output); // const mitk::IGTLMessage* input = this->GetInput(0); // assert(input); itkDebugMacro(<< "GenerateOutputInformation()"); // output->Initialize(input->GetPixelType(), input->GetDimension(), input->GetDimensions()); // // initialize geometry // output->SetPropertyList(input->GetPropertyList()->Clone()); // mitk::TimeGeometry::Pointer clonGeometry = input->GetTimeGeometry()->Clone(); // output->SetTimeGeometry(clonGeometry.GetPointer()); } diff --git a/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.cpp b/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.cpp index 0e8f7cb849..c940bf8a72 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.cpp +++ b/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.cpp @@ -1,360 +1,348 @@ /*=================================================================== 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 "mitkNavigationDataToIGTLMessageFilter.h" #include "igtlQuaternionTrackingDataMessage.h" #include "igtlTrackingDataMessage.h" #include "igtlTransformMessage.h" #include "igtlPositionMessage.h" #include #include mitk::NavigationDataToIGTLMessageFilter::NavigationDataToIGTLMessageFilter() { mitk::IGTLMessage::Pointer output = mitk::IGTLMessage::New(); this->SetNumberOfRequiredOutputs(1); this->SetNthOutput(0, output.GetPointer()); - this->SetNumberOfRequiredInputs(1); // m_OperationMode = Mode3D; m_CurrentTimeStep = 0; // m_RingBufferSize = 50; //the default ring buffer size // m_NumberForMean = 100; } mitk::NavigationDataToIGTLMessageFilter::~NavigationDataToIGTLMessageFilter() { } void mitk::NavigationDataToIGTLMessageFilter::GenerateData() { switch (m_OperationMode) { case ModeSendQTDataMsg: this->GenerateDataModeSendQTDataMsg(); break; case ModeSendTDataMsg: this->GenerateDataModeSendTDataMsg(); break; case ModeSendQTransMsg: this->GenerateDataModeSendQTransMsg(); break; case ModeSendTransMsg: this->GenerateDataModeSendTransMsg(); break; default: break; } - igtl::MessageBase::Pointer curMessage = this->GetOutput()->GetMessage(); - if (dynamic_cast(curMessage.GetPointer()) != nullptr) - { - igtl::TrackingDataMessage* tdMsg = - (igtl::TrackingDataMessage*)(curMessage.GetPointer()); - } - } void mitk::NavigationDataToIGTLMessageFilter::SetInput(const NavigationData* nd) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput(0, const_cast(nd)); this->CreateOutputsForAllInputs(); } void mitk::NavigationDataToIGTLMessageFilter::SetInput(unsigned int idx, const NavigationData* nd) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput(idx, const_cast(nd)); this->CreateOutputsForAllInputs(); } const mitk::NavigationData* mitk::NavigationDataToIGTLMessageFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetInput(0)); } const mitk::NavigationData* mitk::NavigationDataToIGTLMessageFilter::GetInput(unsigned int idx) { if (this->GetNumberOfInputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetInput(idx)); } void mitk::NavigationDataToIGTLMessageFilter::CreateOutputsForAllInputs() { switch (m_OperationMode) { case ModeSendQTDataMsg: // create one message output for all navigation data inputs this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); // set the type for this filter this->SetType("QTDATA"); break; case ModeSendTDataMsg: // create one message output for all navigation data inputs this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); // set the type for this filter this->SetType("TDATA"); break; case ModeSendQTransMsg: // create one message output for all navigation data input together this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); // set the type for this filter this->SetType("POSITION"); break; case ModeSendTransMsg: // create one message output for all navigation data input together this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); // set the type for this filter this->SetType("TRANS"); break; default: break; } for (unsigned int idx = 0; idx < this->GetNumberOfIndexedOutputs(); ++idx) { if (this->GetOutput(idx) == nullptr) { DataObjectPointer newOutput = this->MakeOutput(idx); this->SetNthOutput(idx, newOutput); } this->Modified(); } } void ConvertAffineTransformationIntoIGTLMatrix(mitk::AffineTransform3D* trans, igtl::Matrix4x4 igtlTransform) { const mitk::AffineTransform3D::MatrixType& matrix = trans->GetMatrix(); mitk::Vector3D position = trans->GetOffset(); //copy the data into a matrix type that igtl understands for (unsigned int r = 0; r < 3; r++) { for (unsigned int c = 0; c < 3; c++) { igtlTransform[r][c] = matrix(r, c); } igtlTransform[r][3] = position[r]; } for (unsigned int c = 0; c < 3; c++) { igtlTransform[3][c] = 0.0; } igtlTransform[3][3] = 1.0; } void mitk::NavigationDataToIGTLMessageFilter::GenerateDataModeSendQTransMsg() { // for each output message - for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); ++i) + for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); ++i) { mitk::IGTLMessage* output = this->GetOutput(i); assert(output); const mitk::NavigationData* input = this->GetInput(i); assert(input); // do not add navigation data to message if input is invalid if (input->IsDataValid() == false) continue; //get the navigation data components mitk::NavigationData::PositionType pos = input->GetPosition(); mitk::NavigationData::OrientationType ori = input->GetOrientation(); //insert this information into the message igtl::PositionMessage::Pointer posMsg = igtl::PositionMessage::New(); posMsg->SetPosition(pos[0], pos[1], pos[2]); posMsg->SetQuaternion(ori[0], ori[1], ori[2], ori[3]); - igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); - timestamp->SetTime(input->GetTimeStamp().GetMTime() / 1000, input->GetTimeStamp().GetMTime() % 1000); + igtl::TimeStamp::Pointer timestamp = ConvertToIGTLTimeStamp(input->GetIGTTimeStamp()); posMsg->SetTimeStamp(timestamp); posMsg->SetDeviceName(input->GetName()); posMsg->Pack(); //add the igtl message to the mitk::IGTLMessage output->SetMessage(posMsg.GetPointer()); } } void mitk::NavigationDataToIGTLMessageFilter::GenerateDataModeSendTransMsg() { // for each output message - for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); ++i) + for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); ++i) { mitk::IGTLMessage* output = this->GetOutput(i); assert(output); const mitk::NavigationData* input = this->GetInput(i); assert(input); // do not add navigation data to message if input is invalid if (input->IsDataValid() == false) continue; //get the navigation data components mitk::AffineTransform3D::Pointer transform = input->GetAffineTransform3D(); mitk::NavigationData::PositionType position = transform->GetOffset(); //convert the transform into a igtl type igtl::Matrix4x4 igtlTransform; ConvertAffineTransformationIntoIGTLMatrix(transform, igtlTransform); //insert this information into the message igtl::TransformMessage::Pointer transMsg = igtl::TransformMessage::New(); transMsg->SetMatrix(igtlTransform); transMsg->SetPosition(position[0], position[1], position[2]); - igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); - timestamp->SetTime(input->GetTimeStamp().GetMTime() / 1000, input->GetTimeStamp().GetMTime() % 1000); + igtl::TimeStamp::Pointer timestamp = ConvertToIGTLTimeStamp(input->GetIGTTimeStamp()); transMsg->SetTimeStamp(timestamp); transMsg->SetDeviceName(input->GetName()); transMsg->Pack(); //add the igtl message to the mitk::IGTLMessage output->SetMessage(transMsg.GetPointer()); } } +igtl::TimeStamp::Pointer mitk::NavigationDataToIGTLMessageFilter::ConvertToIGTLTimeStamp(double IGTTimeStamp) +{ + igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); + timestamp->SetTime(IGTTimeStamp / 1000, (int)(IGTTimeStamp) % 1000); + return timestamp; +} void mitk::NavigationDataToIGTLMessageFilter::GenerateDataModeSendQTDataMsg() { mitk::IGTLMessage* output = this->GetOutput(); assert(output); //create a output igtl message igtl::QuaternionTrackingDataMessage::Pointer qtdMsg = igtl::QuaternionTrackingDataMessage::New(); mitk::NavigationData::PositionType pos; mitk::NavigationData::OrientationType ori; for (unsigned int index = 0; index < this->GetNumberOfIndexedInputs(); index++) { const mitk::NavigationData* nd = GetInput(index); assert(nd); //get the navigation data components pos = nd->GetPosition(); ori = nd->GetOrientation(); //insert the information into the tracking element igtl::QuaternionTrackingDataElement::Pointer tde = igtl::QuaternionTrackingDataElement::New(); tde->SetPosition(pos[0], pos[1], pos[2]); tde->SetQuaternion(ori[0], ori[1], ori[2], ori[3]); tde->SetName(nd->GetName()); //insert this element into the tracking data message qtdMsg->AddQuaternionTrackingDataElement(tde); - //copy the time stamp - //todo find a better way to do that - igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); - timestamp->SetTime(nd->GetTimeStamp().GetMTime() / 1000, nd->GetTimeStamp().GetMTime() % 1000); - MITK_INFO << timestamp; + MITK_INFO << ConvertToIGTLTimeStamp(nd->GetIGTTimeStamp()); } qtdMsg->Pack(); //add the igtl message to the mitk::IGTLMessage output->SetMessage(qtdMsg.GetPointer()); } void mitk::NavigationDataToIGTLMessageFilter::GenerateDataModeSendTDataMsg() { bool isValidData = true; mitk::IGTLMessage* output = this->GetOutput(); assert(output); //create a output igtl message igtl::TrackingDataMessage::Pointer tdMsg = igtl::TrackingDataMessage::New(); mitk::AffineTransform3D::Pointer transform; Vector3D position; igtl::Matrix4x4 igtlTransform; vnl_matrix_fixed rotationMatrix; vnl_matrix_fixed rotationMatrixTransposed; for (unsigned int index = 0; index < this->GetNumberOfIndexedInputs(); index++) { const mitk::NavigationData* nd = GetInput(index); assert(nd); //create a new tracking element igtl::TrackingDataElement::Pointer tde = igtl::TrackingDataElement::New(); //get the navigation data components transform = nd->GetAffineTransform3D(); position = transform->GetOffset(); //check the rotation matrix rotationMatrix = transform->GetMatrix().GetVnlMatrix(); rotationMatrixTransposed = rotationMatrix.transpose(); // a quadratic matrix is a rotation matrix exactly when determinant is 1 // and transposed is inverse if (!Equal(1.0, vnl_det(rotationMatrix), 0.1) || !((rotationMatrix*rotationMatrixTransposed).is_identity(0.1))) { //the rotation matrix is not valid! => invalidate the current element isValidData = false; } //convert the transform into a igtl type ConvertAffineTransformationIntoIGTLMatrix(transform, igtlTransform); //fill the tracking element with life tde->SetMatrix(igtlTransform); tde->SetPosition(position[0], position[1], position[2]); std::stringstream name; name << nd->GetName(); if (name.rdbuf()->in_avail() == 0) { name << "TrackingTool" << index; } tde->SetName(name.str().c_str()); //insert this element into the tracking data message tdMsg->AddTrackingDataElement(tde); //copy the time stamp - //todo find a better way to do that - igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); - timestamp->SetTime(nd->GetTimeStamp().GetMTime() / 1000, nd->GetTimeStamp().GetMTime() % 1000); + igtl::TimeStamp::Pointer timestamp = ConvertToIGTLTimeStamp(nd->GetIGTTimeStamp()); tdMsg->SetTimeStamp(timestamp); - } tdMsg->Pack(); //add the igtl message to the mitk::IGTLMessage output->SetMessage(tdMsg.GetPointer()); output->SetDataValid(isValidData); } void mitk::NavigationDataToIGTLMessageFilter::SetOperationMode(OperationMode mode) { m_OperationMode = mode; this->Modified(); - this->CreateOutputsForAllInputs(); } void mitk::NavigationDataToIGTLMessageFilter::ConnectTo( mitk::NavigationDataSource* UpstreamFilter) { for (DataObjectPointerArraySizeType i = 0; i < UpstreamFilter->GetNumberOfOutputs(); i++) { this->SetInput(i, UpstreamFilter->GetOutput(i)); } } diff --git a/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.h b/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.h index 799900d30d..a92dd036b5 100644 --- a/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.h +++ b/Modules/IGT/Algorithms/mitkNavigationDataToIGTLMessageFilter.h @@ -1,170 +1,173 @@ /*=================================================================== 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 _MITKNAVIGATIONDATATOIGTLMessageFILTER_H__ #define _MITKNAVIGATIONDATATOIGTLMessageFILTER_H__ #include "mitkCommon.h" #include "mitkPointSet.h" #include "mitkIGTLMessageSource.h" #include "mitkNavigationData.h" #include "mitkNavigationDataSource.h" namespace mitk { /**Documentation * * \brief This filter creates IGTL messages from mitk::NavigaitionData objects * * * \ingroup IGT * */ class MITKIGT_EXPORT NavigationDataToIGTLMessageFilter : public IGTLMessageSource { public: mitkClassMacro(NavigationDataToIGTLMessageFilter, IGTLMessageSource); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /**Documentation * \brief There are four different operation modes. * * - ModeSendQTransMsg: every input NavigationData is processed into one * output message that contains a position and a orientation (quaternion). * - ModeSendTransMsg: every input NavigationData is processed into one * output message that contains a 4x4 transformation. * - ModeSendQTDataMsg:all input NavigationData is processed into one single * output message that contains a position and orientation (quaternion) for * each navigation data. * - ModeSendTDataMsg:all input NavigationData is processed into one single * output message that contains a 4x4 transformation for * each navigation data. */ enum OperationMode { ModeSendQTransMsg, ModeSendTransMsg, ModeSendQTDataMsg, ModeSendTDataMsg }; /** * \brief filter execute method */ virtual void GenerateData() override; using Superclass::SetInput; /** * \brief Sets one input NavigationData */ virtual void SetInput(const mitk::NavigationData *NavigationData); /** * \brief Sets the input NavigationData at a specific index */ virtual void SetInput(unsigned int idx, const NavigationData* nd); /** * \brief Returns the input of this filter */ const mitk::NavigationData* GetInput(); /** * \brief Returns the input number idx of this filter */ const mitk::NavigationData* GetInput(unsigned int idx); /** * \brief Sets the mode of this filter. * * See OperationMode for the behavior in the different modes * \warn A call to this method will change the number of outputs of the filter. * After calling this method, all previously acquired pointers to outputs are invalid * Always set the operation mode first, then get the outputs with GetOutput() */ virtual void SetOperationMode(OperationMode mode); /** * \brief returns the mode of this filter. * * See OperationMode for the behavior in the different modes */ itkGetConstMacro(OperationMode, OperationMode); /** * empty implementation to prevent calling of the superclass method that * would try to copy information from the input NavigationData to the output * PointSet, which makes no sense! */ void GenerateOutputInformation() override {}; /** *\brief Connects the input of this filter to the outputs of the given * NavigationDataSource * * This method does not support smartpointer. use FilterX.GetPointer() to * retrieve a dumbpointer. */ virtual void ConnectTo(mitk::NavigationDataSource * UpstreamFilter); protected: NavigationDataToIGTLMessageFilter(); virtual ~NavigationDataToIGTLMessageFilter(); /** * \brief Generates the output * */ // virtual void GenerateData(); /** * \brief Generates the output for ModeSendQTDataMsg * */ virtual void GenerateDataModeSendQTDataMsg(); /** * \brief Generates the output for ModeSendTDataMsg */ virtual void GenerateDataModeSendTDataMsg(); /** * \brief Generates the output for ModeSendQTransMsg * */ virtual void GenerateDataModeSendQTransMsg(); /** * \brief Generates the output for ModeSendTransMsg */ virtual void GenerateDataModeSendTransMsg(); /** * \brief create output objects according to OperationMode for all inputs */ virtual void CreateOutputsForAllInputs(); OperationMode m_OperationMode; ///< Stores the mode. See enum OperationMode // unsigned int m_RingBufferSize; ///< Stores the ringbuffer size unsigned int m_CurrentTimeStep; ///< Indicates the current timestamp // unsigned int m_NumberForMean; ///< Number of Navigation Data, which should be averaged + /** Converts a mitk::IGTTimestamp (double, milliseconds) to an OpenIGTLink timestamp */ + igtl::TimeStamp::Pointer ConvertToIGTLTimeStamp(double IGTTimeStamp); + /** Measurement class to calculate latency and frame count */ }; } // namespace mitk #endif // _MITKNAVIGATIONDATATOIGTLMessageFILTER_H__ diff --git a/Modules/IGT/DataManagement/mitkNavigationTool.cpp b/Modules/IGT/DataManagement/mitkNavigationTool.cpp index ffa6c92c34..02e48810a0 100644 --- a/Modules/IGT/DataManagement/mitkNavigationTool.cpp +++ b/Modules/IGT/DataManagement/mitkNavigationTool.cpp @@ -1,129 +1,134 @@ /*=================================================================== 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 "mitkNavigationTool.h" #include "mitkIGTException.h" #include "mitkNavigationData.h" #include "Poco/File.h" #include "mitkUnspecifiedTrackingTypeInformation.h" mitk::NavigationTool::NavigationTool() : m_Identifier("None"), m_Type(mitk::NavigationTool::Unknown), m_CalibrationFile("none"), m_SerialNumber(""), m_TrackingDeviceType(mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName()), m_ToolRegistrationLandmarks(mitk::PointSet::New()), m_ToolCalibrationLandmarks(mitk::PointSet::New()), m_ToolTipOrientation(mitk::Quaternion(0,0,0,1)) { m_ToolTipPosition[0] = 0; m_ToolTipPosition[1] = 0; m_ToolTipPosition[2] = 0; + + m_ToolAxis[0] = 1; + m_ToolAxis[1] = 0; + m_ToolAxis[2] = 0; } mitk::NavigationTool::~NavigationTool() { } mitk::AffineTransform3D::Pointer mitk::NavigationTool::GetToolTipTransform() { mitk::NavigationData::Pointer returnValue = mitk::NavigationData::New(); returnValue->SetPosition(this->m_ToolTipPosition); returnValue->SetOrientation(this->m_ToolTipOrientation); return returnValue->GetAffineTransform3D(); } void mitk::NavigationTool::Graft( const DataObject *data ) { // Attempt to cast data to an NavigationData const Self* nd; try { nd = dynamic_cast( data ); } catch( ... ) { mitkThrowException(mitk::IGTException) << "mitk::NavigationData::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ; } if (!nd) { // pointer could not be cast back down mitkThrowException(mitk::IGTException) << "mitk::NavigationData::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ; } // Now copy anything that is needed m_Identifier = nd->GetIdentifier(); m_Type = nd->GetType(); m_DataNode->SetName(nd->GetDataNode()->GetName()); m_DataNode->SetData(nd->GetDataNode()->GetData()); m_SpatialObject = nd->GetSpatialObject(); m_TrackingTool = nd->GetTrackingTool(); m_CalibrationFile = nd->GetCalibrationFile(); m_SerialNumber = nd->GetSerialNumber(); m_TrackingDeviceType = nd->GetTrackingDeviceType(); m_ToolRegistrationLandmarks = nd->GetToolRegistrationLandmarks(); m_ToolCalibrationLandmarks = nd->GetToolCalibrationLandmarks(); m_ToolTipPosition = nd->GetToolTipPosition(); m_ToolTipOrientation = nd->GetToolTipOrientation(); + m_ToolAxis = nd->GetToolAxis(); } bool mitk::NavigationTool::IsToolTipSet() { if( (m_ToolTipPosition[0] == 0) && (m_ToolTipPosition[1] == 0) && (m_ToolTipPosition[2] == 0) && (m_ToolTipOrientation.x() == 0) && (m_ToolTipOrientation.y() == 0) && (m_ToolTipOrientation.z() == 0) && (m_ToolTipOrientation.r() == 1)) return false; else return true; } void mitk::NavigationTool::SetCalibrationFile(const std::string filename) { //check if file does exist: if (filename=="") { m_CalibrationFile = "none"; } else { Poco::File myFile(filename); if (myFile.exists()) m_CalibrationFile = filename; else m_CalibrationFile = "none"; } } std::string mitk::NavigationTool::GetToolName() { if (this->m_DataNode.IsNull()) {return "";} else {return m_DataNode->GetName();} } mitk::Surface::Pointer mitk::NavigationTool::GetToolSurface() { if (this->m_DataNode.IsNull()) {return nullptr;} else if (this->m_DataNode->GetData() == nullptr) {return nullptr;} else {return dynamic_cast(m_DataNode->GetData());} } diff --git a/Modules/IGT/DataManagement/mitkNavigationTool.h b/Modules/IGT/DataManagement/mitkNavigationTool.h index b5cbad784a..04ce577314 100644 --- a/Modules/IGT/DataManagement/mitkNavigationTool.h +++ b/Modules/IGT/DataManagement/mitkNavigationTool.h @@ -1,197 +1,206 @@ /*=================================================================== 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 NAVIGATIONTOOL_H_INCLUDED #define NAVIGATIONTOOL_H_INCLUDED //itk headers #include #include #include //mitk headers #include #include #include #include #include #include #include namespace mitk { /**Documentation * \brief An object of this class represents a navigation tool in the view of the software. * A few informations like an identifier, a toolname, a surface and a itk spatial * object are stored in such an object. The classes NavigationToolReader and * are availiable to write/read tools to/from the harddisc. If you need a collection * of navigation tools the class NavigationToolStorage could be used. * * \ingroup IGT */ class MITKIGT_EXPORT NavigationTool : public itk::DataObject { public: mitkClassMacroItkParent(NavigationTool,itk::DataObject); itkFactorylessNewMacro(Self) itkCloneMacro(Self) enum NavigationToolType {Instrument, Fiducial, Skinmarker, Unknown}; //## getter and setter ## //NavigationToolType: itkGetConstMacro(Type,NavigationToolType); itkSetMacro(Type,NavigationToolType); //Identifier: itkGetConstMacro(Identifier,std::string); itkSetMacro(Identifier,std::string); //Datatreenode: itkGetConstMacro(DataNode,mitk::DataNode::Pointer); itkSetMacro(DataNode,mitk::DataNode::Pointer); //SpatialObject: itkGetConstMacro(SpatialObject,itk::SpatialObject<3>::Pointer); itkSetMacro(SpatialObject,itk::SpatialObject<3>::Pointer); //TrackingTool: itkGetConstMacro(TrackingTool,mitk::TrackingTool::Pointer); itkSetMacro(TrackingTool,mitk::TrackingTool::Pointer); //CalibrationFile: itkGetConstMacro(CalibrationFile,std::string); void SetCalibrationFile(const std::string filename); //Tool tip definition: itkGetConstMacro(ToolTipPosition,mitk::Point3D); itkSetMacro(ToolTipPosition,mitk::Point3D); itkGetConstMacro(ToolTipOrientation,mitk::Quaternion); itkSetMacro(ToolTipOrientation,mitk::Quaternion); + //Tool Axis definition: + //default tool axis is along x axis, the tool axis must be normalized + itkGetConstMacro(ToolAxis, mitk::Point3D); + itkSetMacro(ToolAxis, mitk::Point3D); + + /** @return Returns the tooltip as transform object. */ mitk::AffineTransform3D::Pointer GetToolTipTransform(); /** @return Returns true if a tooltip is set, false if not. */ bool IsToolTipSet(); //Tool Landmarks: /** For overview, here are descriptons of the two types of tool landmarks: * * tool calibration landmarks: These landmarks may be used clearly define the tools pose only by * using landmarks in the tool coordinate system. E.g., two landmarks for a 5DoF tool and three * landmarks for a 6DoF tool. These landmarks may be used, e.g., for a point based registration * of a tool from image space to tracking space. * * tool registration landmarks: These landmarks are designed for representing defined landmarks * on a tools surface. The number of these landmarks might exeed the number of tool calibration * landmarks for reasons of redundancy and averaging. They are used for, e.g., manually registering * the pose of a tool by visual markers in a CT scan. If you would use these landmarks to do a * point based registration from image space to tracking space later, you might overweight the * tool because of two many landmarks compared to other markers. * * @return Returns the tool registration landmarks which represent markers / special points on a * tool that can be used for registration. The landmarks should be given in tool coordinates. * If there are no landmarks defined for this tool the method returns an empty point set. */ itkGetConstMacro(ToolRegistrationLandmarks,mitk::PointSet::Pointer); /** @brief Sets the tool registration landmarks which represent markers / special points on a * tool that can be used for registration. The landmarks should be given in tool coordinates. */ itkSetMacro(ToolRegistrationLandmarks,mitk::PointSet::Pointer); /** @return Returns the tool calibration landmarks for calibration of the defined points in the * tool coordinate system, e.g. 2 landmarks for a 5DoF tool and 3 landmarks for a 6DoF tool. */ itkGetConstMacro(ToolCalibrationLandmarks,mitk::PointSet::Pointer); /** @brief Sets the tool calibration landmarks for calibration of defined points in the * tool coordinate system, e.g. 2 landmarks for a 5DoF tool and 3 landmarks for a 6DoF tool. */ itkSetMacro(ToolCalibrationLandmarks,mitk::PointSet::Pointer); //SerialNumber: itkGetConstMacro(SerialNumber,std::string); itkSetMacro(SerialNumber,std::string); //TrackingDeviceType: itkGetConstMacro(TrackingDeviceType,mitk::TrackingDeviceType); itkSetMacro(TrackingDeviceType,mitk::TrackingDeviceType); //ToolName (only getter): /** @return Returns the name of this navigation tool. Returns an empty string if there is * no name (for example because the data node has not been set yet). * * Note: There is no setter for the name, * because the name of the corresponding data node is used as tool name. So if you * want to modify the name of this navigation tool only get the data node and modify * its name. */ std::string GetToolName(); //ToolSurface (only getter): /** @return Returns the surface of this navigation tool. Returns nullptr if there is * no surface (for example because the data node has not been set yet). * * Note: There is no setter for the surface, * because the surface is the data of the corresponding data node. So if you * want to set a new surface only get the data node and modify its data. */ mitk::Surface::Pointer GetToolSurface(); /** * \brief Graft the data and information from one NavigationTool to another. * * Copies the content of data into this object. * This is a convenience method to setup a second NavigationTool object with all the meta * information of another NavigationTool object. * Note that this method is different than just using two * SmartPointers to the same NavigationTool object since separate DataObjects are * still maintained. */ virtual void Graft(const DataObject *data) override; //####################### protected: NavigationTool(); ~NavigationTool(); //## data structure of a navigation tool object ## std::string m_Identifier; NavigationToolType m_Type; /** @brief This DataNode holds a toolname and a tool surface */ mitk::DataNode::Pointer m_DataNode; /** @brief This member variable holds a mathamatical description of the tool */ itk::SpatialObject<3>::Pointer m_SpatialObject; /** @brief This member variable holds a pointer to the corresponding tracking tool in the hardware. */ mitk::TrackingTool::Pointer m_TrackingTool; /** @brief The path to the calibration file of the tool. */ std::string m_CalibrationFile; /** @brief A unique serial number of the tool which is needed to identify the tool correctly. This is very important * in case of the NDI Aurora System. */ std::string m_SerialNumber; /** @brief This member holds the tracking device type of the tool. */ mitk::TrackingDeviceType m_TrackingDeviceType; /** @brief Holds landmarks for tool registration. */ mitk::PointSet::Pointer m_ToolRegistrationLandmarks; /** @brief Holds landmarks for calibration of the defined points in the tool coordinate system, * e.g. 2 landmarks for a 5DoF tool and 3 landmarks for a 6DoF tool. */ mitk::PointSet::Pointer m_ToolCalibrationLandmarks; /** @brief Holds the position of the tool tip. */ mitk::Point3D m_ToolTipPosition; /** @brief Holds the orientation of the tool tip. */ mitk::Quaternion m_ToolTipOrientation; + + /** @brief Holds the axis of the tool. */ + mitk::Point3D m_ToolAxis; //################################################# }; } // namespace mitk #endif //NAVIGATIONTOOL diff --git a/Modules/IGT/IO/mitkNavigationDataRecorder.cpp b/Modules/IGT/IO/mitkNavigationDataRecorder.cpp index fa2a457668..96c27d6db2 100644 --- a/Modules/IGT/IO/mitkNavigationDataRecorder.cpp +++ b/Modules/IGT/IO/mitkNavigationDataRecorder.cpp @@ -1,116 +1,125 @@ /*=================================================================== 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 "mitkNavigationDataRecorder.h" #include mitk::NavigationDataRecorder::NavigationDataRecorder() { //set default values m_NumberOfInputs = 0; m_Recording = false; m_StandardizedTimeInitialized = false; m_RecordCountLimit = -1; + m_RecordOnlyValidData = false; } mitk::NavigationDataRecorder::~NavigationDataRecorder() { //mitk::IGTTimeStamp::GetInstance()->Stop(this); //commented out because of bug 18952 } void mitk::NavigationDataRecorder::GenerateData() { // get each input, lookup the associated BaseData and transfer the data DataObjectPointerArray inputs = this->GetIndexedInputs(); //get all inputs //This vector will hold the NavigationDatas that are copied from the inputs std::vector< mitk::NavigationData::Pointer > clonedDatas; + bool atLeastOneInputIsInvalid = false; + // For each input for (unsigned int index=0; index < inputs.size(); index++) { // First copy input to output this->GetOutput(index)->Graft(this->GetInput(index)); // if we are not recording, that's all there is to do if (! m_Recording) continue; + if (atLeastOneInputIsInvalid || !this->GetInput(index)->IsDataValid()) + { + atLeastOneInputIsInvalid = true; + } + // Clone a Navigation Data mitk::NavigationData::Pointer clone = mitk::NavigationData::New(); clone->Graft(this->GetInput(index)); clonedDatas.push_back(clone); if (m_StandardizeTime) { mitk::NavigationData::TimeStampType igtTimestamp = mitk::IGTTimeStamp::GetInstance()->GetElapsed(this); clonedDatas[index]->SetIGTTimeStamp(igtTimestamp); } } // if limitation is set and has been reached, stop recording if ((m_RecordCountLimit > 0) && (m_NavigationDataSet->Size() >= static_cast(m_RecordCountLimit))) m_Recording = false; // We can skip the rest of the method, if recording is deactivated - if (!m_Recording) - return; - + if (!m_Recording) return; + // We can skip the rest of the method, if we read only valid data + if (m_RecordOnlyValidData && atLeastOneInputIsInvalid) return; + // Add data to set m_NavigationDataSet->AddNavigationDatas(clonedDatas); } void mitk::NavigationDataRecorder::StartRecording() { if (m_Recording) { MITK_WARN << "Already recording please stop before start new recording session"; return; } m_Recording = true; // The first time this StartRecording is called, we initialize the standardized time. // Afterwards, it can be reset via ResetNavigationDataSet(); if (! m_StandardizedTimeInitialized) mitk::IGTTimeStamp::GetInstance()->Start(this); if (m_NavigationDataSet.IsNull()) m_NavigationDataSet = mitk::NavigationDataSet::New(GetNumberOfIndexedInputs()); } void mitk::NavigationDataRecorder::StopRecording() { if (!m_Recording) { std::cout << "You have to start a recording first" << std::endl; return; } m_Recording = false; } void mitk::NavigationDataRecorder::ResetRecording() { m_NavigationDataSet = mitk::NavigationDataSet::New(GetNumberOfIndexedInputs()); if (m_Recording) { mitk::IGTTimeStamp::GetInstance()->Stop(this); mitk::IGTTimeStamp::GetInstance()->Start(this); } } int mitk::NavigationDataRecorder::GetNumberOfRecordedSteps() { return m_NavigationDataSet->Size(); } \ No newline at end of file diff --git a/Modules/IGT/IO/mitkNavigationDataRecorder.h b/Modules/IGT/IO/mitkNavigationDataRecorder.h index 4353d493d3..3ab694c634 100644 --- a/Modules/IGT/IO/mitkNavigationDataRecorder.h +++ b/Modules/IGT/IO/mitkNavigationDataRecorder.h @@ -1,120 +1,133 @@ /*=================================================================== 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 _MITK_NavigationDataRecorder_H #define _MITK_NavigationDataRecorder_H #include "mitkNavigationDataToNavigationDataFilter.h" #include "mitkNavigationData.h" #include "mitkNavigationDataSet.h" namespace mitk { /**Documentation * \brief This class records NavigationData objects into NavigationDataSets. * * The recording is started with the call of the method StartRecording(). Now * every Update() stores the current state of the added NavigationDatas into the NavigationDataSet. * With StopRecording() the stream is stopped, but can be resumed anytime. * To start recording to a new NavigationDataSet, call ResetRecording(); * * \warning Do not add inputs while the recorder ist recording. The recorder can't handle that and will cause a nullpointer exception. * \ingroup IGT */ class MITKIGT_EXPORT NavigationDataRecorder : public NavigationDataToNavigationDataFilter { public: mitkClassMacro( NavigationDataRecorder, NavigationDataToNavigationDataFilter ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** * \brief Returns whether the NavigationDataRecorder is currently recording or not */ itkGetMacro(Recording, bool); /** * \brief Returns the set that contains all of the recorded data. */ itkGetMacro(NavigationDataSet, mitk::NavigationDataSet::Pointer); /** * \brief Sets a limit of recorded data sets / frames. Recording will be stopped if the number is reached. values < 1 disable this behaviour. Default is -1. */ itkSetMacro(RecordCountLimit, int); /** * \brief Returns whether to use the navigationdata's time stamp or to create a new one upon recording. */ itkGetMacro(StandardizeTime, bool); /** * \brief If set to false, the navigationDatas Timestamp will be used. If set to false, the recorder * will generate a timestamp when it copies the data to the navigationdataset. */ itkSetMacro(StandardizeTime, bool); + /** + * \brief If set to false, invalid navigationDatas will also be used. If set to true, the recorder + * will record only valid data. Standard is false. + */ + itkSetMacro(RecordOnlyValidData, bool); + + /** + * \brief Returns whether to use valid data only. + */ + itkGetMacro(RecordOnlyValidData, bool); + /** * \brief Starts recording NavigationData into the NAvigationDataSet */ virtual void StartRecording(); /** * \brief Stops StopsRecording to the NavigationDataSet. * * Recording can be resumed to the same Dataset by just calling StartRecording() again. * Call ResetRecording() to start recording to a new Dataset; */ virtual void StopRecording(); /** * \brief Resets the Datasets and the timestamp, so a new recording can happen. * * Do not forget to save the old Dataset, it will be lost after calling this function. */ virtual void ResetRecording(); /** * \brief Returns the number of time steps that were recorded in the current set. * Warning: This Method does NOT Stop Recording! */ virtual int GetNumberOfRecordedSteps(); protected: virtual void GenerateData() override; NavigationDataRecorder(); virtual ~NavigationDataRecorder(); unsigned int m_NumberOfInputs; ///< counts the numbers of added input NavigationDatas mitk::NavigationDataSet::Pointer m_NavigationDataSet; bool m_Recording; ///< indicates whether the recording is started or not bool m_StandardizeTime; //< indicates whether one should use the timestamps in NavigationData or create new timestamps upon recording bool m_StandardizedTimeInitialized; //< set to true the first time start recording is called. int m_RecordCountLimit; ///< limits the number of frames, recording will be stopped if the limit is reached. -1 disables the limit + + bool m_RecordOnlyValidData; //< indicates whether only valid data is recorded }; } #endif // #define _MITK_POINT_SET_SOURCE_H diff --git a/Modules/IGT/IO/mitkNavigationToolReader.cpp b/Modules/IGT/IO/mitkNavigationToolReader.cpp index 347a436428..2d35a82652 100644 --- a/Modules/IGT/IO/mitkNavigationToolReader.cpp +++ b/Modules/IGT/IO/mitkNavigationToolReader.cpp @@ -1,267 +1,272 @@ /*=================================================================== 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. ===================================================================*/ //Poco headers #include #include //mitk headers #include "mitkNavigationToolReader.h" #include "mitkTrackingTypes.h" #include #include //All Tracking devices, which should be available by default #include "mitkNDIAuroraTypeInformation.h" #include "mitkNDIPolarisTypeInformation.h" #include "mitkVirtualTrackerTypeInformation.h" #include "mitkMicronTrackerTypeInformation.h" #include "mitkNPOptitrackTrackingTypeInformation.h" #include "mitkOpenIGTLinkTypeInformation.h" #include "mitkUnspecifiedTrackingTypeInformation.h" mitk::NavigationToolReader::NavigationToolReader() { m_ToolfilePath = mitk::IOUtil::GetTempPath() + Poco::Path::separator() + "IGT_Toolfiles" + Poco::Path::separator(); } mitk::NavigationToolReader::~NavigationToolReader() { } mitk::NavigationTool::Pointer mitk::NavigationToolReader::DoRead(std::string filename) { //decompress all files into a temporary directory std::ifstream file(filename.c_str(), std::ios::binary); if (!file.good()) { m_ErrorMessage = "Cannot open '" + filename + "' for reading"; return nullptr; } std::string tempDirectory = m_ToolfilePath + GetFileWithoutPath(filename); Poco::Zip::Decompress unzipper(file, Poco::Path(tempDirectory)); unzipper.decompressAllFiles(); //use SceneSerialization to load the DataStorage mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New(); mitk::DataStorage::Pointer loadedStorage = mySceneIO->LoadScene(tempDirectory + Poco::Path::separator() + GetFileWithoutPath(filename) + ".storage"); if (loadedStorage->GetAll()->size() == 0 || loadedStorage.IsNull()) { m_ErrorMessage = "Invalid file: cannot parse tool data."; return nullptr; } //convert the DataStorage back to a NavigationTool-Object mitk::DataNode::Pointer myNode = loadedStorage->GetAll()->ElementAt(0); mitk::NavigationTool::Pointer returnValue = ConvertDataNodeToNavigationTool(myNode, tempDirectory); //delete the data-storage file which is not needed any more. The toolfile must be left in the temporary directory becauses it is linked in the datatreenode of the tool std::remove((std::string(tempDirectory + Poco::Path::separator() + GetFileWithoutPath(filename) + ".storage")).c_str()); return returnValue; } mitk::NavigationTool::Pointer mitk::NavigationToolReader::ConvertDataNodeToNavigationTool(mitk::DataNode::Pointer node, std::string toolPath) { mitk::NavigationTool::Pointer returnValue = mitk::NavigationTool::New(); //DateTreeNode with Name and Surface mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(node->GetName()); newNode->SetData(node->GetData()); bool visible = true; node->GetVisibility(visible, NULL); newNode->SetVisibility(visible); returnValue->SetDataNode(newNode); //Identifier std::string identifier; node->GetStringProperty("identifier", identifier); returnValue->SetIdentifier(identifier); //Serial Number std::string serial; node->GetStringProperty("serial number", serial); returnValue->SetSerialNumber(serial); //Tracking Device mitk::TrackingDeviceType device_type; node->GetStringProperty("tracking device type", device_type); //For backward compability with old tool stroages (before 12/2015 device_type was an int value, now it is string) if (device_type.size() == 0) { /* This was the old enum. Numbers inserted for better readibility. Don't delete this if-case to allow loading of ols storages... enum TrackingDeviceType { 0 NDIPolaris, ///< Polaris: optical Tracker from NDI 1 NDIAurora, ///< Aurora: electromagnetic Tracker from NDI 2 ClaronMicron, ///< Micron Tracker: optical Tracker from Claron 3 IntuitiveDaVinci, ///< Intuitive Surgical: DaVinci Telemanipulator API Interface 4 AscensionMicroBird, ///< Ascension microBird / PCIBird family 5 VirtualTracker, ///< Virtual Tracking device class that produces random tracking coordinates 6 TrackingSystemNotSpecified, ///< entry for not specified or initialized tracking system 7 TrackingSystemInvalid, ///< entry for invalid state (mainly for testing) 8 NPOptitrack, ///< NaturalPoint: Optitrack optical Tracking System 9 OpenIGTLinkTrackingDeviceConnection ///< Device which is connected via open igt link }; */ int device_type_old; node->GetIntProperty("tracking device type", device_type_old); switch (device_type_old) { case 0:device_type = mitk::NDIPolarisTypeInformation::GetTrackingDeviceName(); break; case 1:device_type = mitk::NDIAuroraTypeInformation::GetTrackingDeviceName(); break; case 2:device_type = mitk::MicronTrackerTypeInformation::GetTrackingDeviceName(); break; case 3:device_type = "IntuitiveDaVinci"; break; case 4:device_type = "AscensionMicroBird"; break; case 5:device_type = mitk::VirtualTrackerTypeInformation::GetTrackingDeviceName(); break; case 6:device_type = mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); break; case 7:device_type = "TrackingSystemInvalid"; break; case 8:device_type = mitk::NPOptitrackTrackingTypeInformation::GetTrackingDeviceName(); break; case 9:device_type = mitk::OpenIGTLinkTypeInformation::GetTrackingDeviceName(); break; default: device_type = mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); break; //default... unknown... } } returnValue->SetTrackingDeviceType(static_cast(device_type)); //Tool Type int type; node->GetIntProperty("tracking tool type", type); returnValue->SetType(static_cast(type)); //Calibration File Name std::string calibration_filename; node->GetStringProperty("toolfileName", calibration_filename); if (calibration_filename == "none") { returnValue->SetCalibrationFile("none"); } else { std::string calibration_filename_with_path = toolPath + Poco::Path::separator() + calibration_filename; returnValue->SetCalibrationFile(calibration_filename_with_path); } //Tool Landmarks mitk::PointSet::Pointer ToolRegLandmarks = mitk::PointSet::New(); mitk::PointSet::Pointer ToolCalLandmarks = mitk::PointSet::New(); std::string RegLandmarksString; std::string CalLandmarksString; node->GetStringProperty("ToolRegistrationLandmarks", RegLandmarksString); node->GetStringProperty("ToolCalibrationLandmarks", CalLandmarksString); ToolRegLandmarks = ConvertStringToPointSet(RegLandmarksString); ToolCalLandmarks = ConvertStringToPointSet(CalLandmarksString); returnValue->SetToolRegistrationLandmarks(ToolRegLandmarks); returnValue->SetToolCalibrationLandmarks(ToolCalLandmarks); //Tool Tip std::string toolTipPositionString; std::string toolTipOrientationString; bool positionSet = node->GetStringProperty("ToolTipPosition", toolTipPositionString); bool orientationSet = node->GetStringProperty("ToolTipOrientation", toolTipOrientationString); if (positionSet && orientationSet) //only define tooltip if it is set { returnValue->SetToolTipPosition(ConvertStringToPoint(toolTipPositionString)); returnValue->SetToolTipOrientation(ConvertStringToQuaternion(toolTipOrientationString)); } else if (positionSet != orientationSet) { MITK_WARN << "Tooltip definition incomplete: position and orientation have to be set! Skipping tooltip definition."; } + //Tool Axis + std::string ToolAxisString; + node->GetStringProperty("ToolAxis", ToolAxisString); + returnValue->SetToolAxis(ConvertStringToPoint(ToolAxisString)); + return returnValue; } std::string mitk::NavigationToolReader::GetFileWithoutPath(std::string FileWithPath) { Poco::Path myFile(FileWithPath.c_str()); return myFile.getFileName(); } mitk::PointSet::Pointer mitk::NavigationToolReader::ConvertStringToPointSet(std::string string) { mitk::PointSet::Pointer returnValue = mitk::PointSet::New(); std::string pointSeperator = "|"; std::string valueSeperator = ";"; std::vector points; split(string, pointSeperator, points); for (unsigned int i = 0; i < points.size(); i++) { std::vector values; split(points.at(i), valueSeperator, values); if (values.size() == 4) { double index = atof(values.at(0).c_str()); mitk::Point3D point; point[0] = atof(values.at(1).c_str()); point[1] = atof(values.at(2).c_str()); point[2] = atof(values.at(3).c_str()); returnValue->SetPoint(index, point); } } return returnValue; } mitk::Point3D mitk::NavigationToolReader::ConvertStringToPoint(std::string string) { std::string valueSeperator = ";"; std::vector values; split(string, valueSeperator, values); mitk::Point3D point; if (values.size() == 3) { point[0] = atof(values.at(0).c_str()); point[1] = atof(values.at(1).c_str()); point[2] = atof(values.at(2).c_str()); } return point; } mitk::Quaternion mitk::NavigationToolReader::ConvertStringToQuaternion(std::string string) { std::string valueSeperator = ";"; std::vector values; split(string, valueSeperator, values); mitk::Quaternion quat = mitk::Quaternion(0, 0, 0, 1); if (values.size() == 4) { quat = mitk::Quaternion(atof(values.at(0).c_str()), atof(values.at(1).c_str()), atof(values.at(2).c_str()), atof(values.at(3).c_str())); } return quat; } void mitk::NavigationToolReader::split(std::string& text, std::string& separators, std::vector& words) { int n = text.length(); int start, stop; start = text.find_first_not_of(separators); while ((start >= 0) && (start < n)) { stop = text.find_first_of(separators, start); if ((stop < 0) || (stop > n)) stop = n; words.push_back(text.substr(start, stop - start)); start = text.find_first_not_of(separators, stop + 1); } } diff --git a/Modules/IGT/IO/mitkNavigationToolWriter.cpp b/Modules/IGT/IO/mitkNavigationToolWriter.cpp index 25819c8262..b07b333155 100644 --- a/Modules/IGT/IO/mitkNavigationToolWriter.cpp +++ b/Modules/IGT/IO/mitkNavigationToolWriter.cpp @@ -1,176 +1,179 @@ /*=================================================================== 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. ===================================================================*/ //Poco headers #include #include //mitk headers #include "mitkNavigationToolWriter.h" #include #include #include #include #include //std headers #include mitk::NavigationToolWriter::NavigationToolWriter() { } mitk::NavigationToolWriter::~NavigationToolWriter() { } bool mitk::NavigationToolWriter::DoWrite(std::string FileName,mitk::NavigationTool::Pointer Tool) { //some initial validation checks... if ( Tool.IsNull()) { m_ErrorMessage = "Cannot write a navigation tool containing invalid tool data, aborting!"; MITK_ERROR << m_ErrorMessage; return false; } // Workaround for a problem: the geometry might be modified if the tool is tracked. If this // modified geometry is saved the surface representation is moved by this offset. To avoid // this bug, the geometry is set to identity for the saving progress and restored later. mitk::BaseGeometry::Pointer geometryBackup; if ( Tool->GetDataNode().IsNotNull() && (Tool->GetDataNode()->GetData()!=nullptr) && (Tool->GetDataNode()->GetData()->GetGeometry()!=nullptr) ) { geometryBackup = Tool->GetDataNode()->GetData()->GetGeometry()->Clone(); Tool->GetDataNode()->GetData()->GetGeometry()->SetIdentity(); } else {MITK_WARN << "Saving a tool with invalid data node, proceeding but errors might occure!";} //convert whole data to a mitk::DataStorage mitk::StandaloneDataStorage::Pointer saveStorage = mitk::StandaloneDataStorage::New(); mitk::DataNode::Pointer thisTool = ConvertToDataNode(Tool); saveStorage->Add(thisTool); //use SceneSerialization to save the DataStorage std::string DataStorageFileName = mitk::IOUtil::CreateTemporaryDirectory() + Poco::Path::separator() + GetFileWithoutPath(FileName) + ".storage"; mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New(); mySceneIO->SaveScene(saveStorage->GetAll(),saveStorage,DataStorageFileName); //now put the DataStorage and the Toolfile in a ZIP-file std::ofstream file( FileName.c_str(), std::ios::binary | std::ios::out); if (!file.good()) { m_ErrorMessage = "Could not open a zip file for writing: '" + FileName + "'"; MITK_ERROR << m_ErrorMessage; return false; } else { Poco::Zip::Compress zipper( file, true ); zipper.addFile(DataStorageFileName,GetFileWithoutPath(DataStorageFileName)); if (Tool->GetCalibrationFile()!="none") zipper.addFile(Tool->GetCalibrationFile(),GetFileWithoutPath(Tool->GetCalibrationFile())); zipper.close(); } //delete the data storage std::remove(DataStorageFileName.c_str()); //restore original geometry if (geometryBackup.IsNotNull()) {Tool->GetDataNode()->GetData()->SetGeometry(geometryBackup);} return true; } mitk::DataNode::Pointer mitk::NavigationToolWriter::ConvertToDataNode(mitk::NavigationTool::Pointer Tool) { mitk::DataNode::Pointer thisTool = mitk::DataNode::New(); //Name if (Tool->GetDataNode().IsNull()) thisTool->SetName("none"); else thisTool->SetName(Tool->GetDataNode()->GetName().c_str()); //Identifier thisTool->AddProperty("identifier",mitk::StringProperty::New(Tool->GetIdentifier().c_str())); //Serial Number thisTool->AddProperty("serial number",mitk::StringProperty::New(Tool->GetSerialNumber().c_str())); //Tracking Device thisTool->AddProperty("tracking device type",mitk::StringProperty::New(Tool->GetTrackingDeviceType())); //Tool Type thisTool->AddProperty("tracking tool type",mitk::IntProperty::New(Tool->GetType())); //Calibration File Name thisTool->AddProperty("toolfileName",mitk::StringProperty::New(GetFileWithoutPath(Tool->GetCalibrationFile()))); //Surface if (Tool->GetDataNode().IsNotNull()) if (Tool->GetDataNode()->GetData() != NULL) { thisTool->SetData(Tool->GetDataNode()->GetData()); //Visibility bool visible = true; Tool->GetDataNode()->GetVisibility(visible, NULL); thisTool->SetVisibility(visible); } //Tool Landmarks thisTool->AddProperty("ToolRegistrationLandmarks",mitk::StringProperty::New(ConvertPointSetToString(Tool->GetToolRegistrationLandmarks()))); thisTool->AddProperty("ToolCalibrationLandmarks",mitk::StringProperty::New(ConvertPointSetToString(Tool->GetToolCalibrationLandmarks()))); //Tool Tip if (Tool->IsToolTipSet()) { thisTool->AddProperty("ToolTipPosition",mitk::StringProperty::New(ConvertPointToString(Tool->GetToolTipPosition()))); thisTool->AddProperty("ToolTipOrientation",mitk::StringProperty::New(ConvertQuaternionToString(Tool->GetToolTipOrientation()))); } + //Tool Axis + thisTool->AddProperty("ToolAxis", mitk::StringProperty::New(ConvertPointToString(Tool->GetToolAxis()))); + //Material is not needed, to avoid errors in scene serialization we have to do this: thisTool->ReplaceProperty("material",nullptr); return thisTool; } std::string mitk::NavigationToolWriter::GetFileWithoutPath(std::string FileWithPath) { Poco::Path myFile(FileWithPath.c_str()); return myFile.getFileName(); } std::string mitk::NavigationToolWriter::ConvertPointSetToString(mitk::PointSet::Pointer pointSet) { std::stringstream returnValue; mitk::PointSet::PointDataIterator it; for ( it = pointSet->GetPointSet()->GetPointData()->Begin();it != pointSet->GetPointSet()->GetPointData()->End();it++ ) { mitk::Point3D thisPoint = pointSet->GetPoint(it->Index()); returnValue << it->Index() << ";" << ConvertPointToString(thisPoint) << "|"; } return returnValue.str(); } std::string mitk::NavigationToolWriter::ConvertPointToString(mitk::Point3D point) { std::stringstream returnValue; returnValue << point[0] << ";" << point[1] << ";" << point[2]; return returnValue.str(); } std::string mitk::NavigationToolWriter::ConvertQuaternionToString(mitk::Quaternion quat) { std::stringstream returnValue; returnValue << quat.x() << ";" << quat.y() << ";" << quat.z() << ";" << quat.r(); return returnValue.str(); } diff --git a/Modules/IGT/MITKIGTHardware.cmake b/Modules/IGT/MITKIGTHardware.cmake index 21c9309de8..b18e590db4 100644 --- a/Modules/IGT/MITKIGTHardware.cmake +++ b/Modules/IGT/MITKIGTHardware.cmake @@ -1,49 +1,48 @@ #Begin MicronTracker Hardware option(MITK_USE_MICRON_TRACKER "Enable support for micron tracker hardware" OFF) #Begin Optitrack Hardware option(MITK_USE_OPTITRACK_TRACKER "Enable support for Optitrack tracker hardware" OFF) option(MITK_USE_POLHEMUS_TRACKER "Enable support for Polhemus tracker hardware" OFF) # only if MicronTracker is enabled if(MITK_USE_MICRON_TRACKER) find_library(MITK_MICRON_TRACKER_LIB MTC DOC "Path which contains the MT2 library.") get_filename_component(MICRON_TRACKER_SDK_DIR ${MITK_MICRON_TRACKER_LIB} PATH) find_path(MITK_MICRON_TRACKER_INCLUDE_DIR MTC.h ${MICRON_TRACKER_SDK_DIR} DOC "Include directory of the MT2.") - find_path(MITK_MICRON_TRACKER_TEMP_DIR . DOC "Any temporary directory which can be used by the MicronTracker2.") MITK_INSTALL(FILES ${MICRON_TRACKER_SDK_DIR}/MTC.dll CONFIGURATIONS Release) MITK_INSTALL(FILES ${MICRON_TRACKER_SDK_DIR}/MTInterfaceDotNet.dll CONFIGURATIONS Release) MITK_INSTALL(FILES ${MICRON_TRACKER_SDK_DIR}/PGRFlyCapture.dll CONFIGURATIONS Release) ENDIF(MITK_USE_MICRON_TRACKER) #End MicronTracker Hardware #only if Optitrack is enabled if(MITK_USE_OPTITRACK_TRACKER) find_library(MITK_OPTITRACK_TRACKER_LIB NPTrackingTools DOC "Path which contains the Optitrack library. Please choose 32/64 bit version depending on your build.") find_path(MITK_OPTITRACK_TRACKER_INCLUDE_DIR NPTrackinTools.h DOC "Include directory of the Optitrack library.") find_path(MITK_OPTITRACK_TRACKER_LIB_DIR NPTrackingTools.dll) MITK_INSTALL(FILES ${MITK_OPTITRACK_TRACKER_LIB_DIR}/NPTrackingTools.dll CONFIGURATIONS Release) MITK_INSTALL(FILES ${MITK_OPTITRACK_TRACKER_LIB_DIR}/NPTrackingToolsx64.dll CONFIGURATIONS Release) ENDIF(MITK_USE_OPTITRACK_TRACKER) #End Optitrack Hardware if(MITK_USE_POLHEMUS_TRACKER) find_library(MITK_POLHEMUS_TRACKER_LIB PDI DOC "Path which contains the Polhemus library.") find_path(MITK_POLHEMUS_TRACKER_INCLUDE_DIR PDI.h DOC "Include directory of the Polhemus library.") ENDIF(MITK_USE_POLHEMUS_TRACKER) # only on Win32 if(WIN32) #Begin Ascension MicroBird Hardware option(MITK_USE_MICROBIRD_TRACKER "Enable support for Ascension MicroBird tracker hardware" OFF) if(MITK_USE_MICROBIRD_TRACKER) add_definitions(-DMITK_USE_MICROBIRD_TRACKER) find_library(MITK_USE_MICROBIRD_TRACKER_LIB PCIBird3) get_filename_component(MICROBIRD_TRACKER_API_DIR ${MITK_USE_MICROBIRD_TRACKER_LIB} PATH) find_path(MITK_USE_MICROBIRD_TRACKER_INCLUDE_DIR PCIBird3.h ${MICROBIRD_TRACKER_API_DIR}) endif(MITK_USE_MICROBIRD_TRACKER) #End MicroBird Hardware endif(WIN32) diff --git a/Modules/IGT/TrackingDevices/mitkClaronTrackingDevice.cpp b/Modules/IGT/TrackingDevices/mitkClaronTrackingDevice.cpp index dce85d5488..1ded0e39b1 100644 --- a/Modules/IGT/TrackingDevices/mitkClaronTrackingDevice.cpp +++ b/Modules/IGT/TrackingDevices/mitkClaronTrackingDevice.cpp @@ -1,333 +1,331 @@ /*=================================================================== 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 "mitkClaronTrackingDevice.h" #include "mitkClaronTool.h" #include "mitkIGTConfig.h" #include "mitkIGTTimeStamp.h" #include "mitkIGTHardwareException.h" #include #include #include +#include #include typedef itk::MutexLockHolder MutexLockHolder; mitk::ClaronTrackingDevice::ClaronTrackingDevice(): mitk::TrackingDevice() { //set the type of this tracking device this->m_Data = mitk::MicronTrackerTypeInformation::GetDeviceDataMicronTrackerH40(); this->m_MultiThreader = itk::MultiThreader::New(); m_ThreadID = 0; m_Device = mitk::ClaronInterface::New(); - //############################# standard directories (from cmake) ################################## + //############################# standard directories ################################## if (m_Device->IsMicronTrackerInstalled()) { -#ifdef MITK_MICRON_TRACKER_TEMP_DIR - m_ToolfilesDir = std::string(MITK_MICRON_TRACKER_TEMP_DIR); - m_ToolfilesDir.append("/MT-tools"); -#endif + m_ToolfilesDir = mitk::IOUtil::CreateTemporaryDirectory(); #ifdef MITK_MICRON_TRACKER_CALIBRATION_DIR m_CalibrationDir = std::string(MITK_MICRON_TRACKER_CALIBRATION_DIR); #endif } else { m_ToolfilesDir = "Error - No Microntracker installed"; m_CalibrationDir = "Error - No Microntracker installed"; } //################################################################################################## m_Device->Initialize(m_CalibrationDir, m_ToolfilesDir); } bool mitk::ClaronTrackingDevice::IsDeviceInstalled() { mitk::ClaronInterface::Pointer tempInterface = mitk::ClaronInterface::New(); return tempInterface->IsMicronTrackerInstalled(); } mitk::ClaronTrackingDevice::~ClaronTrackingDevice() { } mitk::TrackingTool* mitk::ClaronTrackingDevice::AddTool( const char* toolName, const char* fileName ) { mitk::ClaronTool::Pointer t = mitk::ClaronTool::New(); if (t->LoadFile(fileName) == false) { return nullptr; } t->SetToolName(toolName); if (this->InternalAddTool(t) == false) return nullptr; return t.GetPointer(); } bool mitk::ClaronTrackingDevice::InternalAddTool(ClaronTool::Pointer tool) { m_AllTools.push_back(tool); return true; } std::vector mitk::ClaronTrackingDevice::DetectTools() { std::vector returnValue; std::vector allHandles = m_Device->GetAllActiveTools(); for (auto iter = allHandles.begin(); iter != allHandles.end(); ++iter) { ClaronTool::Pointer newTool = ClaronTool::New(); newTool->SetToolName(m_Device->GetName(*iter)); newTool->SetCalibrationName(m_Device->GetName(*iter)); newTool->SetToolHandle(*iter); returnValue.push_back(newTool); } return returnValue; } bool mitk::ClaronTrackingDevice::StartTracking() { //By Alfred: next line because no temp directory is set if MicronTracker is not installed if (!m_Device->IsMicronTrackerInstalled()) return false; //################################################################################## //be sure that the temp-directory is empty at start: delete all files in the tool files directory itksys::SystemTools::RemoveADirectory(m_ToolfilesDir.c_str()); itksys::SystemTools::MakeDirectory(m_ToolfilesDir.c_str()); //copy all toolfiles into the temp directory for (unsigned int i=0; iGetFile().c_str(), m_ToolfilesDir.c_str()); } this->SetState(Tracking); // go to mode Tracking this->m_StopTrackingMutex->Lock(); // update the local copy of m_StopTracking this->m_StopTracking = false; this->m_StopTrackingMutex->Unlock(); //restart the Microntracker, so it will load the new tool files m_Device->StopTracking(); m_Device->Initialize(m_CalibrationDir,m_ToolfilesDir); if (m_Device->StartTracking()) { mitk::IGTTimeStamp::GetInstance()->Start(this); m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartTracking, this); // start a new thread that executes the TrackTools() method return true; } else {mitkThrowException(mitk::IGTHardwareException) << "Error while trying to start the device!";} } bool mitk::ClaronTrackingDevice::StopTracking() { Superclass::StopTracking(); //delete all files in the tool files directory itksys::SystemTools::RemoveADirectory(m_ToolfilesDir.c_str()); return true; } unsigned int mitk::ClaronTrackingDevice::GetToolCount() const { return (unsigned int)this->m_AllTools.size(); } mitk::TrackingTool* mitk::ClaronTrackingDevice::GetTool(unsigned int toolNumber) const { if ( toolNumber >= this->GetToolCount()) return nullptr; else return this->m_AllTools[toolNumber]; } bool mitk::ClaronTrackingDevice::OpenConnection() { bool returnValue; //Create the temp directory itksys::SystemTools::MakeDirectory(m_ToolfilesDir.c_str()); m_Device->Initialize(m_CalibrationDir,m_ToolfilesDir); returnValue = m_Device->StartTracking(); if (returnValue) { this->SetState(Ready); } else { //reset everything if (m_Device.IsNull()) { m_Device = mitk::ClaronInterface::New(); m_Device->Initialize(m_CalibrationDir, m_ToolfilesDir); } m_Device->StopTracking(); this->SetState(Setup); mitkThrowException(mitk::IGTHardwareException) << "Error while trying to open connection to the MicronTracker."; } return returnValue; } bool mitk::ClaronTrackingDevice::CloseConnection() { bool returnValue = true; if (this->GetState() == Setup) return true; returnValue = m_Device->StopTracking(); //delete the temporary directory itksys::SystemTools::RemoveADirectory(m_ToolfilesDir.c_str()); this->SetState(Setup); return returnValue; } mitk::ClaronInterface* mitk::ClaronTrackingDevice::GetDevice() { return m_Device; } std::vector mitk::ClaronTrackingDevice::GetAllTools() { return this->m_AllTools; } void mitk::ClaronTrackingDevice::TrackTools() { try { /* lock the TrackingFinishedMutex to signal that the execution rights are now transfered to the tracking thread */ MutexLockHolder trackingFinishedLockHolder(*m_TrackingFinishedMutex); // keep lock until end of scope bool localStopTracking; // Because m_StopTracking is used by two threads, access has to be guarded by a mutex. To minimize thread locking, a local copy is used here this->m_StopTrackingMutex->Lock(); // update the local copy of m_StopTracking localStopTracking = this->m_StopTracking; this->m_StopTrackingMutex->Unlock(); while ((this->GetState() == Tracking) && (localStopTracking == false)) { this->GetDevice()->GrabFrame(); std::vector detectedTools = this->DetectTools(); std::vector allTools = this->GetAllTools(); std::vector::iterator itAllTools; for(itAllTools = allTools.begin(); itAllTools != allTools.end(); itAllTools++) { mitk::ClaronTool::Pointer currentTool = *itAllTools; //test if current tool was detected std::vector::iterator itDetectedTools; bool foundTool = false; for(itDetectedTools = detectedTools.begin(); itDetectedTools != detectedTools.end(); itDetectedTools++) { mitk::ClaronTool::Pointer aktuDet = *itDetectedTools; std::string tempString(currentTool->GetCalibrationName()); if (tempString.compare(aktuDet->GetCalibrationName())==0) { currentTool->SetToolHandle(aktuDet->GetToolHandle()); foundTool = true; } } if (!foundTool) { currentTool->SetToolHandle(0); } if (currentTool->GetToolHandle() != 0) { currentTool->SetDataValid(true); //get tip position of tool: std::vector pos_vector = this->GetDevice()->GetTipPosition(currentTool->GetToolHandle()); //write tip position into tool: mitk::Point3D pos; pos[0] = pos_vector[0]; pos[1] = pos_vector[1]; pos[2] = pos_vector[2]; currentTool->SetPosition(pos); //get tip quaternion of tool std::vector quat = this->GetDevice()->GetTipQuaternions(currentTool->GetToolHandle()); //write tip quaternion into tool mitk::Quaternion orientation(quat[1], quat[2], quat[3], quat[0]); currentTool->SetOrientation(orientation); //TODO: read the timestamp data from the tracking device interface currentTool->SetIGTTimeStamp(mitk::IGTTimeStamp::GetInstance()->GetElapsed()); } else { mitk::Point3D origin; origin.Fill(0); currentTool->SetPosition(origin); currentTool->SetOrientation(mitk::Quaternion(0,0,0,0)); currentTool->SetDataValid(false); } } /* Update the local copy of m_StopTracking */ this->m_StopTrackingMutex->Lock(); localStopTracking = m_StopTracking; this->m_StopTrackingMutex->Unlock(); } } catch(...) { this->StopTracking(); mitkThrowException(mitk::IGTHardwareException) << "Error while trying to track tools. Thread stopped."; } } bool mitk::ClaronTrackingDevice::IsMicronTrackerInstalled() { return this->m_Device->IsMicronTrackerInstalled(); } ITK_THREAD_RETURN_TYPE mitk::ClaronTrackingDevice::ThreadStartTracking(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == nullptr) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == nullptr) { return ITK_THREAD_RETURN_VALUE; } ClaronTrackingDevice *trackingDevice = (ClaronTrackingDevice*)pInfo->UserData; if (trackingDevice != nullptr) trackingDevice->TrackTools(); return ITK_THREAD_RETURN_VALUE; } diff --git a/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.cpp b/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.cpp index ab3f6a8190..3c26e8fcbf 100644 --- a/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.cpp +++ b/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.cpp @@ -1,446 +1,638 @@ /*=================================================================== 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 "mitkOpenIGTLinkTrackingDevice.h" #include "mitkOpenIGTLinkTrackingTool.h" #include "mitkIGTConfig.h" #include "mitkIGTTimeStamp.h" #include "mitkIGTHardwareException.h" #include "mitkTrackingTypes.h" #include #include #include #include #include +#include //sleep headers #include #include typedef itk::MutexLockHolder MutexLockHolder; mitk::OpenIGTLinkTrackingDevice::OpenIGTLinkTrackingDevice() : mitk::TrackingDevice(), m_UpdateRate(60) { //set the type of this tracking device this->m_Data = mitk::OpenIGTLinkTypeInformation::GetDeviceDataOpenIGTLinkTrackingDeviceConnection(); m_OpenIGTLinkClient = mitk::IGTLClient::New(true); m_OpenIGTLinkClient->SetName("OpenIGTLink Tracking Device"); + m_OpenIGTLinkClient->EnableNoBufferingMode(false); m_IGTLDeviceSource = mitk::IGTLTransformDeviceSource::New(); m_IGTLDeviceSource->SetIGTLDevice(m_OpenIGTLinkClient); } mitk::OpenIGTLinkTrackingDevice::~OpenIGTLinkTrackingDevice() { } int mitk::OpenIGTLinkTrackingDevice::GetPortNumber() { return m_OpenIGTLinkClient->GetPortNumber(); } +bool mitk::OpenIGTLinkTrackingDevice::AutoDetectToolsAvailable() +{ + return true; +} + +mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::AutoDetectTools() +{ + mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New(); + + if (m_OpenIGTLinkClient->GetPortNumber() == -1) + { + MITK_WARN << "Connection not initialized, aborting (invalid port number)."; + return mitk::NavigationToolStorage::New(); + } + + //open connection + try + { + m_IGTLDeviceSource->Connect(); + m_IGTLDeviceSource->StartCommunication(); + } + catch (std::runtime_error &e) + { + MITK_WARN << "AutoDetection: Open IGT Link device retruned an error while trying to connect: " << e.what(); + return mitk::NavigationToolStorage::New(); + } + + //get a message to find out type + mitk::IGTLMessage::Pointer receivedMessage = ReceiveMessage(100); + + const char* msgType = receivedMessage->GetIGTLMessageType(); + + if (std::string(msgType).empty()) + { + MITK_INFO << "Did not receive a message. Do you have to start the stream manually at the server?"; + MITK_INFO << "Waiting for 10 seconds ..."; + receivedMessage = ReceiveMessage(10000); + msgType = receivedMessage->GetIGTLMessageType(); + } + + mitk::OpenIGTLinkTrackingDevice::TrackingMessageType type = GetMessageTypeFromString(msgType); + + returnValue = DiscoverToolsAndConvertToNavigationTools(type); + /* + switch (type) + { + case TDATA: + returnValue = DiscoverToolsFromTData(dynamic_cast(receivedMessage->GetMessage().GetPointer())); + break; + case QTDATA: + returnValue = DiscoverToolsFromQTData(dynamic_cast(receivedMessage->GetMessage().GetPointer())); + break; + case TRANSFORM: + returnValue = DiscoverToolsFromTransform(); + break; + default: + MITK_INFO << "Server does not send tracking data or received data is not of a compatible type. (Received type: " << msgType << ")"; + } + */ + + //close connection + try + { + m_IGTLDeviceSource->StopCommunication(); + m_IGTLDeviceSource->Disconnect(); + } + catch (std::runtime_error &e) + { + MITK_WARN << "AutoDetection: Open IGT Link device retruned an error while trying to disconnect: " << e.what(); + return mitk::NavigationToolStorage::New(); + } + + + return returnValue; +} + +mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::DiscoverToolsAndConvertToNavigationTools(mitk::OpenIGTLinkTrackingDevice::TrackingMessageType type, int NumberOfMessagesToWait) +{ + MITK_INFO << "Start discovering tools by " << type << " messages"; + mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New(); + std::map toolNameMap; + + for (int j = 0; jUpdate(); + igtl::TransformMessage::Pointer msg = dynamic_cast(m_IGTLDeviceSource->GetOutput()->GetMessage().GetPointer()); + if (msg == nullptr || msg.IsNull()) + { + MITK_INFO << "Received message could not be casted to TransformMessage. Skipping.."; + continue; + } + + int count = toolNameMap[msg->GetDeviceName()]; + if (count == 0) + { + //MITK_WARN << "ADDED NEW TOOL TO TOOLCHAIN: " << msg->GetDeviceName() << " - 1"; + toolNameMap[msg->GetDeviceName()] = 1; + } + else + { + toolNameMap[msg->GetDeviceName()]++; + //MITK_WARN << "INCREMENTED TOOL COUNT IN TOOLCHAIN: " << msg->GetDeviceName() << " - " << toolNameMap[msg->GetDeviceName()]; + } + } + + int i = 0; + for (std::map::iterator it = toolNameMap.begin(); it != toolNameMap.end(); ++it) + { + MITK_INFO << "Found tool: " << it->first; + + std::stringstream name; + name << it->first; + + std::stringstream identifier; + identifier << "AutoDetectedTool-" << i; + i++; + + mitk::NavigationTool::Pointer newTool = ConstructDefaultOpenIGTLinkTool(name.str(), identifier.str()); + + returnValue->AddTool(newTool); + } + + return returnValue; +} + std::string mitk::OpenIGTLinkTrackingDevice::GetHostname() { return m_OpenIGTLinkClient->GetHostname(); } void mitk::OpenIGTLinkTrackingDevice::SetPortNumber(int portNumber) { m_OpenIGTLinkClient->SetPortNumber(portNumber); } void mitk::OpenIGTLinkTrackingDevice::SetHostname(std::string hostname) { m_OpenIGTLinkClient->SetHostname(hostname); } bool mitk::OpenIGTLinkTrackingDevice::IsDeviceInstalled() { return true; } mitk::TrackingTool* mitk::OpenIGTLinkTrackingDevice::AddTool(const char* toolName, const char* fileName) { mitk::OpenIGTLinkTrackingTool::Pointer t;// = mitk::OpenIGTLinkTrackingTool::New(); //TODO: Implement if (this->InternalAddTool(t) == false) return nullptr; return t.GetPointer(); } bool mitk::OpenIGTLinkTrackingDevice::InternalAddTool(OpenIGTLinkTrackingTool::Pointer tool) { m_AllTools.push_back(tool); return true; } bool mitk::OpenIGTLinkTrackingDevice::DiscoverTools(int waitingTime) { if (m_OpenIGTLinkClient->GetPortNumber() == -1) { MITK_WARN << "Connection not initialized, aborting (invalid port number)."; return false; } try { m_IGTLDeviceSource->Connect(); m_IGTLDeviceSource->StartCommunication(); } catch (std::runtime_error &e) { MITK_WARN << "Open IGT Link device retruned an error while trying to connect: " << e.what(); return false; } - //send a message to the server: start tracking stream - mitk::IGTLMessageFactory::Pointer msgFactory = m_OpenIGTLinkClient->GetMessageFactory(); - std::string message = "STT_TDATA"; - igtl::MessageBase::Pointer sttMsg = msgFactory->CreateInstance(message); - //TODO: Fix this to dynamically get this from GUI - ((igtl::StartTrackingDataMessage*)sttMsg.GetPointer())->SetResolution(m_UpdateRate); - m_OpenIGTLinkClient->SendMessage(sttMsg); - - mitk::IGTLMessage::Pointer receivedMessage; - - std::chrono::high_resolution_clock::time_point time = std::chrono::high_resolution_clock::now(); - std::chrono::milliseconds d = std::chrono::milliseconds(waitingTime); - - while (!(receivedMessage.IsNotNull() && receivedMessage->IsDataValid())) - { - m_IGTLDeviceSource->Update(); - receivedMessage = m_IGTLDeviceSource->GetOutput(); - - if ((time + d) < std::chrono::high_resolution_clock::now()) - break; - - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } + mitk::IGTLMessage::Pointer receivedMessage = ReceiveMessage(waitingTime); //check the tracking stream for the number and type of tools //igtl::MessageBase::Pointer receivedMessage = m_OpenIGTLinkClient->GetNextMessage(); if (receivedMessage.IsNull()) { MITK_WARN << "No message was received. Is there really a server?"; return false; } else if (!receivedMessage->IsDataValid()) { MITK_WARN << "Received invalid message."; return false; } const char* msgType = receivedMessage->GetIGTLMessageType(); mitk::OpenIGTLinkTrackingDevice::TrackingMessageType type = GetMessageTypeFromString(msgType); + mitk::NavigationToolStorage::Pointer foundTools; switch (type) { case TDATA: - return DiscoverToolsFromTData(dynamic_cast(receivedMessage->GetMessage().GetPointer())); + foundTools = DiscoverToolsFromTData(dynamic_cast(receivedMessage->GetMessage().GetPointer())); + break; case QTDATA: - return DiscoverToolsFromQTData(dynamic_cast(receivedMessage->GetMessage().GetPointer())); + foundTools = DiscoverToolsFromQTData(dynamic_cast(receivedMessage->GetMessage().GetPointer())); + break; case TRANSFORM: - return DiscoverToolsFromTransform(); + foundTools = DiscoverToolsFromTransform(); + break; default: MITK_INFO << "Server does not send tracking data. Received data is not of a compatible type. Received type: " << msgType; return false; } + if (foundTools.IsNull() || (foundTools->GetToolCount() == 0)) { return false; } + for (int i = 0; i < foundTools->GetToolCount(); i++) { AddNewToolForName(foundTools->GetTool(i)->GetToolName(), i); } + MITK_INFO << "Found tools: " << foundTools->GetToolCount(); + return true; } -bool mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromTData(igtl::TrackingDataMessage::Pointer tdMsg) +mitk::IGTLMessage::Pointer mitk::OpenIGTLinkTrackingDevice::ReceiveMessage(int waitingTime) { + mitk::IGTLMessage::Pointer receivedMessage; + //send a message to the server: start tracking stream + mitk::IGTLMessageFactory::Pointer msgFactory = m_OpenIGTLinkClient->GetMessageFactory(); + std::string message[2] = {"STT_QTDATA","STT_TDATA"}; + + for (int i = 0; i < 2; i++) + { + igtl::MessageBase::Pointer sttMsg = msgFactory->CreateInstance(message[i]); + //TODO: Fix this to dynamically get this from GUI + ((igtl::StartTrackingDataMessage*)sttMsg.GetPointer())->SetResolution(m_UpdateRate); + m_OpenIGTLinkClient->SendMessage(mitk::IGTLMessage::New(sttMsg)); + } + + std::chrono::high_resolution_clock::time_point time = std::chrono::high_resolution_clock::now(); + std::chrono::milliseconds d = std::chrono::milliseconds(waitingTime); + + while (!(receivedMessage.IsNotNull() && receivedMessage->IsDataValid())) + { + m_IGTLDeviceSource->Update(); + receivedMessage = m_IGTLDeviceSource->GetOutput(); + + if ((time + d) < std::chrono::high_resolution_clock::now()) + break; + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + return receivedMessage; + +} + +mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromTData(igtl::TrackingDataMessage::Pointer tdMsg) +{ + mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New(); MITK_INFO << "Start discovering tools by TDATA messages"; if (tdMsg == nullptr) { MITK_WARN << "Message was not a TrackingDataMessage, aborting!"; - return false; + return returnValue; } int numberOfTools = tdMsg->GetNumberOfTrackingDataElements(); MITK_INFO << "Found " << numberOfTools << " tools"; for (int i = 0; i < numberOfTools; i++) { igtl::TrackingDataElement::Pointer currentTrackingData; tdMsg->GetTrackingDataElement(i, currentTrackingData); std::string name = currentTrackingData->GetName(); - AddNewToolForName(name, i); + + std::stringstream identifier; + identifier << "AutoDetectedTool-" << i; + i++; + + mitk::NavigationTool::Pointer newTool = ConstructDefaultOpenIGTLinkTool(name, identifier.str()); + + returnValue->AddTool(newTool); } m_IGTLDeviceSource->StopCommunication(); SetState(Ready); - return true; + return returnValue; } -bool mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromQTData(igtl::QuaternionTrackingDataMessage::Pointer msg) +mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromQTData(igtl::QuaternionTrackingDataMessage::Pointer msg) { + mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New(); MITK_INFO << "Start discovering tools by QTDATA messages"; if (msg == nullptr) { MITK_WARN << "Message was not a QuaternionTrackingDataMessage, aborting!"; - return false; + return returnValue; } int numberOfTools = msg->GetNumberOfQuaternionTrackingDataElements(); MITK_INFO << "Found " << numberOfTools << " tools"; for (int i = 0; i < numberOfTools; i++) { igtl::QuaternionTrackingDataElement::Pointer currentTrackingData; msg->GetQuaternionTrackingDataElement(i, currentTrackingData); std::string name = currentTrackingData->GetName(); - AddNewToolForName(name, i); + + std::stringstream identifier; + identifier << "AutoDetectedTool-" << i; + i++; + + mitk::NavigationTool::Pointer newTool = ConstructDefaultOpenIGTLinkTool(name, identifier.str()); + + returnValue->AddTool(newTool); } m_IGTLDeviceSource->StopCommunication(); SetState(Ready); - return true; + return returnValue; } void mitk::OpenIGTLinkTrackingDevice::AddNewToolForName(std::string name, int i) { mitk::OpenIGTLinkTrackingTool::Pointer newTool = mitk::OpenIGTLinkTrackingTool::New(); if (name == "") //if no name was given create a default name { std::stringstream defaultName; defaultName << "OpenIGTLinkTool#" << i; name = defaultName.str(); } MITK_INFO << "Added tool " << name << " to tracking device."; newTool->SetToolName(name); InternalAddTool(newTool); } -bool mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromTransform() +mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromTransform(int NumberOfMessagesToWait) { MITK_INFO << "Start discovering tools by TRANSFORM messages"; + mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New(); std::map toolNameMap; - bool condition = false; - while (!condition) + + for (int j=0; jUpdate(); igtl::TransformMessage::Pointer msg = dynamic_cast(m_IGTLDeviceSource->GetOutput()->GetMessage().GetPointer()); if (msg == nullptr || msg.IsNull()) { MITK_INFO << "Received message could not be casted to TransformMessage. Skipping.."; continue; } - condition = true; int count = toolNameMap[msg->GetDeviceName()]; if (count == 0) { - MITK_WARN << "ADDED NEW TOOL TO TOOLCHAIN: " << msg->GetDeviceName() << " - 1"; + //MITK_WARN << "ADDED NEW TOOL TO TOOLCHAIN: " << msg->GetDeviceName() << " - 1"; toolNameMap[msg->GetDeviceName()] = 1; } else { toolNameMap[msg->GetDeviceName()]++; - MITK_WARN << "INCREMENTED TOOL COUNT IN TOOLCHAIN: " << msg->GetDeviceName() << " - " << toolNameMap[msg->GetDeviceName()]; - } - - for (std::map::iterator it = toolNameMap.begin(); it != toolNameMap.end(); ++it) - { - if (it->second < 5) - { - condition = false; - break; - } + //MITK_WARN << "INCREMENTED TOOL COUNT IN TOOLCHAIN: " << msg->GetDeviceName() << " - " << toolNameMap[msg->GetDeviceName()]; } } int i = 0; for (std::map::iterator it = toolNameMap.begin(); it != toolNameMap.end(); ++it) { - AddNewToolForName(it->first, i++); + MITK_INFO << "Found tool: " << it->first; + + std::stringstream name; + name << it->first; + + std::stringstream identifier; + identifier << "AutoDetectedTool-" << i; + i++; + + mitk::NavigationTool::Pointer newTool = ConstructDefaultOpenIGTLinkTool(name.str(), identifier.str()); + + returnValue->AddTool(newTool); } - //TODO InternalAddTool for all tools - return true; + return returnValue; +} + +mitk::NavigationTool::Pointer mitk::OpenIGTLinkTrackingDevice::ConstructDefaultOpenIGTLinkTool(std::string name, std::string identifier) +{ + mitk::DataNode::Pointer newNode = mitk::DataNode::New(); + + newNode->SetName(name); + + mitk::Surface::Pointer myCone = mitk::Surface::New(); + vtkConeSource *vtkData = vtkConeSource::New(); + vtkData->SetAngle(5.0); + vtkData->SetResolution(50); + vtkData->SetHeight(6.0f); + vtkData->SetRadius(2.0f); + vtkData->SetCenter(0.0, 0.0, 0.0); + vtkData->Update(); + myCone->SetVtkPolyData(vtkData->GetOutput()); + vtkData->Delete(); + newNode->SetData(myCone); + + mitk::NavigationTool::Pointer newTool = mitk::NavigationTool::New(); + newTool->SetDataNode(newNode); + newTool->SetIdentifier(identifier); + + newTool->SetTrackingDeviceType(mitk::OpenIGTLinkTypeInformation::GetDeviceDataOpenIGTLinkTrackingDeviceConnection().Line); + + return newTool; + } void mitk::OpenIGTLinkTrackingDevice::UpdateTools() { if (this->GetState() != Tracking) { MITK_ERROR << "Method was called in the wrong state, something went wrong!"; return; } m_IGTLMsgToNavDataFilter->Update(); mitk::NavigationData::Pointer currentNavData = m_IGTLMsgToNavDataFilter->GetOutput(); const char* name = currentNavData->GetName(); //MITK_WARN << name; for (int i = 0; i < m_AllTools.size(); i++) { if (strcmp(m_AllTools.at(i)->GetToolName(), name) == 0) { m_AllTools.at(i)->SetDataValid(currentNavData->IsDataValid()); m_AllTools.at(i)->SetPosition(currentNavData->GetPosition()); m_AllTools.at(i)->SetOrientation(currentNavData->GetOrientation()); m_AllTools.at(i)->SetIGTTimeStamp(currentNavData->GetIGTTimeStamp()); } } } bool mitk::OpenIGTLinkTrackingDevice::StartTracking() { //check tracking state if (this->GetState() != Ready) { MITK_WARN << "Cannot start tracking, device is not ready!"; return false; } try { m_IGTLDeviceSource->StartCommunication(); //send a message to the server: start tracking stream mitk::IGTLMessageFactory::Pointer msgFactory = m_OpenIGTLinkClient->GetMessageFactory(); std::string message = "STT_TDATA"; //m_OpenIGTLinkClient->SendMessage(msgFactory->CreateInstance(message)); } catch (std::runtime_error &e) { MITK_WARN << "Open IGT Link device retruned an error while starting communication: " << e.what(); return false; } //create internal igtl pipeline m_IGTLMsgToNavDataFilter = mitk::IGTLMessageToNavigationDataFilter::New(); m_IGTLMsgToNavDataFilter->SetNumberOfExpectedOutputs(this->GetToolCount()); m_IGTLMsgToNavDataFilter->ConnectTo(m_IGTLDeviceSource); //connect itk events typedef itk::SimpleMemberCommand< mitk::OpenIGTLinkTrackingDevice > CurCommandType; CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); messageReceivedCommand->SetCallbackFunction(this, &mitk::OpenIGTLinkTrackingDevice::UpdateTools); m_MessageReceivedObserverTag = m_OpenIGTLinkClient->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); + m_OpenIGTLinkClient->EnableNoBufferingMode(true); this->SetState(Tracking); return true; } bool mitk::OpenIGTLinkTrackingDevice::StopTracking() { //check tracking state if (this->GetState() != Tracking) { MITK_WARN << "Cannot open connection, device is already connected!"; return false; } m_OpenIGTLinkClient->RemoveObserver(m_MessageReceivedObserverTag); //disconnect itk events try { m_IGTLDeviceSource->StopCommunication(); } catch (std::runtime_error &e) { MITK_WARN << "Open IGT Link device retruned an error while stopping communication: " << e.what(); return false; } + m_OpenIGTLinkClient->EnableNoBufferingMode(false); this->SetState(Ready); return true; } unsigned int mitk::OpenIGTLinkTrackingDevice::GetToolCount() const { return (unsigned int)this->m_AllTools.size(); } mitk::TrackingTool* mitk::OpenIGTLinkTrackingDevice::GetTool(unsigned int toolNumber) const { if (toolNumber >= this->GetToolCount()) return nullptr; else return this->m_AllTools[toolNumber]; } bool mitk::OpenIGTLinkTrackingDevice::OpenConnection() { //check tracking state if (this->GetState() != Setup) { MITK_WARN << "Cannot open connection, device is already connected!"; return false; } try { m_IGTLDeviceSource->Connect(); } catch (std::runtime_error &e) { MITK_WARN << "Open IGT Link device retruned an error while trying to connect: " << e.what(); return false; } this->SetState(Ready); return true; } bool mitk::OpenIGTLinkTrackingDevice::CloseConnection() { //check tracking state if (this->GetState() != Ready) { MITK_WARN << "Cannot close connection, device is in the wrong state!"; return false; } try { m_IGTLDeviceSource->Disconnect(); } catch (std::runtime_error &e) { MITK_WARN << "Open IGT Link device retruned an error while trying to disconnect: " << e.what(); return false; } this->SetState(Setup); return true; } std::vector mitk::OpenIGTLinkTrackingDevice::GetAllTools() { return this->m_AllTools; } mitk::OpenIGTLinkTrackingDevice::TrackingMessageType mitk::OpenIGTLinkTrackingDevice::GetMessageTypeFromString(const char* messageTypeString) { if (strcmp(messageTypeString, "TDATA") == 0) { return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::TDATA; } else if (strcmp(messageTypeString, "QTDATA") == 0) { return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::QTDATA; } else if (strcmp(messageTypeString, "TRANSFORM") == 0) { return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::TRANSFORM; } else { return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::UNKNOWN; } } diff --git a/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.h b/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.h index a2263a7043..e040ce5ee5 100644 --- a/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.h +++ b/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.h @@ -1,166 +1,188 @@ /*=================================================================== 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 MITKOPENIGTLINKTRACKINGDEVICE_H_HEADER_INCLUDED_ #define MITKOPENIGTLINKTRACKINGDEVICE_H_HEADER_INCLUDED_ #include #include #include #include #include #include #include #include #include #include #include "mitkIGTLTransformDeviceSource.h" namespace mitk { /** Documentation: * \brief An object of this class represents the MicronTracker device. You can add tools to this * device, then open the connection and start tracking. The tracking device will then * continuously update the tool coordinates. * \ingroup IGT */ class MITKIGT_EXPORT OpenIGTLinkTrackingDevice : public TrackingDevice { public: mitkClassMacro(OpenIGTLinkTrackingDevice, TrackingDevice); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Sets the port number for the Open IGT Link connection. Default value is -1 (invalid). */ void SetPortNumber(int portNumber); /** Sets the hostname for the Open IGT Link connection. Default value is 127.0.0.1 (localhost). */ void SetHostname(std::string hostname); int GetPortNumber(); std::string GetHostname(); /** * \brief Starts the tracking. * \return Returns true if the tracking is started. Throws an exception if an error occures. * @throw mitk::IGTHardwareException Throws an exception if there is an error during start tracking. */ virtual bool StartTracking(); /** * \brief Stops the tracking. * \return Returns true if the tracking is stopped. */ virtual bool StopTracking(); /** * \brief Opens the connection to the device. This have to be done before the tracking is started. * @throw mitk::IGTHardwareException Throws an exception if there is an error during open connection. */ virtual bool OpenConnection(); /** * \brief Closes the connection and clears all resources. */ virtual bool CloseConnection(); /** * \return Returns the number of tools which have been added to the device. */ virtual unsigned int GetToolCount() const; /** * \param toolNumber The number of the tool which should be given back. * \return Returns the tool which the number "toolNumber". Returns nullptr, if there is * no tool with this number. */ TrackingTool* GetTool(unsigned int toolNumber) const; /** * \brief Discover the tools available from the connected OpenIGTLink device and adds these tools to this tracking device. Therefore, a connection * is opened, the tools are discovered and added. * \param WaitingTime Defines how long the method waits for an answer from the server (in milliseconds). Default value is 10000 (10 seconds). * \return Returns true if the connection was established and the tools were discovered successfully and - if at least one tool was found - were added to this device. * Retruns false if no valid connection is available. */ bool DiscoverTools(int WaitingTime = 10000); /** * \brief Create a new OpenIGTLink tool with toolName and fileName and add it to the list of tools * * Note that tools are usually provided by the OpenIGTLink connection. In most cases, the method DiscoverTools() should be used * instead which automatically finds the provided tools. If you use this method to manually add tools be sure that you add the * same number and type of tools that are provided by the connected device. Otherwise problems might occur when you try to start * tracking. */ mitk::TrackingTool* AddTool(const char* toolName, const char* fileName); + /** @return Returns true if this device can autodetects its tools. */ + virtual bool AutoDetectToolsAvailable(); + + /** Autodetects tools from the current OpenIGTLink connection and returns them as a navigation tool storage. + * @return Returns the detected tools. Returns an empty storage if no tools are present + * or if OpenIGTLink Connection is not possible + */ + virtual mitk::NavigationToolStorage::Pointer AutoDetectTools(); + bool IsDeviceInstalled(); itkSetMacro(UpdateRate, int); ///< Sets the update rate of the device in fps. Default value is 60 fps. itkGetConstMacro(UpdateRate, int); ///< Returns the update rate of the device in fps protected: OpenIGTLinkTrackingDevice(); ~OpenIGTLinkTrackingDevice(); /** * \brief Adds a tool to the tracking device. * * \param tool The tool which will be added. * \return Returns true if the tool has been added, false otherwise. */ bool InternalAddTool(OpenIGTLinkTrackingTool::Pointer tool); /** Updates the tools from the open IGT link connection. Is called every time a message received event is invoked.*/ void UpdateTools(); unsigned long m_MessageReceivedObserverTag; + /** Receives one message from the OpenIGTLink connection. Starts the tracking stream if required. + */ + mitk::IGTLMessage::Pointer ReceiveMessage(int waitingTime); + /** * \return Returns all tools of the tracking device. */ std::vector GetAllTools(); //OpenIGTLink connection class mitk::IGTLClient::Pointer m_OpenIGTLinkClient; //OpenIGTLink pipeline mitk::IGTLTransformDeviceSource::Pointer m_IGTLDeviceSource; mitk::IGTLMessageToNavigationDataFilter::Pointer m_IGTLMsgToNavDataFilter; std::vector m_AllTools; ///< vector holding all tools int m_UpdateRate; ///< holds the update rate in FPS (will be set automatically when the OpenIGTLink connection is established) private: enum TrackingMessageType { TDATA, TRANSFORM, QTDATA, UNKNOWN }; mitk::OpenIGTLinkTrackingDevice::TrackingMessageType GetMessageTypeFromString(const char* messageTypeString); - bool DiscoverToolsFromTData(igtl::TrackingDataMessage::Pointer msg); + /** Discovers tools from the OpenIGTLink connection and converts them to MITK navigation tool objects. + @return Returns a navigation tool storage holding all found tools. Returns an empty storage if no tools were found or if there was an error.*/ + mitk::NavigationToolStorage::Pointer DiscoverToolsAndConvertToNavigationTools(mitk::OpenIGTLinkTrackingDevice::TrackingMessageType type, int NumberOfMessagesToWait = 50); + + /** Discovers tools from the input (type TDATA) */ + mitk::NavigationToolStorage::Pointer DiscoverToolsFromTData(igtl::TrackingDataMessage::Pointer msg); - bool DiscoverToolsFromQTData(igtl::QuaternionTrackingDataMessage::Pointer msg); + /** Discovers tools from the input (type QTDATA) */ + mitk::NavigationToolStorage::Pointer DiscoverToolsFromQTData(igtl::QuaternionTrackingDataMessage::Pointer msg); - bool DiscoverToolsFromTransform(); + /** Discovers tools from the input (type TRANSFORM) and waits for the given number of messages */ + mitk::NavigationToolStorage::Pointer DiscoverToolsFromTransform(int NumberOfMessagesToWait = 50); void AddNewToolForName(std::string name, int i); + + mitk::NavigationTool::Pointer ConstructDefaultOpenIGTLinkTool(std::string name, std::string identifier); }; }//mitk #endif /* MITKOpenIGTLinkTRACKINGDEVICE_H_HEADER_INCLUDED_ */ diff --git a/Modules/IGT/TrackingDevices/mitkPolhemusInterface.cpp b/Modules/IGT/TrackingDevices/mitkPolhemusInterface.cpp index 26f1b570b8..7e4af215c8 100644 --- a/Modules/IGT/TrackingDevices/mitkPolhemusInterface.cpp +++ b/Modules/IGT/TrackingDevices/mitkPolhemusInterface.cpp @@ -1,200 +1,207 @@ /*=================================================================== 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 #define _USE_MATH_DEFINES #include #include BYTE MotionBuf[0x1FA400]; -mitk::PolhemusInterface::PolhemusInterface() +mitk::PolhemusInterface::PolhemusInterface() : m_continousTracking(false) { m_pdiDev = new CPDIdev(); } mitk::PolhemusInterface::~PolhemusInterface() { delete m_pdiDev; } bool mitk::PolhemusInterface::InitializeDevice() { m_pdiDev->ResetTracker(); m_pdiDev->ResetSAlignment(-1); m_pdiDev->Trace(TRUE, 7); + m_continousTracking = false; return true; } bool mitk::PolhemusInterface::SetupDevice() { m_pdiDev->SetPnoBuffer(MotionBuf, 0x1FA400); m_pdiDev->SetMetric(true); //use cm instead of inches m_pdiDev->StartPipeExport(); CPDImdat pdiMDat; pdiMDat.Empty(); pdiMDat.Append(PDI_MODATA_FRAMECOUNT); pdiMDat.Append(PDI_MODATA_POS); pdiMDat.Append(PDI_MODATA_ORI); m_pdiDev->SetSDataList(-1, pdiMDat); CPDIbiterr cBE; m_pdiDev->GetBITErrs(cBE); if (!(cBE.IsClear())) {m_pdiDev->ClearBITErrs();} if (this->m_HemisphereTrackingEnabled) { m_pdiDev->SetSHemiTrack(-1); } else { m_pdiDev->SetSHemisphere(-1, { (float)2.54,0,0 }); } return true; } bool mitk::PolhemusInterface::StartTracking() { LPCTSTR szWindowClass = _T("PDIconsoleWinClass"); HINSTANCE hInst = GetModuleHandle(0); HWND hwnd = CreateWindowEx( WS_EX_NOACTIVATE,//WS_EX_STATICEDGE, // szWindowClass, _T("MyWindowName"), WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, 0, hInst, 0); m_continousTracking = true; return m_pdiDev->StartContPno(hwnd); } bool mitk::PolhemusInterface::StopTracking() { m_continousTracking = false; return true; } bool mitk::PolhemusInterface::Connect() { if (!InitializeDevice()) { return false; } if (m_pdiDev->CnxReady()) { return true; } CPDIser pdiSer; m_pdiDev->SetSerialIF(&pdiSer); ePiCommType eType = m_pdiDev->DiscoverCnx(); switch (eType) { case PI_CNX_USB: MITK_INFO << "USB Connection: " << m_pdiDev->GetLastResultStr(); break; case PI_CNX_SERIAL: MITK_INFO << "Serial Connection: " << m_pdiDev->GetLastResultStr(); break; default: MITK_INFO << "DiscoverCnx result: " << m_pdiDev->GetLastResultStr(); break; } if (!SetupDevice()) { return false; } return m_pdiDev->CnxReady(); } bool mitk::PolhemusInterface::Disconnect() { if (m_continousTracking) { m_continousTracking = false; if (!m_pdiDev->Disconnect()) return false; } return true; } std::vector mitk::PolhemusInterface::GetLastFrame() { PBYTE pBuf; DWORD dwSize; //read one frame if (!m_pdiDev->LastPnoPtr(pBuf, dwSize)) {MITK_WARN << m_pdiDev->GetLastResultStr();} std::vector returnValue = ParsePolhemusRawData(pBuf, dwSize); if (returnValue.empty()) { MITK_WARN << "Cannot parse data / no tools present"; } return returnValue; } unsigned int mitk::PolhemusInterface::GetNumberOfTools() { if (m_continousTracking) return GetLastFrame().size(); else return GetSingleFrame().size(); } std::vector mitk::PolhemusInterface::GetSingleFrame() { - if (m_continousTracking) return std::vector(); - + if (m_continousTracking) + { + MITK_WARN << "Cannot get tool count when continously tracking"; + return std::vector(); + } PBYTE pBuf; DWORD dwSize; //read one frame - if (!m_pdiDev->ReadSinglePnoBuf(pBuf, dwSize)) { MITK_WARN << m_pdiDev->GetLastResultStr(); } + if (!m_pdiDev->ReadSinglePnoBuf(pBuf, dwSize)) { + MITK_WARN << m_pdiDev->GetLastResultStr(); + return std::vector(); + } return ParsePolhemusRawData(pBuf, dwSize); } std::vector mitk::PolhemusInterface::ParsePolhemusRawData(PBYTE pBuf, DWORD dwSize) { std::vector returnValue; DWORD i = 0; while (i eulerQuat(rollAngle, elevationAngle, azimuthAngle); currentTrackingData.rot = eulerQuat; returnValue.push_back(currentTrackingData); i += shSize; } return returnValue; } diff --git a/Modules/IGT/TrackingDevices/mitkTrackingVolumeGenerator.cpp b/Modules/IGT/TrackingDevices/mitkTrackingVolumeGenerator.cpp index 5f044a9fbf..caed56dd1e 100644 --- a/Modules/IGT/TrackingDevices/mitkTrackingVolumeGenerator.cpp +++ b/Modules/IGT/TrackingDevices/mitkTrackingVolumeGenerator.cpp @@ -1,131 +1,195 @@ /*=================================================================== 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 "mitkTrackingVolumeGenerator.h" #include "mitkStandardFileLocations.h" #include "mitkConfig.h" #include #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include #include +#include +#include +#include #include "mitkUnspecifiedTrackingTypeInformation.h" #include "mitkTrackingDeviceTypeCollection.h" +#include + +namespace { + +//! Workaround until IOUtil::LoadSurface will guarantee to load mitk::Surface +//! even in presence of reader services that load STL as another type of +//! BaseData (T19825). +mitk::Surface::Pointer LoadCoreSurface(const us::ModuleResource& usResource) +{ + us::ModuleResourceStream resStream(usResource, std::ios_base::in); + + mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); + // get mime types for file (extension) and for surfaces + std::vector mimetypesForFile = mimeTypeProvider->GetMimeTypesForFile(usResource.GetResourcePath()); + std::vector mimetypesForSurface = mimeTypeProvider->GetMimeTypesForCategory(mitk::IOMimeTypes::CATEGORY_SURFACES()); + + // construct our candidates as the intersection of both sets because we need something that + // handles the type type _and_ produces a surface out of it + std::vector mimetypes; + + std::sort(mimetypesForFile.begin(), mimetypesForFile.end()); + std::sort(mimetypesForSurface.begin(), mimetypesForSurface.end()); + std::set_intersection(mimetypesForFile.begin(), mimetypesForFile.end(), + mimetypesForSurface.begin(), mimetypesForSurface.end(), + std::back_inserter(mimetypes)); + + mitk::Surface::Pointer surface; + if (mimetypes.empty()) + { + mitkThrow() << "No mimetype for resource stream: " << usResource.GetResourcePath(); + return surface; + } + + mitk::FileReaderRegistry fileReaderRegistry; + std::vector> refs = fileReaderRegistry.GetReferences(mimetypes[0]); + if (refs.empty()) + { + mitkThrow() << "No reader available for resource stream: " << usResource.GetResourcePath(); + return surface; + } + + mitk::IFileReader *reader = fileReaderRegistry.GetReader(refs[0]); + reader->SetInput(usResource.GetResourcePath(), &resStream); + auto basedatas = reader->Read(); + if (!basedatas.empty()) + { + surface = dynamic_cast(basedatas.front().GetPointer()); + } + + return surface; +} + +} // unnamed namespace + mitk::TrackingVolumeGenerator::TrackingVolumeGenerator() { m_Data = mitk::UnspecifiedTrackingTypeInformation::GetDeviceDataUnspecified(); } void mitk::TrackingVolumeGenerator::SetTrackingDevice (mitk::TrackingDevice::Pointer tracker) { std::vector > refs = us::GetModuleContext()->GetServiceReferences(); if (refs.empty()) { MITK_ERROR << "No tracking device service found!"; } mitk::TrackingDeviceTypeCollection* deviceTypeCollection = us::GetModuleContext()->GetService(refs.front()); this->m_Data = deviceTypeCollection->GetFirstCompatibleDeviceDataForLine(tracker->GetType()); } void mitk::TrackingVolumeGenerator::GenerateData() { mitk::Surface::Pointer output = this->GetOutput(); //the surface wich represents the tracking volume - std::string filepath = ""; // Full path to file (wil be resolved later) std::string filename = this->m_Data.VolumeModelLocation; // Name of the file or possibly a magic String, e.g. "cube" MITK_INFO << "volume: " << filename; // See if filename matches a magic string. if (filename.compare("cube") == 0){ vtkSmartPointer cubeSource = vtkSmartPointer::New(); double bounds[6]; bounds[0] = bounds[2] = bounds[4] = -400.0; // initialize bounds to -400 ... +400 cube. This is the default value of the bounds[1] = bounds[3] = bounds[5] = 400.0; // virtual tracking device, but it can be changed. In that case, // the tracking volume polydata has to be updated manually cubeSource->SetBounds(bounds); cubeSource->Update(); output->SetVtkPolyData(cubeSource->GetOutput()); //set the vtkCubeSource as polyData of the surface return; } if (filename.compare("") == 0) // empty String means no model, return empty output { // initialize with empty poly data (otherwise old surfaces may be returned) => so an empty surface is returned vtkPolyData *emptyPolyData = vtkPolyData::New(); output->SetVtkPolyData(emptyPolyData); emptyPolyData->Delete(); return; } // from here on, we assume that filename contains an actual filename and not a magic string us::Module* module = us::GetModuleContext()->GetModule(); - us::ModuleResource moduleResource = module->GetResource(filename); - std::vector data = mitk::IOUtil::Load(moduleResource); - - if(data.empty()) - MITK_ERROR << "Exception while reading file:"; - - mitk::Surface::Pointer fileoutput = dynamic_cast(data[0].GetPointer()); - - output->SetVtkPolyData(fileoutput->GetVtkPolyData()); + // TODO one would want to call mitk::IOUtils::LoadSurface(moduleResource) here. + // However this function is not guaranteed to find a reader that loads + // named resource as a Surface (given the presence of alternative readers + // that produce another data type but has a higher ranking than the core + // surface reader) - see bug T22608. + mitk::Surface::Pointer fileoutput = LoadCoreSurface(moduleResource); + if (fileoutput == nullptr) + { + MITK_ERROR << "Exception while casting data loaded from file: " << moduleResource.GetResourcePath(); + output->SetVtkPolyData(vtkSmartPointer(vtkPolyData::New())); + } + else + { + output->SetVtkPolyData(fileoutput->GetVtkPolyData()); + } } void mitk::TrackingVolumeGenerator::SetTrackingDeviceType(mitk::TrackingDeviceType deviceType) { std::vector > refs = us::GetModuleContext()->GetServiceReferences(); if (refs.empty()) { MITK_ERROR << "No tracking device service found!"; } mitk::TrackingDeviceTypeCollection* deviceTypeCollection = us::GetModuleContext()->GetService(refs.front()); m_Data = deviceTypeCollection->GetFirstCompatibleDeviceDataForLine(deviceType); } mitk::TrackingDeviceType mitk::TrackingVolumeGenerator::GetTrackingDeviceType() const { return m_Data.Line; } void mitk::TrackingVolumeGenerator::SetTrackingDeviceData(mitk::TrackingDeviceData deviceData) { m_Data= deviceData; } mitk::TrackingDeviceData mitk::TrackingVolumeGenerator::GetTrackingDeviceData() const { return m_Data; } diff --git a/Modules/IGT/autoload/DeviceRegistry/src/mitkIGTActivator.cpp b/Modules/IGT/autoload/DeviceRegistry/src/mitkIGTActivator.cpp index 8e34c40cd4..9965796486 100644 --- a/Modules/IGT/autoload/DeviceRegistry/src/mitkIGTActivator.cpp +++ b/Modules/IGT/autoload/DeviceRegistry/src/mitkIGTActivator.cpp @@ -1,70 +1,78 @@ /*=================================================================== 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 "mitkIGTConfig.h" #include "mitkIGTActivator.h" //All Tracking devices, which should be available by default #include "mitkNDIAuroraTypeInformation.h" #include "mitkNDIPolarisTypeInformation.h" #include "mitkVirtualTrackerTypeInformation.h" +#ifdef MITK_USE_MICRON_TRACKER #include "mitkMicronTrackerTypeInformation.h" +#endif +#ifdef MITK_USE_OPTITRACK_TRACKER #include "mitkNPOptitrackTrackingTypeInformation.h" +#endif #include "mitkOpenIGTLinkTypeInformation.h" #ifdef MITK_USE_POLHEMUS_TRACKER #include "mitkPolhemusTrackerTypeInformation.h" #endif namespace mitk { IGTActivator::IGTActivator() { } IGTActivator::~IGTActivator() { } void IGTActivator::Load(us::ModuleContext*) { m_DeviceTypeCollection.RegisterTrackingDeviceType(new mitk::NDIAuroraTypeInformation()); m_DeviceTypeCollection.RegisterTrackingDeviceType(new mitk::NDIPolarisTypeInformation()); - m_DeviceTypeCollection.RegisterTrackingDeviceType(new mitk::MicronTrackerTypeInformation()); - m_DeviceTypeCollection.RegisterTrackingDeviceType(new mitk::NPOptitrackTrackingTypeInformation()); m_DeviceTypeCollection.RegisterTrackingDeviceType(new mitk::VirtualTrackerTypeInformation()); m_DeviceTypeCollection.RegisterTrackingDeviceType(new mitk::OpenIGTLinkTypeInformation()); +#ifdef MITK_USE_OPTITRACK_TRACKER + m_DeviceTypeCollection.RegisterTrackingDeviceType(new mitk::NPOptitrackTrackingTypeInformation()); +#endif +#ifdef MITK_USE_MICRON_TRACKER + m_DeviceTypeCollection.RegisterTrackingDeviceType(new mitk::MicronTrackerTypeInformation()); +#endif #ifdef MITK_USE_POLHEMUS_TRACKER m_DeviceTypeCollection.RegisterTrackingDeviceType(new mitk::PolhemusTrackerTypeInformation()); #endif m_DeviceTypeCollection.RegisterAsMicroservice(); } void IGTActivator::Unload(us::ModuleContext*) { try { m_DeviceTypeCollection.UnRegisterMicroservice(); } catch (std::exception& e) { MITK_WARN << "Unable to unregister IGT DeviceTypeCollection Microservice: "< #include #include #include namespace mitk { /**Documentation * \brief Navigation Data * * This class represents the data object that is passed through the MITK-IGT navigation filter * pipeline. It encapsulates position and orientation of a tracked tool/sensor. Additionally, * it contains a data structure that contains error/plausibility information * * It provides methods to work with the affine transformation represented by its orientation and position. * Additionally, it provides a constructor to construct a NavigationData object from an AffineTransform3D and * a getter to create an AffineTransform3D from a NavigationData object. * * \ingroup IGT */ class MITKIGTBASE_EXPORT NavigationData : public itk::DataObject { public: mitkClassMacroItkParent(NavigationData, itk::DataObject); itkFactorylessNewMacro(Self); itkCloneMacro(Self); mitkNewMacro2Param(Self, mitk::AffineTransform3D::Pointer, const bool); mitkNewMacro1Param(Self, mitk::AffineTransform3D::Pointer); /** * \brief Type that holds the position part of the tracking data */ typedef mitk::Point3D PositionType; /** * \brief Type that holds the orientation part of the tracking data */ typedef mitk::Quaternion OrientationType; /** * \brief type that holds the error characterization of the position and orientation measurements */ typedef itk::Matrix CovarianceMatrixType; /** - * \brief type that holds the time at which the data was recorded + * \brief type that holds the time at which the data was recorded in milliseconds */ typedef double TimeStampType; /** * \brief sets the position of the NavigationData object */ itkSetMacro(Position, PositionType); /** * \brief returns position of the NavigationData object */ itkGetConstMacro(Position, PositionType); /** * \brief sets the orientation of the NavigationData object */ itkSetMacro(Orientation, OrientationType); /** * \brief returns the orientation of the NavigationData object */ itkGetConstMacro(Orientation, OrientationType); /** * \brief returns true if the object contains valid data */ virtual bool IsDataValid() const; /** * \brief sets the dataValid flag of the NavigationData object indicating if the object contains valid data */ itkSetMacro(DataValid, bool); /** - * \brief sets the IGT timestamp of the NavigationData object + * \brief sets the IGT timestamp of the NavigationData object in milliseconds */ itkSetMacro(IGTTimeStamp, TimeStampType); /** - * \brief gets the IGT timestamp of the NavigationData object + * \brief gets the IGT timestamp of the NavigationData object in milliseconds * Please note, that there is also the GetTimeStamp method provided by the ITK object. Within IGT you should always use GetIGTTimeStamp ! */ itkGetConstMacro(IGTTimeStamp, TimeStampType); /** * \brief sets the HasPosition flag of the NavigationData object */ itkSetMacro(HasPosition, bool); /** * \brief gets the HasPosition flag of the NavigationData object */ itkGetConstMacro(HasPosition, bool); /** * \brief sets the HasOrientation flag of the NavigationData object */ itkSetMacro(HasOrientation, bool); /** * \brief gets the HasOrientation flag of the NavigationData object */ itkGetConstMacro(HasOrientation, bool); /** * \brief sets the 6x6 Error Covariance Matrix of the NavigationData object */ itkSetMacro(CovErrorMatrix, CovarianceMatrixType); /** * \brief gets the 6x6 Error Covariance Matrix of the NavigationData object */ itkGetConstMacro(CovErrorMatrix, CovarianceMatrixType); /** * \brief set the name of the NavigationData object */ itkSetStringMacro(Name); /** * \brief returns the name of the NavigationData object */ itkGetStringMacro(Name); /** * \brief Graft the data and information from one NavigationData to another. * * Copies the content of data into this object. * This is a convenience method to setup a second NavigationData object with all the meta * information of another NavigationData object. * Note that this method is different than just using two * SmartPointers to the same NavigationData object since separate DataObjects are * still maintained. */ virtual void Graft(const DataObject *data) override; /** * \brief copy meta data of a NavigationData object * * copies all meta data from NavigationData data to this object */ virtual void CopyInformation(const DataObject* data) override; /** * \brief Prints the object information to the given stream os. * \param os The stream which is used to print the output. * \param indent Defines the indentation of the output. */ void PrintSelf(std::ostream& os, itk::Indent indent) const override; /** * Set the position part of m_CovErrorMatrix to I*error^2 * This means that all position variables are assumed to be independent */ void SetPositionAccuracy(mitk::ScalarType error); /** * Set the orientation part of m_CovErrorMatrix to I*error^2 * This means that all orientation variables are assumed to be independent */ void SetOrientationAccuracy(mitk::ScalarType error); /** * \brief Calculate AffineTransform3D from the transformation held by this NavigationData. * TODO: should throw an error if transformation is invalid. */ mitk::AffineTransform3D::Pointer GetAffineTransform3D() const; /** * \brief Calculate the RotationMatrix of this transformation. */ mitk::Matrix3D GetRotationMatrix() const; /** * \brief Transform by an affine transformation * * This method applies the affine transform given by self to a * given point, returning the transformed point. */ mitk::Point3D TransformPoint(const mitk::Point3D point) const; /** * Get inverse of the Transformation represented by this NavigationData. * @throws mitk::Exception in case the transformation is invalid (only case: quaternion is zero) */ mitk::NavigationData::Pointer GetInverse() const; /** Compose with another NavigationData * * This method composes self with another NavigationData of the * same dimension, modifying self to be the composition of self * and other. If the argument pre is true, then other is * precomposed with self; that is, the resulting transformation * consists of first applying other to the source, followed by * self. If pre is false or omitted, then other is post-composed * with self; that is the resulting transformation consists of * first applying self to the source, followed by other. */ void Compose(const mitk::NavigationData::Pointer n, const bool pre = false); protected: mitkCloneMacro(Self); NavigationData(); /* * Copy constructor internally used. */ NavigationData(const mitk::NavigationData& toCopy); /** * Creates a NavigationData object from an affineTransform3D. * Caution: NavigationData doesn't support spacing, only translation and rotation. If the affine * transform includes spacing it cannot be converted to a NavigationData and an exception is thrown. * @param checkForRotationMatrix if this is true, the rotation matrix coming from the affineTransform is checked * for being a rotation matrix. If it isn't, an exception is thrown. Disable this check by * setting checkForRotationMatrix to false. * * @throws mitkException if checkForRotationMatrix is true and a non rotation matrix was introduced by * AffineTransform. */ NavigationData(mitk::AffineTransform3D::Pointer affineTransform3D, const bool checkForRotationMatrix = true); virtual ~NavigationData(); /** * \brief holds the position part of the tracking data */ PositionType m_Position; /** * \brief holds the orientation part of the tracking data */ OrientationType m_Orientation; /** * \brief A 6x6 covariance matrix parameterizing the Gaussian error * distribution of the measured position and orientation. * * The hasPosition/hasOrientation fields define which entries * are valid. */ CovarianceMatrixType m_CovErrorMatrix; ///< holds the error characterization of the position and orientation /** * \brief defines if position part of m_CovErrorMatrix is valid */ bool m_HasPosition; /** * \brief defines if orientation part of m_CovErrorMatrix is valid */ bool m_HasOrientation; /** * \brief defines if the object contains valid values */ bool m_DataValid; /** * \brief contains the time at which the tracking data was recorded */ TimeStampType m_IGTTimeStamp; /** * \brief name of the navigation data */ std::string m_Name; private: void ResetCovarianceValidity(); // pre = false static mitk::NavigationData::Pointer getComposition(const mitk::NavigationData::Pointer nd1, const mitk::NavigationData::Pointer nd2); }; /** * @brief Equal A function comparing two navigation data objects for beeing equal in meta- and imagedata * * @ingroup MITKTestingAPI * * Following aspects are tested for equality: * - position * - orientation * - other members and flags of the class * * @param rightHandSide An NavigationData to be compared * @param leftHandSide An NavigationData to be compared * @param eps Tolarence for comparison. You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @return true, if all subsequent comparisons are true, false otherwise */ MITKIGTBASE_EXPORT bool Equal( const mitk::NavigationData& leftHandSide, const mitk::NavigationData& rightHandSide, ScalarType eps = mitk::eps, bool verbose = false ); } // namespace mitk #endif /* MITKNAVIGATIONDATA_H_HEADER_INCLUDED_ */ diff --git a/Modules/IGTBase/src/mitkNavigationData.cpp b/Modules/IGTBase/src/mitkNavigationData.cpp index d9050923b3..629cbcc928 100644 --- a/Modules/IGTBase/src/mitkNavigationData.cpp +++ b/Modules/IGTBase/src/mitkNavigationData.cpp @@ -1,385 +1,392 @@ /*=================================================================== 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 "mitkNavigationData.h" #include "vnl/vnl_det.h" #include "mitkException.h" mitk::NavigationData::NavigationData() : itk::DataObject(), m_Position(), m_Orientation(0.0, 0.0, 0.0, 1.0), m_CovErrorMatrix(), m_HasPosition(true), m_HasOrientation(true), m_DataValid(false), m_IGTTimeStamp(0.0), m_Name() { m_Position.Fill(0.0); m_CovErrorMatrix.SetIdentity(); } mitk::NavigationData::NavigationData(const mitk::NavigationData& toCopy) : itk::DataObject(), m_Position(toCopy.GetPosition()), m_Orientation(toCopy.GetOrientation()), m_CovErrorMatrix(toCopy.GetCovErrorMatrix()), m_HasPosition(toCopy.GetHasPosition()), m_HasOrientation(toCopy.GetHasOrientation()), m_DataValid(toCopy.IsDataValid()), m_IGTTimeStamp(toCopy.GetIGTTimeStamp()), m_Name(toCopy.GetName()) {/* TODO SW: Graft does the same, remove code duplications, set Graft to deprecated, remove duplication in tescode */} mitk::NavigationData::~NavigationData() { } void mitk::NavigationData::Graft( const DataObject *data ) { // Attempt to cast data to an NavigationData const Self* nd; try { nd = dynamic_cast( data ); } catch( ... ) { itkExceptionMacro( << "mitk::NavigationData::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ); return; } if (!nd) { // pointer could not be cast back down itkExceptionMacro( << "mitk::NavigationData::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ); return; } // Now copy anything that is needed this->SetPosition(nd->GetPosition()); this->SetOrientation(nd->GetOrientation()); this->SetDataValid(nd->IsDataValid()); this->SetIGTTimeStamp(nd->GetIGTTimeStamp()); this->SetHasPosition(nd->GetHasPosition()); this->SetHasOrientation(nd->GetHasOrientation()); this->SetCovErrorMatrix(nd->GetCovErrorMatrix()); this->SetName(nd->GetName()); } bool mitk::NavigationData::IsDataValid() const { - return m_DataValid; + if (m_Position[0] == 0.0 && m_Position[1] == 0.0 && m_Position[2] == 0.0) + { + return false; + } + else + { + return m_DataValid; + } } void mitk::NavigationData::PrintSelf(std::ostream& os, itk::Indent indent) const { this->Superclass::PrintSelf(os, indent); os << indent << "data valid: " << this->IsDataValid() << std::endl; os << indent << "Position: " << this->GetPosition() << std::endl; os << indent << "Orientation: " << this->GetOrientation() << std::endl; os << indent << "TimeStamp: " << this->GetIGTTimeStamp() << std::endl; os << indent << "HasPosition: " << this->GetHasPosition() << std::endl; os << indent << "HasOrientation: " << this->GetHasOrientation() << std::endl; os << indent << "CovErrorMatrix: " << this->GetCovErrorMatrix() << std::endl; } void mitk::NavigationData::CopyInformation( const DataObject* data ) { this->Superclass::CopyInformation( data ); const Self * nd = nullptr; try { nd = dynamic_cast(data); } catch( ... ) { // data could not be cast back down itkExceptionMacro(<< "mitk::NavigationData::CopyInformation() cannot cast " << typeid(data).name() << " to " << typeid(Self*).name() ); } if ( !nd ) { // pointer could not be cast back down itkExceptionMacro(<< "mitk::NavigationData::CopyInformation() cannot cast " << typeid(data).name() << " to " << typeid(Self*).name() ); } /* copy all meta data */ } void mitk::NavigationData::SetPositionAccuracy(mitk::ScalarType error) { for ( int i = 0; i < 3; i++ ) for ( int j = 0; j < 3; j++ ) { m_CovErrorMatrix[ i ][ j ] = 0; // assume independence of position and orientation m_CovErrorMatrix[ i + 3 ][ j ] = 0; m_CovErrorMatrix[ i ][ j + 3 ] = 0; } m_CovErrorMatrix[0][0] = m_CovErrorMatrix[1][1] = m_CovErrorMatrix[2][2] = error * error; } void mitk::NavigationData::SetOrientationAccuracy(mitk::ScalarType error) { for ( int i = 0; i < 3; i++ ) for ( int j = 0; j < 3; j++ ) { m_CovErrorMatrix[ i + 3 ][ j + 3 ] = 0; // assume independence of position and orientation m_CovErrorMatrix[ i + 3 ][ j ] = 0; m_CovErrorMatrix[ i ][ j + 3 ] = 0; } m_CovErrorMatrix[3][3] = m_CovErrorMatrix[4][4] = m_CovErrorMatrix[5][5] = error * error; } void mitk::NavigationData::Compose(const mitk::NavigationData::Pointer n, const bool pre) { NavigationData::Pointer nd3; if (!pre) nd3 = getComposition(this, n); else nd3 = getComposition(n, this); this->Graft(nd3); } mitk::NavigationData::NavigationData( mitk::AffineTransform3D::Pointer affineTransform3D, const bool checkForRotationMatrix) : itk::DataObject(), m_Position(), m_CovErrorMatrix(), m_HasPosition(true), m_HasOrientation(true), m_DataValid(true), m_IGTTimeStamp(0.0), m_Name() { mitk::Vector3D offset = affineTransform3D->GetOffset(); m_Position[0] = offset[0]; m_Position[1] = offset[1]; m_Position[2] = offset[2]; vnl_matrix_fixed rotationMatrix = affineTransform3D->GetMatrix().GetVnlMatrix(); vnl_matrix_fixed rotationMatrixTransposed = rotationMatrix.transpose(); if (checkForRotationMatrix) { // a quadratic matrix is a rotation matrix exactly when determinant is 1 and transposed is inverse if (!Equal(1.0, vnl_det(rotationMatrix), 0.1) || !((rotationMatrix*rotationMatrixTransposed).is_identity(0.1))) { mitkThrow() << "tried to initialize NavigationData with non-rotation matrix :" << rotationMatrix << " (Does your AffineTransform3D object include spacing? This is not supported by NavigationData objects!)"; } } // the transpose is because vnl_quaterion expects a transposed rotation matrix m_Orientation = Quaternion(rotationMatrixTransposed); } mitk::AffineTransform3D::Pointer mitk::NavigationData::GetAffineTransform3D() const { AffineTransform3D::Pointer affineTransform3D = AffineTransform3D::New(); // first set rotation affineTransform3D->SetMatrix(this->GetRotationMatrix()); // now set offset Vector3D vector3D; for (int i = 0; i < 3; ++i) { vector3D[i] = m_Position[i]; } affineTransform3D->SetOffset(vector3D); return affineTransform3D; } mitk::Matrix3D mitk::NavigationData::GetRotationMatrix() const { vnl_matrix_fixed vnl_rotation = m_Orientation.rotation_matrix_transpose().transpose(); // :-) Matrix3D mitkRotation; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { mitkRotation[i][j] = vnl_rotation[i][j]; } } return mitkRotation; } mitk::Point3D mitk::NavigationData::TransformPoint(const mitk::Point3D point) const { vnl_vector_fixed vnlPoint; for (int i = 0; i < 3; ++i) { vnlPoint[i] = point[i]; } Quaternion normalizedQuaternion = this->GetOrientation().normalize(); // first get rotated point vnlPoint = normalizedQuaternion.rotate(vnlPoint); Point3D resultingPoint; for (int i = 0; i < 3; ++i) { // now copy it to our format + offset resultingPoint[i] = vnlPoint[i] + this->GetPosition()[i]; } return resultingPoint; } mitk::NavigationData::Pointer mitk::NavigationData::GetInverse() const { // non-zero quaternion does not have inverse: throw exception in this case. Quaternion zeroQuaternion; zeroQuaternion.fill(0); if (Equal(zeroQuaternion, this->GetOrientation())) mitkThrow() << "tried to invert zero quaternion in NavigationData"; mitk::NavigationData::Pointer navigationDataInverse = this->Clone(); navigationDataInverse->SetOrientation(this->GetOrientation().inverse()); // To vnl_vector vnl_vector_fixed vnlPoint; for (int i = 0; i < 3; ++i) { vnlPoint[i] = this->GetPosition()[i]; } // invert position vnlPoint = -(navigationDataInverse->GetOrientation().rotate(vnlPoint)); // back to Point3D Point3D invertedPosition = this->GetPosition(); for (int i = 0; i < 3; ++i) { invertedPosition[i] = vnlPoint[i]; } navigationDataInverse->SetPosition(invertedPosition); // Inversion does not care for covariances for now navigationDataInverse->ResetCovarianceValidity(); return navigationDataInverse; } void mitk::NavigationData::ResetCovarianceValidity() { this->SetHasPosition(false); this->SetHasOrientation(false); } mitk::NavigationData::Pointer mitk::NavigationData::getComposition(const mitk::NavigationData::Pointer nd1, const mitk::NavigationData::Pointer nd2) { NavigationData::Pointer nd3 = nd1->Clone(); // A2 * A1 nd3->SetOrientation(nd2->GetOrientation() * nd1->GetOrientation()); // first: b1, b2 vnl vector vnl_vector_fixed b1, b2, b3; for (int i = 0; i < 3; ++i) { b1[i] = nd1->GetPosition()[i]; b2[i] = nd2->GetPosition()[i]; } // b3 = A2b1 + b2 b3 = nd2->GetOrientation().rotate(b1) + b2; // back to mitk::Point3D Point3D point; for (int i = 0; i < 3; ++i) { point[i] = b3[i]; } nd3->SetPosition(point); nd3->ResetCovarianceValidity(); return nd3; } bool mitk::Equal(const mitk::NavigationData& leftHandSide, const mitk::NavigationData& rightHandSide, ScalarType eps, bool verbose) { bool returnValue = true; // Dimensionality if( !mitk::Equal(rightHandSide.GetPosition(), leftHandSide.GetPosition(), eps) ) { if(verbose) { MITK_INFO << "[( NavigationData )] Position differs."; MITK_INFO << "leftHandSide is " << leftHandSide.GetPosition() << "rightHandSide is " << rightHandSide.GetPosition(); } returnValue = false; } // Dimensionality if( !mitk::Equal(rightHandSide.GetOrientation(), leftHandSide.GetOrientation(), eps) ) { if(verbose) { MITK_INFO << "[( NavigationData )] Orientation differs."; MITK_INFO << "leftHandSide is " << leftHandSide.GetOrientation() << "rightHandSide is " << rightHandSide.GetOrientation(); } returnValue = false; } if( rightHandSide.GetCovErrorMatrix() != leftHandSide.GetCovErrorMatrix() ) { if(verbose) { MITK_INFO << "[( NavigationData )] CovErrorMatrix differs."; MITK_INFO << "leftHandSide is " << leftHandSide.GetCovErrorMatrix() << "rightHandSide is " << rightHandSide.GetCovErrorMatrix(); } returnValue = false; } if( std::string(rightHandSide.GetName()) != std::string(leftHandSide.GetName()) ) { if(verbose) { MITK_INFO << "[( NavigationData )] Name differs."; MITK_INFO << "leftHandSide is " << leftHandSide.GetName() << "rightHandSide is " << rightHandSide.GetName(); } returnValue = false; } if( rightHandSide.GetIGTTimeStamp() != leftHandSide.GetIGTTimeStamp() ) { if(verbose) { MITK_INFO << "[( NavigationData )] IGTTimeStamp differs."; MITK_INFO << "leftHandSide is " << leftHandSide.GetIGTTimeStamp() << "rightHandSide is " << rightHandSide.GetIGTTimeStamp(); } returnValue = false; } return returnValue; } diff --git a/Modules/IGTUI/Qmitk/QmitkIGTCommonHelper.cpp b/Modules/IGTUI/Qmitk/QmitkIGTCommonHelper.cpp new file mode 100644 index 0000000000..b5ca3695ea --- /dev/null +++ b/Modules/IGTUI/Qmitk/QmitkIGTCommonHelper.cpp @@ -0,0 +1,70 @@ +/*=================================================================== + +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 + +const std::string QmitkIGTCommonHelper::VIEW_ID = "org.mitk.views.igtcommonhelper"; + +void QmitkIGTCommonHelper::SetLastFileSavePath(const QString &str) +{ + QSettings settings; + settings.beginGroup(QString::fromStdString(QmitkIGTCommonHelper::VIEW_ID)); + settings.setValue("LastFileSavePath",QVariant(str)); + settings.endGroup(); +} + +void QmitkIGTCommonHelper::SetLastFileSavePathByFileName(const QString &str) +{ + QFileInfo file(str); + SetLastFileSavePath(file.absolutePath()); +} + +const QString QmitkIGTCommonHelper::GetLastFileSavePath() +{ + QString path = ""; + QSettings settings; + settings.beginGroup(QString::fromStdString(QmitkIGTCommonHelper::VIEW_ID)); + path = settings.value("LastFileSavePath",QString("")).toString(); + settings.endGroup(); + + return path; +} + +void QmitkIGTCommonHelper::SetLastFileLoadPath(const QString &str) +{ + QSettings settings; + settings.beginGroup(QString::fromStdString(QmitkIGTCommonHelper::VIEW_ID)); + settings.setValue("LastFileLoadPath",QVariant(str)); + settings.endGroup(); +} + +void QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(const QString &str) +{ + QFileInfo file(str); + SetLastFileLoadPath(file.absolutePath()); +} + +const QString QmitkIGTCommonHelper::GetLastFileLoadPath() +{ + QString path = ""; + QSettings settings; + settings.beginGroup(QString::fromStdString(QmitkIGTCommonHelper::VIEW_ID)); + path = settings.value("LastFileLoadPath",QString("")).toString(); + settings.endGroup(); + + return path; +} diff --git a/Modules/IGTUI/Qmitk/QmitkIGTCommonHelper.h b/Modules/IGTUI/Qmitk/QmitkIGTCommonHelper.h new file mode 100644 index 0000000000..2b72ea7290 --- /dev/null +++ b/Modules/IGTUI/Qmitk/QmitkIGTCommonHelper.h @@ -0,0 +1,46 @@ +/*=================================================================== + +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 QmitkIGTCommonHelper_H +#define QmitkIGTCommonHelper_H + +#include "MitkIGTUIExports.h" +#include + + /** Documentation: + * \brief Simple and fast access to a pre-configured TrackingDeviceSource. + * + * \ingroup IGTUI + */ +class MITKIGTUI_EXPORT QmitkIGTCommonHelper +{ + +public: + + static const std::string VIEW_ID; + + static void SetLastFileSavePath(const QString& str); + + static void SetLastFileSavePathByFileName(const QString& str); + + static const QString GetLastFileSavePath(); + + static void SetLastFileLoadPath(const QString& str); + + static void SetLastFileLoadPathByFileName(const QString& str); + + static const QString GetLastFileLoadPath(); +}; +#endif diff --git a/Modules/IGTUI/Qmitk/QmitkIGTConnectionWidget.cpp b/Modules/IGTUI/Qmitk/QmitkIGTConnectionWidget.cpp index b50b126985..d86c9516d2 100644 --- a/Modules/IGTUI/Qmitk/QmitkIGTConnectionWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkIGTConnectionWidget.cpp @@ -1,213 +1,215 @@ /*=================================================================== 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 "QmitkIGTConnectionWidget.h" #include "QmitkTrackingDeviceConfigurationWidget.h" #include "mitkClaronTrackingDevice.h" #include "mitkNDITrackingDevice.h" #include "mitkOptitrackTrackingDevice.h" #include "mitkNavigationToolStorageDeserializer.h" #include "mitkTrackingDeviceSourceConfigurator.h" +#include "QmitkIGTCommonHelper.h" #include #include const std::string QmitkIGTConnectionWidget::VIEW_ID = "org.mitk.views.igtconnectionwidget"; QmitkIGTConnectionWidget::QmitkIGTConnectionWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Controls = nullptr; CreateQtPartControl(this); CreateConnections(); m_TrackingDevice = nullptr; m_TrackingDeviceSource = nullptr; m_NavigationToolStorage = nullptr; m_DataStorage = nullptr; m_ErrorMessage = ""; } QmitkIGTConnectionWidget::~QmitkIGTConnectionWidget() { } void QmitkIGTConnectionWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTConnectionWidgetControls; m_Controls->setupUi(parent); } } void QmitkIGTConnectionWidget::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->connectButton), SIGNAL(clicked()), this, SLOT(OnConnect()) ); } } void QmitkIGTConnectionWidget::OnConnect() { if (m_Controls->connectButton->isChecked()) // Load tools and connect tracking device { m_Controls->connectButton->setChecked(false); // create TrackingDevice m_TrackingDevice = m_Controls->trackingDeviceConfigurationWidget->GetTrackingDevice(); if (m_TrackingDevice.IsNotNull()) { - QString fileName = QFileDialog::getOpenFileName(nullptr,tr("Open Navigation tool storage"), "/", tr("Toolfile (*.tfl)")); + QString fileName = QFileDialog::getOpenFileName(nullptr,tr("Open Navigation tool storage"), QmitkIGTCommonHelper::GetLastFileLoadPath(), tr("Toolfile (*.tfl)")); + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(fileName); if (LoadToolfile(fileName)) { // Create TrackingDeviceSource and add tools mitk::TrackingDeviceSourceConfigurator::Pointer myTrackingDeviceSourceFactory = mitk::TrackingDeviceSourceConfigurator::New(this->m_NavigationToolStorage,m_TrackingDevice); m_TrackingDeviceSource = myTrackingDeviceSourceFactory->CreateTrackingDeviceSource(); m_TrackingDeviceSource->Connect(); m_TrackingDeviceSource->StartTracking(); // change button text m_Controls->connectButton->setText("Disconnect"); m_Controls->connectButton->setChecked(true); // disable configuration widget m_Controls->trackingDeviceConfigurationWidget->setEnabled(false); // emit connected signal emit TrackingDeviceConnected(); } else { QString error(m_ErrorMessage.c_str()); QMessageBox::warning(nullptr,"Warning",error); // reset button to unchecked m_Controls->connectButton->setChecked(false); // remove tool nodes from DataStorage this->RemoveToolNodes(); // reset NavigationToolStorage m_NavigationToolStorage = nullptr; } } else { // reset button to unchecked m_Controls->connectButton->setChecked(false); MITK_ERROR<<"Could not create TrackingDevice"; } } else // Disconnect tracking device { // disconnect TrackingDeviceSource if (m_TrackingDeviceSource.IsNotNull()) { m_TrackingDeviceSource->StopTracking(); m_TrackingDeviceSource->Disconnect(); } // remove tool nodes from DataStorage this->RemoveToolNodes(); // reset members m_NavigationToolStorage = nullptr; m_TrackingDevice = nullptr; m_TrackingDeviceSource = nullptr; // change button text m_Controls->connectButton->setText("Connect"); // enable configuration widget m_Controls->trackingDeviceConfigurationWidget->setEnabled(true); // emit disconnected signal emit TrackingDeviceDisconnected(); } } bool QmitkIGTConnectionWidget::LoadToolfile(QString qFilename) { if (m_DataStorage.IsNotNull()) { std::string filename = qFilename.toStdString(); mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(this->m_DataStorage); mitk::NavigationToolStorage::Pointer tempStorage = myDeserializer->Deserialize(filename); m_NavigationToolStorage = tempStorage; if (tempStorage.IsNull()) { m_ErrorMessage = myDeserializer->GetErrorMessage(); return false; } // check if there are tools in the storage mitk::TrackingDeviceType lastDevice; if (tempStorage->GetToolCount()>0) { lastDevice = tempStorage->GetTool(0)->GetTrackingDeviceType(); } else { m_ErrorMessage = "Error: Didn't find a tool in the storage. Do you want to navigate without even an instrument?"; return false; } //check if all tools are from the same device for (int i=1; iGetToolCount(); i++) { if (lastDevice!=tempStorage->GetTool(i)->GetTrackingDeviceType()) { m_ErrorMessage = "Error: Toolfile contains tools of different tracking devices which is not acceptable for this application."; return false; } else lastDevice = tempStorage->GetTool(i)->GetTrackingDeviceType(); } // check if tracking device typ of tools corresponds with chosen tracking device if (m_TrackingDevice->GetType()!=tempStorage->GetTool(0)->GetTrackingDeviceType()) { m_ErrorMessage = "Tools are not compliant with this tracking device. Please use correct toolfile for specified device."; return false; } m_NavigationToolStorage = tempStorage; return true; } else { m_ErrorMessage = "Error: No DataStorage available! Make sure the widget is initialized with a DataStorage"; return false; } } void QmitkIGTConnectionWidget::RemoveToolNodes() { for (int i=0; iGetToolCount(); i++) { mitk::DataNode::Pointer currentNode = m_NavigationToolStorage->GetTool(i)->GetDataNode(); if (currentNode.IsNotNull()) { m_DataStorage->Remove(currentNode); } } } mitk::TrackingDeviceSource::Pointer QmitkIGTConnectionWidget::GetTrackingDeviceSource() { return m_TrackingDeviceSource; } void QmitkIGTConnectionWidget::SetDataStorage( mitk::DataStorage::Pointer dataStorage ) { m_DataStorage = dataStorage; } mitk::NavigationToolStorage::Pointer QmitkIGTConnectionWidget::GetNavigationToolStorage() { return m_NavigationToolStorage; } diff --git a/Modules/IGTUI/Qmitk/QmitkIGTPlayerWidget.cpp b/Modules/IGTUI/Qmitk/QmitkIGTPlayerWidget.cpp index d607dbf839..6d751ce80f 100644 --- a/Modules/IGTUI/Qmitk/QmitkIGTPlayerWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkIGTPlayerWidget.cpp @@ -1,573 +1,575 @@ /*=================================================================== 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 "QmitkIGTPlayerWidget.h" //mitk headers #include "mitkTrackingTypes.h" #include #include #include #include #include #include #include #include +#include //qt headers #include #include #include QmitkIGTPlayerWidget::QmitkIGTPlayerWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_RealTimePlayer(mitk::NavigationDataPlayer::New()), m_SequentialPlayer(mitk::NavigationDataSequentialPlayer::New()), m_StartTime(-1.0), m_CurrentSequentialPointNumber(0), m_Controls(new Ui::QmitkIGTPlayerWidgetControls) { m_Controls->setupUi(this); m_PlayingTimer = new QTimer(this); // initialize update timer CreateConnections(); m_Controls->samplePositionHorizontalSlider->setVisible(false); this->ResetLCDNumbers(); // reset lcd numbers at start } QmitkIGTPlayerWidget::~QmitkIGTPlayerWidget() { m_PlayingTimer->stop(); delete m_Controls; } void QmitkIGTPlayerWidget::CreateConnections() { connect( (QObject*)(m_Controls->playPushButton), SIGNAL(clicked(bool)), this, SLOT(OnPlayButtonClicked(bool)) ); // play button connect( (QObject*)(m_PlayingTimer), SIGNAL(timeout()), this, SLOT(OnPlaying()) ); // update timer connect( (QObject*) (m_Controls->beginPushButton), SIGNAL(clicked()), this, SLOT(OnGoToBegin()) ); // reset player and go to begin connect( (QObject*) (m_Controls->stopPushButton), SIGNAL(clicked()), this, SLOT(OnGoToEnd()) ); // reset player // pass this widgets protected combobox signal to public signal connect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) ); // pass this widgets protected checkbox signal to public signal connect( m_Controls->splineModeCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(SignalSplineModeToggled(bool)) ); //connect( m_Controls->sequencialModeCheckBox, SIGNAL(toggled(bool)), this, SLOT(OnSequencialModeToggled(bool)) ); connect( m_Controls->samplePositionHorizontalSlider, SIGNAL(sliderPressed()), this, SLOT(OnSliderPressed()) ); connect( m_Controls->samplePositionHorizontalSlider, SIGNAL(sliderReleased()), this, SLOT(OnSliderReleased()) ); connect( m_Controls->m_OpenFileButton, SIGNAL(clicked()), this, SLOT(OnOpenFileButtonPressed()) ); } bool QmitkIGTPlayerWidget::IsTrajectoryInSplineMode() { return m_Controls->splineModeCheckBox->isChecked(); } bool QmitkIGTPlayerWidget::CheckInputFileValid() { QFile file(m_CmpFilename); // check if file exists if(!file.exists()) { QMessageBox::warning(nullptr, "IGTPlayer: Error", "No valid input file was loaded. Please load input file first!"); return false; } return true; } unsigned int QmitkIGTPlayerWidget::GetNumberOfTools() { unsigned int result = 0; if(this->GetCurrentPlaybackMode() == RealTimeMode) { if(m_RealTimePlayer.IsNotNull()) result = m_RealTimePlayer->GetNumberOfOutputs(); } else if(this->GetCurrentPlaybackMode() == SequentialMode) { if(m_SequentialPlayer.IsNotNull()) result = m_SequentialPlayer->GetNumberOfOutputs(); } // at the moment this works only if player is initialized return result; } void QmitkIGTPlayerWidget::SetUpdateRate(unsigned int msecs) { m_PlayingTimer->setInterval((int) msecs); // set update timer update rate } void QmitkIGTPlayerWidget::OnPlayButtonClicked(bool checked) { if ( ! checked ) { if ( this->GetCurrentPlaybackMode() == RealTimeMode ) { m_RealTimePlayer->StopPlaying(); } else if ( this->GetCurrentPlaybackMode() == SequentialMode ) { // m_SequentialPlayer-> } } if(CheckInputFileValid()) // no playing possible without valid input file { switch ( this->GetCurrentPlaybackMode() ) { case RealTimeMode: { break; } case SequentialMode: { break; } } PlaybackMode currentMode = this->GetCurrentPlaybackMode(); bool isRealTimeMode = currentMode == RealTimeMode; bool isSequentialMode = currentMode == SequentialMode; if(checked) // play { if( (isRealTimeMode && m_RealTimePlayer.IsNull()) || (isSequentialMode && m_SequentialPlayer.IsNull())) // start play { mitk::NavigationDataSet::Pointer navigationDataSet; try { navigationDataSet = dynamic_cast (mitk::IOUtil::LoadBaseData(m_CmpFilename.toStdString()).GetPointer()); } catch(mitk::IGTException) { std::string errormessage = "Error during start playing. Invalid or wrong file?"; QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str()); m_Controls->playPushButton->setChecked(false); m_RealTimePlayer = nullptr; return; } if(isRealTimeMode) { m_RealTimePlayer = mitk::NavigationDataPlayer::New(); m_RealTimePlayer->SetNavigationDataSet(navigationDataSet); try { m_RealTimePlayer->StartPlaying(); } catch(mitk::IGTException) { std::string errormessage = "Error during start playing. Invalid or wrong file?"; QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str()); m_Controls->playPushButton->setChecked(false); m_RealTimePlayer = nullptr; return; } } else if(isSequentialMode) { m_SequentialPlayer = mitk::NavigationDataSequentialPlayer::New(); try { m_SequentialPlayer->SetNavigationDataSet(navigationDataSet); } catch(mitk::IGTException) { std::string errormessage = "Error during start playing. Invalid or wrong file type?"; QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str()); m_Controls->playPushButton->setChecked(false); m_RealTimePlayer = nullptr; return; } m_Controls->samplePositionHorizontalSlider->setMinimum(0); m_Controls->samplePositionHorizontalSlider->setMaximum(m_SequentialPlayer->GetNumberOfSnapshots()); m_Controls->samplePositionHorizontalSlider->setEnabled(true); } m_PlayingTimer->start(100); emit SignalPlayingStarted(); } else // resume play { if(isRealTimeMode) m_RealTimePlayer->Resume(); m_PlayingTimer->start(100); emit SignalPlayingResumed(); } } else // pause { if(isRealTimeMode) m_RealTimePlayer->Pause(); m_PlayingTimer->stop(); emit SignalPlayingPaused(); } } else { m_Controls->playPushButton->setChecked(false); // uncheck play button if file unvalid } } QmitkIGTPlayerWidget::PlaybackMode QmitkIGTPlayerWidget::GetCurrentPlaybackMode() { /*if(m_Controls->sequencialModeCheckBox->isChecked()) return SequentialMode; else*/ return RealTimeMode; } QTimer* QmitkIGTPlayerWidget::GetPlayingTimer() { return m_PlayingTimer; } void QmitkIGTPlayerWidget::OnStopPlaying() { this->StopPlaying(); } void QmitkIGTPlayerWidget::StopPlaying() { m_PlayingTimer->stop(); emit SignalPlayingStopped(); if(m_RealTimePlayer.IsNotNull()) m_RealTimePlayer->StopPlaying(); m_StartTime = -1; // set starttime back m_CurrentSequentialPointNumber = 0; m_Controls->samplePositionHorizontalSlider->setSliderPosition(m_CurrentSequentialPointNumber); m_Controls->sampleLCDNumber->display(static_cast(m_CurrentSequentialPointNumber)); this->ResetLCDNumbers(); m_Controls->playPushButton->setChecked(false); // set play button unchecked } void QmitkIGTPlayerWidget::OnPlaying() { switch ( this->GetCurrentPlaybackMode() ) { case RealTimeMode: { if ( m_RealTimePlayer.IsNull() ) { return; } if ( m_StartTime < 0 ) { // get playback start time m_StartTime = m_RealTimePlayer->GetOutput()->GetTimeStamp(); } if( ! m_RealTimePlayer->IsAtEnd() ) { m_RealTimePlayer->Update(); // update player int msc = (int) (m_RealTimePlayer->GetOutput()->GetTimeStamp() - m_StartTime); // calculation for playing time display int ms = msc % 1000; msc = (msc - ms) / 1000; int s = msc % 60; int min = (msc-s) / 60; // set lcd numbers m_Controls->msecLCDNumber->display(ms); m_Controls->secLCDNumber->display(s); m_Controls->minLCDNumber->display(min); emit SignalPlayerUpdated(); // player successfully updated } else { this->StopPlaying(); // if player is at EOF } break; } case SequentialMode: { if ( m_SequentialPlayer.IsNull() ) { return; } if ( m_CurrentSequentialPointNumber < m_SequentialPlayer->GetNumberOfSnapshots() ) { m_SequentialPlayer->Update(); // update sequential player m_Controls->samplePositionHorizontalSlider->setSliderPosition(m_CurrentSequentialPointNumber++); // refresh slider position m_Controls->sampleLCDNumber->display(static_cast(m_CurrentSequentialPointNumber)); //for debugging purposes //std::cout << "Sample: " << m_CurrentSequentialPointNumber << " X: " << m_SequentialPlayer->GetOutput()->GetPosition()[0] << " Y: " << m_SequentialPlayer->GetOutput()->GetPosition()[1] << " Y: " << m_SequentialPlayer->GetOutput()->GetPosition()[2] << std::endl; emit SignalPlayerUpdated(); // player successfully updated } else { this->StopPlaying(); // if player is at EOF } break; } } } const std::vector QmitkIGTPlayerWidget::GetNavigationDatas() { std::vector navDatas; if(this->GetCurrentPlaybackMode() == RealTimeMode && m_RealTimePlayer.IsNotNull()) { for(unsigned int i=0; i < m_RealTimePlayer->GetNumberOfOutputs(); ++i) { navDatas.push_back(m_RealTimePlayer->GetOutput(i)); // push back current navigation data for each tool } } else if(this->GetCurrentPlaybackMode() == SequentialMode && m_SequentialPlayer.IsNotNull()) { for(unsigned int i=0; i < m_SequentialPlayer->GetNumberOfOutputs(); ++i) { navDatas.push_back(m_SequentialPlayer->GetOutput(i)); // push back current navigation data for each tool } } return navDatas; } const mitk::PointSet::Pointer QmitkIGTPlayerWidget::GetNavigationDatasPointSet() { mitk::PointSet::Pointer result = mitk::PointSet::New(); mitk::PointSet::PointType pointType; PlaybackMode currentMode = this->GetCurrentPlaybackMode(); bool isRealTimeMode = currentMode == RealTimeMode; bool isSequentialMode = currentMode == SequentialMode; if( (isRealTimeMode && m_RealTimePlayer.IsNotNull()) || (isSequentialMode && m_SequentialPlayer.IsNotNull())) { int numberOfOutputs = 0; if(isRealTimeMode) numberOfOutputs = m_RealTimePlayer->GetNumberOfOutputs(); else if(isSequentialMode) numberOfOutputs = m_SequentialPlayer->GetNumberOfOutputs(); for(unsigned int i=0; i < m_RealTimePlayer->GetNumberOfOutputs(); ++i) { mitk::NavigationData::PositionType position; if(isRealTimeMode) position = m_RealTimePlayer->GetOutput(i)->GetPosition(); else if(isSequentialMode) position = m_SequentialPlayer->GetOutput(i)->GetPosition(); pointType[0] = position[0]; pointType[1] = position[1]; pointType[2] = position[2]; result->InsertPoint(i,pointType); // insert current ND as Pointtype in PointSet for return } } return result; } const mitk::PointSet::PointType QmitkIGTPlayerWidget::GetNavigationDataPoint(unsigned int index) { if( index > this->GetNumberOfTools() || index < 0 ) throw std::out_of_range("Tool Index out of range!"); PlaybackMode currentMode = this->GetCurrentPlaybackMode(); bool isRealTimeMode = currentMode == RealTimeMode; bool isSequentialMode = currentMode == SequentialMode; // create return PointType from current ND for tool index mitk::PointSet::PointType result; if( (isRealTimeMode && m_RealTimePlayer.IsNotNull()) || (isSequentialMode && m_SequentialPlayer.IsNotNull())) { mitk::NavigationData::PositionType position; if(isRealTimeMode) position = m_RealTimePlayer->GetOutput(index)->GetPosition(); else if(isSequentialMode) position = m_SequentialPlayer->GetOutput(index)->GetPosition(); result[0] = position[0]; result[1] = position[1]; result[2] = position[2]; } return result; } /*void QmitkIGTPlayerWidget::SetRealTimePlayer( mitk::NavigationDataPlayer::Pointer player ) { if(player.IsNotNull()) m_RealTimePlayer = player; } void QmitkIGTPlayerWidget::SetSequentialPlayer( mitk::NavigationDataSequentialPlayer::Pointer player ) { if(player.IsNotNull()) m_SequentialPlayer = player; }*/ void QmitkIGTPlayerWidget::OnOpenFileButtonPressed() { - QString filename = QFileDialog::getOpenFileName(this, "Load tracking data", QDir::currentPath(),"XML files (*.xml)"); + QString filename = QFileDialog::getOpenFileName(this, "Load tracking data", QmitkIGTCommonHelper::GetLastFileLoadPath(),"XML files (*.xml)"); QFile file(filename); + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(filename); // if something went wrong or user pressed cancel in the save dialog if ( filename.isEmpty() || ! file.exists() ) { QMessageBox::warning(nullptr, "Warning", QString("Please enter valid path. Using previous path again.")); return; } m_CmpFilename = filename; this->OnGoToEnd(); /// stops playing and resets lcd numbers m_Controls->m_ActiveFileLabel->setText(m_CmpFilename); emit SignalInputFileChanged(); mitk::NavigationDataSet::Pointer navigationDataSet = dynamic_cast (mitk::IOUtil::LoadBaseData(m_CmpFilename.toStdString()).GetPointer()); m_RealTimePlayer->SetNavigationDataSet(navigationDataSet); m_SequentialPlayer->SetNavigationDataSet(navigationDataSet); m_Controls->m_PlayerControlsGroupBox->setEnabled(true); } void QmitkIGTPlayerWidget::OnGoToEnd() { this->StopPlaying(); // reset lcd numbers this->ResetLCDNumbers(); } void QmitkIGTPlayerWidget::OnGoToBegin() { // stop player manual so no PlayingStopped() m_PlayingTimer->stop(); if(this->GetCurrentPlaybackMode() == RealTimeMode && m_RealTimePlayer.IsNotNull()) { m_RealTimePlayer->StopPlaying(); m_RealTimePlayer = nullptr; // set player to nullptr so it can be initialized again if playback is called afterwards } m_StartTime = -1; // set starttime back //reset view elements m_Controls->playPushButton->setChecked(false); this->ResetLCDNumbers(); } void QmitkIGTPlayerWidget::ResetLCDNumbers() { m_Controls->minLCDNumber->display(QString("00")); m_Controls->secLCDNumber->display(QString("00")); m_Controls->msecLCDNumber->display(QString("000")); } void QmitkIGTPlayerWidget::SetTrajectoryNames(const QStringList toolNames) { QComboBox* cBox = m_Controls->trajectorySelectComboBox; if(cBox->count() > 0) this->ClearTrajectorySelectCombobox(); // before making changed to QComboBox it is recommended to disconnet it's SIGNALS and SLOTS disconnect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) ); if(!toolNames.isEmpty()) m_Controls->trajectorySelectComboBox->insertItems(0, toolNames); // adding current tool names to combobox // reconnect after performed changes connect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) ); } int QmitkIGTPlayerWidget::GetResolution() { return m_Controls->resolutionSpinBox->value(); // return currently selected trajectory resolution } void QmitkIGTPlayerWidget::ClearTrajectorySelectCombobox() { // before making changed to QComboBox it is recommended to disconnet it's SIGNALS and SLOTS disconnect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) ); m_Controls->trajectorySelectComboBox->clear(); // reconnect after performed changes connect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) ); } void QmitkIGTPlayerWidget::OnSequencialModeToggled(bool toggled) { this->StopPlaying(); // stop playing when mode is changed if(toggled) { m_Controls->samplePositionHorizontalSlider->setEnabled(true); // enable slider if sequential mode } else if(!toggled) { m_Controls->samplePositionHorizontalSlider->setSliderPosition(0); // set back and disable slider m_Controls->samplePositionHorizontalSlider->setDisabled(true); } } void QmitkIGTPlayerWidget::OnSliderReleased() { int currentSliderValue = m_Controls->samplePositionHorizontalSlider->value(); // current slider value selected through user movement if(currentSliderValue > static_cast(m_CurrentSequentialPointNumber)) // at the moment only forward scrolling is possible { auto snapshotNumber = static_cast(currentSliderValue); m_SequentialPlayer->GoToSnapshot(snapshotNumber); // move player to selected snapshot m_CurrentSequentialPointNumber = currentSliderValue; m_Controls->sampleLCDNumber->display(currentSliderValue); // update lcdnumber in widget } else m_Controls->samplePositionHorizontalSlider->setValue(m_CurrentSequentialPointNumber); } void QmitkIGTPlayerWidget::OnSliderPressed() { if(m_Controls->playPushButton->isChecked()) // check if widget is playing m_Controls->playPushButton->click(); // perform click to pause the play } diff --git a/Modules/IGTUI/Qmitk/QmitkMicronTrackerWidget.cpp b/Modules/IGTUI/Qmitk/QmitkMicronTrackerWidget.cpp index 3d0842916b..953b1c1ed0 100644 --- a/Modules/IGTUI/Qmitk/QmitkMicronTrackerWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkMicronTrackerWidget.cpp @@ -1,168 +1,171 @@ /*=================================================================== 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 "QmitkMicronTrackerWidget.h" #include #include #include #include #include #include +#include + const std::string QmitkMicronTrackerWidget::VIEW_ID = "org.mitk.views.NDIMicronTrackerWidget"; QmitkMicronTrackerWidget::QmitkMicronTrackerWidget(QWidget* parent, Qt::WindowFlags f) : QmitkAbstractTrackingDeviceWidget(parent, f) , m_Controls(nullptr) { } void QmitkMicronTrackerWidget::Initialize() { InitializeSuperclassWidget(); CreateQtPartControl(this); CreateConnections(); m_MTCalibrationFile = ""; } QmitkMicronTrackerWidget::~QmitkMicronTrackerWidget() { delete m_Controls; } void QmitkMicronTrackerWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkMicronTrackerWidget; m_Controls->setupUi(parent); } } void QmitkMicronTrackerWidget::CreateConnections() { if (m_Controls) { connect((QObject*)(m_Controls->m_testConnectionMicronTracker), SIGNAL(clicked()), this, SLOT(TestConnection())); connect((QObject*)(m_Controls->m_SetMTCalibrationFile), SIGNAL(clicked()), this, SLOT(SetMTCalibrationFileClicked())); } } void QmitkMicronTrackerWidget::ResetOutput() { m_Controls->m_outputTextMicronTracker->setHtml("output:"); } void QmitkMicronTrackerWidget::AddOutput(std::string s) { m_Controls->m_outputTextMicronTracker->setHtml(QString(s.c_str())); m_Controls->m_outputTextMicronTracker->verticalScrollBar()->setValue(m_Controls->m_outputTextMicronTracker->verticalScrollBar()->maximum()); } mitk::TrackingDevice::Pointer QmitkMicronTrackerWidget::ConstructTrackingDevice() { mitk::ClaronTrackingDevice::Pointer newDevice = mitk::ClaronTrackingDevice::New(); if (this->m_MTCalibrationFile.empty()) //if configuration file for MicronTracker is empty: load default { mitk::ClaronTrackingDevice::Pointer tempDevice = mitk::ClaronTrackingDevice::New(); m_MTCalibrationFile = tempDevice->GetCalibrationDir(); Poco::Path myPath = Poco::Path(m_MTCalibrationFile.c_str()); m_Controls->m_MTCalibrationFile->setText("Calibration File: " + QString(myPath.getFileName().c_str())); } if (!this->m_MTCalibrationFile.empty()) { //extract path from calibration file and set the calibration dir of the device std::string path = itksys::SystemTools::GetFilenamePath(m_MTCalibrationFile); newDevice->SetCalibrationDir(path); } else AddOutput("
Warning: Calibration file is not set!"); return static_cast(newDevice); } void QmitkMicronTrackerWidget::StoreUISettings() { std::string id = "org.mitk.modules.igt.ui.trackingdeviceconfigurationwidget"; if (this->GetPersistenceService()) // now save the settings using the persistence service { mitk::PropertyList::Pointer propList = this->GetPersistenceService()->GetPropertyList(id); propList->Set("MTCalibrationFile", m_MTCalibrationFile); } else // QSettings as a fallback if the persistence service is not available { QSettings settings; settings.beginGroup(QString::fromStdString(id)); settings.setValue("mTCalibrationFile", QVariant(QString::fromStdString(m_MTCalibrationFile))); settings.endGroup(); } } void QmitkMicronTrackerWidget::LoadUISettings() { std::string id = "org.mitk.modules.igt.ui.trackingdeviceconfigurationwidget"; if (this->GetPersistenceService()) { mitk::PropertyList::Pointer propList = this->GetPersistenceService()->GetPropertyList(id); if (propList.IsNull()) { MITK_ERROR << "Property list for this UI (" << id << ") is not available, could not load UI settings!"; return; } propList->Get("MTCalibrationFile", m_MTCalibrationFile); } else { // QSettings as a fallback if the persistence service is not available QSettings settings; settings.beginGroup(QString::fromStdString(id)); m_MTCalibrationFile = settings.value("mTCalibrationFile", "").toString().toStdString(); settings.endGroup(); } m_Controls->m_MTCalibrationFile->setText("Calibration File: " + QString::fromStdString(m_MTCalibrationFile)); } bool QmitkMicronTrackerWidget::IsDeviceInstalled() { return mitk::ClaronTrackingDevice::New()->IsDeviceInstalled(); } void QmitkMicronTrackerWidget::SetMTCalibrationFileClicked() { - std::string filename = QFileDialog::getOpenFileName(nullptr, tr("Open Calibration File"), "/", "*.*").toLatin1().data(); + std::string filename = QFileDialog::getOpenFileName(nullptr, tr("Open Calibration File"), QmitkIGTCommonHelper::GetLastFileLoadPath(), "*.*").toLatin1().data(); if (filename == "") { return; } else { + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(QString::fromStdString(filename)); m_MTCalibrationFile = filename; Poco::Path myPath = Poco::Path(m_MTCalibrationFile.c_str()); m_Controls->m_MTCalibrationFile->setText("Calibration File: " + QString(myPath.getFileName().c_str())); } } QmitkMicronTrackerWidget* QmitkMicronTrackerWidget::Clone(QWidget* parent) const { QmitkMicronTrackerWidget* clonedWidget = new QmitkMicronTrackerWidget(parent); clonedWidget->Initialize(); clonedWidget->m_MTCalibrationFile = m_MTCalibrationFile; m_Controls->m_MTCalibrationFile->setText("Calibration File: " + QString::fromStdString(m_MTCalibrationFile)); return clonedWidget; } diff --git a/Modules/IGTUI/Qmitk/QmitkNDIConfigurationWidget.cpp b/Modules/IGTUI/Qmitk/QmitkNDIConfigurationWidget.cpp index 3019ef64cf..d90e459440 100644 --- a/Modules/IGTUI/Qmitk/QmitkNDIConfigurationWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkNDIConfigurationWidget.cpp @@ -1,886 +1,893 @@ /*=================================================================== 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 "QmitkNDIConfigurationWidget.h" #include #include #include #include #include #include #include #include #include #include +#include #include "QmitkCustomVariants.h" //#include #include "QmitkNDIToolDelegate.h" #include "mitkNDIAuroraTypeInformation.h" #include "mitkNDIPolarisTypeInformation.h" /* VIEW MANAGEMENT */ QmitkNDIConfigurationWidget::QmitkNDIConfigurationWidget(QWidget* parent) : QWidget(parent), m_Controls(nullptr), m_Tracker(nullptr), m_Source(nullptr), m_Delegate(nullptr), m_SROMCellDefaultText(""), m_RepresentatonCellDefaultText("") { this->CreateQtPartControl(this); } QmitkNDIConfigurationWidget::~QmitkNDIConfigurationWidget() { m_Controls = nullptr; m_Tracker = nullptr; m_Source = nullptr; } void QmitkNDIConfigurationWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkNDIConfigurationWidget; m_Controls->setupUi(parent); QStringList comPorts; #ifdef WIN32 comPorts << "COM1" << "COM2" << "COM3" << "COM4" << "COM5" << "COM6" << "COM7" << "COM8" << "COM9"; #else comPorts << "/dev/ttyS1" << "/dev/ttyS2" << "/dev/ttyS3" << "/dev/ttyS4" << "/dev/ttyS5" << "/dev/ttyUSB0" << "/dev/ttyUSB1" << "/dev/ttyUSB2" << "/dev/ttyUSB3"; #endif m_Controls->m_ComPortSelector->addItems(comPorts); m_Delegate = new QmitkNDIToolDelegate(m_Controls->m_ToolTable); m_Delegate->SetDataStorage(nullptr); //needs to be set later using the setter methods m_Delegate->SetPredicate(nullptr); m_Delegate->SetTypes(QStringList()); m_Controls->m_ToolTable->setItemDelegate(m_Delegate); this->CreateConnections(); this->HidePolarisOptionsGroupbox(true); this->HideAuroraOptionsGroupbox(true); } } void QmitkNDIConfigurationWidget::CreateConnections() { connect(m_Controls->m_Connect, SIGNAL(clicked()), this, SLOT(OnConnect())); connect(m_Controls->m_DiscoverToolsBtn, SIGNAL(clicked()), this, SLOT(OnDiscoverTools())); connect(m_Controls->m_AddToolBtn, SIGNAL(clicked()), this, SLOT(OnAddPassiveTool())); connect(m_Controls->m_DisoverDevicesBtn, SIGNAL(clicked()), this, SLOT(OnDiscoverDevices())); connect(m_Controls->m_ToolTable->model(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(UpdateTrackerFromToolTable(const QModelIndex &, const QModelIndex &))); connect(m_Controls->m_DisoverDevicesBtnInfo, SIGNAL(clicked()), this, SLOT(OnDisoverDevicesBtnInfo())); connect(m_Controls->m_SaveToolPushButton, SIGNAL(clicked()), this, SLOT(OnSaveTool()) ); connect(m_Controls->m_LoadToolPushButton, SIGNAL(clicked()), this, SLOT(OnLoadTool()) ); } void QmitkNDIConfigurationWidget::OnConnect() { if (m_Tracker.IsNotNull()) { m_Tracker->CloseConnection(); m_Tracker = nullptr; } this->CreateTracker(); this->SetupTracker(); bool okay = false; try { okay = m_Tracker->OpenConnection(); } catch(mitk::IGTException &e) { QMessageBox::warning(nullptr, "Error", QString("Connection failed, error message: ") + e.GetDescription()); m_Tracker->CloseConnection(); this->m_Tracker = nullptr; } if (okay) { // show/hide options according to connected device if(m_Tracker->GetType() == mitk::NDIPolarisTypeInformation::GetTrackingDeviceName()) { this->HideAuroraOptionsGroupbox(true); this->HidePolarisOptionsGroupbox(false); } else if (m_Tracker->GetType() == mitk::NDIAuroraTypeInformation::GetTrackingDeviceName()) { this->HidePolarisOptionsGroupbox(true); this->HideAuroraOptionsGroupbox(false); } this->UpdateWidgets(); this->UpdateToolTable(); connect(m_Controls->m_ToolTable, SIGNAL(cellChanged(int,int)), this, SLOT(OnTableCellChanged(int,int))); emit ToolsAdded(this->GetToolNamesList()); emit Connected(); } else { QMessageBox::warning(nullptr, "Error", QString("Connection failed due to an unknown reason!")); m_Tracker->CloseConnection(); this->m_Tracker = nullptr; } } void QmitkNDIConfigurationWidget::OnDisconnect() { if (m_Tracker.IsNull()) return; m_Tracker->CloseConnection(); m_Tracker = nullptr; disconnect(m_Controls->m_ToolTable, SIGNAL(cellChanged(int,int)), this, SLOT(OnTableCellChanged(int,int))); m_Controls->m_ToolSelectionComboBox->clear(); this->UpdateToolTable(); this->UpdateWidgets(); emit ToolsAdded(this->GetToolNamesList()); emit Disconnected(); this->HidePolarisOptionsGroupbox(true); this->HideAuroraOptionsGroupbox(true); } void QmitkNDIConfigurationWidget::UpdateWidgets() { m_Controls->m_DeviceStatus->setText(this->GetStatusText()); if (m_Tracker.IsNull()) // not connected to tracker { m_Controls->m_Connect->setText("Connect"); m_Controls->m_lConnection->setText("III. Enable connection to device "); disconnect(m_Controls->m_Connect, SIGNAL(clicked()), this, SLOT(OnDisconnect())); connect(m_Controls->m_Connect, SIGNAL(clicked()), this, SLOT(OnConnect())); m_Controls->m_DiscoverToolsBtn->setDisabled(true); m_Controls->m_AddToolBtn->setDisabled(true); return; } if (m_Tracker->GetState() == mitk::TrackingDevice::Setup) { m_Controls->m_Connect->setText("Connect"); m_Controls->m_lConnection->setText("III. Enable connection to device "); disconnect(m_Controls->m_Connect, SIGNAL(clicked()), this, SLOT(OnDisconnect())); connect(m_Controls->m_Connect, SIGNAL(clicked()), this, SLOT(OnConnect())); m_Controls->m_DiscoverToolsBtn->setDisabled(true); m_Controls->m_AddToolBtn->setDisabled(true); return; } if ((m_Tracker->GetState() == mitk::TrackingDevice::Ready) || (m_Tracker->GetState() == mitk::TrackingDevice::Tracking)) { m_Controls->m_Connect->setText("Disconnect"); m_Controls->m_lConnection->setText("III. Disable connection to device "); disconnect(m_Controls->m_Connect, SIGNAL(clicked()), this, SLOT(OnConnect())); connect(m_Controls->m_Connect, SIGNAL(clicked()), this, SLOT(OnDisconnect())); m_Controls->m_DiscoverToolsBtn->setEnabled(true); m_Controls->m_AddToolBtn->setEnabled(true); } } QString QmitkNDIConfigurationWidget::GetStatusText() { if (m_Tracker.IsNull()) return QString("Not connected"); QString devName = QString::fromStdString(m_Tracker->GetType()); if (m_Tracker->GetState() == mitk::TrackingDevice::Ready) return QString("Connected to %1 on %2. Device is ready.").arg(devName).arg(m_Tracker->GetDeviceName()); if (m_Tracker->GetState() == mitk::TrackingDevice::Tracking) return QString("%1 is tracking.").arg(devName); return QString(""); } void QmitkNDIConfigurationWidget::OnDiscoverTools() { if (m_Tracker.IsNull()) { QMessageBox::warning(nullptr, "Error", QString("Connection failed. No tracking device found.")); return; } m_Tracker->DiscoverWiredTools(); this->UpdateToolTable(); emit ToolsAdded(this->GetToolNamesList()); } void QmitkNDIConfigurationWidget::OnAddPassiveTool() { if (m_Tracker.IsNull()) this->CreateTracker(); - QStringList filenames = QFileDialog::getOpenFileNames(this, "Select NDI SROM file", QDir::currentPath(),"NDI SROM files (*.rom)"); + QStringList filenames = QFileDialog::getOpenFileNames(this, "Select NDI SROM file", QmitkIGTCommonHelper::GetLastFileLoadPath(),"NDI SROM files (*.rom)"); if (filenames.isEmpty()) { this->m_Tracker = nullptr; return; } + + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(filenames.at(0)); + foreach(QString fileName, filenames) { //QString toolName = QInputDialog::getText(this, "Enter a name for the tool", "Name of the tool: ", QLineEdit::Normal, QFileInfo(filename).baseName(), &ok); //if (ok == false || toolName.isEmpty()) // return; m_Tracker->AddTool(QFileInfo(fileName).baseName().toLatin1(), fileName.toLatin1()); m_Tracker->Modified(); } emit ToolsAdded(this->GetToolNamesList()); this->UpdateToolTable(); } void QmitkNDIConfigurationWidget::CreateTracker() { m_Tracker = mitk::NDITrackingDevice::New(); } void QmitkNDIConfigurationWidget::SetupTracker() { if (m_Tracker.IsNull()) return; m_Tracker->SetDeviceName(this->GetDeviceName()); m_Tracker->SetBaudRate(mitk::SerialCommunication::BaudRate115200); } std::string QmitkNDIConfigurationWidget::GetDeviceName() const { if (m_Controls == nullptr) return nullptr; QString deviceName = m_Controls->m_ComPortSelector->currentText(); #if WIN32 deviceName.prepend("\\\\.\\"); // always prepend "\\.\ to all COM ports, to be able to connect to ports > 9" #endif return deviceName.toStdString(); } void QmitkNDIConfigurationWidget::SetDeviceName( const char* dev ) { if (m_Controls == nullptr) return; m_Controls->m_ComPortSelector->setCurrentIndex(m_Controls->m_ComPortSelector->findText(dev)); } void QmitkNDIConfigurationWidget::UpdateToolTable() { //disconnect(m_Controls->m_ToolTable, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(OnTableItemChanged(QTableWidgetItem*))); // stop listening to table changes disconnect(m_Controls->m_ToolTable->model(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(UpdateTrackerFromToolTable(const QModelIndex &, const QModelIndex &))); disconnect(m_Controls->m_ToolTable, SIGNAL( clicked ( const QModelIndex & )), this, SLOT ( OnTableItemClicked( const QModelIndex & ))); m_Controls->m_ToolTable->clearContents(); m_Controls->m_ToolTable->setRowCount(0); if (m_Tracker.IsNull() || (m_Controls == nullptr)) return; m_Controls->m_ToolSelectionComboBox->clear(); m_Controls->m_ToolTable->setRowCount(m_Tracker->GetToolCount()); for (unsigned int i = 0; i < m_Tracker->GetToolCount(); ++i) { mitk::TrackingTool* t = m_Tracker->GetTool(i); if (t == nullptr) { m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::IndexCol, new QTableWidgetItem("INVALID")); // Index continue; } m_Controls->m_ToolSelectionComboBox->addItem(m_Tracker->GetTool(i)->GetToolName()); m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::IndexCol, new QTableWidgetItem(QString::number(i))); // Index m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::NameCol, new QTableWidgetItem(t->GetToolName())); // Name if (dynamic_cast(t)->GetSROMDataLength() > 0) m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::SROMCol, new QTableWidgetItem("SROM file loaded")); // SROM file else m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::SROMCol, new QTableWidgetItem(m_SROMCellDefaultText)); // SROM file m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::TypeCol, new QTableWidgetItem("")); // Type if (t->IsEnabled()) m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::StatusCol, new QTableWidgetItem("Enabled")); // Status else m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::StatusCol, new QTableWidgetItem("Disabled")); // Status m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::NodeCol, new QTableWidgetItem("")); // Node m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::RepCol, new QTableWidgetItem(m_RepresentatonCellDefaultText)); // Representation /* set read-only/editable flags */ m_Controls->m_ToolTable->item(i, QmitkNDIToolDelegate::IndexCol)->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled); // Index m_Controls->m_ToolTable->item(i, QmitkNDIToolDelegate::NodeCol)->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled); // Name m_Controls->m_ToolTable->item(i, QmitkNDIToolDelegate::SROMCol)->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled); // SROM file m_Controls->m_ToolTable->item(i, QmitkNDIToolDelegate::TypeCol)->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled); // Type m_Controls->m_ToolTable->item(i, QmitkNDIToolDelegate::StatusCol)->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled); // Status m_Controls->m_ToolTable->item(i, QmitkNDIToolDelegate::NodeCol)->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled); // Node m_Controls->m_ToolTable->item(i, QmitkNDIToolDelegate::RepCol)->setFlags(Qt::NoItemFlags); // Representation surface file } m_Controls->m_ToolTable->resizeColumnsToContents(); //connect(m_Controls->m_ToolTable, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(OnTableItemChanged(QTableWidgetItem*))); // listen to table changes again connect(m_Controls->m_ToolTable->model(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(UpdateTrackerFromToolTable(const QModelIndex &, const QModelIndex &))); connect(m_Controls->m_ToolTable, SIGNAL( clicked ( const QModelIndex & )), this, SLOT ( OnTableItemClicked( const QModelIndex & ))); } void QmitkNDIConfigurationWidget::OnDiscoverDevices() { PortDeviceMap portsAndDevices; QString status = "Scanning "; #ifdef WIN32 QString devName; for (unsigned int i = 1; i < 40; ++i) { if (i<10) devName = QString("COM%1").arg(i); else devName = QString("\\\\.\\COM%1").arg(i); // prepend "\\.\ to COM ports >9, to be able to allow connection" portsAndDevices[devName]; status += QString("COM%1").arg(i) + ", "; } #else //linux/posix systems for(unsigned int i = 1; i < 6; ++i) { QString devName = QString("/dev/ttyS%1").arg(i); portsAndDevices[devName]; status += devName + ", "; } for(unsigned int i = 0; i <7; ++i) { QString devName = QString("/dev/ttyUSB%1").arg(i); portsAndDevices[devName]; status += devName + ", "; } #endif status.chop(2); // remove last ", " status += " for NDI tracking devices..."; m_Controls->m_DeviceStatus->setText(status); ScanPortsForNDITrackingDevices(portsAndDevices); m_Controls->m_ComPortSelector->clear(); QString result = "The following tracking devices were found:
\n"; for (PortDeviceMap::const_iterator it = portsAndDevices.begin(); it != portsAndDevices.end(); ++it) { QString tmpComPort = it.key(); if (tmpComPort.startsWith("\\")) { tmpComPort.remove(0,4); // remove "\\.\" for nice ui visualisation } result += tmpComPort + ": "; if (mitk::NDIPolarisTypeInformation::GetTrackingDeviceName() == it.value() || mitk::NDIAuroraTypeInformation::GetTrackingDeviceName() == it.value()) { result += QString::fromStdString(it.value()); result += "
\n"; m_Controls->m_ComPortSelector->addItem(tmpComPort); } else { result += "No NDI tracking device found
\n"; } } //QMessageBox::information(nullptr, "Tracking Device Discovery", result); m_Controls->m_DeviceStatus->setText(result); } mitk::TrackingDeviceType QmitkNDIConfigurationWidget::ScanPort(QString port) { mitk::NDITrackingDevice::Pointer tracker = mitk::NDITrackingDevice::New(); tracker->SetDeviceName(port.toStdString()); return tracker->TestConnection(); } void QmitkNDIConfigurationWidget::ScanPortsForNDITrackingDevices( PortDeviceMap& portsAndDevices ) { // Iterative scanning: for (PortDeviceMap::iterator it = portsAndDevices.begin(); it != portsAndDevices.end(); ++it) it.value() = this->ScanPort(it.key()); // \Todo: use parallel scanning //QtConcurrent::blockingMap( portsAndDevices.begin(), portsAndDevices.end(), ScanPort ); //MITK_INFO << portsAndDevices; } QStringList QmitkNDIConfigurationWidget::GetToolNamesList() { QStringList toolNames; if (m_Tracker.IsNull()) return toolNames; for (unsigned int i = 0; i < m_Tracker->GetToolCount(); ++i) { mitk::TrackingTool* t = m_Tracker->GetTool(i); if (t == nullptr) continue; toolNames << t->GetToolName(); } return toolNames; } mitk::NDITrackingDevice* QmitkNDIConfigurationWidget::GetTracker() const { return m_Tracker.GetPointer(); } void QmitkNDIConfigurationWidget::SetToolTypes(const QStringList& types) { m_Delegate->SetTypes(types); } void QmitkNDIConfigurationWidget::SetDataStorage(mitk::DataStorage* ds) { m_Delegate->SetDataStorage(ds); } void QmitkNDIConfigurationWidget::SetPredicate(mitk::NodePredicateBase::Pointer p) { m_Delegate->SetPredicate(p); } void QmitkNDIConfigurationWidget::SetTagPropertyName( const std::string& name ) { m_Delegate->SetTagPropertyName(name); } void QmitkNDIConfigurationWidget::SetTagProperty( mitk::BaseProperty::Pointer prop ) { m_Delegate->SetTagProperty(prop); } void QmitkNDIConfigurationWidget::OnTableItemClicked(const QModelIndex & topLeft ) { QString filename; QTableWidgetItem* filenameItem; switch (topLeft.column()) { case QmitkNDIToolDelegate::RepCol: - filename = QFileDialog::getOpenFileName(this, "Select Surface File", QDir::currentPath(),"STL files (*.stl)"); + filename = QFileDialog::getOpenFileName(this, "Select Surface File", QmitkIGTCommonHelper::GetLastFileLoadPath(),"STL files (*.stl)"); + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(filename); filenameItem = new QTableWidgetItem(filename); m_Controls->m_ToolTable->setItem( topLeft.row(), topLeft.column(), filenameItem ); if(QFileInfo(filename).exists()) { mitk::Surface::Pointer surface = this->LoadSurfaceFromSTLFile(filename); if(surface.IsNotNull()) emit RepresentationChanged( topLeft.row(), surface); } break; default: break; } } void QmitkNDIConfigurationWidget::UpdateTrackerFromToolTable(const QModelIndex & topLeft, const QModelIndex & /*bottomRight*/) { //Colums ID doesn't have to be processed. if (topLeft.column()<1) return; if (m_Tracker.IsNull()) return; if (topLeft.row() >= (int) m_Tracker->GetToolCount()) return; QAbstractItemModel* model = m_Controls->m_ToolTable->model(); //define topleft contains row and column; row 0 is tool 0; column is index =0, Name =1, SROMFileName = 2; Type = 3; Status = 4; Node (?) = 5 //only update the changed item mitk::NDIPassiveTool* tool = dynamic_cast (m_Tracker->GetTool(topLeft.row())); if (tool == nullptr) return; switch (topLeft.column()) { case QmitkNDIToolDelegate::IndexCol: //index break; case QmitkNDIToolDelegate::NameCol: //name tool->SetToolName(model->data(model->index(topLeft.row(), 1)).toString().toLatin1()); emit ToolsChanged(); break; case QmitkNDIToolDelegate::SROMCol: //SROM File Name { QString romfile = model->data(model->index(topLeft.row(), QmitkNDIToolDelegate::SROMCol)).toString(); if (QFileInfo(romfile).exists()) tool->LoadSROMFile(romfile.toLatin1()); m_Tracker->UpdateTool(tool); break; } //TODO: Add Node Status and Type here as well default: break; } } const QString QmitkNDIConfigurationWidget::GetToolType( unsigned int index ) const { if (m_Controls == nullptr) return QString(""); QAbstractItemModel* model = m_Controls->m_ToolTable->model(); QModelIndex modelIndex = model->index(index, QmitkNDIToolDelegate::TypeCol); if (modelIndex.isValid() == false) return QString(""); return model->data(modelIndex).toString(); } const QString QmitkNDIConfigurationWidget::GetToolName( unsigned int index ) const { if (m_Controls == nullptr) return QString(""); QAbstractItemModel* model = m_Controls->m_ToolTable->model(); QModelIndex modelIndex = model->index(index, QmitkNDIToolDelegate::NameCol); if (modelIndex.isValid() == false) return QString(""); return model->data(modelIndex).toString(); } QMap QmitkNDIConfigurationWidget::GetToolAndTypes() const { QMap map; if (m_Controls == nullptr) return map; QAbstractItemModel* model = m_Controls->m_ToolTable->model(); for (int i = 0; i < model->rowCount(); ++i) { QModelIndex indexIndex = model->index(i, QmitkNDIToolDelegate::IndexCol); QModelIndex typeIndex = model->index(i, QmitkNDIToolDelegate::TypeCol); if ((indexIndex.isValid() == false) || (typeIndex.isValid() == false)) continue; map.insert(model->data(typeIndex).toString(), model->data(indexIndex).toUInt()); } return map; } QList QmitkNDIConfigurationWidget::GetToolsByToolType( QString toolType ) const { QList list; if (m_Controls == nullptr) return list; QAbstractItemModel* model = m_Controls->m_ToolTable->model(); for (int i = 0; i < model->rowCount(); ++i) { QModelIndex indexIndex = model->index(i, QmitkNDIToolDelegate::IndexCol); QModelIndex typeIndex = model->index(i, QmitkNDIToolDelegate::TypeCol); if ((indexIndex.isValid() == false) || (typeIndex.isValid() == false)) continue; if (model->data(typeIndex).toString() == toolType) list.append(model->data(indexIndex).toUInt()); } return list; } mitk::DataNode* QmitkNDIConfigurationWidget::GetNode( unsigned int index ) const { if (m_Controls == nullptr) return nullptr; QAbstractItemModel* model = m_Controls->m_ToolTable->model(); QVariant data = model->data(model->index(index, QmitkNDIToolDelegate::NodeCol), QmitkNDIToolDelegate::OrganNodeRole); return data.value(); } void QmitkNDIConfigurationWidget::HidePolarisOptionsGroupbox( bool on ) { m_Controls->m_gbPolarisOptions->setHidden(on); } void QmitkNDIConfigurationWidget::HideAuroraOptionsGroupbox( bool on ) { m_Controls->m_gbAuroraOptions->setHidden(on); } void QmitkNDIConfigurationWidget::ShowToolRepresentationColumn() { int cols = m_Controls->m_ToolTable->columnCount(); //checking if representation column is inserted at right index if(cols != QmitkNDIToolDelegate::RepCol) { //throw std::exception("Representation Column is not inserted at it's designated index!"); return; } m_Controls->m_ToolTable->insertColumn(cols); // insert new column at end of table m_Controls->m_ToolTable->setHorizontalHeaderItem(QmitkNDIToolDelegate::RepCol, new QTableWidgetItem(QString("Representation"))); // inser column header for new colum //m_Controls->m_ToolTable->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers); int rows = m_Controls->m_ToolTable->rowCount(); // make all representation colum items not editable for(int i=0; i < rows; ++i) { m_Controls->m_ToolTable->setItem(i, QmitkNDIToolDelegate::RepCol, new QTableWidgetItem("")); // Representation m_Controls->m_ToolTable->item(i,QmitkNDIToolDelegate::RepCol)->setFlags(Qt::NoItemFlags); } //connect(m_Controls->m_ToolTable, SIGNAL( clicked ( const QModelIndex & )), this, SLOT ( OnTableItemClicked( const QModelIndex & ))); } void QmitkNDIConfigurationWidget::OnDisoverDevicesBtnInfo() { QMessageBox *infoBox = new QMessageBox(this); infoBox->setText("Click \"Scan Ports\" to get a list of all connected NDI tracking devices. This will clear the selection menu below and add the ports for discovered NDI tracking devices. Use this function, if a port is not listed."); infoBox->exec(); delete infoBox; } void QmitkNDIConfigurationWidget::OnTableCellChanged(int row, int column) { if(m_Tracker.IsNull()) return; QString toolName; switch (column) { case QmitkNDIToolDelegate::NameCol: toolName = m_Controls->m_ToolTable->item(row,column)->text(); m_Controls->m_ToolSelectionComboBox->setItemText(row, toolName); emit SignalToolNameChanged(row, toolName); break; default: break; } } void QmitkNDIConfigurationWidget::OnSaveTool() { if(m_Tracker.IsNull() || m_Tracker->GetToolCount() <= 0) return; int currId = m_Controls->m_ToolSelectionComboBox->currentIndex(); QString filename = QFileDialog::getSaveFileName(nullptr, "Save NDI-Tool", QString(QString(m_Tracker->GetTool(currId)->GetToolName())),"NDI Tracking Tool file(*.ntf)"); mitk::TrackingTool* selectedTool = m_Tracker->GetTool(currId); if(filename.isEmpty()) return; mitk::NavigationTool::Pointer navTool = mitk::NavigationTool::New(); mitk::NavigationToolWriter::Pointer toolWriter = mitk::NavigationToolWriter::New(); try { toolWriter->DoWrite(filename.toStdString(), this->GenerateNavigationTool(selectedTool)); } catch( ... ) { QMessageBox::warning(nullptr, "Saving Tool Error", QString("An error occured! Could not save tool!\n\n")); MBI_ERROR<<"Could not save tool surface!"; MBI_ERROR<< toolWriter->GetErrorMessage(); QFile maybeCorruptFile(filename); if(maybeCorruptFile.exists()) maybeCorruptFile.remove(); } emit SignalSavedTool(currId, filename); } void QmitkNDIConfigurationWidget::OnLoadTool() { if(m_Tracker.IsNull() || m_Tracker->GetToolCount() <= 0) return; - QString filename = QFileDialog::getOpenFileName(nullptr, "Load NDI-Tools", QDir::currentPath(),"NDI Tracking Tool file(*.ntf)"); + QString filename = QFileDialog::getOpenFileName(nullptr, "Load NDI-Tools", QmitkIGTCommonHelper::GetLastFileLoadPath(),"NDI Tracking Tool file(*.ntf)"); int currId = m_Controls->m_ToolSelectionComboBox->currentIndex(); if(filename.isEmpty()) return; + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(filename); + mitk::DataNode::Pointer toolNode; mitk::NavigationToolReader::Pointer toolReader = mitk::NavigationToolReader::New(); mitk::NavigationTool::Pointer navTool; try { navTool = toolReader->DoRead(filename.toStdString()); } catch( ... ) { QMessageBox::warning(nullptr, "Loading Tool Error", QString("An error occured! Could not load tool!\n\n")); MBI_ERROR<<"Could not load tool surface!"; MBI_ERROR<< toolReader->GetErrorMessage(); } int currSelectedToolID = m_Controls->m_ToolSelectionComboBox->currentIndex(); // name m_Controls->m_ToolTable->item(currSelectedToolID,QmitkNDIToolDelegate::NameCol)->setText(navTool->GetToolName().c_str()); dynamic_cast(m_Tracker->GetTool(currSelectedToolID))->SetToolName(navTool->GetToolName().c_str()); // also setting name to tool directly //calibration file (.srom) filename m_Controls->m_ToolTable->item(currSelectedToolID,QmitkNDIToolDelegate::SROMCol)->setText(navTool->GetCalibrationFile().c_str()); //type if(navTool->GetType() == mitk::NavigationTool::Instrument) m_Controls->m_ToolTable->item(currSelectedToolID,QmitkNDIToolDelegate::TypeCol)->setText("Instrument"); else if(navTool->GetType() == mitk::NavigationTool::Fiducial) m_Controls->m_ToolTable->item(currSelectedToolID,QmitkNDIToolDelegate::TypeCol)->setText("Fiducial"); else if(navTool->GetType() == mitk::NavigationTool::Skinmarker) m_Controls->m_ToolTable->item(currSelectedToolID,QmitkNDIToolDelegate::TypeCol)->setText("Skinmarker"); else m_Controls->m_ToolTable->item(currSelectedToolID,QmitkNDIToolDelegate::TypeCol)->setText("Unknown"); //representation m_Controls->m_ToolTable->item(currSelectedToolID,QmitkNDIToolDelegate::SROMCol)->setText(m_RepresentatonCellDefaultText); emit SignalLoadTool(currId, navTool->GetDataNode()); } mitk::NavigationTool::Pointer QmitkNDIConfigurationWidget::GenerateNavigationTool(mitk::TrackingTool* tool) { mitk::NavigationTool::Pointer navTool = mitk::NavigationTool::New(); mitk::NDIPassiveTool::Pointer passiveTool = dynamic_cast(tool); if(passiveTool.IsNull()) throw std::runtime_error("Could not cast TrackingTool to PassiveTool"); int currSelectedToolID = m_Controls->m_ToolSelectionComboBox->currentIndex(); QString sromFileName = m_Controls->m_ToolTable->item(currSelectedToolID, QmitkNDIToolDelegate::SROMCol)->text(); QString surfaceFileName = m_Controls->m_ToolTable->item(currSelectedToolID, QmitkNDIToolDelegate::RepCol)->text(); //calibration file (.srom) filename QFile sromFile(sromFileName); if(sromFile.exists()) navTool->SetCalibrationFile(sromFileName.toStdString()); //serial number navTool->SetSerialNumber(passiveTool->GetSerialNumber()); // name and surface as dataNode mitk::DataNode::Pointer node = mitk::DataNode::New(); mitk::Surface::Pointer toolSurface; try{ toolSurface = this->LoadSurfaceFromSTLFile(surfaceFileName); } catch( ... ) { QMessageBox::warning(nullptr, "Loading Surface Error", QString("An error occured! Could not load surface from .stl file!\n\n")); MBI_ERROR<<"Could not load .stl tool surface!"; } if(toolSurface.IsNotNull()) { node->SetData(toolSurface); node->SetName(tool->GetToolName()); } navTool->SetDataNode(node); // type mitk::NavigationTool::NavigationToolType type; QString currentToolType = m_Controls->m_ToolTable->item(currSelectedToolID,QmitkNDIToolDelegate::TypeCol)->text(); if(currentToolType.compare("Instrument") == 0) type = mitk::NavigationTool::Instrument; else if(currentToolType.compare("Fiducial") == 0) type = mitk::NavigationTool::Fiducial; else if(currentToolType.compare("Skinmarker") == 0) type = mitk::NavigationTool::Skinmarker; else type = mitk::NavigationTool::Unknown; navTool->SetType(type); return navTool; } mitk::Surface::Pointer QmitkNDIConfigurationWidget::LoadSurfaceFromSTLFile(QString surfaceFilename) { mitk::Surface::Pointer toolSurface; QFile surfaceFile(surfaceFilename); if(surfaceFile.exists()) { try{ toolSurface = mitk::IOUtil::LoadSurface(surfaceFilename.toStdString().c_str()); } catch(std::exception& e ) { MBI_ERROR<<"Could not load surface for tool!"; MBI_ERROR<< e.what(); throw e; } } return toolSurface; } void QmitkNDIConfigurationWidget::EnableAddToolsButton(bool enable) { m_Controls->m_AddToolBtn->setEnabled(enable); } void QmitkNDIConfigurationWidget::EnableDiscoverNewToolsButton(bool enable) { m_Controls->m_DiscoverToolsBtn->setEnabled(enable); } diff --git a/Modules/IGTUI/Qmitk/QmitkNPOptitrackWidget.cpp b/Modules/IGTUI/Qmitk/QmitkNPOptitrackWidget.cpp index ac0ca48415..47f43dbd0e 100644 --- a/Modules/IGTUI/Qmitk/QmitkNPOptitrackWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkNPOptitrackWidget.cpp @@ -1,120 +1,122 @@ /*=================================================================== 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 "QmitkNPOptitrackWidget.h" #include "mitkOptitrackTrackingDevice.h" #include "mitkNPOptitrackTrackingTypeInformation.h" +#include "QmitkIGTCommonHelper.h" #include #include #include const std::string QmitkNPOptitrackWidget::VIEW_ID = "org.mitk.views.NPOptitrackWidget"; QmitkNPOptitrackWidget::QmitkNPOptitrackWidget(QWidget* parent, Qt::WindowFlags f) : QmitkAbstractTrackingDeviceWidget(parent, f) , m_Controls(nullptr) { } void QmitkNPOptitrackWidget::Initialize() { InitializeSuperclassWidget(); CreateQtPartControl(this); CreateConnections(); } QmitkNPOptitrackWidget::~QmitkNPOptitrackWidget() { delete m_Controls; } void QmitkNPOptitrackWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkNPOptitrackWidget; m_Controls->setupUi(parent); } } void QmitkNPOptitrackWidget::CreateConnections() { if (m_Controls) { connect((QObject*)(m_Controls->m_testConnectionOptitrack), SIGNAL(clicked()), this, SLOT(TestConnection())); connect((QObject*)(m_Controls->m_SetOptitrackCalibrationFile), SIGNAL(clicked()), this, SLOT(SetOptitrackCalibrationFileClicked())); } } void QmitkNPOptitrackWidget::ResetOutput() { m_Controls->m_outputTextOptitrack->setHtml("output:"); } void QmitkNPOptitrackWidget::AddOutput(std::string s) { m_Controls->m_outputTextOptitrack->setHtml(QString(s.c_str())); m_Controls->m_outputTextOptitrack->verticalScrollBar()->setValue(m_Controls->m_outputTextOptitrack->verticalScrollBar()->maximum()); } mitk::TrackingDevice::Pointer QmitkNPOptitrackWidget::ConstructTrackingDevice() { // Create the Tracking Device mitk::OptitrackTrackingDevice::Pointer tempTrackingDevice = mitk::OptitrackTrackingDevice::New(); // Set the calibration File tempTrackingDevice->SetCalibrationPath(m_OptitrackCalibrationFile); //Set the camera parameters tempTrackingDevice->SetExp(m_Controls->m_OptitrackExp->value()); tempTrackingDevice->SetLed(m_Controls->m_OptitrackLed->value()); tempTrackingDevice->SetThr(m_Controls->m_OptitrackThr->value()); tempTrackingDevice->SetType(mitk::NPOptitrackTrackingTypeInformation::GetTrackingDeviceName()); return static_cast(tempTrackingDevice); } bool QmitkNPOptitrackWidget::IsDeviceInstalled() { return mitk::OptitrackTrackingDevice::New()->IsDeviceInstalled(); } void QmitkNPOptitrackWidget::SetOptitrackCalibrationFileClicked() { - std::string filename = QFileDialog::getOpenFileName(nullptr, tr("Open Calibration File"), "/", "*.*").toLatin1().data(); + std::string filename = QFileDialog::getOpenFileName(nullptr, tr("Open Calibration File"), QmitkIGTCommonHelper::GetLastFileLoadPath(), "*.*").toLatin1().data(); if (filename == "") { return; } else { + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(QString::fromStdString(filename)); m_OptitrackCalibrationFile = filename; Poco::Path myPath = Poco::Path(m_OptitrackCalibrationFile.c_str()); m_Controls->m_OptitrackCalibrationFile->setText("Calibration File: " + QString(myPath.getFileName().c_str())); } } QmitkNPOptitrackWidget* QmitkNPOptitrackWidget::Clone(QWidget* parent) const { QmitkNPOptitrackWidget* clonedWidget = new QmitkNPOptitrackWidget(parent); clonedWidget->Initialize(); clonedWidget->m_OptitrackCalibrationFile = this->m_OptitrackCalibrationFile; clonedWidget->m_Controls->m_OptitrackCalibrationFile->setText(m_Controls->m_OptitrackCalibrationFile->text()); clonedWidget->m_Controls->m_OptitrackExp->setValue(m_Controls->m_OptitrackExp->value()); clonedWidget->m_Controls->m_OptitrackLed->setValue(m_Controls->m_OptitrackLed->value()); clonedWidget->m_Controls->m_OptitrackThr->setValue(m_Controls->m_OptitrackThr->value()); return clonedWidget; } diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.cpp b/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.cpp index 4621ac9e63..bffcd3b5fd 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.cpp @@ -1,336 +1,347 @@ /*=================================================================== 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 "QmitkNavigationToolCreationWidget.h" //mitk headers #include #include #include #include #include "mitkTrackingDeviceTypeCollection.h" //qt headers #include #include #include #include +#include //poco headers #include // vtk #include #include const std::string QmitkNavigationToolCreationWidget::VIEW_ID = "org.mitk.views.navigationtoolcreationwizardwidget"; QmitkNavigationToolCreationWidget::QmitkNavigationToolCreationWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Controls = nullptr; m_AdvancedWidget = new QmitkNavigationToolCreationAdvancedWidget(this); m_AdvancedWidget->setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); m_AdvancedWidget->setWindowTitle("Tool Creation Advanced Options"); m_AdvancedWidget->setModal(false); CreateQtPartControl(this); CreateConnections(); RefreshTrackingDeviceCollection(); } QmitkNavigationToolCreationWidget::~QmitkNavigationToolCreationWidget() { m_Controls->m_CalibrationLandmarksList->SetPointSetNode(nullptr); m_Controls->m_RegistrationLandmarksList->SetPointSetNode(nullptr); delete m_AdvancedWidget; } void QmitkNavigationToolCreationWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkNavigationToolCreationWidgetControls; m_Controls->setupUi(parent); } } void QmitkNavigationToolCreationWidget::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_cancel), SIGNAL(clicked()), this, SLOT(OnCancel()) ); connect( (QObject*)(m_Controls->m_finished), SIGNAL(clicked()), this, SLOT(OnFinished()) ); connect( (QObject*)(m_Controls->m_LoadSurface), SIGNAL(clicked()), this, SLOT(OnLoadSurface()) ); connect( (QObject*)(m_Controls->m_LoadCalibrationFile), SIGNAL(clicked()), this, SLOT(OnLoadCalibrationFile()) ); connect( (QObject*)(m_Controls->m_ShowAdvancedOptionsPB), SIGNAL(toggled(bool)), this, SLOT(OnShowAdvancedOptions(bool)) ); connect( (QObject*)(m_AdvancedWidget), SIGNAL(DialogCloseRequested()), this, SLOT(OnProcessDialogCloseRequest()) ); connect( (QObject*)(m_AdvancedWidget), SIGNAL(RetrieveDataForManualToolTipManipulation()), this, SLOT(OnRetrieveDataForManualTooltipManipulation()) ); connect( m_Controls->m_Surface_Use_Other, SIGNAL(toggled(bool)), this, SLOT(OnSurfaceUseOtherToggled(bool))); } } void QmitkNavigationToolCreationWidget::Initialize(mitk::DataStorage* dataStorage, const std::string& supposedIdentifier, const std::string& supposedName) { m_DataStorage = dataStorage; //initialize UI components m_Controls->m_SurfaceChooser->SetDataStorage(m_DataStorage); m_Controls->m_SurfaceChooser->SetAutoSelectNewItems(true); m_Controls->m_SurfaceChooser->SetPredicate(mitk::NodePredicateDataType::New("Surface")); //set default data m_Controls->m_ToolNameEdit->setText(supposedName.c_str()); m_Controls->m_CalibrationFileName->setText("none"); m_Controls->m_Surface_Use_Sphere->setChecked(true); m_AdvancedWidget->SetDataStorage(m_DataStorage); m_Controls->m_IdentifierEdit->setText(supposedIdentifier.c_str()); this->InitializeUIToolLandmarkLists(); m_Controls->m_CalibrationLandmarksList->EnableEditButton(false); m_Controls->m_RegistrationLandmarksList->EnableEditButton(false); } void QmitkNavigationToolCreationWidget::SetTrackingDeviceType(mitk::TrackingDeviceType type, bool changeable) { int index = m_Controls->m_TrackingDeviceTypeChooser->findText(QString::fromStdString(type)); if (index >= 0) { m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(index); } } mitk::NavigationTool::Pointer QmitkNavigationToolCreationWidget::GetCreatedTool() { return m_CreatedTool; } //################################################################################## //############################## slots ############################ //################################################################################## void QmitkNavigationToolCreationWidget::OnFinished() { //here we create a new tool m_CreatedTool = mitk::NavigationTool::New(); //create DataNode... mitk::DataNode::Pointer newNode = mitk::DataNode::New(); if(m_Controls->m_Surface_Use_Sphere->isChecked()) { //create small sphere and use it as surface mitk::Surface::Pointer mySphere = mitk::Surface::New(); vtkConeSource *vtkData = vtkConeSource::New(); vtkData->SetAngle(5.0); vtkData->SetResolution(50); vtkData->SetHeight(6.0f); vtkData->SetRadius(2.0f); vtkData->SetCenter(0.0, 0.0, 0.0); vtkData->Update(); mySphere->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); newNode->SetData(mySphere); } else { newNode->SetData(m_Controls->m_SurfaceChooser->GetSelectedNode()->GetData()); } newNode->SetName(m_Controls->m_ToolNameEdit->text().toLatin1()); m_CreatedTool->SetDataNode(newNode); //fill NavigationTool object m_CreatedTool->SetCalibrationFile(m_Controls->m_CalibrationFileName->text().toLatin1().data()); m_CreatedTool->SetIdentifier(m_Controls->m_IdentifierEdit->text().toLatin1().data()); m_CreatedTool->SetSerialNumber(m_Controls->m_SerialNumberEdit->text().toLatin1().data()); //Tracking Device m_CreatedTool->SetTrackingDeviceType(m_Controls->m_TrackingDeviceTypeChooser->currentText().toStdString()); //ToolType if (m_Controls->m_ToolTypeChooser->currentText()=="Instrument") m_CreatedTool->SetType(mitk::NavigationTool::Instrument); else if (m_Controls->m_ToolTypeChooser->currentText()=="Fiducial") m_CreatedTool->SetType(mitk::NavigationTool::Fiducial); else if (m_Controls->m_ToolTypeChooser->currentText()=="Skinmarker") m_CreatedTool->SetType(mitk::NavigationTool::Skinmarker); else m_CreatedTool->SetType(mitk::NavigationTool::Unknown); //Tool Tip mitk::NavigationData::Pointer tempND = mitk::NavigationData::New(m_AdvancedWidget->GetManipulatedToolTip()); m_CreatedTool->SetToolTipOrientation(tempND->GetOrientation()); m_CreatedTool->SetToolTipPosition(tempND->GetPosition()); //Tool Landmarks mitk::PointSet::Pointer toolCalLandmarks, toolRegLandmarks; GetUIToolLandmarksLists(toolCalLandmarks,toolRegLandmarks); m_CreatedTool->SetToolCalibrationLandmarks(toolCalLandmarks); m_CreatedTool->SetToolRegistrationLandmarks(toolRegLandmarks); + //Tool Axis + mitk::Point3D toolAxis; + toolAxis.SetElement(0, (m_Controls->m_ToolAxisX->value())); + toolAxis.SetElement(1, (m_Controls->m_ToolAxisY->value())); + toolAxis.SetElement(2, (m_Controls->m_ToolAxisZ->value())); + m_CreatedTool->SetToolAxis(toolAxis); + emit NavigationToolFinished(); } void QmitkNavigationToolCreationWidget::OnCancel() { m_CreatedTool = nullptr; emit Canceled(); } void QmitkNavigationToolCreationWidget::OnLoadSurface() { - std::string filename = QFileDialog::getOpenFileName(nullptr,tr("Open Surface"), "/", tr("STL (*.stl)")).toLatin1().data(); + std::string filename = QFileDialog::getOpenFileName(nullptr,tr("Open Surface"), QmitkIGTCommonHelper::GetLastFileLoadPath(), tr("STL (*.stl)")).toLatin1().data(); + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(QString::fromStdString(filename)); try { mitk::IOUtil::Load(filename.c_str(), *m_DataStorage); } catch (mitk::Exception &e) { MITK_ERROR << "Exception occured: " << e.what(); } } void QmitkNavigationToolCreationWidget::OnLoadCalibrationFile() { - m_Controls->m_CalibrationFileName->setText(QFileDialog::getOpenFileName(nullptr,tr("Open Calibration File"), "/", "*.*")); + QString fileName = QFileDialog::getOpenFileName(nullptr,tr("Open Calibration File"), QmitkIGTCommonHelper::GetLastFileLoadPath(), "*.*"); + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(fileName); + m_Controls->m_CalibrationFileName->setText(fileName); } void QmitkNavigationToolCreationWidget::SetDefaultData(mitk::NavigationTool::Pointer DefaultTool) { m_Controls->m_ToolNameEdit->setText(QString(DefaultTool->GetDataNode()->GetName().c_str())); m_Controls->m_IdentifierEdit->setText(QString(DefaultTool->GetIdentifier().c_str())); m_Controls->m_SerialNumberEdit->setText(QString(DefaultTool->GetSerialNumber().c_str())); m_AdvancedWidget->SetDefaultTooltip( DefaultTool->GetToolTipTransform() ); int index = m_Controls->m_TrackingDeviceTypeChooser->findText(QString::fromStdString(DefaultTool->GetTrackingDeviceType())); if (index >= 0) { m_Controls->m_TrackingDeviceTypeChooser->setCurrentIndex(index); } m_Controls->m_CalibrationFileName->setText(QString(DefaultTool->GetCalibrationFile().c_str())); m_Controls->m_Surface_Use_Other->setChecked(true); switch(DefaultTool->GetType()) { case mitk::NavigationTool::Instrument: m_Controls->m_ToolTypeChooser->setCurrentIndex(0); break; case mitk::NavigationTool::Fiducial: m_Controls->m_ToolTypeChooser->setCurrentIndex(1); break; case mitk::NavigationTool::Skinmarker: m_Controls->m_ToolTypeChooser->setCurrentIndex(2); break; case mitk::NavigationTool::Unknown: m_Controls->m_ToolTypeChooser->setCurrentIndex(3); break; } m_Controls->m_SurfaceChooser->SetSelectedNode(DefaultTool->GetDataNode()); FillUIToolLandmarkLists(DefaultTool->GetToolCalibrationLandmarks(),DefaultTool->GetToolRegistrationLandmarks()); } //################################################################################## //############################## internal help methods ############################# //################################################################################## void QmitkNavigationToolCreationWidget::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkNavigationToolCreationWidget::OnShowAdvancedOptions(bool state) { if(state) { m_AdvancedWidget->show(); m_AdvancedWidget->SetDefaultTooltip(m_AdvancedWidget->GetManipulatedToolTip()); //use the last one, if there is one m_AdvancedWidget->ReInitialize(); // reinit the views with the new nodes mitk::DataStorage::SetOfObjects::ConstPointer rs = m_DataStorage->GetAll(); mitk::TimeGeometry::Pointer bounds = m_DataStorage->ComputeBoundingGeometry3D(rs, "visible"); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeViews(bounds); } else { m_AdvancedWidget->hide(); } } void QmitkNavigationToolCreationWidget::OnProcessDialogCloseRequest() { m_AdvancedWidget->hide(); m_Controls->m_ShowAdvancedOptionsPB->setChecked(false); } void QmitkNavigationToolCreationWidget::OnRetrieveDataForManualTooltipManipulation() { if(m_Controls->m_Surface_Use_Sphere->isChecked()) { m_AdvancedWidget->SetToolTipSurface(true); } else { m_AdvancedWidget->SetToolTipSurface(false, dynamic_cast(m_Controls->m_SurfaceChooser->GetSelectedNode().GetPointer())); } } void QmitkNavigationToolCreationWidget::OnSurfaceUseOtherToggled(bool checked) { m_Controls->m_LoadSurface->setEnabled(checked); } void QmitkNavigationToolCreationWidget::FillUIToolLandmarkLists(mitk::PointSet::Pointer calLandmarks, mitk::PointSet::Pointer regLandmarks) { m_calLandmarkNode->SetData(calLandmarks); m_regLandmarkNode->SetData(regLandmarks); m_Controls->m_CalibrationLandmarksList->SetPointSetNode(m_calLandmarkNode); m_Controls->m_RegistrationLandmarksList->SetPointSetNode(m_regLandmarkNode); } void QmitkNavigationToolCreationWidget::GetUIToolLandmarksLists(mitk::PointSet::Pointer& calLandmarks, mitk::PointSet::Pointer& regLandmarks) { calLandmarks = dynamic_cast(m_calLandmarkNode->GetData()); regLandmarks = dynamic_cast(m_regLandmarkNode->GetData()); } void QmitkNavigationToolCreationWidget::InitializeUIToolLandmarkLists() { m_calLandmarkNode = mitk::DataNode::New(); m_regLandmarkNode = mitk::DataNode::New(); FillUIToolLandmarkLists(mitk::PointSet::New(),mitk::PointSet::New()); } void QmitkNavigationToolCreationWidget::RefreshTrackingDeviceCollection() { us::ModuleContext* context = us::GetModuleContext(); std::vector > refs = context->GetServiceReferences(); if (refs.empty()) { MITK_WARN << "No tracking device service found!"; return; } mitk::TrackingDeviceTypeCollection* _DeviceTypeCollection = context->GetService(refs.front()); for (auto name : _DeviceTypeCollection->GetTrackingDeviceTypeNames()) { //if the device is not included yet, add name to comboBox and widget to stackedWidget if (m_Controls->m_TrackingDeviceTypeChooser->findText(QString::fromStdString(name)) == -1) { m_Controls->m_TrackingDeviceTypeChooser->addItem(QString::fromStdString(name)); } } } diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui b/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui index 67abcf9f91..d65184df95 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui +++ b/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui @@ -1,511 +1,571 @@ QmitkNavigationToolCreationWidgetControls 0 0 - 254 + 255 309 Form Device Type: 150 0 150 16777215 0 0 0 236 - 115 + 90 Basic Information 100 0 Name: NewTool 100 0 Calibration File: none 40 16777215 Load Qt::Vertical 20 40 0 0 - 303 - 98 + 310 + 113 Tool Visualization Use Simple Cone true Use Surface: Qt::Horizontal QSizePolicy::Fixed 25 20 200 0 150 16777215 false 40 16777215 Load Qt::Horizontal 40 20 Qt::Vertical 20 8 0 0 - 236 - 115 + 157 + 84 Tool Landmarks 1 Calibration Landmarks Registration Landmarks 0 0 - 276 - 133 + 286 + 183 Advanced 100 0 Tool Type: 150 0 150 16777215 Instrument Fiducial Skinmarker Unkown 100 0 Identifier: <not given> 100 0 Serial Number: <not given> Tooltip: Qt::Horizontal 40 20 Edit Tooltip true Qt::Vertical 20 40 + + + + + + Tool Axis: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + QAbstractSpinBox::CorrectToPreviousValue + + + -9999 + + + 9999 + + + 1 + + + + + + + -9999 + + + 9999 + + + + + + + -9999 + + + 9999 + + + + + Qt::Horizontal Qt::Horizontal 40 20 Cancel Finished QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
1
QmitkPointListWidget QWidget
QmitkPointListWidget.h
1
diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidget.cpp b/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidget.cpp index 2f78379f4a..acdeae0ceb 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidget.cpp @@ -1,396 +1,419 @@ /*=================================================================== 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 "QmitkNavigationToolManagementWidget.h" //mitk headers #include "mitkTrackingTypes.h" #include #include #include #include #include #include +#include //qt headers #include #include #include +#include //poco headers #include const std::string QmitkNavigationToolManagementWidget::VIEW_ID = "org.mitk.views.navigationtoolmanagementwidget"; QmitkNavigationToolManagementWidget::QmitkNavigationToolManagementWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Controls = nullptr; CreateQtPartControl(this); CreateConnections(); } QmitkNavigationToolManagementWidget::~QmitkNavigationToolManagementWidget() { } void QmitkNavigationToolManagementWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkNavigationToolManagementWidgetControls; m_Controls->setupUi(parent); } //Disable StorageControls in the beginning, because there is no storage to edit DisableStorageControls(); } void QmitkNavigationToolManagementWidget::OnLoadTool() { if (m_NavigationToolStorage->isLocked()) { MessageBox("Storage is locked, cannot modify it. Maybe the tracking device which uses this storage is connected. If you want to modify the storage please disconnect the device first."); return; } mitk::NavigationToolReader::Pointer myReader = mitk::NavigationToolReader::New(); - std::string filename = QFileDialog::getOpenFileName(nullptr, tr("Add Navigation Tool"), "/", "*.IGTTool").toLatin1().data(); + std::string filename = QFileDialog::getOpenFileName(nullptr,tr("Add Navigation Tool"), QmitkIGTCommonHelper::GetLastFileLoadPath(), "*.IGTTool").toLatin1().data(); + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(QString::fromStdString(filename)); if (filename == "") return; mitk::NavigationTool::Pointer readTool = myReader->DoRead(filename); if (readTool.IsNull()) MessageBox("Error: " + myReader->GetErrorMessage()); else { if (!m_NavigationToolStorage->AddTool(readTool)) { MessageBox("Error: Can't add tool!"); m_DataStorage->Remove(readTool->GetDataNode()); } UpdateToolTable(); m_NavigationToolStorage->UpdateMicroservice(); } } void QmitkNavigationToolManagementWidget::OnSaveTool() { //if no item is selected, show error message: if (m_Controls->m_ToolList->currentItem() == nullptr) { MessageBox("Error: Please select tool first!"); return; } - mitk::NavigationToolWriter::Pointer myWriter = mitk::NavigationToolWriter::New(); - std::string filename = QFileDialog::getSaveFileName(nullptr, tr("Save Navigation Tool"), "/", "*.IGTTool").toLatin1().data(); - filename.append(".IGTTool"); - if (filename == "") return; - if (!myWriter->DoWrite(filename, m_NavigationToolStorage->GetTool(m_Controls->m_ToolList->currentIndex().row()))) - MessageBox("Error: " + myWriter->GetErrorMessage()); + mitk::NavigationToolWriter::Pointer myWriter = mitk::NavigationToolWriter::New(); + std::string filename = QFileDialog::getSaveFileName(nullptr,tr("Save Navigation Tool"), QmitkIGTCommonHelper::GetLastFileSavePath(), "*.IGTTool").toLatin1().data(); + QmitkIGTCommonHelper::SetLastFileSavePathByFileName(QString::fromStdString(filename)); + if (filename == "") return; + std::string fileExt = Poco::Path(filename).getExtension(); + if (fileExt == "") { filename.append(".IGTTool"); } + if (!myWriter->DoWrite(filename,m_NavigationToolStorage->GetTool(m_Controls->m_ToolList->currentIndex().row()))) + MessageBox("Error: "+ myWriter->GetErrorMessage()); } void QmitkNavigationToolManagementWidget::CreateConnections() { if (m_Controls) { //main widget page: connect((QObject*)(m_Controls->m_AddTool), SIGNAL(clicked()), this, SLOT(OnAddTool())); connect((QObject*)(m_Controls->m_DeleteTool), SIGNAL(clicked()), this, SLOT(OnDeleteTool())); connect((QObject*)(m_Controls->m_EditTool), SIGNAL(clicked()), this, SLOT(OnEditTool())); connect((QObject*)(m_Controls->m_MoveToolUp), SIGNAL(clicked()), this, SLOT(OnMoveToolUp())); connect((QObject*)(m_Controls->m_MoveToolDown), SIGNAL(clicked()), this, SLOT(OnMoveToolDown())); connect((QObject*)(m_Controls->m_LoadStorage), SIGNAL(clicked()), this, SLOT(OnLoadStorage())); connect((QObject*)(m_Controls->m_SaveStorage), SIGNAL(clicked()), this, SLOT(OnSaveStorage())); connect((QObject*)(m_Controls->m_LoadTool), SIGNAL(clicked()), this, SLOT(OnLoadTool())); connect((QObject*)(m_Controls->m_SaveTool), SIGNAL(clicked()), this, SLOT(OnSaveTool())); connect((QObject*)(m_Controls->m_CreateNewStorage), SIGNAL(clicked()), this, SLOT(OnCreateStorage())); //widget page "add tool": connect((QObject*)(m_Controls->m_ToolCreationWidget), SIGNAL(Canceled()), this, SLOT(OnAddToolCancel())); connect((QObject*)(m_Controls->m_ToolCreationWidget), SIGNAL(NavigationToolFinished()), this, SLOT(OnAddToolSave())); } } void QmitkNavigationToolManagementWidget::Initialize(mitk::DataStorage* dataStorage) { m_DataStorage = dataStorage; m_Controls->m_ToolCreationWidget->Initialize(m_DataStorage, "Tool0"); } void QmitkNavigationToolManagementWidget::LoadStorage(mitk::NavigationToolStorage::Pointer storageToLoad) { if (storageToLoad.IsNotNull()) { m_NavigationToolStorage = storageToLoad; m_Controls->m_StorageName->setText(m_NavigationToolStorage->GetName().c_str()); EnableStorageControls(); } else { m_NavigationToolStorage = nullptr; DisableStorageControls(); } UpdateToolTable(); m_NavigationToolStorage->UpdateMicroservice(); } //################################################################################## //############################## slots: main widget ################################ //################################################################################## void QmitkNavigationToolManagementWidget::OnMoveToolUp() { if (m_NavigationToolStorage.IsNotNull()) { int toolIndex = m_Controls->m_ToolList->currentIndex().row(); if (toolIndex >= 0) { mitk::NavigationTool::Pointer currentNavigationTool = m_NavigationToolStorage->GetTool(toolIndex); if (currentNavigationTool.IsNotNull()) { std::string currentIdentifier = currentNavigationTool->GetIdentifier(); int NewNumber = m_Controls->m_ToolList->currentIndex().row() - 1; if (NewNumber < 0) { MITK_WARN << "Cannot move tool up because it is on the top!"; } else { m_NavigationToolStorage->AssignToolNumber(currentIdentifier, NewNumber); } UpdateToolTable(); m_NavigationToolStorage->UpdateMicroservice(); } } } } void QmitkNavigationToolManagementWidget::OnMoveToolDown() { if (m_NavigationToolStorage.IsNotNull()) { int toolIndex = m_Controls->m_ToolList->currentIndex().row(); if (toolIndex >= 0) { mitk::NavigationTool::Pointer currentNavigationTool = m_NavigationToolStorage->GetTool(toolIndex); if (currentNavigationTool.IsNotNull()) { std::string currentIdentifier = currentNavigationTool->GetIdentifier(); int NewNumber = m_Controls->m_ToolList->currentIndex().row() + 1; if (NewNumber >= m_NavigationToolStorage->GetToolCount()) { MITK_WARN << "Cannot move tool down because it is the last tool in this storage!"; } else { m_NavigationToolStorage->AssignToolNumber(currentIdentifier, NewNumber); } UpdateToolTable(); m_NavigationToolStorage->UpdateMicroservice(); } } } } void QmitkNavigationToolManagementWidget::OnAddTool() { if (m_NavigationToolStorage->isLocked()) { MessageBox("Storage is locked, cannot modify it. Maybe the tracking device which uses this storage is connected. If you want to modify the storage please disconnect the device first."); return; } QString defaultIdentifier = "NavigationTool#" + QString::number(m_NavigationToolStorage->GetToolCount()); QString defaultName = "NavigationTool" + QString::number(m_NavigationToolStorage->GetToolCount()); m_Controls->m_ToolCreationWidget->Initialize(m_DataStorage, defaultIdentifier.toStdString(), defaultName.toStdString()); m_edit = false; m_Controls->m_MainWidgets->setCurrentIndex(1); m_NavigationToolStorage->UpdateMicroservice(); } void QmitkNavigationToolManagementWidget::OnDeleteTool() { //first: some checks if (m_NavigationToolStorage->isLocked()) { MessageBox("Storage is locked, cannot modify it. Maybe the tracking device which uses this storage is connected. If you want to modify the storage please disconnect the device first."); return; } else if (m_Controls->m_ToolList->currentItem() == nullptr) //if no item is selected, show error message: { MessageBox("Error: Please select tool first!"); return; } m_DataStorage->Remove(m_NavigationToolStorage->GetTool(m_Controls->m_ToolList->currentIndex().row())->GetDataNode()); m_NavigationToolStorage->DeleteTool(m_Controls->m_ToolList->currentIndex().row()); UpdateToolTable(); m_NavigationToolStorage->UpdateMicroservice(); } void QmitkNavigationToolManagementWidget::OnEditTool() { if (m_NavigationToolStorage->isLocked()) { MessageBox("Storage is locked, cannot modify it. Maybe the tracking device which uses this storage is connected. If you want to modify the storage please disconnect the device first."); return; } else if (m_Controls->m_ToolList->currentItem() == nullptr) //if no item is selected, show error message: { MessageBox("Error: Please select tool first!"); return; } mitk::NavigationTool::Pointer selectedTool = m_NavigationToolStorage->GetTool(m_Controls->m_ToolList->currentIndex().row()); m_Controls->m_ToolCreationWidget->SetDefaultData(selectedTool); m_NavigationToolStorage->SetName("test"); m_edit = true; m_Controls->m_MainWidgets->setCurrentIndex(1); m_NavigationToolStorage->UpdateMicroservice(); } void QmitkNavigationToolManagementWidget::OnCreateStorage() { QString storageName = QInputDialog::getText(nullptr, "Storage Name", "Name of the new tool storage:"); if (storageName.isNull()) return; m_NavigationToolStorage = mitk::NavigationToolStorage::New(this->m_DataStorage); m_NavigationToolStorage->SetName(storageName.toStdString()); m_Controls->m_StorageName->setText(m_NavigationToolStorage->GetName().c_str()); EnableStorageControls(); emit NewStorageAdded(m_NavigationToolStorage, storageName.toStdString()); } void QmitkNavigationToolManagementWidget::OnLoadStorage() { mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(m_DataStorage); std::string filename = QFileDialog::getOpenFileName(nullptr, tr("Open Navigation Tool Storage"), "/", tr("IGT Tool Storage (*.IGTToolStorage)")).toStdString(); if (filename == "") return; try { - mitk::NavigationToolStorage::Pointer tempStorage = myDeserializer->Deserialize(filename); + mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(m_DataStorage); + std::string filename = QFileDialog::getOpenFileName(NULL, tr("Open Navigation Tool Storage"), QmitkIGTCommonHelper::GetLastFileLoadPath(), tr("IGT Tool Storage (*.IGTToolStorage)")).toStdString(); + if (filename == "") return; + + QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(QString::fromStdString(filename)); - if (tempStorage.IsNull()) MessageBox("Error" + myDeserializer->GetErrorMessage()); - else + try + { + mitk::NavigationToolStorage::Pointer tempStorage = myDeserializer->Deserialize(filename); + + if (tempStorage.IsNull()) MessageBox("Error" + myDeserializer->GetErrorMessage()); + else + { + Poco::Path myPath = Poco::Path(filename.c_str()); + tempStorage->SetName(myPath.getFileName()); //set the filename as name for the storage, so the user can identify it + this->LoadStorage(tempStorage); + emit NewStorageAdded(m_NavigationToolStorage,myPath.getFileName()); + m_NavigationToolStorage->UpdateMicroservice(); + } + } + catch (const mitk::Exception& exception) { - Poco::Path myPath = Poco::Path(filename.c_str()); - tempStorage->SetName(myPath.getFileName()); //set the filename as name for the storage, so the user can identify it - this->LoadStorage(tempStorage); - emit NewStorageAdded(m_NavigationToolStorage, myPath.getFileName()); + MessageBox(exception.GetDescription()); } } catch (const mitk::Exception& exception) { MessageBox(exception.GetDescription()); } m_NavigationToolStorage->UpdateMicroservice(); } void QmitkNavigationToolManagementWidget::OnSaveStorage() -{ - //read in filename - QString filename = QFileDialog::getSaveFileName(nullptr, tr("Save Navigation Tool Storage"), "/", tr("IGT Tool Storage (*.IGTToolStorage)")); - if (filename.isEmpty()) return; //canceled by the user + { + QFileDialog *fileDialog = new QFileDialog; + fileDialog->setDefaultSuffix("IGTToolStorage"); + QString suffix = "IGT Tool Storage (*.IGTToolStorage)"; + QString filename = fileDialog->getSaveFileName(nullptr, tr("Save Navigation Tool Storage"), QmitkIGTCommonHelper::GetLastFileSavePath(), suffix, &suffix); - // add file extension if it wasn't added by the file dialog - if (filename.right(15) != ".IGTToolStorage") { filename += ".IGTToolStorage"; } + if (filename.isEmpty()) return; //canceled by the user + // check file suffix + QFileInfo file(filename); + if(file.suffix().isEmpty()) filename += ".IGTToolStorage"; //serialize tool storage mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); if (!mySerializer->Serialize(filename.toStdString(), m_NavigationToolStorage)) { MessageBox("Error: " + mySerializer->GetErrorMessage()); return; + QmitkIGTCommonHelper::SetLastFileSavePath(file.absolutePath()); } Poco::Path myPath = Poco::Path(filename.toStdString()); m_Controls->m_StorageName->setText(QString::fromStdString(myPath.getFileName())); } //################################################################################## //############################## slots: add tool widget ############################ //################################################################################## void QmitkNavigationToolManagementWidget::OnAddToolSave() { mitk::NavigationTool::Pointer newTool = m_Controls->m_ToolCreationWidget->GetCreatedTool(); if (m_edit) //here we edit a existing tool { mitk::NavigationTool::Pointer editedTool = m_NavigationToolStorage->GetTool(m_Controls->m_ToolList->currentIndex().row()); editedTool->Graft(newTool); } else //here we create a new tool { m_NavigationToolStorage->AddTool(newTool); } UpdateToolTable(); m_Controls->m_MainWidgets->setCurrentIndex(0); m_NavigationToolStorage->UpdateMicroservice(); } void QmitkNavigationToolManagementWidget::OnAddToolCancel() { m_Controls->m_MainWidgets->setCurrentIndex(0); } //################################################################################## //############################## private help methods ############################## //################################################################################## void QmitkNavigationToolManagementWidget::UpdateToolTable() { m_Controls->m_ToolList->clear(); if (m_NavigationToolStorage.IsNull()) return; for (int i = 0; i < m_NavigationToolStorage->GetToolCount(); i++) { QString currentTool = "Tool" + QString::number(i) + ": " + QString(m_NavigationToolStorage->GetTool(i)->GetDataNode()->GetName().c_str()) + " "; currentTool += "(" + QString::fromStdString(m_NavigationToolStorage->GetTool(i)->GetTrackingDeviceType()) + "/"; switch (m_NavigationToolStorage->GetTool(i)->GetType()) { case mitk::NavigationTool::Instrument: currentTool += "Instrument)"; break; case mitk::NavigationTool::Fiducial: currentTool += "Fiducial)"; break; case mitk::NavigationTool::Skinmarker: currentTool += "Skinmarker)"; break; default: currentTool += "Unknown)"; } m_Controls->m_ToolList->addItem(currentTool); } } void QmitkNavigationToolManagementWidget::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkNavigationToolManagementWidget::DisableStorageControls() { m_Controls->m_StorageName->setText(""); m_Controls->m_AddTool->setEnabled(false); m_Controls->m_LoadTool->setEnabled(false); m_Controls->m_MoveToolUp->setEnabled(false); m_Controls->m_MoveToolDown->setEnabled(false); m_Controls->m_selectedLabel->setEnabled(false); m_Controls->m_DeleteTool->setEnabled(false); m_Controls->m_EditTool->setEnabled(false); m_Controls->m_SaveTool->setEnabled(false); m_Controls->m_ToolList->setEnabled(false); m_Controls->m_SaveStorage->setEnabled(false); m_Controls->m_ToolLabel->setEnabled(false); } void QmitkNavigationToolManagementWidget::EnableStorageControls() { m_Controls->m_AddTool->setEnabled(true); m_Controls->m_LoadTool->setEnabled(true); m_Controls->m_MoveToolUp->setEnabled(true); m_Controls->m_MoveToolDown->setEnabled(true); m_Controls->m_selectedLabel->setEnabled(true); m_Controls->m_DeleteTool->setEnabled(true); m_Controls->m_EditTool->setEnabled(true); m_Controls->m_SaveTool->setEnabled(true); m_Controls->m_ToolList->setEnabled(true); m_Controls->m_SaveStorage->setEnabled(true); m_Controls->m_ToolLabel->setEnabled(true); } diff --git a/Modules/IGTUI/files.cmake b/Modules/IGTUI/files.cmake index 9678e39cb4..df2e5e6088 100644 --- a/Modules/IGTUI/files.cmake +++ b/Modules/IGTUI/files.cmake @@ -1,114 +1,116 @@ set(CPP_FILES Qmitk/QmitkTrackingDeviceWidget.cpp Qmitk/QmitkTrackingDeviceConfigurationWidget.cpp Qmitk/QmitkNDIConfigurationWidget.cpp Qmitk/QmitkFiducialRegistrationWidget.cpp Qmitk/QmitkNDIToolDelegate.cpp Qmitk/QmitkNavigationToolManagementWidget.cpp Qmitk/QmitkIGTLoggerWidget.cpp Qmitk/QmitkUpdateTimerWidget.cpp Qmitk/QmitkToolDistanceWidget.cpp Qmitk/QmitkToolTrackingStatusWidget.cpp Qmitk/QmitkTrackingSourcesCheckBoxPanelWidget.cpp Qmitk/QmitkIGTPlayerWidget.cpp Qmitk/QmitkIGTConnectionWidget.cpp Qmitk/QmitkToolSelectionWidget.cpp Qmitk/QmitkNavigationToolCreationWidget.cpp Qmitk/QmitkNavigationToolCreationAdvancedWidget.cpp Qmitk/QmitkNavigationDataSourceSelectionWidget.cpp Qmitk/QmitkInteractiveTransformationWidget.cpp Qmitk/QmitkNavigationToolStorageSelectionWidget.cpp Qmitk/QmitkNavigationDataPlayerControlWidget.cpp Qmitk/QmitkNavigationDataSequentialPlayerControlWidget.cpp Qmitk/QmitkNDIAuroraWidget.cpp Qmitk/QmitkNDIPolarisWidget.cpp Qmitk/QmitkMicronTrackerWidget.cpp Qmitk/QmitkNPOptitrackWidget.cpp Qmitk/QmitkVirtualTrackerWidget.cpp Qmitk/QmitkOpenIGTLinkWidget.cpp Qmitk/mitkTrackingDeviceWidgetCollection.cpp Qmitk/QmitkTrackingDeviceConfigurationWidgetScanPortsWorker.cpp Qmitk/QmitkTrackingDeviceConfigurationWidgetConnectionWorker.cpp Qmitk/QmitkNDIAbstractDeviceWidget.cpp Qmitk/QmitkAbstractTrackingDeviceWidget.cpp + Qmitk/QmitkIGTCommonHelper.cpp ) set(UI_FILES Qmitk/QmitkNavigationToolManagementWidgetControls.ui Qmitk/QmitkTrackingDeviceConfigurationWidgetControls.ui Qmitk/QmitkNDIConfigurationWidget.ui Qmitk/QmitkFiducialRegistrationWidget.ui Qmitk/QmitkIGTLoggerWidgetControls.ui Qmitk/QmitkUpdateTimerWidgetControls.ui Qmitk/QmitkToolDistanceWidgetControls.ui Qmitk/QmitkToolTrackingStatusWidgetControls.ui Qmitk/QmitkTrackingSourcesCheckBoxPanelWidgetControls.ui Qmitk/QmitkIGTPlayerWidgetControls.ui Qmitk/QmitkIGTConnectionWidgetControls.ui Qmitk/QmitkToolSelectionWidgetControls.ui Qmitk/QmitkNavigationToolCreationWidget.ui Qmitk/QmitkNavigationToolCreationAdvancedWidgetControls.ui Qmitk/QmitkNavigationDataSourceSelectionWidgetControls.ui Qmitk/QmitkInteractiveTransformationWidgetControls.ui Qmitk/QmitkNavigationToolStorageSelectionWidgetControls.ui Qmitk/QmitkNavigationDataPlayerControlWidget.ui Qmitk/QmitkNavigationDataSequentialPlayerControlWidget.ui Qmitk/QmitkNDIAuroraWidget.ui Qmitk/QmitkNDIPolarisWidget.ui Qmitk/QmitkMicronTrackerWidget.ui Qmitk/QmitkNPOptitrackWidget.ui Qmitk/QmitkVirtualTrackerWidget.ui Qmitk/QmitkOpenIGTLinkWidget.ui ) set(MOC_H_FILES Qmitk/QmitkNavigationToolManagementWidget.h Qmitk/QmitkTrackingDeviceWidget.h Qmitk/QmitkTrackingDeviceConfigurationWidget.h Qmitk/QmitkNDIConfigurationWidget.h Qmitk/QmitkFiducialRegistrationWidget.h Qmitk/QmitkNDIToolDelegate.h Qmitk/QmitkIGTLoggerWidget.h Qmitk/QmitkUpdateTimerWidget.h Qmitk/QmitkToolDistanceWidget.h Qmitk/QmitkToolTrackingStatusWidget.h Qmitk/QmitkTrackingSourcesCheckBoxPanelWidget.h Qmitk/QmitkIGTPlayerWidget.h Qmitk/QmitkIGTConnectionWidget.h Qmitk/QmitkToolSelectionWidget.h Qmitk/QmitkNavigationToolCreationWidget.h Qmitk/QmitkNavigationToolCreationAdvancedWidget.h Qmitk/QmitkNavigationDataSourceSelectionWidget.h Qmitk/QmitkInteractiveTransformationWidget.h Qmitk/QmitkNavigationToolStorageSelectionWidget.h Qmitk/QmitkNavigationDataPlayerControlWidget.h Qmitk/QmitkNavigationDataSequentialPlayerControlWidget.h Qmitk/QmitkNDIAuroraWidget.h Qmitk/QmitkNDIPolarisWidget.h Qmitk/QmitkMicronTrackerWidget.h Qmitk/QmitkNPOptitrackWidget.h Qmitk/QmitkVirtualTrackerWidget.h Qmitk/QmitkOpenIGTLinkWidget.h Qmitk/QmitkTrackingDeviceConfigurationWidgetScanPortsWorker.h Qmitk/QmitkTrackingDeviceConfigurationWidgetConnectionWorker.h Qmitk/QmitkNDIAbstractDeviceWidget.h Qmitk/QmitkAbstractTrackingDeviceWidget.h + Qmitk/QmitkIGTCommonHelper.h ) if(MITK_USE_POLHEMUS_TRACKER) set(CPP_FILES ${CPP_FILES} Qmitk/QmitkPolhemusTrackerWidget.cpp) set(UI_FILES ${UI_FILES} Qmitk/QmitkPolhemusTrackerWidget.ui) set(MOC_H_FILES ${MOC_H_FILES} Qmitk/QmitkPolhemusTrackerWidget.h) endif(MITK_USE_POLHEMUS_TRACKER) set(QRC_FILES resources/IGTUI.qrc ) diff --git a/Modules/OpenIGTLink/DeviceSources/mitkIGTL2DImageDeviceSource.cpp b/Modules/OpenIGTLink/DeviceSources/mitkIGTL2DImageDeviceSource.cpp index 509992e296..2883114c31 100644 --- a/Modules/OpenIGTLink/DeviceSources/mitkIGTL2DImageDeviceSource.cpp +++ b/Modules/OpenIGTLink/DeviceSources/mitkIGTL2DImageDeviceSource.cpp @@ -1,58 +1,55 @@ /*=================================================================== 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 "mitkIGTL2DImageDeviceSource.h" #include "mitkIGTLMessage.h" //Microservices #include #include #include #include //itk #include mitk::IGTL2DImageDeviceSource::IGTL2DImageDeviceSource() : mitk::IGTLDeviceSource() { this->SetName("IGTLDeviceSource (2D Images)"); } mitk::IGTL2DImageDeviceSource::~IGTL2DImageDeviceSource() { } void mitk::IGTL2DImageDeviceSource::GenerateData() { if (m_IGTLDevice.IsNull()) return; /* update output with message from the device */ IGTLMessage* msgOut = this->GetOutput(); assert(msgOut); igtl::MessageBase::Pointer msgIn = dynamic_cast(m_IGTLDevice->GetNextImage2dMessage().GetPointer()); if (msgIn.IsNotNull()) { assert(msgIn); - - MITK_INFO << "Received valid image"; - msgOut->SetMessage(msgIn); msgOut->SetName(msgIn->GetDeviceName()); } } diff --git a/Modules/OpenIGTLink/DeviceSources/mitkIGTLTransformDeviceSource.cpp b/Modules/OpenIGTLink/DeviceSources/mitkIGTLTransformDeviceSource.cpp index 25e4699a6d..26483d2f4c 100644 --- a/Modules/OpenIGTLink/DeviceSources/mitkIGTLTransformDeviceSource.cpp +++ b/Modules/OpenIGTLink/DeviceSources/mitkIGTLTransformDeviceSource.cpp @@ -1,58 +1,55 @@ /*=================================================================== 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 "mitkIGTLTransformDeviceSource.h" #include "mitkIGTLMessage.h" //Microservices #include #include #include #include //itk #include mitk::IGTLTransformDeviceSource::IGTLTransformDeviceSource() : mitk::IGTLDeviceSource() { this->SetName("IGTLDeviceSource (Transforms)"); } mitk::IGTLTransformDeviceSource::~IGTLTransformDeviceSource() { } void mitk::IGTLTransformDeviceSource::GenerateData() { if (m_IGTLDevice.IsNull()) return; /* update output with message from the device */ IGTLMessage* msgOut = this->GetOutput(); assert(msgOut); igtl::MessageBase::Pointer msgIn = dynamic_cast(m_IGTLDevice->GetNextTransformMessage().GetPointer()); if (msgIn.IsNotNull()) { assert(msgIn); - - //MITK_INFO << "Received valid image"; - msgOut->SetMessage(msgIn); msgOut->SetName(msgIn->GetDeviceName()); } } diff --git a/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.cpp b/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.cpp index ef30992896..e9a7426e10 100644 --- a/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.cpp +++ b/Modules/OpenIGTLink/Filters/mitkImageToIGTLMessageFilter.cpp @@ -1,259 +1,262 @@ /*=================================================================== 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 "mitkImageToIGTLMessageFilter.h" #include "mitkImageReadAccessor.h" #include "itkByteSwapper.h" #include "igtlImageMessage.h" mitk::ImageToIGTLMessageFilter::ImageToIGTLMessageFilter() { mitk::IGTLMessage::Pointer output = mitk::IGTLMessage::New(); this->SetNumberOfRequiredOutputs(1); this->SetNthOutput(0, output.GetPointer()); this->SetNumberOfRequiredInputs(1); } void mitk::ImageToIGTLMessageFilter::GenerateData() { // MITK_INFO << "ImageToIGTLMessageFilter.GenerateData()"; for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); ++i) { mitk::IGTLMessage* output = this->GetOutput(i); assert(output); const mitk::Image* img = this->GetInput(i); int dims = img->GetDimension(); int chn = img->GetNumberOfChannels(); - MITK_INFO << "Sending image. Dimensions: " << dims << " Channels: " << chn << "\n"; - if (dims < 1) { MITK_ERROR << "Can not handle dimensionless images"; } if (dims > 3) { MITK_ERROR << "Can not handle more than three dimensions"; continue; } if (chn != 1) { MITK_ERROR << "Can not handle anything but one channel. Image contained " << chn; continue; } igtl::ImageMessage::Pointer imgMsg = igtl::ImageMessage::New(); // TODO: Which kind of coordinate system does MITK really use? imgMsg->SetCoordinateSystem(igtl::ImageMessage::COORDINATE_RAS); // We could do this based on the host endiannes, but that's weird. // We instead use little endian, as most modern systems are little endian, // so there will probably not be an endian swap involved. imgMsg->SetEndian(igtl::ImageMessage::ENDIAN_LITTLE); // Set number of components. mitk::PixelType type = img->GetPixelType(); imgMsg->SetNumComponents(type.GetNumberOfComponents()); // Set scalar type. switch (type.GetComponentType()) { case itk::ImageIOBase::CHAR: imgMsg->SetScalarTypeToInt8(); break; case itk::ImageIOBase::UCHAR: imgMsg->SetScalarTypeToUint8(); break; case itk::ImageIOBase::SHORT: imgMsg->SetScalarTypeToInt16(); break; case itk::ImageIOBase::USHORT: imgMsg->SetScalarTypeToUint16(); break; case itk::ImageIOBase::INT: imgMsg->SetScalarTypeToInt32(); break; case itk::ImageIOBase::UINT: imgMsg->SetScalarTypeToUint32(); break; case itk::ImageIOBase::LONG: // OIGTL doesn't formally support 64bit int scalars, but if they are // ever added, // they will have the identifier 8 assigned. imgMsg->SetScalarType(8); break; case itk::ImageIOBase::ULONG: // OIGTL doesn't formally support 64bit uint scalars, but if they are // ever added, // they will have the identifier 9 assigned. imgMsg->SetScalarType(9); break; case itk::ImageIOBase::FLOAT: // The igtl library has no method for this. Correct type is 10. imgMsg->SetScalarType(10); break; case itk::ImageIOBase::DOUBLE: // The igtl library has no method for this. Correct type is 11. imgMsg->SetScalarType(11); break; default: MITK_ERROR << "Can not handle pixel component type " << type.GetComponentType(); return; } // Set transformation matrix. vtkMatrix4x4* matrix = img->GetGeometry()->GetVtkMatrix(); float matF[4][4]; for (size_t i = 0; i < 4; ++i) { for (size_t j = 0; j < 4; ++j) { matF[i][j] = matrix->GetElement(i, j); } } imgMsg->SetMatrix(matF); float spacing[3]; auto spacingImg = img->GetGeometry()->GetSpacing(); for (int i = 0; i < 3; ++i) spacing[i] = spacingImg[i]; imgMsg->SetSpacing(spacing); // Set dimensions. int sizes[3]; for (size_t j = 0; j < 3; ++j) { sizes[j] = img->GetDimension(j); } imgMsg->SetDimensions(sizes); // Allocate and copy data. imgMsg->AllocatePack(); imgMsg->AllocateScalars(); size_t num_pixel = sizes[0] * sizes[1] * sizes[2]; void* out = imgMsg->GetScalarPointer(); { // Scoped, so that readAccess will be released ASAP. mitk::ImageReadAccessor readAccess(img, img->GetChannelData(0)); const void* in = readAccess.GetData(); memcpy(out, in, num_pixel * type.GetSize()); } // We want to byte swap to little endian. We would like to just // swap by number of bytes for each component, but itk::ByteSwapper // is templated over element type, not over element size. So we need to // switch on the size and use types of the same size. size_t num_scalars = num_pixel * type.GetNumberOfComponents(); switch (type.GetComponentType()) { case itk::ImageIOBase::CHAR: case itk::ImageIOBase::UCHAR: // No endian conversion necessary, because a char is exactly one byte! break; case itk::ImageIOBase::SHORT: case itk::ImageIOBase::USHORT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian((short*)out, num_scalars); break; case itk::ImageIOBase::INT: case itk::ImageIOBase::UINT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian((int*)out, num_scalars); break; case itk::ImageIOBase::LONG: case itk::ImageIOBase::ULONG: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian((long*)out, num_scalars); break; case itk::ImageIOBase::FLOAT: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian((float*)out, num_scalars); break; case itk::ImageIOBase::DOUBLE: itk::ByteSwapper::SwapRangeFromSystemToLittleEndian( (double*)out, num_scalars); break; } + //copy timestamp of mitk image + igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New(); + timestamp->SetTime(img->GetMTime() / 1000, (int)(img->GetMTime()) % 1000); + imgMsg->SetTimeStamp(timestamp); + imgMsg->Pack(); output->SetMessage(imgMsg.GetPointer()); } } void mitk::ImageToIGTLMessageFilter::SetInput(const mitk::Image* img) { this->ProcessObject::SetNthInput(0, const_cast(img)); this->CreateOutputsForAllInputs(); } void mitk::ImageToIGTLMessageFilter::SetInput(unsigned int idx, const Image* img) { this->ProcessObject::SetNthInput(idx, const_cast(img)); this->CreateOutputsForAllInputs(); } const mitk::Image* mitk::ImageToIGTLMessageFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetInput(0)); } const mitk::Image* mitk::ImageToIGTLMessageFilter::GetInput(unsigned int idx) { if (this->GetNumberOfInputs() < idx + 1) { return nullptr; } return static_cast(this->ProcessObject::GetInput(idx)); } void mitk::ImageToIGTLMessageFilter::ConnectTo(mitk::ImageSource* upstream) { MITK_INFO << "Image source for this (" << this << ") mitkImageToIGTLMessageFilter is " << upstream; for (DataObjectPointerArraySizeType i = 0; i < upstream->GetNumberOfOutputs(); i++) { this->SetInput(i, upstream->GetOutput(i)); } } void mitk::ImageToIGTLMessageFilter::CreateOutputsForAllInputs() { // create one message output for all image inputs this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs()); for (size_t idx = 0; idx < this->GetNumberOfIndexedOutputs(); ++idx) { if (this->GetOutput(idx) == nullptr) { this->SetNthOutput(idx, this->MakeOutput(idx)); } this->Modified(); } } diff --git a/Modules/OpenIGTLink/Testing/mitkOpenIGTLinkClientServerTest.cpp b/Modules/OpenIGTLink/Testing/mitkOpenIGTLinkClientServerTest.cpp index 75c190525c..d2238e53fb 100644 --- a/Modules/OpenIGTLink/Testing/mitkOpenIGTLinkClientServerTest.cpp +++ b/Modules/OpenIGTLink/Testing/mitkOpenIGTLinkClientServerTest.cpp @@ -1,260 +1,260 @@ /*=================================================================== 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. ===================================================================*/ //TEST #include #include //STD #include #include //MITK #include "mitkIGTLServer.h" #include "mitkIGTLClient.h" #include "mitkIGTLMessageFactory.h" //IGTL #include "igtlStatusMessage.h" #include "igtlClientSocket.h" #include "igtlServerSocket.h" static int PORT = 35352; static const std::string HOSTNAME = "localhost"; static const std::string SERVER_DEVICE_NAME = "Test Server"; static const std::string CLIENT_ONE_DEVICE_NAME = "Test Client 1"; static const std::string CLIENT_TWO_DEVICE_NAME = "Test Client 2"; class mitkOpenIGTLinkClientServerTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkOpenIGTLinkClientServerTestSuite); //MITK_TEST(Test_JustIGTLImpl_OpenAndCloseAndThenReopenAndCloseServer_Successful); //MITK_TEST(Test_ConnectingOneClientAndOneServer_Successful); //MITK_TEST(Test_ConnectingMultipleClientsToOneServer_Successful); #ifdef _WIN32 //does only work under windows, see bug 19633 MITK_TEST(Test_DisconnectionServerFirst_Successful); #endif //MITK_TEST(Test_SendingMessageFromServerToOneClient_Successful); //MITK_TEST(Test_SendingMessageFromServerToMultipleClients_Successful); CPPUNIT_TEST_SUITE_END(); private: std::string m_Message; mitk::IGTLServer::Pointer m_Server; mitk::IGTLClient::Pointer m_Client_One; mitk::IGTLClient::Pointer m_Client_Two; mitk::IGTLMessageFactory::Pointer m_MessageFactory; public: void setUp() override { std::this_thread::sleep_for(std::chrono::milliseconds(20)); m_Message = "This is a test status message"; m_MessageFactory = mitk::IGTLMessageFactory::New(); m_Server = mitk::IGTLServer::New(true); m_Client_One = mitk::IGTLClient::New(true); m_Client_Two = mitk::IGTLClient::New(true); m_Server->SetObjectName(SERVER_DEVICE_NAME); m_Server->SetHostname(HOSTNAME); m_Server->SetName(SERVER_DEVICE_NAME); m_Server->SetPortNumber(PORT); m_Client_One->SetObjectName(CLIENT_ONE_DEVICE_NAME); m_Client_One->SetHostname(HOSTNAME); m_Client_One->SetName(CLIENT_ONE_DEVICE_NAME); m_Client_One->SetPortNumber(PORT); m_Client_Two->SetObjectName(CLIENT_TWO_DEVICE_NAME); m_Client_Two->SetHostname(HOSTNAME); m_Client_Two->SetName(CLIENT_TWO_DEVICE_NAME); m_Client_Two->SetPortNumber(PORT); } void tearDown() override { std::this_thread::sleep_for(std::chrono::milliseconds(20)); m_Message.clear(); m_Server = nullptr; m_Client_One = nullptr; m_Client_Two = nullptr; m_MessageFactory = nullptr; } void testMessagesEqual(igtl::MessageBase::Pointer sentMessage, igtl::MessageBase::Pointer receivedMessage) { std::string lhs(sentMessage->GetDeviceName()); std::string rhs(receivedMessage->GetDeviceName()); CPPUNIT_ASSERT_MESSAGE("The device names were not the same", lhs == rhs); igtl::StatusMessage::Pointer receivedStatusMessage = dynamic_cast(receivedMessage.GetPointer()); igtl::StatusMessage::Pointer sentStatusMessage = dynamic_cast(sentMessage.GetPointer()); CPPUNIT_ASSERT_MESSAGE("The received message was not of the appropriate type.", receivedStatusMessage != nullptr); CPPUNIT_ASSERT_MESSAGE("The sent message was not of the appropriate type.", sentStatusMessage != nullptr); lhs = receivedStatusMessage->GetStatusString(); rhs = sentStatusMessage->GetStatusString(); CPPUNIT_ASSERT_MESSAGE("The sent and received message did not contain the same status message.", lhs == rhs); CPPUNIT_ASSERT_MESSAGE("The sent message did not contain the correct status message.", lhs == m_Message); CPPUNIT_ASSERT_MESSAGE("The received message did not contain the correct status message.", m_Message == rhs); }; void Test_JustIGTLImpl_OpenAndCloseAndThenReopenAndCloseServer_Successful() { igtl::ServerSocket::Pointer server = igtl::ServerSocket::New(); igtl::ClientSocket::Pointer client = igtl::ClientSocket::New(); CPPUNIT_ASSERT(server->CreateServer(PORT) == 0); CPPUNIT_ASSERT(client->ConnectToServer("localhost", PORT) == 0); client->CloseSocket(); server->CloseSocket(); CPPUNIT_ASSERT(server->CreateServer(PORT) == 0); CPPUNIT_ASSERT(client->ConnectToServer("localhost", PORT) == 0); client->CloseSocket(); server->CloseSocket(); server = nullptr; client = nullptr; } void Test_ConnectingOneClientAndOneServer_Successful() { CPPUNIT_ASSERT_MESSAGE("Could not open Connection with Server", m_Server->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Could not connect to Server with first client", m_Client_One->OpenConnection()); CPPUNIT_ASSERT(m_Client_One->CloseConnection()); CPPUNIT_ASSERT(m_Server->CloseConnection()); } void Test_ConnectingMultipleClientsToOneServer_Successful() { CPPUNIT_ASSERT_MESSAGE("Could not open Connection with Server", m_Server->OpenConnection()); m_Server->StartCommunication(); CPPUNIT_ASSERT_MESSAGE("Could not connect to Server with first client", m_Client_One->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Could not start communication with first client", m_Client_One->StartCommunication()); CPPUNIT_ASSERT_MESSAGE("Could not connect to Server with second client", m_Client_Two->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Could not start communication with second client", m_Client_Two->StartCommunication()); CPPUNIT_ASSERT(m_Client_One->CloseConnection()); CPPUNIT_ASSERT(m_Client_Two->CloseConnection()); CPPUNIT_ASSERT(m_Server->CloseConnection()); } void Test_DisconnectionServerFirst_Successful() { CPPUNIT_ASSERT_MESSAGE("Could not open Connection with Server", m_Server->OpenConnection()); m_Server->StartCommunication(); CPPUNIT_ASSERT_MESSAGE("Could not connect to Server with first client", m_Client_One->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Could not start communication with first client", m_Client_One->StartCommunication()); CPPUNIT_ASSERT_MESSAGE("Could not connect to Server with second client", m_Client_Two->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Could not start communication with second client", m_Client_Two->StartCommunication()); std::this_thread::sleep_for(std::chrono::milliseconds(200)); CPPUNIT_ASSERT(m_Server->CloseConnection()); CPPUNIT_ASSERT(m_Client_One->CloseConnection()); CPPUNIT_ASSERT(m_Client_Two->CloseConnection()); } void Test_SendingMessageFromServerToOneClient_Successful() { CPPUNIT_ASSERT_MESSAGE("Server not connected to Client.", m_Server->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Client 1 not connected to Server.", m_Client_One->OpenConnection()); m_Server->StartCommunication(); m_Client_One->StartCommunication(); igtl::MessageBase::Pointer sentMessage = m_MessageFactory->CreateInstance("STATUS"); dynamic_cast(sentMessage.GetPointer())->SetStatusString(m_Message.c_str()); - m_Server->SendMessage(sentMessage); + m_Server->SendMessage(mitk::IGTLMessage::New(sentMessage)); igtl::MessageBase::Pointer receivedMessage; int steps = 0; while ((receivedMessage = m_Client_One->GetMessageQueue()->PullMiscMessage()) == nullptr) { std::this_thread::sleep_for(std::chrono::milliseconds(5)); if (++steps > 20) break; } CPPUNIT_ASSERT(receivedMessage != nullptr); CPPUNIT_ASSERT(m_Client_One->StopCommunication()); CPPUNIT_ASSERT(m_Server->StopCommunication()); CPPUNIT_ASSERT(m_Client_One->CloseConnection()); CPPUNIT_ASSERT(m_Server->CloseConnection()); testMessagesEqual(sentMessage, receivedMessage); } void Test_SendingMessageFromServerToMultipleClients_Successful() { CPPUNIT_ASSERT_MESSAGE("Server not connected to Client.", m_Server->OpenConnection()); m_Server->StartCommunication(); CPPUNIT_ASSERT_MESSAGE("Client 1 not connected to Server.", m_Client_One->OpenConnection()); m_Client_One->StartCommunication(); CPPUNIT_ASSERT_MESSAGE("Client 2 not connected to Server.", m_Client_Two->OpenConnection()); m_Client_Two->StartCommunication(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); igtl::MessageBase::Pointer sentMessage = m_MessageFactory->CreateInstance("STATUS"); dynamic_cast(sentMessage.GetPointer())->SetStatusString(m_Message.c_str()); - m_Server->SendMessage(sentMessage); + m_Server->SendMessage(mitk::IGTLMessage::New(sentMessage)); MITK_INFO << "SENT MESSAGE"; igtl::MessageBase::Pointer receivedMessage1; igtl::MessageBase::Pointer receivedMessage2; int steps = 0; while (receivedMessage1 == nullptr || receivedMessage2 == nullptr) { std::this_thread::sleep_for(std::chrono::milliseconds(20)); igtl::MessageBase::Pointer tmpMessage1 = m_Client_One->GetMessageQueue()->PullMiscMessage(); if (tmpMessage1.IsNotNull()) receivedMessage1 = tmpMessage1; igtl::MessageBase::Pointer tmpMessage2 = m_Client_Two->GetMessageQueue()->PullMiscMessage(); if (tmpMessage2.IsNotNull()) receivedMessage2 = tmpMessage2; if (++steps > 50) break; } CPPUNIT_ASSERT(m_Client_Two->StopCommunication()); CPPUNIT_ASSERT(m_Client_One->StopCommunication()); CPPUNIT_ASSERT(m_Server->StopCommunication()); CPPUNIT_ASSERT(m_Client_Two->CloseConnection()); CPPUNIT_ASSERT(m_Client_One->CloseConnection()); CPPUNIT_ASSERT(m_Server->CloseConnection()); CPPUNIT_ASSERT_MESSAGE("Message from first client was null..", receivedMessage1 != nullptr); CPPUNIT_ASSERT_MESSAGE("Message from first client was null..", receivedMessage1.IsNotNull()); CPPUNIT_ASSERT_MESSAGE("Message from second client was null..", receivedMessage2 != nullptr); CPPUNIT_ASSERT_MESSAGE("Message from second client was null..", receivedMessage2.IsNotNull()); testMessagesEqual(sentMessage, receivedMessage1); testMessagesEqual(sentMessage, receivedMessage2); testMessagesEqual(receivedMessage2, receivedMessage1); } }; MITK_TEST_SUITE_REGISTRATION(mitkOpenIGTLinkClientServer) diff --git a/Modules/OpenIGTLink/mitkIGTLClient.cpp b/Modules/OpenIGTLink/mitkIGTLClient.cpp index 953c8a4ad2..e480a92f8c 100644 --- a/Modules/OpenIGTLink/mitkIGTLClient.cpp +++ b/Modules/OpenIGTLink/mitkIGTLClient.cpp @@ -1,124 +1,124 @@ /*=================================================================== 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 "mitkIGTLClient.h" //#include "mitkIGTTimeStamp.h" //#include "mitkIGTHardwareException.h" #include "igtlTrackingDataMessage.h" #include #include #include #include #include typedef itk::MutexLockHolder MutexLockHolder; mitk::IGTLClient::IGTLClient(bool ReadFully) : IGTLDevice(ReadFully) { } mitk::IGTLClient::~IGTLClient() { } bool mitk::IGTLClient::OpenConnection() { if (this->GetState() != Setup) { mitkThrowException(mitk::Exception) << "Can only try to open the connection if in setup mode. State was " << this->GetState(); return false; } std::string hostname = this->GetHostname(); int portNumber = this->GetPortNumber(); if (portNumber == -1 || hostname.size() <= 0) { //port number or hostname was not correct MITK_WARN << "Port number or hostname was not correct"; return false; } //create a new client socket m_Socket = igtl::ClientSocket::New(); //try to connect to the igtl server int response = dynamic_cast(m_Socket.GetPointer())-> ConnectToServer(hostname.c_str(), portNumber); //check the response if (response != 0) { MITK_ERROR << "The client could not connect to " << hostname << " port: " << portNumber; return false; } // everything is initialized and connected so the communication can be started this->SetState(Ready); //inform observers about this new client this->InvokeEvent(NewClientConnectionEvent()); return true; } void mitk::IGTLClient::Receive() { //MITK_INFO << "Trying to receive message"; //try to receive a message, if the socket is not present anymore stop the //communication unsigned int status = this->ReceivePrivate(this->m_Socket); if (status == IGTL_STATUS_NOT_PRESENT) { this->StopCommunicationWithSocket(this->m_Socket); //inform observers about loosing the connection to this socket this->InvokeEvent(LostConnectionEvent()); MITK_WARN("IGTLClient") << "Lost connection to server socket."; } } void mitk::IGTLClient::Send() { - igtl::MessageBase::Pointer curMessage; + mitk::IGTLMessage::Pointer mitkMessage; //get the latest message from the queue - curMessage = this->m_MessageQueue->PullSendMessage(); + mitkMessage = this->m_MessageQueue->PullSendMessage(); // there is no message => return - if (curMessage.IsNull()) + if (mitkMessage.IsNull()) return; - if (!this->SendMessagePrivate(curMessage.GetPointer(), this->m_Socket)) + if (!this->SendMessagePrivate(mitkMessage, this->m_Socket)) { MITK_WARN("IGTLDevice") << "Could not send the message."; } } void mitk::IGTLClient::StopCommunicationWithSocket(igtl::Socket* /*socket*/) { m_StopCommunicationMutex->Lock(); m_StopCommunication = true; m_StopCommunicationMutex->Unlock(); } unsigned int mitk::IGTLClient::GetNumberOfConnections() { return this->m_Socket->GetConnected(); } diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.cpp b/Modules/OpenIGTLink/mitkIGTLDevice.cpp index ce7c9cc0be..9b2ec6b70c 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.cpp +++ b/Modules/OpenIGTLink/mitkIGTLDevice.cpp @@ -1,562 +1,564 @@ /*=================================================================== 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 "mitkIGTLDevice.h" //#include "mitkIGTException.h" //#include "mitkIGTTimeStamp.h" #include #include #include #include #include #include //remove later #include //TODO: Which timeout is acceptable and also needed to transmit image data? Is there a maximum data limit? static const int SOCKET_SEND_RECEIVE_TIMEOUT_MSEC = 100; typedef itk::MutexLockHolder MutexLockHolder; mitk::IGTLDevice::IGTLDevice(bool ReadFully) : // m_Data(mitk::DeviceDataUnspecified), m_State(mitk::IGTLDevice::Setup), m_Name("Unspecified Device"), m_StopCommunication(false), m_Hostname("127.0.0.1"), m_PortNumber(-1), m_MultiThreader(nullptr), m_SendThreadID(0), m_ReceiveThreadID(0), m_ConnectThreadID(0) { m_ReadFully = ReadFully; m_StopCommunicationMutex = itk::FastMutexLock::New(); m_StateMutex = itk::FastMutexLock::New(); // m_LatestMessageMutex = itk::FastMutexLock::New(); m_SendingFinishedMutex = itk::FastMutexLock::New(); m_ReceivingFinishedMutex = itk::FastMutexLock::New(); m_ConnectingFinishedMutex = itk::FastMutexLock::New(); // execution rights are owned by the application thread at the beginning m_SendingFinishedMutex->Lock(); m_ReceivingFinishedMutex->Lock(); m_ConnectingFinishedMutex->Lock(); m_MultiThreader = itk::MultiThreader::New(); // m_Data = mitk::DeviceDataUnspecified; // m_LatestMessage = igtl::MessageBase::New(); m_MessageFactory = mitk::IGTLMessageFactory::New(); m_MessageQueue = mitk::IGTLMessageQueue::New(); } mitk::IGTLDevice::~IGTLDevice() { /* stop communication and disconnect from igtl device */ if (GetState() == Running) { this->StopCommunication(); this->CloseConnection(); } else if (GetState() == Ready) { this->CloseConnection(); } /* cleanup tracking thread */ if (m_MultiThreader.IsNotNull()) { if ((m_SendThreadID != 0)) { m_MultiThreader->TerminateThread(m_SendThreadID); } if ((m_ReceiveThreadID != 0)) { m_MultiThreader->TerminateThread(m_ReceiveThreadID); } if ((m_ConnectThreadID != 0)) { m_MultiThreader->TerminateThread(m_ConnectThreadID); } } m_MultiThreader = nullptr; } mitk::IGTLDevice::IGTLDeviceState mitk::IGTLDevice::GetState() const { MutexLockHolder lock(*m_StateMutex); return m_State; } void mitk::IGTLDevice::SetState(IGTLDeviceState state) { itkDebugMacro("setting m_State to " << state); m_StateMutex->Lock(); // MutexLockHolder lock(*m_StateMutex); // lock and unlock the mutex if (m_State == state) { m_StateMutex->Unlock(); return; } m_State = state; m_StateMutex->Unlock(); this->Modified(); } bool mitk::IGTLDevice::TestConnection() { return true; } unsigned int mitk::IGTLDevice::ReceivePrivate(igtl::Socket* socket) { // Create a message buffer to receive header igtl::MessageHeader::Pointer headerMsg; headerMsg = igtl::MessageHeader::New(); // Initialize receive buffer headerMsg->InitPack(); // Receive generic header from the socket int r = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), 0); //MITK_INFO << "Server received r = " << r; //MITK_INFO << "Received r = " << r; if (r == 0) //connection error { // an error was received, therefore the communication with this socket // must be stoppedy return IGTL_STATUS_NOT_PRESENT; } else if (r == -1) //timeout { // a timeout was received, this is no error state, thus, do nothing return IGTL_STATUS_TIME_OUT; } else if (r == headerMsg->GetPackSize()) { // Deserialize the header and check the CRC // ERROR HERE: This probably means the header data is corrupted... int crcCheck = headerMsg->Unpack(1); if (crcCheck & igtl::MessageHeader::UNPACK_HEADER) { // Allocate a time stamp igtl::TimeStamp::Pointer ts; ts = igtl::TimeStamp::New(); // Get time stamp igtlUint32 sec; igtlUint32 nanosec; headerMsg->GetTimeStamp(ts); ts->GetTimeStamp(&sec, &nanosec); // std::cerr << "Time stamp: " // << sec << "." // << nanosec << std::endl; // std::cerr << "Dev type and name: " << headerMsg->GetDeviceType() << " " // << headerMsg->GetDeviceName() << std::endl; // headerMsg->Print(std::cout); //check the type of the received message //if it is a GET_, STP_ or RTS_ command push it into the command queue //otherwise continue reading the whole message from the socket const char* curDevType = headerMsg->GetDeviceType(); if (std::strstr(curDevType, "GET_") != nullptr || std::strstr(curDevType, "STP_") != nullptr || std::strstr(curDevType, "RTS_") != nullptr) { this->m_MessageQueue->PushCommandMessage(headerMsg); this->InvokeEvent(CommandReceivedEvent()); return IGTL_STATUS_OK; } //Create a message according to the header message igtl::MessageBase::Pointer curMessage; curMessage = m_MessageFactory->CreateInstance(headerMsg); //check if the curMessage is created properly, if not the message type is //not supported and the message has to be skipped if (curMessage.IsNull()) { socket->Skip(headerMsg->GetBodySizeToRead(), 0); // MITK_ERROR("IGTLDevice") << "The received type is not supported. Please " // "add it to the message factory."; return IGTL_STATUS_NOT_FOUND; } //insert the header to the message and allocate the pack curMessage->SetMessageHeader(headerMsg); curMessage->AllocatePack(); // Receive transform data from the socket int receiveCheck = 0; receiveCheck = socket->Receive(curMessage->GetPackBodyPointer(), curMessage->GetPackBodySize(), m_ReadFully); if (receiveCheck > 0) { int c = curMessage->Unpack(1); if (!(c & igtl::MessageHeader::UNPACK_BODY)) { return IGTL_STATUS_CHECKSUM_ERROR; } //check the type of the received message //if it is a command push it into the command queue //otherwise into the normal receive queue //STP_ commands are handled here because they implemented additional //member variables that are not stored in the header message if (std::strstr(curDevType, "STT_") != nullptr) { this->m_MessageQueue->PushCommandMessage(curMessage); this->InvokeEvent(CommandReceivedEvent()); } else { + if(m_LogMessages) + MITK_INFO << "Received Message: " << mitk::IGTLMessage::New(curMessage)->ToString(); this->m_MessageQueue->PushMessage(curMessage); this->InvokeEvent(MessageReceivedEvent()); } return IGTL_STATUS_OK; } else { MITK_ERROR("IGTLDevice") << "Received a valid header but could not " << "read the whole message."; return IGTL_STATUS_UNKNOWN_ERROR; } } else { //CRC check failed MITK_ERROR << "CRC Check failed"; return IGTL_STATUS_CHECKSUM_ERROR; } } else { //Message size information and actual data size don't match. //this state is not suppossed to be reached, return unknown error MITK_ERROR << "IGTL status unknown"; return IGTL_STATUS_UNKNOWN_ERROR; } } -void mitk::IGTLDevice::SendMessage(const mitk::IGTLMessage* msg) +void mitk::IGTLDevice::SendMessage(mitk::IGTLMessage::Pointer msg) { - this->SendMessage(msg->GetMessage()); -} - -void mitk::IGTLDevice::SendMessage(igtl::MessageBase::Pointer msg) -{ - //add the message to the queue m_MessageQueue->PushSendMessage(msg); } -unsigned int mitk::IGTLDevice::SendMessagePrivate(igtl::MessageBase::Pointer msg, +unsigned int mitk::IGTLDevice::SendMessagePrivate(mitk::IGTLMessage::Pointer msg, igtl::Socket::Pointer socket) { //check the input message if (msg.IsNull()) { MITK_ERROR("IGTLDevice") << "Could not send message because message is not " "valid. Please check."; return false; } - // add the name of this device to the message - msg->SetDeviceName(this->GetName().c_str()); + igtl::MessageBase* sendMessage = msg->GetMessage(); // Pack (serialize) and send - msg->Pack(); + sendMessage->Pack(); - int sendSuccess = socket->Send(msg->GetPackPointer(), msg->GetPackSize()); + int sendSuccess = socket->Send(sendMessage->GetPackPointer(), sendMessage->GetPackSize()); if (sendSuccess) { + if(m_LogMessages) + MITK_INFO << "Send IGTL message: " << msg->ToString(); + this->InvokeEvent(MessageSentEvent()); return IGTL_STATUS_OK; } else { return IGTL_STATUS_UNKNOWN_ERROR; } } void mitk::IGTLDevice::RunCommunication(void (IGTLDevice::*ComFunction)(void), itk::FastMutexLock* mutex) { if (this->GetState() != Running) return; try { // keep lock until end of scope MutexLockHolder communicationFinishedLockHolder(*mutex); // Because m_StopCommunication is used by two threads, access has to be guarded // by a mutex. To minimize thread locking, a local copy is used here bool localStopCommunication; // update the local copy of m_StopCommunication this->m_StopCommunicationMutex->Lock(); localStopCommunication = this->m_StopCommunication; this->m_StopCommunicationMutex->Unlock(); while ((this->GetState() == Running) && (localStopCommunication == false)) { (this->*ComFunction)(); /* Update the local copy of m_StopCommunication */ this->m_StopCommunicationMutex->Lock(); localStopCommunication = m_StopCommunication; this->m_StopCommunicationMutex->Unlock(); // time to relax, this sets the maximum ever possible framerate to 1000 Hz itksys::SystemTools::Delay(1); } } catch (...) { mutex->Unlock(); this->StopCommunication(); MITK_ERROR("IGTLDevice::RunCommunication") << "Error while communicating. Thread stopped."; //mitkThrowException(mitk::IGTException) << "Error while communicating. Thread stopped."; } // StopCommunication was called, thus the mode should be changed back to Ready now // that the tracking loop has ended. //this->SetState(Ready); //this is done elsewhere MITK_DEBUG("IGTLDevice::RunCommunication") << "Reached end of communication."; // returning from this function (and ThreadStartCommunication()) // this will end the thread return; } bool mitk::IGTLDevice::StartCommunication() { if (this->GetState() != Ready) return false; // go to mode Running this->SetState(Running); // set a timeout for the sending and receiving this->m_Socket->SetTimeout(SOCKET_SEND_RECEIVE_TIMEOUT_MSEC); // update the local copy of m_StopCommunication this->m_StopCommunicationMutex->Lock(); this->m_StopCommunication = false; this->m_StopCommunicationMutex->Unlock(); // transfer the execution rights to tracking thread m_SendingFinishedMutex->Unlock(); m_ReceivingFinishedMutex->Unlock(); m_ConnectingFinishedMutex->Unlock(); // start new threads that execute the communication m_SendThreadID = m_MultiThreader->SpawnThread(this->ThreadStartSending, this); m_ReceiveThreadID = m_MultiThreader->SpawnThread(this->ThreadStartReceiving, this); m_ConnectThreadID = m_MultiThreader->SpawnThread(this->ThreadStartConnecting, this); // mitk::IGTTimeStamp::GetInstance()->Start(this); return true; } bool mitk::IGTLDevice::StopCommunication() { if (this->GetState() == Running) // Only if the object is in the correct state { // m_StopCommunication is used by two threads, so we have to ensure correct // thread handling m_StopCommunicationMutex->Lock(); m_StopCommunication = true; m_StopCommunicationMutex->Unlock(); // we have to wait here that the other thread recognizes the STOP-command // and executes it m_SendingFinishedMutex->Lock(); m_ReceivingFinishedMutex->Lock(); m_ConnectingFinishedMutex->Lock(); // mitk::IGTTimeStamp::GetInstance()->Stop(this); // notify realtime clock // StopCommunication was called, thus the mode should be changed back // to Ready now that the tracking loop has ended. this->SetState(Ready); } return true; } bool mitk::IGTLDevice::CloseConnection() { if (this->GetState() == Setup) { return true; } else if (this->GetState() == Running) { this->StopCommunication(); } m_Socket->CloseSocket(); /* return to setup mode */ this->SetState(Setup); // this->InvokeEvent(mitk::LostConnectionEvent()); return true; } bool mitk::IGTLDevice::SendRTSMessage(const char* type) { //construct the device type for the return message, it starts with RTS_ and //continues with the requested type std::string returnType("RTS_"); returnType.append(type); //create a return message igtl::MessageBase::Pointer rtsMsg = this->m_MessageFactory->CreateInstance(returnType); //if retMsg is nullptr there is no return message defined and thus it is not //necessary to send one back if (rtsMsg.IsNotNull()) { - this->SendMessage(rtsMsg); + this->SendMessage(mitk::IGTLMessage::New(rtsMsg)); return true; } else { return false; } } void mitk::IGTLDevice::Connect() { MITK_DEBUG << "mitk::IGTLDevice::Connect();"; } igtl::ImageMessage::Pointer mitk::IGTLDevice::GetNextImage2dMessage() { return this->m_MessageQueue->PullImage2dMessage(); } igtl::ImageMessage::Pointer mitk::IGTLDevice::GetNextImage3dMessage() { return this->m_MessageQueue->PullImage3dMessage(); } igtl::TransformMessage::Pointer mitk::IGTLDevice::GetNextTransformMessage() { return this->m_MessageQueue->PullTransformMessage(); } igtl::TrackingDataMessage::Pointer mitk::IGTLDevice::GetNextTrackingDataMessage() { igtl::TrackingDataMessage::Pointer msg = this->m_MessageQueue->PullTrackingMessage(); return msg; } igtl::StringMessage::Pointer mitk::IGTLDevice::GetNextStringMessage() { return this->m_MessageQueue->PullStringMessage(); } igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextMiscMessage() { return this->m_MessageQueue->PullMiscMessage(); } igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextCommand() { return m_MessageQueue->PullCommandMessage(); } +void mitk::IGTLDevice::EnableNoBufferingMode(bool enable) +{ + m_MessageQueue->EnableNoBufferingMode(enable); +} -void mitk::IGTLDevice::EnableInfiniteBufferingMode( +void mitk::IGTLDevice::EnableNoBufferingMode( mitk::IGTLMessageQueue::Pointer queue, bool enable) { - queue->EnableInfiniteBuffering(enable); + queue->EnableNoBufferingMode(enable); } ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartSending(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == nullptr) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == nullptr) { return ITK_THREAD_RETURN_VALUE; } IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; if (igtlDevice != nullptr) { igtlDevice->RunCommunication(&mitk::IGTLDevice::Send, igtlDevice->m_SendingFinishedMutex); } igtlDevice->m_SendThreadID = 0; // erase thread id because thread will end. return ITK_THREAD_RETURN_VALUE; } ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartReceiving(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == nullptr) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == nullptr) { return ITK_THREAD_RETURN_VALUE; } IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; if (igtlDevice != nullptr) { igtlDevice->RunCommunication(&mitk::IGTLDevice::Receive, igtlDevice->m_ReceivingFinishedMutex); } igtlDevice->m_ReceiveThreadID = 0; // erase thread id because thread will end. return ITK_THREAD_RETURN_VALUE; } ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartConnecting(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == nullptr) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == nullptr) { return ITK_THREAD_RETURN_VALUE; } IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; if (igtlDevice != nullptr) { igtlDevice->RunCommunication(&mitk::IGTLDevice::Connect, igtlDevice->m_ConnectingFinishedMutex); } igtlDevice->m_ConnectThreadID = 0; // erase thread id because thread will end. return ITK_THREAD_RETURN_VALUE; } diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.h b/Modules/OpenIGTLink/mitkIGTLDevice.h index f337a304f2..15a499f6af 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.h +++ b/Modules/OpenIGTLink/mitkIGTLDevice.h @@ -1,417 +1,417 @@ /*=================================================================== 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 MITKIGTLDEVICE_H #define MITKIGTLDEVICE_H #include "mitkCommon.h" //itk #include "itkObject.h" #include "itkFastMutexLock.h" #include "itkMultiThreader.h" //igtl #include "igtlSocket.h" #include "igtlMessageBase.h" #include "igtlTransformMessage.h" //mitkIGTL #include "MitkOpenIGTLinkExports.h" #include "mitkIGTLMessageFactory.h" #include "mitkIGTLMessageQueue.h" #include "mitkIGTLMessage.h" namespace mitk { /** * \brief Interface for all OpenIGTLink Devices * * Defines the methods that are common for all devices using OpenIGTLink. It * can open/close a connection, start/stop a communication and send/receive * messages. * * It uses message queues to store the incoming and outgoing mails. They are * configurable, you can set buffering on and off. * * The device is in one of three different states: Setup, Ready or Running. * Setup is the initial state. From this state on you can call * OpenConnection() and arrive in the Ready state. From the Ready state you * call StartCommunication() to arrive in the Running state. Now the device * is continuosly checking for new connections, receiving messages and * sending messages. This runs in a seperate thread. To stop the communication * call StopCommunication() (to arrive in Ready state) or CloseConnection() * (to arrive in the Setup state). * * \ingroup OpenIGTLink * */ class MITKOPENIGTLINK_EXPORT IGTLDevice : public itk::Object { public: mitkClassMacroItkParent(IGTLDevice, itk::Object) IGTLDevice(bool ReadFully); /** * \brief Type for state variable. * The IGTLDevice is always in one of these states. * */ enum IGTLDeviceState { Setup, Ready, Running }; /** * \brief Opens a connection to the device * * This may only be called if there is currently no connection to the * device. If OpenConnection() is successful, the object will change from * Setup state to Ready state. */ virtual bool OpenConnection() = 0; /** * \brief Closes the connection to the device * * This may only be called if there is currently a connection to the * device, but device is not running (e.g. object is in Ready state) */ virtual bool CloseConnection(); /** * \brief Stops the communication between the two devices * * This may only be called if the device is in Running state. */ virtual bool StopCommunication(); /** * \brief Starts the communication between the two devices * * This may only be called if the device is in Ready state. */ bool StartCommunication(); /** * \brief Continuously calls the given function * * This may only be called if the device is in Running state and only from * a seperate thread. * * \param ComFunction function pointer that specifies the method to be executed * \param mutex the mutex that corresponds to the function pointer */ void RunCommunication(void (IGTLDevice::*ComFunction)(void), itk::FastMutexLock* mutex); + /** * \brief Adds the given message to the sending queue * * This may only be called after the connection to the device has been * established with a call to OpenConnection(). Note that the message * is not send directly. This method just adds it to the send queue. * \param msg The message to be added to the sending queue */ - void SendMessage(igtl::MessageBase::Pointer msg); - - /** - * \brief Adds the given message to the sending queue - * - * Convenience function to work with mitk::IGTLMessage directly. - * \param msg The message to be added to the sending queue - */ - void SendMessage(const IGTLMessage* msg); + void SendMessage(mitk::IGTLMessage::Pointer msg); /** * \brief Returns current object state (Setup, Ready or Running) */ IGTLDeviceState GetState() const; /** * \brief Returns the oldest message in the command queue * \return The oldest message from the command queue. */ igtl::MessageBase::Pointer GetNextCommand(); /** * \brief Returns the oldest message in the receive queue * \return The oldest message from the receive queue */ igtl::ImageMessage::Pointer GetNextImage2dMessage(); igtl::ImageMessage::Pointer GetNextImage3dMessage(); igtl::TransformMessage::Pointer GetNextTransformMessage(); igtl::TrackingDataMessage::Pointer GetNextTrackingDataMessage(); igtl::StringMessage::Pointer GetNextStringMessage(); igtl::MessageBase::Pointer GetNextMiscMessage(); /** * \brief Sets the port number of the device */ itkSetMacro(PortNumber, int); /** * \brief Returns the port number of the device */ itkGetMacro(PortNumber, int); /** * \brief Sets the ip/hostname of the device */ itkSetMacro(Hostname, std::string); /** * \brief Returns the ip/hostname of the device */ itkGetMacro(Hostname, std::string); /** * \brief Returns the name of this device */ itkGetConstMacro(Name, std::string); /** * \brief Sets the name of this device */ itkSetMacro(Name, std::string); /** * \brief Advises this IGTL Device to always block until the whole message is read. */ itkSetMacro(ReadFully, bool); /** * \brief Returns a const reference to the receive queue */ itkGetConstMacro(MessageQueue, mitk::IGTLMessageQueue::Pointer); /** * \brief Returns the message factory */ itkGetMacro(MessageFactory, mitk::IGTLMessageFactory::Pointer); /** * \brief static start method for the sending thread. * \param data a void pointer to the IGTLDevice object. */ static ITK_THREAD_RETURN_TYPE ThreadStartSending(void* data); /** * \brief static start method for the receiving thread. * \param data a void pointer to the IGTLDevice object. */ static ITK_THREAD_RETURN_TYPE ThreadStartReceiving(void* data); /** * \brief static start method for the connection thread. * \param data a void pointer to the IGTLDevice object. */ static ITK_THREAD_RETURN_TYPE ThreadStartConnecting(void* data); /** * \brief TestConnection() tries to connect to a IGTL device on the current * ip and port * * \todo Implement this method. Send a status message and check the answer. * * TestConnection() tries to connect to a IGTL server on the current * ip and port and returns which device it has found. * \return It returns the type of the device that answers. Throws an * exception * if no device is available on that ip/port. * @throw mitk::Exception Throws an exception if there are errors * while connecting to the device. */ virtual bool TestConnection(); /** * \brief Send RTS message of given type */ bool SendRTSMessage(const char* type); /** * \brief Sets the buffering mode of the given queue */ - void EnableInfiniteBufferingMode(mitk::IGTLMessageQueue::Pointer queue, + void EnableNoBufferingMode(mitk::IGTLMessageQueue::Pointer queue, bool enable = true); + void EnableNoBufferingMode(bool enable = true); + /** * \brief Returns the number of connections of this device */ virtual unsigned int GetNumberOfConnections() = 0; + itkGetMacro(LogMessages, bool); + itkSetMacro(LogMessages, bool); + protected: /** * \brief Sends a message. * * This may only be called after the connection to the device has been * established with a call to OpenConnection(). This method uses the given * socket to send the given MessageReceivedEvent * * \param msg the message to be sent * \param socket the socket used to communicate with the other device * * \retval IGTL_STATUS_OK the message was sent * \retval IGTL_STATUS_UNKONWN_ERROR the message was not sent because an * unknown error occurred */ - unsigned int SendMessagePrivate(igtl::MessageBase::Pointer msg, + unsigned int SendMessagePrivate(mitk::IGTLMessage::Pointer msg, igtl::Socket::Pointer socket); /** * \brief Call this method to receive a message. * * The message will be saved in the receive queue. */ virtual void Receive() = 0; /** * \brief Call this method to receive a message from the given device. * * The message will be saved in the receive queue. * * \param device the socket that connects this device with the other one. * * \retval IGTL_STATUS_OK a message or a command was received * \retval IGTL_STATUS_NOT_PRESENT the socket is not connected anymore * \retval IGTL_STATUS_TIME_OUT the socket timed out * \retval IGTL_STATUS_CHECKSUM_ERROR the checksum of the received msg was * incorrect * \retval IGTL_STATUS_UNKNOWN_ERROR an unknown error occurred */ unsigned int ReceivePrivate(igtl::Socket* device); /** * \brief Call this method to send a message. The message will be read from * the queue. */ virtual void Send() = 0; /** * \brief Call this method to check for other devices that want to connect * to this one. * * In case of a client this method is doing nothing. In case of a server it * is checking for other devices and if there is one it establishes a * connection. */ virtual void Connect(); /** * \brief Stops the communication with the given socket * */ virtual void StopCommunicationWithSocket(igtl::Socket* socket) = 0; /** * \brief change object state */ void SetState(IGTLDeviceState state); IGTLDevice(); virtual ~IGTLDevice(); /** current object state (Setup, Ready or Running) */ IGTLDeviceState m_State; /** the name of this device */ std::string m_Name; /** signal used to stop the thread*/ bool m_StopCommunication; /** mutex to control access to m_StopCommunication */ itk::FastMutexLock::Pointer m_StopCommunicationMutex; /** mutex used to make sure that the send thread is just started once */ itk::FastMutexLock::Pointer m_SendingFinishedMutex; /** mutex used to make sure that the receive thread is just started once */ itk::FastMutexLock::Pointer m_ReceivingFinishedMutex; /** mutex used to make sure that the connect thread is just started once */ itk::FastMutexLock::Pointer m_ConnectingFinishedMutex; /** mutex to control access to m_State */ itk::FastMutexLock::Pointer m_StateMutex; /** the hostname or ip of the device */ std::string m_Hostname; /** the port number of the device */ int m_PortNumber; /** the socket used to communicate with other IGTL devices */ igtl::Socket::Pointer m_Socket; /** The message receive queue */ mitk::IGTLMessageQueue::Pointer m_MessageQueue; /** A message factory that provides the New() method for all msg types */ mitk::IGTLMessageFactory::Pointer m_MessageFactory; + bool m_LogMessages; + private: /** creates worker thread that continuously polls interface for new messages */ itk::MultiThreader::Pointer m_MultiThreader; /** ID of sending thread */ int m_SendThreadID; /** ID of receiving thread */ int m_ReceiveThreadID; /** ID of connecting thread */ int m_ConnectThreadID; /** Always try to read the full message. */ bool m_ReadFully; }; /** * \brief connect to this Event to get notified when a message was successfully sent * * \note This event is invoked in the communication thread, therefore do not use it to make * changes in the GUI!!! Use the QT signal slot system to decouple this call from the com thread * */ itkEventMacro(MessageSentEvent, itk::AnyEvent); /** * \brief connect to this Event to get notified when a message was received * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacro(MessageReceivedEvent, itk::AnyEvent); /** * \brief connect to this Event to get notified when a command was received * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacro(CommandReceivedEvent, itk::AnyEvent); /** * \brief connect to this Event to get notified when another igtl device * connects with this device. * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacro(NewClientConnectionEvent, itk::AnyEvent); /** * \brief connect to this Event to get notified when this device looses the * connection to a socket. * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacro(LostConnectionEvent, itk::AnyEvent); } // namespace mitk #endif /* MITKIGTLDEVICE_H */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessage.cpp b/Modules/OpenIGTLink/mitkIGTLMessage.cpp index d0958d2553..5dd4b976c0 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessage.cpp +++ b/Modules/OpenIGTLink/mitkIGTLMessage.cpp @@ -1,170 +1,181 @@ /*=================================================================== 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 "mitkIGTLMessage.h" #include "mitkException.h" #include "mitkIGTLMessageCommon.h" mitk::IGTLMessage::IGTLMessage() : itk::DataObject(), -m_DataValid(false), m_IGTTimeStamp(0.0), m_Name() + m_DataValid(false), m_IGTTimeStamp(0), m_Name() { m_Message = igtl::MessageBase::New(); } mitk::IGTLMessage::IGTLMessage(const mitk::IGTLMessage& toCopy) : itk::DataObject() { // TODO SW: Graft does the same, remove code duplications, set Graft to // deprecated, remove duplication in tescode this->Graft(&toCopy); } mitk::IGTLMessage::~IGTLMessage() { } -mitk::IGTLMessage::IGTLMessage(igtl::MessageBase::Pointer message, - std::string name) +mitk::IGTLMessage::IGTLMessage(igtl::MessageBase::Pointer message) { this->SetMessage(message); - this->SetName(name); + this->SetName(message->GetDeviceName()); } void mitk::IGTLMessage::Graft( const DataObject *data ) { // Attempt to cast data to an IGTLMessage const Self* msg; try { msg = dynamic_cast(data); } catch( ... ) { itkExceptionMacro( << "mitk::IGTLMessage::Graft cannot cast " - << typeid(data).name() << " to " - << typeid(const Self *).name() ); + << typeid(data).name() << " to " + << typeid(const Self *).name() ); return; } if (!msg) { // pointer could not be cast back down itkExceptionMacro( << "mitk::IGTLMessage::Graft cannot cast " - << typeid(data).name() << " to " - << typeid(const Self *).name() ); + << typeid(data).name() << " to " + << typeid(const Self *).name() ); return; } // Now copy anything that is needed this->SetMessage(msg->GetMessage()); this->SetDataValid(msg->IsDataValid()); this->SetIGTTimeStamp(msg->GetIGTTimeStamp()); this->SetName(msg->GetName()); } void mitk::IGTLMessage::SetMessage(igtl::MessageBase::Pointer msg) { m_Message = msg; unsigned int ts = 0; unsigned int frac = 0; - m_Message->GetTimeStamp(&ts, &frac); - this->SetIGTTimeStamp((double)ts + (double)frac/1000.0); + m_Message->GetTimeStamp(&ts, &frac); //ts = seconds / frac = nanoseconds + this->SetName(m_Message->GetDeviceName()); + double timestamp = ts * 1000.0 + frac; + this->SetIGTTimeStamp(timestamp); this->SetDataValid(true); } bool mitk::IGTLMessage::IsDataValid() const { return m_DataValid; } void mitk::IGTLMessage::PrintSelf(std::ostream& os, itk::Indent indent) const { this->Superclass::PrintSelf(os, indent); os << indent << "name: " << this->GetName() << std::endl; os << indent << "data valid: " << this->IsDataValid() << std::endl; os << indent << "TimeStamp: " << this->GetIGTTimeStamp() << std::endl; os << indent << "OpenIGTLinkMessage: " << std::endl; m_Message->Print(os); } +std::string mitk::IGTLMessage::ToString() const +{ + std::stringstream output; + output << "name: " << this->GetName() << std::endl << + "MessageType: " << this->GetIGTLMessageType() << std::endl << + "TimeStamp: " << this->GetIGTTimeStamp() << std::endl << + "OpenIGTLinkMessage: " << std::endl; + return output.str(); +} + void mitk::IGTLMessage::CopyInformation( const DataObject* data ) { this->Superclass::CopyInformation( data ); const Self * nd = nullptr; try { nd = dynamic_cast(data); } catch( ... ) { // data could not be cast back down itkExceptionMacro(<< "mitk::IGTLMessage::CopyInformation() cannot cast " - << typeid(data).name() << " to " - << typeid(Self*).name() ); + << typeid(data).name() << " to " + << typeid(Self*).name() ); } if ( !nd ) { // pointer could not be cast back down itkExceptionMacro(<< "mitk::IGTLMessage::CopyInformation() cannot cast " - << typeid(data).name() << " to " - << typeid(Self*).name() ); + << typeid(data).name() << " to " + << typeid(Self*).name() ); } /* copy all meta data */ } bool mitk::Equal(const mitk::IGTLMessage& leftHandSide, const mitk::IGTLMessage& rightHandSide, ScalarType /*eps*/, bool verbose) { bool returnValue = true; if( std::string(rightHandSide.GetName()) != std::string(leftHandSide.GetName()) ) { if(verbose) { MITK_INFO << "[( IGTLMessage )] Name differs."; MITK_INFO << "leftHandSide is " << leftHandSide.GetName() - << "rightHandSide is " << rightHandSide.GetName(); + << "rightHandSide is " << rightHandSide.GetName(); } returnValue = false; } if( rightHandSide.GetIGTTimeStamp() != leftHandSide.GetIGTTimeStamp() ) { if(verbose) { MITK_INFO << "[( IGTLMessage )] IGTTimeStamp differs."; MITK_INFO << "leftHandSide is " << leftHandSide.GetIGTTimeStamp() - << "rightHandSide is " << rightHandSide.GetIGTTimeStamp(); + << "rightHandSide is " << rightHandSide.GetIGTTimeStamp(); } returnValue = false; } return returnValue; } const char* mitk::IGTLMessage::GetIGTLMessageType() const { return this->m_Message->GetDeviceType(); } template < typename IGTLMessageType > IGTLMessageType* mitk::IGTLMessage::GetMessage() const { return dynamic_cast(this->m_Message); } diff --git a/Modules/OpenIGTLink/mitkIGTLMessage.h b/Modules/OpenIGTLink/mitkIGTLMessage.h index ff66f82e14..4ad923f8a7 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessage.h +++ b/Modules/OpenIGTLink/mitkIGTLMessage.h @@ -1,197 +1,199 @@ /*=================================================================== 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 MITKIGTLMESSAGEH_HEADER_INCLUDED_ #define MITKIGTLMESSAGEH_HEADER_INCLUDED_ #include #include "MitkOpenIGTLinkExports.h" #include #include #include "igtlMessageBase.h" namespace mitk { /**Documentation * \brief A wrapper for the OpenIGTLink message type * * This class represents the data object that is passed through the * MITK-OpenIGTLink filter pipeline. It wraps the OpenIGTLink message type. * Additionally, it contains a data structure that contains error/plausibility * information. * */ class MITKOPENIGTLINK_EXPORT IGTLMessage : public itk::DataObject { public: mitkClassMacroItkParent(IGTLMessage, itk::DataObject); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - mitkNewMacro2Param(Self, igtl::MessageBase::Pointer,std::string); + mitkNewMacro1Param(Self, igtl::MessageBase::Pointer); /** - * \brief type that holds the time at which the data was recorded + * \brief type that holds the time at which the data was recorded in milliseconds */ typedef double TimeStampType; /** * \brief Sets the OpenIGTLink message */ void SetMessage(igtl::MessageBase::Pointer msg); /** * \brief returns the OpenIGTLink message */ itkGetConstMacro(Message, igtl::MessageBase::Pointer); /** * \brief returns true if the object contains valid data */ virtual bool IsDataValid() const; /** * \brief sets the dataValid flag of the IGTLMessage object indicating if * the object contains valid data */ itkSetMacro(DataValid, bool); /** * \brief gets the IGT timestamp of the IGTLMessage object */ itkGetConstMacro(IGTTimeStamp, TimeStampType); /** * \brief set the name of the IGTLMessage object */ itkSetStringMacro(Name); /** * \brief returns the name of the IGTLMessage object */ itkGetStringMacro(Name); /** * \brief Graft the data and information from one IGTLMessage to another. * * Copies the content of data into this object. * This is a convenience method to setup a second IGTLMessage object with * all the meta information of another IGTLMessage object. * Note that this method is different than just using two * SmartPointers to the same IGTLMessage object since separate DataObjects * are still maintained. */ virtual void Graft(const DataObject *data) override; /** * \brief copy meta data of a IGTLMessage object * * copies all meta data from IGTLMessage data to this object */ virtual void CopyInformation(const DataObject* data) override; /** * \brief Prints the object information to the given stream os. * \param os The stream which is used to print the output. * \param indent Defines the indentation of the output. */ void PrintSelf(std::ostream& os, itk::Indent indent) const override; + std::string ToString() const; + /** Compose with another IGTLMessage * * This method composes self with another IGTLMessage of the * same dimension, modifying self to be the composition of self * and other. If the argument pre is true, then other is * precomposed with self; that is, the resulting transformation * consists of first applying other to the source, followed by * self. If pre is false or omitted, then other is post-composed * with self; that is the resulting transformation consists of * first applying self to the source, followed by other. */ void Compose(const mitk::IGTLMessage::Pointer n, const bool pre = false); /** Returns the OpenIGTL Message type **/ const char* GetIGTLMessageType() const; template < typename IGTLMessageType > IGTLMessageType* GetMessage() const; protected: mitkCloneMacro(Self); IGTLMessage(); /** * Copy constructor internally used. */ IGTLMessage(const mitk::IGTLMessage& toCopy); /** * Creates a IGTLMessage object from an igtl::MessageBase and a given name. */ - IGTLMessage(igtl::MessageBase::Pointer message, std::string name = ""); + IGTLMessage(igtl::MessageBase::Pointer message); virtual ~IGTLMessage(); /** * \brief holds the actual OpenIGTLink message */ igtl::MessageBase::Pointer m_Message; /** * \brief defines if the object contains valid values */ bool m_DataValid; /** * \brief contains the time at which the tracking data was recorded */ TimeStampType m_IGTTimeStamp; /** * \brief name of the navigation data */ std::string m_Name; private: // pre = false static mitk::IGTLMessage::Pointer getComposition( const mitk::IGTLMessage::Pointer nd1, const mitk::IGTLMessage::Pointer nd2); /** * \brief sets the IGT timestamp of the IGTLMessage object */ itkSetMacro(IGTTimeStamp, TimeStampType); }; /** * @brief Equal A function comparing two OpenIGTLink message objects for * being equal in meta- and imagedata * * @ingroup MITKTestingAPI * * Following aspects are tested for equality: * - TBD * * @param rightHandSide An IGTLMessage to be compared * @param leftHandSide An IGTLMessage to be compared * @param eps Tolarence for comparison. You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output * or not. * @return true, if all subsequent comparisons are true, false otherwise */ MITKOPENIGTLINK_EXPORT bool Equal( const mitk::IGTLMessage& leftHandSide, const mitk::IGTLMessage& rightHandSide, ScalarType eps = mitk::eps, bool verbose = false ); } // namespace mitk #endif /* MITKIGTLMESSAGEH_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp b/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp index f7a76bf6fe..19500d89c2 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp +++ b/Modules/OpenIGTLink/mitkIGTLMessageProvider.cpp @@ -1,436 +1,432 @@ /*=================================================================== 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 "mitkIGTLMessageProvider.h" #include "mitkIGTLDevice.h" #include "mitkIGTLMessage.h" #include "mitkIGTLMessageFactory.h" #include "mitkCallbackFromGUIThread.h" //Microservices #include "usServiceReference.h" #include "usModuleContext.h" #include "usServiceEvent.h" #include "mitkServiceInterface.h" #include "usGetModuleContext.h" //igt (remove this later) #include "igtlBindMessage.h" #include "igtlQuaternionTrackingDataMessage.h" #include "igtlTrackingDataMessage.h" #ifndef WIN32 #include #endif mitk::IGTLMessageProvider::IGTLMessageProvider() : mitk::IGTLDeviceSource() { this->SetName("IGTLMessageProvider"); //m_MultiThreader = itk::MultiThreader::New(); m_StreamingTimeMutex = itk::FastMutexLock::New(); //m_StopStreamingThreadMutex = itk::FastMutexLock::New(); //m_ThreadId = 0; m_IsStreaming = false; // Create a command object. The function will be called later from the main thread this->m_StopStreamingCommand = ProviderCommand::New(); m_StopStreamingCommand->SetCallbackFunction(this, &mitk::IGTLMessageProvider::InvokeStopStreamingEvent); this->m_StreamingCommand = ProviderCommand::New(); m_StreamingCommand->SetCallbackFunction(this, &mitk::IGTLMessageProvider::InvokeStartStreamingEvent); } mitk::IGTLMessageProvider::~IGTLMessageProvider() { //// terminate worker thread on destruction //this->m_StopStreamingThreadMutex->Lock(); //this->m_StopStreamingThread = true; //this->m_StopStreamingThreadMutex->Unlock(); //if ( m_ThreadId >= 0) //{ // this->m_MultiThreader->TerminateThread(m_ThreadId); //} this->InvokeEvent(StreamingStartRequiredEvent()); } void mitk::IGTLMessageProvider::Update() { Superclass::Update(); if (this->GetInput() != nullptr) { igtl::MessageBase::Pointer curMessage = this->GetInput()->GetMessage(); if (dynamic_cast(curMessage.GetPointer()) != nullptr) { igtl::TrackingDataMessage* tdMsg = (igtl::TrackingDataMessage*)(curMessage.GetPointer()); igtl::TrackingDataElement::Pointer trackingData = igtl::TrackingDataElement::New(); tdMsg->GetTrackingDataElement(0, trackingData); float x_pos, y_pos, z_pos; trackingData->GetPosition(&x_pos, &y_pos, &z_pos); } } } void mitk::IGTLMessageProvider::GenerateData() { if (this->m_IGTLDevice.IsNull()) return; for (unsigned int index = 0; index < this->GetNumberOfIndexedInputs(); index++) { - const IGTLMessage* msg = this->GetInput(index); + mitk::IGTLMessage::Pointer msg = const_cast(this->GetInput(index)); if (msg == nullptr) { continue; } if ( !msg->IsDataValid() ) { continue; } - igtl::MessageBase::Pointer igtlMsg = msg->GetMessage(); - - if ( igtlMsg.IsNotNull() ) - { - //send the message - this->m_IGTLDevice->SendMessage(igtlMsg); - } + this->m_IGTLDevice->SendMessage(msg); } } void mitk::IGTLMessageProvider::CreateOutputs() { //if outputs are set then delete them if (this->GetNumberOfOutputs() > 0) { for (int numOP = this->GetNumberOfOutputs() - 1; numOP >= 0; numOP--) this->RemoveOutput(numOP); this->Modified(); } //fill the outputs if a valid OpenIGTLink device is set if (m_IGTLDevice.IsNull()) return; this->SetNumberOfIndexedOutputs(1); if (this->GetOutput(0) == nullptr) { DataObjectPointer newOutput = this->MakeOutput(0); this->SetNthOutput(0, newOutput); this->Modified(); } } //void mitk::IGTLMessageProvider::UpdateOutputInformation() //{ // this->Modified(); // make sure that we need to be updated // Superclass::UpdateOutputInformation(); //} void mitk::IGTLMessageProvider::OnIncomingMessage() { } void mitk::IGTLMessageProvider::OnLostConnection() { //in case the provider is streaming at the moment we have to stop it if (m_IsStreaming) { MITK_DEBUG("IGTLMessageProvider") << "lost connection, stop streaming"; this->StopStreamingOfAllSources(); } } std::string RemoveRequestPrefixes(std::string requestType) { return requestType.substr(4); } void mitk::IGTLMessageProvider::OnIncomingCommand() { //get the next command igtl::MessageBase::Pointer curCommand = this->m_IGTLDevice->GetNextCommand(); //extract the type const char * requestType = curCommand->GetDeviceType(); //check the type std::string reqType(requestType); bool isGetMsg = !reqType.find("GET_"); bool isSTTMsg = !reqType.find("STT_"); bool isSTPMsg = !reqType.find("STP_"); bool isRTSMsg = !reqType.find("RTS_"); //get the type from the request type (remove STT_, STP_, GET_, RTS_) std::string type = RemoveRequestPrefixes(requestType); //check all microservices if there is a fitting source for the requested type mitk::IGTLMessageSource::Pointer source = this->GetFittingSource(type.c_str()); //if there is no fitting source return a RTS message, if there is a RTS //type defined in the message factory send it if ( source.IsNull() ) { if ( !this->GetIGTLDevice()->SendRTSMessage(type.c_str()) ) { //sending RTS message failed, probably because the type is not in the //message factory MITK_WARN("IGTLMessageProvider") << "Tried to send a RTS message but did " "not succeed. Check if this type ( " << type << " ) was added to the message " "factory. "; } } else { if ( isGetMsg ) //if it is a single value push it into sending queue { //first it is necessary to update the source. This needs additional time //but is necessary. But are we really allowed to call this here? In which //thread are we? Is the source thread safe? source->Update(); mitk::IGTLMessage::Pointer sourceOutput = source->GetOutput(); if (sourceOutput.IsNotNull() && sourceOutput->IsDataValid()) { - igtl::MessageBase::Pointer sourceMsg = sourceOutput->GetMessage(); if ( source.IsNotNull() ) { - this->GetIGTLDevice()->SendMessage(sourceMsg); + this->GetIGTLDevice()->SendMessage(sourceOutput); } } } else if ( isSTTMsg ) { //read the requested frames per second int fps = 10; //read the fps from the command igtl::MessageBase* curCommandPt = curCommand.GetPointer(); if ( std::strcmp( curCommand->GetDeviceType(), "STT_BIND" ) == 0 ) { fps = ((igtl::StartBindMessage*)curCommandPt)->GetResolution(); } else if ( std::strcmp( curCommand->GetDeviceType(), "STT_QTDATA" ) == 0 ) { fps = ((igtl::StartQuaternionTrackingDataMessage*)curCommandPt)->GetResolution(); } else if ( std::strcmp( curCommand->GetDeviceType(), "STT_TDATA" ) == 0 ) { fps = ((igtl::StartTrackingDataMessage*)curCommandPt)->GetResolution(); } this->StartStreamingOfSource(source, fps); } else if ( isSTPMsg ) { this->StopStreamingOfSource(source); } else { //do nothing } } } bool mitk::IGTLMessageProvider::IsStreaming() { return m_IsStreaming; } void mitk::IGTLMessageProvider::StartStreamingOfSource(IGTLMessageSource* src, unsigned int fps) { if ( src == nullptr ) return; //so far the provider allows the streaming of a single source only //if the streaming thread is already running return a RTS message if ( !m_IsStreaming ) { //if it is a stream establish a connection between the provider and the //source this->ConnectTo(src); // calculate the streaming time this->m_StreamingTimeMutex->Lock(); this->m_StreamingTime = 1.0 / (double) fps * 1000.0; this->m_StreamingTimeMutex->Unlock(); //// For streaming we need a continues time signal, since there is no timer //// available we start a thread that generates a timing signal //// This signal is invoked from the other thread the update of the pipeline //// has to be executed from the main thread. Thus, we use the //// callbackfromGUIThread class to pass the execution to the main thread //this->m_ThreadId = m_MultiThreader->SpawnThread(this->TimerThread, this); mitk::CallbackFromGUIThread::GetInstance()->CallThisFromGUIThread( this->m_StreamingCommand); this->m_IsStreaming = true; } else { MITK_WARN("IGTLMessageProvider") << "This provider just supports the " "streaming of one source."; } } void mitk::IGTLMessageProvider::InvokeStartStreamingEvent() { this->InvokeEvent(StreamingStartRequiredEvent()); } void mitk::IGTLMessageProvider::InvokeStopStreamingEvent() { this->InvokeEvent(StreamingStopRequiredEvent()); } void mitk::IGTLMessageProvider::StopStreamingOfSource(IGTLMessageSource* src) { //this is something bad!!! The streaming thread has to be stopped before the //source is disconnected otherwise it can cause a crash. This has to be added!! this->DisconnectFrom(src); //this->m_StopStreamingThreadMutex->Lock(); //this->m_StopStreamingThread = true; //this->m_StopStreamingThreadMutex->Unlock(); mitk::CallbackFromGUIThread::GetInstance()->CallThisFromGUIThread( this->m_StopStreamingCommand); //does this flag needs a mutex??? this->m_IsStreaming = false; } void mitk::IGTLMessageProvider::StopStreamingOfAllSources() { // \todo remove all inputs mitk::CallbackFromGUIThread::GetInstance()->CallThisFromGUIThread( this->m_StopStreamingCommand); //does this flag needs a mutex??? this->m_IsStreaming = false; } mitk::IGTLMessageSource::Pointer mitk::IGTLMessageProvider::GetFittingSource(const char* requestedType) { //get the context us::ModuleContext* context = us::GetModuleContext(); //define the interface name std::string interface = mitk::IGTLMessageSource::US_INTERFACE_NAME; //specify a filter that defines the requested type std::string filter = "(" + mitk::IGTLMessageSource::US_PROPKEY_DEVICETYPE + "=" + requestedType + ")"; //find the fitting service std::vector serviceReferences = context->GetServiceReferences(interface, filter); //check if a service reference was found. It is also possible that several //services were found. This is not checked here, just the first one is taken. if ( serviceReferences.size() ) { mitk::IGTLMessageSource::Pointer curSource = context->GetService(serviceReferences.front()); if ( curSource.IsNotNull() ) return curSource; } //no service reference was found or found service reference has no valid source return nullptr; } -void mitk::IGTLMessageProvider::Send(const mitk::IGTLMessage* msg) +void mitk::IGTLMessageProvider::Send(mitk::IGTLMessage::Pointer msg) { if (msg != nullptr) + { + MITK_INFO << "Sending OpenIGTLink Message: " << msg->ToString(); this->m_IGTLDevice->SendMessage(msg); + } } void mitk::IGTLMessageProvider::ConnectTo( mitk::IGTLMessageSource* UpstreamFilter ) { for (DataObjectPointerArraySizeType i = 0; i < UpstreamFilter->GetNumberOfOutputs(); i++) { this->SetInput(i, UpstreamFilter->GetOutput(i)); } } void mitk::IGTLMessageProvider::DisconnectFrom( mitk::IGTLMessageSource* UpstreamFilter ) { for (DataObjectPointerArraySizeType i = 0; i < UpstreamFilter->GetNumberOfOutputs(); i++) { this->RemoveInput(UpstreamFilter->GetOutput(i)); } } //ITK_THREAD_RETURN_TYPE mitk::IGTLMessageProvider::TimerThread(void* pInfoStruct) //{ // // extract this pointer from thread info structure // struct itk::MultiThreader::ThreadInfoStruct * pInfo = // (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; // mitk::IGTLMessageProvider* thisObject = // static_cast(pInfo->UserData); // // itk::SimpleMutexLock mutex; // mutex.Lock(); // // thisObject->m_StopStreamingThreadMutex->Lock(); // thisObject->m_StopStreamingThread = false; // thisObject->m_StopStreamingThreadMutex->Unlock(); // // thisObject->m_StreamingTimeMutex->Lock(); // unsigned int waitingTime = thisObject->m_StreamingTime; // thisObject->m_StreamingTimeMutex->Unlock(); // // while (true) // { // thisObject->m_StopStreamingThreadMutex->Lock(); // bool stopThread = thisObject->m_StopStreamingThread; // thisObject->m_StopStreamingThreadMutex->Unlock(); // // if (stopThread) // { // break; // } // // //wait for the time given // //I know it is not the nicest solution but we just need an approximate time // //sleeps for 20 ms // #if defined (WIN32) || defined (_WIN32) // Sleep(waitingTime); // #else // usleep(waitingTime * 1000); // #endif // // // Ask to execute that command from the GUI thread // mitk::CallbackFromGUIThread::GetInstance()->CallThisFromGUIThread( // thisObject->m_StreamingCommand); // } // // thisObject->m_ThreadId = 0; // // mutex.Unlock(); // // return ITK_THREAD_RETURN_VALUE; //} diff --git a/Modules/OpenIGTLink/mitkIGTLMessageProvider.h b/Modules/OpenIGTLink/mitkIGTLMessageProvider.h index 77f2a43cb6..720513c774 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageProvider.h +++ b/Modules/OpenIGTLink/mitkIGTLMessageProvider.h @@ -1,226 +1,228 @@ /*=================================================================== 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 IGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ #define IGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ #include "mitkIGTLDevice.h" #include "mitkIGTLDeviceSource.h" //itk #include "itkCommand.h" namespace mitk { /** * \brief Provides information/objects from a MITK-Pipeline to other OpenIGTLink * devices * * This class is intended as the drain of the pipeline. Other OpenIGTLink * devices connect with the IGTLDevice hold by this provider. The other device * asks for a certain data type. The provider checks if there are other * IGTLMessageSources available that provide this data type. If yes the provider * connects with this source and sends the message to the requesting device. * * If a STT message was received the provider looks for fitting messageSources. * Once found it connects with it, starts a timing thread (which updates the * pipeline) and sends the result to the requesting device. * * If a GET message was received the provider just calls an update of the * found source and sends the result without connecting to the source. * * If a STP message was received it stops the thread and disconnects from the * previous source. * * So far the provider can just connect with one source. * * \ingroup OpenIGTLink */ class MITKOPENIGTLINK_EXPORT IGTLMessageProvider : public IGTLDeviceSource { public: mitkClassMacro(IGTLMessageProvider, IGTLDeviceSource); itkFactorylessNewMacro(Self) itkCloneMacro(Self) typedef itk::SimpleMemberCommand ProviderCommand; /** * \brief sends the msg to the requesting client * * Note: so far it broadcasts the message to all registered clients */ - void Send(const IGTLMessage* msg); + void Send(mitk::IGTLMessage::Pointer msg); /** * \brief Starts the streaming of the given message source with the given fps. */ void StartStreamingOfSource(mitk::IGTLMessageSource* src, unsigned int fps); /** * \brief Stops the streaming of the given message source. */ void StopStreamingOfSource(mitk::IGTLMessageSource* src); /** * \brief Stops the streaming of all message source. */ void StopStreamingOfAllSources(); /** * \brief Returns the streaming state. */ bool IsStreaming(); /** * \brief Get method for the streaming time */ itkGetMacro(StreamingTime, unsigned int); virtual void Update() override; protected: IGTLMessageProvider(); virtual ~IGTLMessageProvider(); /** * \brief filter execute method * * queries the OpenIGTLink device for new messages and updates its output * igtl::MessageBase objects with it. * \warning Will raise a std::out_of_range exception, if tools were added to * the OpenIGTLink device after it was set as input for this filter */ virtual void GenerateData() override; /** * \brief Create the necessary outputs for the m_IGTLDevice * * This Method is called internally whenever outputs need to be reset. Old * Outputs are deleted when called. **/ void CreateOutputs(); /** * \brief This method is called when the IGTL device hold by this class * receives a new message **/ virtual void OnIncomingMessage() override; /** * \brief This method is called when the IGTL device hold by this class * receives a new command **/ virtual void OnIncomingCommand() override; /** * \brief This method is called when the IGTL device lost the connection to the other side **/ virtual void OnLostConnection() override; /** *\brief Connects the input of this filter to the outputs of the given * IGTLMessageSource * * This method does not support smartpointer. use FilterX.GetPointer() to * retrieve a dumbpointer. */ void ConnectTo( mitk::IGTLMessageSource* UpstreamFilter ); /** *\brief Disconnects this filter from the outputs of the given * IGTLMessageSource * * This method does not support smartpointer. use FilterX.GetPointer() to * retrieve a dumbpointer. */ void DisconnectFrom( mitk::IGTLMessageSource* UpstreamFilter ); /** * \brief Looks for microservices that provide messages with the requested * type. **/ mitk::IGTLMessageSource::Pointer GetFittingSource(const char* requestedType); /** Invokes the start streaming event. This separate method is required, because it * has to be started from the main thread. (It is used as callback function) */ void InvokeStartStreamingEvent(); /** Invokes the stop streaming event. This separate method is required, because it * has to be started from the main thread. (It is used as callback function) */ void InvokeStopStreamingEvent(); private: /** * \brief a command that has to be executed in the main thread */ ProviderCommand::Pointer m_StreamingCommand; ProviderCommand::Pointer m_StopStreamingCommand; ///** // * \brief Timer thread for generating a continuous time signal for the stream // * // * Everyt time the time is passed a time signal is invoked. // * // * \param pInfoStruct pointer to the mitkIGTLMessageProvider object // * \return // */ //static ITK_THREAD_RETURN_TYPE TimerThread(void* pInfoStruct); //int m_ThreadId; ///** \brief timer thread will terminate after the next wakeup if set to true */ //bool m_StopStreamingThread; //itk::SmartPointer m_MultiThreader; /** \brief the time used for streaming */ unsigned int m_StreamingTime; /** \brief mutex for guarding m_Time */ itk::SmartPointer m_StreamingTimeMutex; ///** \brief mutex for guarding m_StopStreamingThread */ //itk::SmartPointer m_StopStreamingThreadMutex; /** \brief flag to indicate if the provider is streaming */ bool m_IsStreaming; unsigned long m_LostConnectionObserverTag; + + bool m_LogMessages; }; /** * \brief connect to this Event to get notified when a stream is requested * * \note It is necessary to do the following things to have streaming support: 1. listen to this * event. 2. When emitted start a timer with the given interval. 3. In the timeout method of * this timer call IGTLMessageProvider::Update. 4. Also listen to the StreamingStopRequiredEvent * and stop the timer imdediately. * */ itkEventMacro(StreamingStartRequiredEvent, itk::AnyEvent); /** * \brief connect to this Event to get notified when a stream shall be stopped * * \note It is necessary to connect to this event and stop the streaming timer when called. * */ itkEventMacro(StreamingStopRequiredEvent, itk::AnyEvent); } // namespace mitk #endif /* MITKIGTLMESSAGEPROVIDER_H_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp b/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp index 4d2244067b..9b8a1a1e15 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp +++ b/Modules/OpenIGTLink/mitkIGTLMessageQueue.cpp @@ -1,312 +1,312 @@ /*=================================================================== 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 "mitkIGTLMessageQueue.h" #include #include "igtlMessageBase.h" -void mitk::IGTLMessageQueue::PushSendMessage(igtl::MessageBase::Pointer message) +void mitk::IGTLMessageQueue::PushSendMessage(mitk::IGTLMessage::Pointer message) { this->m_Mutex->Lock(); - if (this->m_BufferingType == IGTLMessageQueue::Infinit) + if (this->m_BufferingType == IGTLMessageQueue::NoBuffering) m_SendQueue.clear(); m_SendQueue.push_back(message); this->m_Mutex->Unlock(); } void mitk::IGTLMessageQueue::PushCommandMessage(igtl::MessageBase::Pointer message) { this->m_Mutex->Lock(); - if (this->m_BufferingType == IGTLMessageQueue::Infinit) + if (this->m_BufferingType == IGTLMessageQueue::NoBuffering) m_CommandQueue.clear(); m_CommandQueue.push_back(message); this->m_Mutex->Unlock(); } void mitk::IGTLMessageQueue::PushMessage(igtl::MessageBase::Pointer msg) { this->m_Mutex->Lock(); std::stringstream infolog; infolog << "Received message of type "; if (dynamic_cast(msg.GetPointer()) != nullptr) { - if (this->m_BufferingType == IGTLMessageQueue::Infinit) + if (this->m_BufferingType == IGTLMessageQueue::NoBuffering) m_TrackingDataQueue.clear(); this->m_TrackingDataQueue.push_back(dynamic_cast(msg.GetPointer())); infolog << "TDATA"; } else if (dynamic_cast(msg.GetPointer()) != nullptr) { - if (this->m_BufferingType == IGTLMessageQueue::Infinit) + if (this->m_BufferingType == IGTLMessageQueue::NoBuffering) m_TransformQueue.clear(); this->m_TransformQueue.push_back(dynamic_cast(msg.GetPointer())); infolog << "TRANSFORM"; } else if (dynamic_cast(msg.GetPointer()) != nullptr) { - if (this->m_BufferingType == IGTLMessageQueue::Infinit) + if (this->m_BufferingType == IGTLMessageQueue::NoBuffering) m_StringQueue.clear(); this->m_StringQueue.push_back(dynamic_cast(msg.GetPointer())); infolog << "STRING"; } else if (dynamic_cast(msg.GetPointer()) != nullptr) { igtl::ImageMessage::Pointer imageMsg = dynamic_cast(msg.GetPointer()); int* dim = new int[3]; imageMsg->GetDimensions(dim); if (dim[2] > 1) { - if (this->m_BufferingType == IGTLMessageQueue::Infinit) + if (this->m_BufferingType == IGTLMessageQueue::NoBuffering) m_Image3dQueue.clear(); this->m_Image3dQueue.push_back(dynamic_cast(msg.GetPointer())); infolog << "IMAGE3D"; } else { - if (this->m_BufferingType == IGTLMessageQueue::Infinit) + if (this->m_BufferingType == IGTLMessageQueue::NoBuffering) m_Image2dQueue.clear(); this->m_Image2dQueue.push_back(dynamic_cast(msg.GetPointer())); infolog << "IMAGE2D"; } } else { - if (this->m_BufferingType == IGTLMessageQueue::Infinit) + if (this->m_BufferingType == IGTLMessageQueue::NoBuffering) m_MiscQueue.clear(); this->m_MiscQueue.push_back(msg); infolog << "OTHER"; } m_Latest_Message = msg; //MITK_INFO << infolog.str(); this->m_Mutex->Unlock(); } -igtl::MessageBase::Pointer mitk::IGTLMessageQueue::PullSendMessage() +mitk::IGTLMessage::Pointer mitk::IGTLMessageQueue::PullSendMessage() { - igtl::MessageBase::Pointer ret = nullptr; + mitk::IGTLMessage::Pointer ret = nullptr; this->m_Mutex->Lock(); if (this->m_SendQueue.size() > 0) { ret = this->m_SendQueue.front(); this->m_SendQueue.pop_front(); } this->m_Mutex->Unlock(); return ret; } igtl::MessageBase::Pointer mitk::IGTLMessageQueue::PullMiscMessage() { igtl::MessageBase::Pointer ret = nullptr; this->m_Mutex->Lock(); if (this->m_MiscQueue.size() > 0) { ret = this->m_MiscQueue.front(); this->m_MiscQueue.pop_front(); } this->m_Mutex->Unlock(); return ret; } igtl::ImageMessage::Pointer mitk::IGTLMessageQueue::PullImage2dMessage() { igtl::ImageMessage::Pointer ret = nullptr; this->m_Mutex->Lock(); if (this->m_Image2dQueue.size() > 0) { ret = this->m_Image2dQueue.front(); this->m_Image2dQueue.pop_front(); } this->m_Mutex->Unlock(); return ret; } igtl::ImageMessage::Pointer mitk::IGTLMessageQueue::PullImage3dMessage() { igtl::ImageMessage::Pointer ret = nullptr; this->m_Mutex->Lock(); if (this->m_Image3dQueue.size() > 0) { ret = this->m_Image3dQueue.front(); this->m_Image3dQueue.pop_front(); } this->m_Mutex->Unlock(); return ret; } igtl::TrackingDataMessage::Pointer mitk::IGTLMessageQueue::PullTrackingMessage() { igtl::TrackingDataMessage::Pointer ret = nullptr; this->m_Mutex->Lock(); if (this->m_TrackingDataQueue.size() > 0) { ret = this->m_TrackingDataQueue.front(); this->m_TrackingDataQueue.pop_front(); } this->m_Mutex->Unlock(); return ret; } igtl::MessageBase::Pointer mitk::IGTLMessageQueue::PullCommandMessage() { igtl::MessageBase::Pointer ret = nullptr; this->m_Mutex->Lock(); if (this->m_CommandQueue.size() > 0) { ret = this->m_CommandQueue.front(); this->m_CommandQueue.pop_front(); } this->m_Mutex->Unlock(); return ret; } igtl::StringMessage::Pointer mitk::IGTLMessageQueue::PullStringMessage() { igtl::StringMessage::Pointer ret = nullptr; this->m_Mutex->Lock(); if (this->m_StringQueue.size() > 0) { ret = this->m_StringQueue.front(); this->m_StringQueue.pop_front(); } this->m_Mutex->Unlock(); return ret; } igtl::TransformMessage::Pointer mitk::IGTLMessageQueue::PullTransformMessage() { igtl::TransformMessage::Pointer ret = nullptr; this->m_Mutex->Lock(); if (this->m_TransformQueue.size() > 0) { ret = this->m_TransformQueue.front(); this->m_TransformQueue.pop_front(); } this->m_Mutex->Unlock(); return ret; } std::string mitk::IGTLMessageQueue::GetNextMsgInformationString() { this->m_Mutex->Lock(); std::stringstream s; if (this->m_Latest_Message != nullptr) { s << "Device Type: " << this->m_Latest_Message->GetDeviceType() << std::endl; s << "Device Name: " << this->m_Latest_Message->GetDeviceName() << std::endl; } else { s << "No Msg"; } this->m_Mutex->Unlock(); return s.str(); } std::string mitk::IGTLMessageQueue::GetNextMsgDeviceType() { this->m_Mutex->Lock(); std::stringstream s; if (m_Latest_Message != nullptr) { s << this->m_Latest_Message->GetDeviceType(); } else { s << ""; } this->m_Mutex->Unlock(); return s.str(); } std::string mitk::IGTLMessageQueue::GetLatestMsgInformationString() { this->m_Mutex->Lock(); std::stringstream s; if (m_Latest_Message != nullptr) { s << "Device Type: " << this->m_Latest_Message->GetDeviceType() << std::endl; s << "Device Name: " << this->m_Latest_Message->GetDeviceName() << std::endl; } else { s << "No Msg"; } this->m_Mutex->Unlock(); return s.str(); } std::string mitk::IGTLMessageQueue::GetLatestMsgDeviceType() { this->m_Mutex->Lock(); std::stringstream s; if (m_Latest_Message != nullptr) { s << this->m_Latest_Message->GetDeviceType(); } else { s << ""; } this->m_Mutex->Unlock(); return s.str(); } int mitk::IGTLMessageQueue::GetSize() { return (this->m_CommandQueue.size() + this->m_Image2dQueue.size() + this->m_Image3dQueue.size() + this->m_MiscQueue.size() + this->m_StringQueue.size() + this->m_TrackingDataQueue.size() + this->m_TransformQueue.size()); } -void mitk::IGTLMessageQueue::EnableInfiniteBuffering(bool enable) +void mitk::IGTLMessageQueue::EnableNoBufferingMode(bool enable) { this->m_Mutex->Lock(); if (enable) - this->m_BufferingType = IGTLMessageQueue::BufferingType::Infinit; - else this->m_BufferingType = IGTLMessageQueue::BufferingType::NoBuffering; + else + this->m_BufferingType = IGTLMessageQueue::BufferingType::Infinit; this->m_Mutex->Unlock(); } mitk::IGTLMessageQueue::IGTLMessageQueue() { this->m_Mutex = itk::FastMutexLock::New(); - this->m_BufferingType = IGTLMessageQueue::Infinit; + this->m_BufferingType = IGTLMessageQueue::NoBuffering; } mitk::IGTLMessageQueue::~IGTLMessageQueue() { this->m_Mutex->Unlock(); -} \ No newline at end of file +} diff --git a/Modules/OpenIGTLink/mitkIGTLMessageQueue.h b/Modules/OpenIGTLink/mitkIGTLMessageQueue.h index 367d46c865..82626d4aa4 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageQueue.h +++ b/Modules/OpenIGTLink/mitkIGTLMessageQueue.h @@ -1,144 +1,143 @@ /*=================================================================== 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 IGTLMessageQueue_H #define IGTLMessageQueue_H #include "MitkOpenIGTLinkExports.h" #include "itkObject.h" #include "itkFastMutexLock.h" #include "mitkCommon.h" #include +#include //OpenIGTLink #include "igtlMessageBase.h" #include "igtlImageMessage.h" #include "igtlStringMessage.h" #include "igtlTrackingDataMessage.h" #include "igtlTransformMessage.h" namespace mitk { /** * \class IGTLMessageQueue * \brief Thread safe message queue to store OpenIGTLink messages. * * \ingroup OpenIGTLink */ class MITKOPENIGTLINK_EXPORT IGTLMessageQueue : public itk::Object { public: mitkClassMacroItkParent(mitk::IGTLMessageQueue, itk::Object) itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** * \brief Different buffering types * Infinit buffering means that you can push as many messages as you want * NoBuffering means that the queue just stores a single message */ enum BufferingType { Infinit, NoBuffering }; - void PushSendMessage(igtl::MessageBase::Pointer message); + void PushSendMessage(mitk::IGTLMessage::Pointer message); /** * \brief Adds the message to the queue */ void PushMessage(igtl::MessageBase::Pointer message); /** * \brief Adds the message to the queue */ void PushCommandMessage(igtl::MessageBase::Pointer message); /** * \brief Returns and removes the oldest message from the queue */ igtl::MessageBase::Pointer PullMiscMessage(); igtl::ImageMessage::Pointer PullImage2dMessage(); igtl::ImageMessage::Pointer PullImage3dMessage(); igtl::TrackingDataMessage::Pointer PullTrackingMessage(); igtl::MessageBase::Pointer PullCommandMessage(); igtl::StringMessage::Pointer PullStringMessage(); igtl::TransformMessage::Pointer PullTransformMessage(); - igtl::MessageBase::Pointer PullSendMessage(); + mitk::IGTLMessage::Pointer PullSendMessage(); /** * \brief Get the number of messages in the queue */ int GetSize(); /** * \brief Returns a string with information about the oldest message in the * queue */ std::string GetNextMsgInformationString(); /** * \brief Returns the device type of the oldest message in the queue */ std::string GetNextMsgDeviceType(); /** * \brief Returns a string with information about the oldest message in the * queue */ std::string GetLatestMsgInformationString(); /** * \brief Returns the device type of the oldest message in the queue */ std::string GetLatestMsgDeviceType(); /** - * \brief Sets infinite buffering on/off. - * Initiale value is enabled. - */ - void EnableInfiniteBuffering(bool enable); + */ + void EnableNoBufferingMode(bool enable); protected: IGTLMessageQueue(); virtual ~IGTLMessageQueue(); protected: /** * \brief Mutex to take car of the queue */ itk::FastMutexLock::Pointer m_Mutex; /** * \brief the queue that stores pointer to the inserted messages */ std::deque< igtl::MessageBase::Pointer > m_CommandQueue; std::deque< igtl::ImageMessage::Pointer > m_Image2dQueue; std::deque< igtl::ImageMessage::Pointer > m_Image3dQueue; std::deque< igtl::TransformMessage::Pointer > m_TransformQueue; std::deque< igtl::TrackingDataMessage::Pointer > m_TrackingDataQueue; std::deque< igtl::StringMessage::Pointer > m_StringQueue; std::deque< igtl::MessageBase::Pointer > m_MiscQueue; - std::deque< igtl::MessageBase::Pointer> m_SendQueue; + std::deque< mitk::IGTLMessage::Pointer > m_SendQueue; igtl::MessageBase::Pointer m_Latest_Message; /** * \brief defines the kind of buffering */ BufferingType m_BufferingType; }; } #endif diff --git a/Modules/OpenIGTLink/mitkIGTLServer.cpp b/Modules/OpenIGTLink/mitkIGTLServer.cpp index bafb56e16b..610bcbb1c0 100644 --- a/Modules/OpenIGTLink/mitkIGTLServer.cpp +++ b/Modules/OpenIGTLink/mitkIGTLServer.cpp @@ -1,218 +1,216 @@ /*=================================================================== 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 "mitkIGTLServer.h" #include #include #include #include #include #include #include mitk::IGTLServer::IGTLServer(bool ReadFully) : IGTLDevice(ReadFully) { m_ReceiveListMutex = itk::FastMutexLock::New(); m_SentListMutex = itk::FastMutexLock::New(); } mitk::IGTLServer::~IGTLServer() { m_ReceiveListMutex = nullptr; m_SentListMutex = nullptr; } bool mitk::IGTLServer::OpenConnection() { if (this->GetState() != Setup) { mitkThrowException(mitk::Exception) << "Can only try to create a server if in setup mode"; return false; } int portNumber = this->GetPortNumber(); if (portNumber == -1) { //port number was not correct return false; } //create a new server socket m_Socket = igtl::ServerSocket::New(); //try to create the igtl server int response = dynamic_cast(m_Socket.GetPointer())-> CreateServer(portNumber); //check the response if (response != 0) { mitkThrowException(mitk::Exception) << "The server could not be created. Port: " << portNumber; return false; } // everything is initialized and connected so the communication can be started this->SetState(Ready); return true; } bool mitk::IGTLServer::CloseConnection() { //remove all registered clients m_SentListMutex->Lock(); m_ReceiveListMutex->Lock(); SocketListType allRegisteredSockets(m_RegisteredClients); m_SentListMutex->Unlock(); m_ReceiveListMutex->Unlock(); this->StopCommunicationWithSocket(allRegisteredSockets); return mitk::IGTLDevice::CloseConnection(); } void mitk::IGTLServer::Connect() { igtl::Socket::Pointer socket; //check if another igtl device wants to connect to this socket socket = ((igtl::ServerSocket*)(this->m_Socket.GetPointer()))->WaitForConnection(1); //if there is a new connection the socket is not null if (socket.IsNotNull()) { //add the new client socket to the list of registered clients m_SentListMutex->Lock(); m_ReceiveListMutex->Lock(); this->m_RegisteredClients.push_back(socket); m_SentListMutex->Unlock(); m_ReceiveListMutex->Unlock(); //inform observers about this new client this->InvokeEvent(NewClientConnectionEvent()); MITK_INFO("IGTLServer") << "Connected to a new client: " << socket; } } void mitk::IGTLServer::Receive() { unsigned int status = IGTL_STATUS_OK; SocketListType socketsToBeRemoved; //the server can be connected with several clients, therefore it has to check //all registered clients SocketListIteratorType it; m_ReceiveListMutex->Lock(); auto it_end = this->m_RegisteredClients.end(); for (it = this->m_RegisteredClients.begin(); it != it_end; ++it) { //it is possible that ReceivePrivate detects that the current socket is //already disconnected. Therefore, it is necessary to remove this socket //from the registered clients list status = this->ReceivePrivate(*it); if (status == IGTL_STATUS_NOT_PRESENT) { //remember this socket for later, it is not a good idea to remove it //from the list directly because we iterate over the list at this point socketsToBeRemoved.push_back(*it); MITK_WARN("IGTLServer") << "Lost connection to a client socket. "; } else if (status != 1) { - MITK_WARN("IGTLServer") << "IGTL Message with status: " << status; + MITK_DEBUG("IGTLServer") << "IGTL Message with status: " << status; } } m_ReceiveListMutex->Unlock(); if (socketsToBeRemoved.size() > 0) { //remove the sockets that are not connected anymore this->StopCommunicationWithSocket(socketsToBeRemoved); //inform observers about loosing the connection to these sockets this->InvokeEvent(LostConnectionEvent()); } } void mitk::IGTLServer::Send() { - igtl::MessageBase::Pointer curMessage; - //get the latest message from the queue - curMessage = this->m_MessageQueue->PullSendMessage(); + mitk::IGTLMessage::Pointer curMessage = this->m_MessageQueue->PullSendMessage(); // there is no message => return if (curMessage.IsNull()) return; //the server can be connected with several clients, therefore it has to check //all registered clients //sending a message to all registered clients might not be the best solution, //it could be better to store the client together with the requested type. Then //the data would be send to the appropriate client and to noone else. //(I know it is no excuse but PLUS is doing exactly the same, they broadcast //everything) m_SentListMutex->Lock(); SocketListIteratorType it; auto it_end = this->m_RegisteredClients.end(); for (it = this->m_RegisteredClients.begin(); it != it_end; ++it) { //maybe there should be a check here if the current socket is still active - this->SendMessagePrivate(curMessage.GetPointer(), *it); + this->SendMessagePrivate(curMessage, *it); MITK_DEBUG("IGTLServer") << "Sent IGTL Message"; } m_SentListMutex->Unlock(); } void mitk::IGTLServer::StopCommunicationWithSocket( SocketListType& toBeRemovedSockets) { for (auto i = toBeRemovedSockets.begin(); i != toBeRemovedSockets.end(); i++) this->StopCommunicationWithSocket(*i); } void mitk::IGTLServer::StopCommunicationWithSocket(igtl::Socket* client) { m_SentListMutex->Lock(); m_ReceiveListMutex->Lock(); auto i = m_RegisteredClients.begin(); auto end = m_RegisteredClients.end(); while (i != end) { if ((*i) == client) { // //close the socket (*i)->CloseSocket(); //and remove it from the list i = this->m_RegisteredClients.erase(i); MITK_INFO("IGTLServer") << "Removed client socket from server client list."; break; } else { ++i; } } m_SentListMutex->Unlock(); m_ReceiveListMutex->Unlock(); } unsigned int mitk::IGTLServer::GetNumberOfConnections() { return this->m_RegisteredClients.size(); } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp index 071fa8637f..7fac13dfed 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp @@ -1,293 +1,293 @@ /*=================================================================== 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 "QmitkIGTLDeviceCommandWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include const std::string QmitkIGTLDeviceCommandWidget::VIEW_ID = "org.mitk.views.igtldevicesourcemanagementwidget"; QmitkIGTLDeviceCommandWidget::QmitkIGTLDeviceCommandWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false), m_MessageReceivedObserverTag(0), m_CommandReceivedObserverTag(0), m_LostConnectionObserverTag(0), m_NewConnectionObserverTag(0), m_StateModifiedObserverTag(0) { m_Controls = nullptr; this->m_IGTLDevice = nullptr; CreateQtPartControl(this); } QmitkIGTLDeviceCommandWidget::~QmitkIGTLDeviceCommandWidget() { if (m_MessageReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); if (m_CommandReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); if (m_LostConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); if (m_NewConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); if (m_StateModifiedObserverTag) this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } void QmitkIGTLDeviceCommandWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLDeviceCommandWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } //connect slots with signals CreateConnections(); } void QmitkIGTLDeviceCommandWidget::CreateConnections() { if (m_Controls) { // connect the widget items with the methods connect( m_Controls->butSendCommand, SIGNAL(clicked()), this, SLOT(OnSendCommand())); connect( m_Controls->commandsComboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(OnCommandChanged(const QString &))); } //this is used for thread seperation, otherwise the worker thread would change the ui elements //which would cause an exception connect(this, SIGNAL(AdaptGUIToStateSignal()), this, SLOT(AdaptGUIToState())); } void QmitkIGTLDeviceCommandWidget::OnDeviceStateChanged() { //this->AdaptGUIToState(); emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceCommandWidget::AdaptGUIToState() { if (this->m_IGTLDevice.IsNotNull()) { //check the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDevice->GetState(); switch (state) { case mitk::IGTLDevice::Setup: this->m_Controls->commandsComboBox->setEnabled(false); this->m_Controls->butSendCommand->setEnabled(false); this->m_Controls->fpsSpinBox->setEnabled(false); break; case mitk::IGTLDevice::Ready: this->m_Controls->commandsComboBox->setEnabled(true); this->m_Controls->butSendCommand->setEnabled(true); this->m_Controls->fpsSpinBox->setEnabled(false); break; case mitk::IGTLDevice::Running: if ( this->m_IGTLDevice->GetNumberOfConnections() == 0 ) { //just a server can run and have 0 connections this->m_Controls->butSendCommand->setEnabled(false); this->m_Controls->fpsSpinBox->setEnabled(false); this->m_Controls->commandsComboBox->setEnabled(false); } else { this->m_Controls->commandsComboBox->setEnabled(true); this->m_Controls->butSendCommand->setEnabled(true); // this->m_Controls->fpsSpinBox->setEnabled(true); } break; default: mitkThrow() << "Invalid Device State"; break; } } else { this->DisableSourceControls(); } } void QmitkIGTLDeviceCommandWidget::Initialize(mitk::IGTLDevice::Pointer device) { //reset the GUI DisableSourceControls(); //reset the observers if ( this->m_IGTLDevice.IsNotNull() ) { this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } if(device.IsNotNull()) { //get the device this->m_IGTLDevice = device; //check if the device is a server or a client if ( dynamic_cast( this->m_IGTLDevice.GetPointer()) == nullptr ) { m_IsClient = false; } else { m_IsClient = true; } typedef itk::SimpleMemberCommand< QmitkIGTLDeviceCommandWidget > CurCommandType; // CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); // messageReceivedCommand->SetCallbackFunction( // this, &QmitkIGTLDeviceCommandWidget::OnMessageReceived ); // this->m_MessageReceivedObserverTag = // this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); // CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); // commandReceivedCommand->SetCallbackFunction( // this, &QmitkIGTLDeviceCommandWidget::OnCommandReceived ); // this->m_CommandReceivedObserverTag = // this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); connectionLostCommand->SetCallbackFunction( this, &QmitkIGTLDeviceCommandWidget::OnLostConnection ); this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::LostConnectionEvent(), connectionLostCommand); CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkIGTLDeviceCommandWidget::OnNewConnection ); this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); stateModifiedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceCommandWidget::OnDeviceStateChanged ); this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( itk::ModifiedEvent(), stateModifiedCommand); //Fill the commands combo box with all available commands FillCommandsComboBox(); } else { m_IGTLDevice = nullptr; } this->AdaptGUIToState(); } void QmitkIGTLDeviceCommandWidget::DisableSourceControls() { this->m_Controls->commandsComboBox->setEnabled(false); this->m_Controls->butSendCommand->setEnabled(false); this->m_Controls->fpsSpinBox->setEnabled(false); } void QmitkIGTLDeviceCommandWidget::OnSendCommand() { //Set the frames per second of the current command in case of a STT_ command if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_BIND" ) == 0 ) { ((igtl::StartBindMessage*)this->m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } else if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_QTDATA" ) == 0 ) { ((igtl::StartQuaternionTrackingDataMessage*)m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } else if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_TDATA" ) == 0 ) { ((igtl::StartTrackingDataMessage*)this->m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } - m_IGTLDevice->SendMessage(m_CurrentCommand.GetPointer()); + m_IGTLDevice->SendMessage(mitk::IGTLMessage::New(m_CurrentCommand)); } void QmitkIGTLDeviceCommandWidget::OnCommandChanged( const QString & curCommand) { if ( curCommand.isEmpty() ) return; mitk::IGTLMessageFactory::Pointer msgFactory = this->m_IGTLDevice->GetMessageFactory(); //create a new message that fits to the selected get message type command this->m_CurrentCommand = msgFactory->CreateInstance( curCommand.toStdString()); //enable/disable the FPS spinbox this->m_Controls->fpsSpinBox->setEnabled(curCommand.contains("STT_")); } void QmitkIGTLDeviceCommandWidget::OnLostConnection() { //get the IGTL device that invoked this event // mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; //this->AdaptGUIToState(); emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceCommandWidget::OnNewConnection() { //this->AdaptGUIToState(); emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceCommandWidget::FillCommandsComboBox() { //load the msg factory from the client (maybe this will be moved later on) mitk::IGTLMessageFactory::Pointer msgFactory = this->m_IGTLDevice->GetMessageFactory(); //get the available commands as std::list std::list commandsList_ = msgFactory->GetAvailableMessageRequestTypes(); //create a string list to convert the std::list this->m_Controls->commandsComboBox->clear(); while ( commandsList_.size() ) { //fill the combo box with life this->m_Controls->commandsComboBox->addItem( QString::fromStdString(commandsList_.front())); commandsList_.pop_front(); } } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp index 561433fb83..7e4801aebc 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSetupConnectionWidget.cpp @@ -1,410 +1,410 @@ /*=================================================================== 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 "QmitkIGTLDeviceSetupConnectionWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include const std::string QmitkIGTLDeviceSetupConnectionWidget::VIEW_ID = "org.mitk.views.igtldevicesetupconnectionwidget"; QmitkIGTLDeviceSetupConnectionWidget::QmitkIGTLDeviceSetupConnectionWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false) { m_Controls = nullptr; this->m_IGTLDevice = nullptr; CreateQtPartControl(this); m_NumSentFramesSinceLastUpdate = 0; m_NumReceivedFramesSinceLastUpdate = 0; } QmitkIGTLDeviceSetupConnectionWidget::~QmitkIGTLDeviceSetupConnectionWidget() { this->RemoveObserver(); } void QmitkIGTLDeviceSetupConnectionWidget::RemoveObserver() { if (this->m_IGTLDevice.IsNotNull()) { this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_MessageSentObserverTag); this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } } void QmitkIGTLDeviceSetupConnectionWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLDeviceSetupConnectionWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } // set the validator for the ip edit box (values must be between 0 and 255 and // there are four of them, seperated with a point QRegExpValidator *v = new QRegExpValidator(this); QRegExp rx("((1{0,1}[0-9]{0,2}|2[0-4]{1,1}[0-9]{1,1}|25[0-5]{1,1})\\.){3,3}(1{0,1}[0-9]{0,2}|2[0-4]{1,1}[0-9]{1,1}|25[0-5]{1,1})"); v->setRegExp(rx); m_Controls->editIP->setValidator(v); // set the validator for the port edit box (values must be between 1 and 65535) m_Controls->editPort->setValidator(new QIntValidator(1, 65535, this)); m_FPSCalculationTimer.start(1000); //connect slots with signals CreateConnections(); } void QmitkIGTLDeviceSetupConnectionWidget::CreateConnections() { if (m_Controls) { // connect the widget items with the methods connect(m_Controls->butConnect, SIGNAL(clicked()), this, SLOT(OnConnect())); connect(m_Controls->editPort, SIGNAL(editingFinished()), this, SLOT(OnPortChanged())); connect(m_Controls->editIP, SIGNAL(editingFinished()), this, SLOT(OnHostnameChanged())); connect(m_Controls->bufferInMsgCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnBufferIncomingMessages(int))); connect(m_Controls->bufferOutMsgCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnBufferOutgoingMessages(int))); connect(&m_FPSCalculationTimer, SIGNAL(timeout()), this, SLOT(OnUpdateFPSLabel())); } //this is used for thread seperation, otherwise the worker thread would change the ui elements //which would cause an exception connect(this, SIGNAL(AdaptGUIToStateSignal()), this, SLOT(AdaptGUIToState())); } void QmitkIGTLDeviceSetupConnectionWidget::OnDeviceStateChanged() { emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSetupConnectionWidget::AdaptGUIToState() { //check the validity of the device if (this->m_IGTLDevice.IsNull()) { return; } //check the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDevice->GetState(); switch (state) { case mitk::IGTLDevice::Setup: if (!m_IsClient) { m_Controls->butConnect->setText("Go Online"); this->m_Controls->editIP->setEnabled(false); } else { m_Controls->butConnect->setText("Connect"); this->m_Controls->editIP->setEnabled(true); } this->m_Controls->editPort->setEnabled(true); this->m_Controls->logIncomingMsg->setEnabled(false); this->m_Controls->logOutgoingMsg->setEnabled(false); this->m_Controls->bufferInMsgCheckBox->setEnabled(false); this->m_Controls->bufferOutMsgCheckBox->setEnabled(false); this->m_Controls->butConnect->setEnabled(true); this->m_Controls->fpsInLabel->setEnabled(false); this->m_Controls->fpsOutLabel->setEnabled(false); this->m_Controls->fpsInDescrLabel->setEnabled(false); this->m_Controls->fpsOutDescrLabel->setEnabled(false); break; case mitk::IGTLDevice::Ready: if (m_IsClient) { this->m_Controls->butConnect->setText("Disconnect"); } else { this->m_Controls->butConnect->setText("Go Offline"); } this->m_Controls->editIP->setEnabled(false); this->m_Controls->editPort->setEnabled(false); this->m_Controls->logIncomingMsg->setEnabled(true); this->m_Controls->logOutgoingMsg->setEnabled(true); this->m_Controls->bufferInMsgCheckBox->setEnabled(true); this->m_Controls->bufferOutMsgCheckBox->setEnabled(true); this->m_Controls->butConnect->setEnabled(true); this->m_Controls->fpsInLabel->setEnabled(true); this->m_Controls->fpsOutLabel->setEnabled(true); this->m_Controls->fpsInDescrLabel->setEnabled(true); this->m_Controls->fpsOutDescrLabel->setEnabled(true); break; case mitk::IGTLDevice::Running: if (m_IsClient) { this->m_Controls->butConnect->setText("Disconnect"); } else { this->m_Controls->butConnect->setText("Go Offline"); } this->m_Controls->editIP->setEnabled(false); this->m_Controls->editPort->setEnabled(false); this->m_Controls->logIncomingMsg->setEnabled(true); this->m_Controls->logOutgoingMsg->setEnabled(true); this->m_Controls->bufferInMsgCheckBox->setEnabled(true); this->m_Controls->bufferOutMsgCheckBox->setEnabled(true); this->m_Controls->butConnect->setEnabled(true); this->m_Controls->fpsInLabel->setEnabled(true); this->m_Controls->fpsOutLabel->setEnabled(true); this->m_Controls->fpsInDescrLabel->setEnabled(true); this->m_Controls->fpsOutDescrLabel->setEnabled(true); break; default: mitkThrow() << "Invalid Device State"; break; } } void QmitkIGTLDeviceSetupConnectionWidget::Initialize( mitk::IGTLDevice::Pointer device) { //reset the GUI DisableSourceControls(); //reset the observers this->RemoveObserver(); if (device.IsNotNull()) { this->m_IGTLDevice = device; //check if the device is a server or a client if (dynamic_cast( this->m_IGTLDevice.GetPointer()) == nullptr) { m_IsClient = false; } else { m_IsClient = true; } this->AdaptGUIToState(); typedef itk::SimpleMemberCommand< QmitkIGTLDeviceSetupConnectionWidget > CurCommandType; CurCommandType::Pointer messageSentCommand = CurCommandType::New(); messageSentCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnMessageSent); this->m_MessageSentObserverTag = this->m_IGTLDevice->AddObserver( mitk::MessageSentEvent(), messageSentCommand); CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); messageReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnMessageReceived); this->m_MessageReceivedObserverTag = this->m_IGTLDevice->AddObserver( mitk::MessageReceivedEvent(), messageReceivedCommand); CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); commandReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnCommandReceived); this->m_CommandReceivedObserverTag = this->m_IGTLDevice->AddObserver( mitk::CommandReceivedEvent(), commandReceivedCommand); CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); connectionLostCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnLostConnection); this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::LostConnectionEvent(), connectionLostCommand); CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnNewConnection); this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); stateModifiedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSetupConnectionWidget::OnDeviceStateChanged); this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( itk::ModifiedEvent(), stateModifiedCommand); OnBufferIncomingMessages(m_Controls->bufferInMsgCheckBox->isChecked()); OnBufferOutgoingMessages(m_Controls->bufferOutMsgCheckBox->isChecked()); } else { m_IGTLDevice = nullptr; } } void QmitkIGTLDeviceSetupConnectionWidget::DisableSourceControls() { m_Controls->editIP->setEnabled(false); m_Controls->editPort->setEnabled(false); m_Controls->butConnect->setEnabled(false); m_Controls->bufferInMsgCheckBox->setEnabled(false); m_Controls->bufferOutMsgCheckBox->setEnabled(false); m_Controls->logIncomingMsg->setEnabled(false); m_Controls->logOutgoingMsg->setEnabled(false); } void QmitkIGTLDeviceSetupConnectionWidget::OnConnect() { if (m_IGTLDevice->GetState() == mitk::IGTLDevice::Setup) { QString port = m_Controls->editPort->text(); m_IGTLDevice->SetPortNumber(port.toInt()); std::string hostname = m_Controls->editIP->text().toStdString(); m_IGTLDevice->SetHostname(hostname); //connect with the other OpenIGTLink device => changes the state from Setup //to Ready if (m_IGTLDevice->OpenConnection()) { //starts the communication thread => changes the state from Ready to //Running if (m_IGTLDevice->StartCommunication()) { if (this->m_IsClient) { MITK_INFO("IGTLDeviceSourceManagementWidget") << "Successfully connected to " << hostname << " on port " << port.toStdString(); } } else { MITK_ERROR("QmitkIGTLDeviceSetupConnectionWidget") << "Could not start a communication with the" "server because the client is in the wrong state"; } } else { MITK_ERROR("QmitkIGTLDeviceSetupConnectionWidget") << "Could not connect to the server. " "Please check the hostname and port."; } } else if (m_IGTLDevice->GetState() == mitk::IGTLDevice::Ready || m_IGTLDevice->GetState() == mitk::IGTLDevice::Running) { m_IGTLDevice->CloseConnection(); MITK_INFO("QmitkIGTLDeviceSetupConnectionWidget") << "Closed connection"; } else { mitkThrow() << "Invalid state of IGTLDevice"; } this->AdaptGUIToState(); } void QmitkIGTLDeviceSetupConnectionWidget::OnPortChanged() { } void QmitkIGTLDeviceSetupConnectionWidget::OnHostnameChanged() { } void QmitkIGTLDeviceSetupConnectionWidget::OnLostConnection() { emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSetupConnectionWidget::OnNewConnection() { emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSetupConnectionWidget::OnMessageReceived() { if (this->m_Controls->logIncomingMsg->isChecked()) { MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Received a message: " << this->m_IGTLDevice->GetMessageQueue()->GetLatestMsgInformationString(); } m_NumReceivedFramesSinceLastUpdate++; } void QmitkIGTLDeviceSetupConnectionWidget::OnMessageSent() { if (this->m_Controls->logOutgoingMsg->isChecked()) { MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Sent a message."; } m_NumSentFramesSinceLastUpdate++; } void QmitkIGTLDeviceSetupConnectionWidget::OnCommandReceived() { if (this->m_Controls->logIncomingMsg->isChecked()) { MITK_INFO("IGTLDeviceSetupConnectionWidget") << "Received a command: " << this->m_IGTLDevice->GetMessageQueue()->GetLatestMsgInformationString(); } } void QmitkIGTLDeviceSetupConnectionWidget::OnBufferIncomingMessages(int state) { if (this->m_IGTLDevice.IsNotNull()) { - this->m_IGTLDevice->EnableInfiniteBufferingMode( + this->m_IGTLDevice->EnableNoBufferingMode( this->m_IGTLDevice->GetMessageQueue(), (bool)state); } } void QmitkIGTLDeviceSetupConnectionWidget::OnBufferOutgoingMessages(int state) { if (this->m_IGTLDevice.IsNotNull()) { - this->m_IGTLDevice->EnableInfiniteBufferingMode( + this->m_IGTLDevice->EnableNoBufferingMode( this->m_IGTLDevice->GetMessageQueue(), (bool)state); } } void QmitkIGTLDeviceSetupConnectionWidget::OnUpdateFPSLabel() { double fpsIn = m_NumReceivedFramesSinceLastUpdate / 1.0; double fpsOut = m_NumSentFramesSinceLastUpdate / 1.0; this->m_Controls->fpsInLabel->setText(QString::number(fpsIn)); this->m_Controls->fpsOutLabel->setText(QString::number(fpsOut)); m_NumReceivedFramesSinceLastUpdate = 0; m_NumSentFramesSinceLastUpdate = 0; } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp index 3f835d9fda..9979b38a2e 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp @@ -1,246 +1,246 @@ /*=================================================================== 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 "QmitkIGTLDeviceSourceManagementWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include const std::string QmitkIGTLDeviceSourceManagementWidget::VIEW_ID = "org.mitk.views.igtldevicesourcemanagementwidget"; QmitkIGTLDeviceSourceManagementWidget::QmitkIGTLDeviceSourceManagementWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false), m_MessageReceivedObserverTag(0), m_CommandReceivedObserverTag(0), m_LostConnectionObserverTag(0), m_NewConnectionObserverTag(0), m_StateModifiedObserverTag(0) { m_Controls = nullptr; this->m_IGTLDevice = nullptr; CreateQtPartControl(this); } QmitkIGTLDeviceSourceManagementWidget::~QmitkIGTLDeviceSourceManagementWidget() { if (m_MessageReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); if (m_CommandReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); if (m_LostConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); if (m_NewConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); if (m_StateModifiedObserverTag) this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } void QmitkIGTLDeviceSourceManagementWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLDeviceSourceManagementWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } //connect slots with signals CreateConnections(); } void QmitkIGTLDeviceSourceManagementWidget::CreateConnections() { if (m_Controls) { connect( m_Controls->butSend, SIGNAL(clicked()), this, SLOT(OnSendMessage())); } //this is used for thread seperation, otherwise the worker thread would change the ui elements //which would cause an exception connect(this, SIGNAL(AdaptGUIToStateSignal()), this, SLOT(AdaptGUIToState())); } void QmitkIGTLDeviceSourceManagementWidget::OnDeviceStateChanged() { emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSourceManagementWidget::AdaptGUIToState() { if (this->m_IGTLDeviceSource.IsNotNull()) { //check the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDeviceSource->GetIGTLDevice()->GetState(); switch (state) { case mitk::IGTLDevice::Setup: this->m_Controls->editSend->setEnabled(false); this->m_Controls->butSend->setEnabled(false); break; case mitk::IGTLDevice::Ready: this->m_Controls->editSend->setEnabled(false); this->m_Controls->butSend->setEnabled(false); break; case mitk::IGTLDevice::Running: if ( this->m_IGTLDevice->GetNumberOfConnections() == 0 ) { //just a server can run and have 0 connections this->m_Controls->editSend->setEnabled(false); this->m_Controls->butSend->setEnabled(false); } else { this->m_Controls->editSend->setEnabled(true); this->m_Controls->butSend->setEnabled(true); } break; default: mitkThrow() << "Invalid Device State"; break; } m_Controls->selectedSourceLabel->setText( m_IGTLDeviceSource->GetName().c_str()); } else { this->DisableSourceControls(); } } void QmitkIGTLDeviceSourceManagementWidget::LoadSource( mitk::IGTLDeviceSource::Pointer sourceToLoad) { //reset the GUI DisableSourceControls(); //reset the observers if ( this->m_IGTLDevice.IsNotNull() ) { if (m_MessageReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); if (m_CommandReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); if (m_LostConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); if (m_NewConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); if (m_StateModifiedObserverTag) this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } if(sourceToLoad.IsNotNull()) { this->m_IGTLDeviceSource = sourceToLoad; //get the device this->m_IGTLDevice = this->m_IGTLDeviceSource->GetIGTLDevice(); //initialize the other GUI elements this->m_Controls->connectionSetupWidget->Initialize(this->m_IGTLDevice); this->m_Controls->commandWidget->Initialize(this->m_IGTLDevice); //check if the device is a server or a client if ( dynamic_cast( this->m_IGTLDeviceSource->GetIGTLDevice()) == nullptr ) { m_IsClient = false; } else { m_IsClient = true; } typedef itk::SimpleMemberCommand< QmitkIGTLDeviceSourceManagementWidget > CurCommandType; CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); messageReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived ); this->m_MessageReceivedObserverTag = this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); commandReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnCommandReceived ); this->m_CommandReceivedObserverTag = this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); connectionLostCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnLostConnection ); this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::LostConnectionEvent(), connectionLostCommand); CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnNewConnection ); this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); stateModifiedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnDeviceStateChanged ); this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( itk::ModifiedEvent(), stateModifiedCommand); } else { m_IGTLDeviceSource = nullptr; } this->AdaptGUIToState(); } void QmitkIGTLDeviceSourceManagementWidget::DisableSourceControls() { m_Controls->selectedSourceLabel->setText(""); m_Controls->editSend->setEnabled(false); m_Controls->butSend->setEnabled(false); } void QmitkIGTLDeviceSourceManagementWidget::OnSendMessage() { std::string toBeSend = m_Controls->editSend->text().toStdString(); igtl::StringMessage::Pointer msg = igtl::StringMessage::New(); msg->SetString(toBeSend); - this->m_IGTLDevice->SendMessage(msg.GetPointer()); + this->m_IGTLDevice->SendMessage(mitk::IGTLMessage::New((igtl::MessageBase::Pointer)msg)); } void QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived() { } void QmitkIGTLDeviceSourceManagementWidget::OnCommandReceived() { } void QmitkIGTLDeviceSourceManagementWidget::OnLostConnection() { emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSourceManagementWidget::OnNewConnection() { emit AdaptGUIToStateSignal(); } diff --git a/Modules/US/USNavigation/Filter/mitkNeedleProjectionFilter.cpp b/Modules/US/USNavigation/Filter/mitkNeedleProjectionFilter.cpp index a186f8e255..4b4065d024 100644 --- a/Modules/US/USNavigation/Filter/mitkNeedleProjectionFilter.cpp +++ b/Modules/US/USNavigation/Filter/mitkNeedleProjectionFilter.cpp @@ -1,150 +1,169 @@ /*=================================================================== 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. ===================================================================*/ // MITK #include "mitkNeedleProjectionFilter.h" #include +#include "mitkUSCombinedModality.h" // VTK #include + mitk::NeedleProjectionFilter::NeedleProjectionFilter() : m_Projection(mitk::PointSet::New()), - m_OriginalPoints(mitk::PointSet::New()), - m_SelectedInput(-1) + m_OriginalPoints(mitk::PointSet::New()), + m_SelectedInput(-1) { - // Tool Coordinates: First point - Tip of Needle, Second Point - 40 cm distance from needle + // Tool Coordinates:x axis is chosen as default axis when no axis is specified for (int i = 0; i < 2; i++) { mitk::Point3D point; - point.SetElement(0,0); - point.SetElement(1,0); - point.SetElement(2, i * 400); + point.SetElement(0, i * 400); + point.SetElement(1, 0); + point.SetElement(2, 0); m_OriginalPoints->InsertPoint(i, point); } } -mitk::NeedleProjectionFilter::~NeedleProjectionFilter() +void mitk::NeedleProjectionFilter::SetToolAxisForFilter(mitk::Point3D point) { + // Tool Coordinates: First point - Tip of Needle, Second Point - 40 cm distance from needle + mitk::Point3D originPoint; + originPoint.SetElement(0, 0); + originPoint.SetElement(1, 0); + originPoint.SetElement(2, 0); + m_OriginalPoints->SetPoint(0, originPoint); + + mitk::Point3D endPoint; + endPoint.SetElement(0, point.GetElement(0) * 400); + endPoint.SetElement(1, point.GetElement(1) * 400); + endPoint.SetElement(2, point.GetElement(2) * 400); + MITK_INFO << "Tool axis in project filter:"; + MITK_INFO << endPoint; + m_OriginalPoints->SetPoint(1, endPoint); } +mitk::NeedleProjectionFilter::~NeedleProjectionFilter() +{ +} void mitk::NeedleProjectionFilter::SelectInput(int i) { if (i < 0) mitkThrow() << "Negative Input selected in NeedleProjectionFilter"; if (! (static_cast(i) < this->GetInputs().size())) mitkThrow() << "Selected input index is larger than actual number of inputs in NeedleProjectionFilter"; m_SelectedInput = i; } void mitk::NeedleProjectionFilter::GenerateData() { // copy the navigation data from the inputs to the outputs mitk::NavigationDataPassThroughFilter::GenerateData(); // If no reference has been set yet, warn and abort if (m_SelectedInput == -1) { MITK_INFO << "No input has been selected in NeedleProjection Filter. Only forwarding NavigationData..."; return; } // Cancel, if selected tool is currently not being tracked if (! GetInput(m_SelectedInput)->IsDataValid()) return; // Outputs have been updated, now to calculate the Projection // 1) Generate Pseudo-Geometry for Input mitk::AffineTransform3D::Pointer refTrans = this->NavigationDataToTransform(this->GetInput(m_SelectedInput)); mitk::Geometry3D::Pointer refGeom = this->TransformToGeometry(refTrans); // 2) Transform Original Pointset m_OriginalPoints->SetGeometry(refGeom); // Update Projection (We do not clone, since we want to keep properties alive) m_Projection->SetPoint(0, m_OriginalPoints->GetPoint(0)); m_Projection->SetPoint(1, m_OriginalPoints->GetPoint(1)); // 3a) If no target Plane has been set, then leave it at that if (this->m_TargetPlane.IsNull()) return; // 3b) else, calculate intersection with plane mitk::PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); plane->SetIndexToWorldTransform(m_TargetPlane); //plane->TransferItkToVtkTransform(); //included in SetIndexToWorldTransform double t; double x[3]; // Points that define the needle vector double p1[3] = {m_OriginalPoints->GetPoint(0)[0], m_OriginalPoints->GetPoint(0)[1], m_OriginalPoints->GetPoint(0)[2]}; double p2[3] = {m_OriginalPoints->GetPoint(1)[0], m_OriginalPoints->GetPoint(1)[1], m_OriginalPoints->GetPoint(1)[2]}; // Center of image plane and it's normal double center[3] = {plane->GetCenter()[0], plane->GetCenter()[1], plane->GetCenter()[2]}; double normal[3] = {plane->GetNormal()[0], plane->GetNormal()[1], plane->GetNormal()[2]}; vtkPlane::IntersectWithLine(p1, p2, normal, center, t, x); // change (cut) needle path only if the needle points to the image plane; // otherwise the needle path direction would be changed pointing to the image plane if ( t >= 0 ) { // Convert vtk to itk mitk::Point3D intersection; intersection[0] = x[0]; intersection[1] = x[1]; intersection[2] = x[2]; // Replace distant point with image intersection m_Projection->SetPoint(1, intersection); } } mitk::AffineTransform3D::Pointer mitk::NeedleProjectionFilter::NavigationDataToTransform(const mitk::NavigationData * nd) { mitk::AffineTransform3D::Pointer affineTransform = mitk::AffineTransform3D::New(); affineTransform->SetIdentity(); //calculate the transform from the quaternions static itk::QuaternionRigidTransform::Pointer quatTransform = itk::QuaternionRigidTransform::New(); mitk::NavigationData::OrientationType orientation = nd->GetOrientation(); // convert mitk::ScalarType quaternion to double quaternion because of itk bug vnl_quaternion doubleQuaternion(orientation.x(), orientation.y(), orientation.z(), orientation.r()); quatTransform->SetIdentity(); quatTransform->SetRotation(doubleQuaternion); quatTransform->Modified(); /* because of an itk bug, the transform can not be calculated with float data type. To use it in the mitk geometry classes, it has to be transfered to mitk::ScalarType which is float */ static AffineTransform3D::MatrixType m; mitk::TransferMatrix(quatTransform->GetMatrix(), m); affineTransform->SetMatrix(m); /*set the offset by convert from itkPoint to itkVector and setting offset of transform*/ mitk::Vector3D pos; pos.SetVnlVector(nd->GetPosition().GetVnlVector()); affineTransform->SetOffset(pos); affineTransform->Modified(); return affineTransform; } mitk::Geometry3D::Pointer mitk::NeedleProjectionFilter::TransformToGeometry(mitk::AffineTransform3D::Pointer transform){ mitk::Geometry3D::Pointer g3d = mitk::Geometry3D::New(); mitk::ScalarType scale[] = {1.0, 1.0, 1.0}; g3d->SetSpacing(scale); g3d->SetIndexToWorldTransform(transform); //g3d->TransferItkToVtkTransform(); // update VTK Transform for rendering too //included in SetIndexToWorldTransform g3d->Modified(); return g3d; } diff --git a/Modules/US/USNavigation/Filter/mitkNeedleProjectionFilter.h b/Modules/US/USNavigation/Filter/mitkNeedleProjectionFilter.h index aa6be02285..1b03ffd6ea 100644 --- a/Modules/US/USNavigation/Filter/mitkNeedleProjectionFilter.h +++ b/Modules/US/USNavigation/Filter/mitkNeedleProjectionFilter.h @@ -1,85 +1,86 @@ /*=================================================================== 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 NEEDLEPROJECTIONFILTER_H_INCLUDED #define NEEDLEPROJECTIONFILTER_H_INCLUDED #include // MITK #include #include #include #include namespace mitk { /** * \brief This filter projects a needle's path onto a plane. * * To use it, hook it up to a NavigationDataStream, * select an input and set an AffineTransform 3D that represents the target plane. * You can then call GetProjection to retrieve a pointset that represents the projected path. * You may change the PointSet's properties, these changes will not be overwritten. * If no Input is selected, the target Pointset will not update * If no Target Plane is selected, The projection line will always be 40 cm long * Any points you add to the pointSet will be overwritten during the next Update. * The point with index zero is the Tip of the Needle. * The Point with index one is the projection onto the plane. * * Projection will happen onto an extension of the plane as well - the filter does not regard boundaries * This Filter currently only supports projection of one needle. Extension to multiple needles / planes should be easy. * * \ingroup US */ class MITKUSNAVIGATION_EXPORT NeedleProjectionFilter : public NavigationDataPassThroughFilter { public: mitkClassMacro(NeedleProjectionFilter, NavigationDataPassThroughFilter); itkNewMacro(Self); virtual void SelectInput(int i); itkGetMacro(TargetPlane, mitk::AffineTransform3D::Pointer); itkSetMacro(TargetPlane, mitk::AffineTransform3D::Pointer); itkGetMacro(Projection, mitk::PointSet::Pointer); + void SetToolAxisForFilter(mitk::Point3D point); protected: NeedleProjectionFilter(); virtual ~NeedleProjectionFilter(); virtual void GenerateData() override; mitk::AffineTransform3D::Pointer m_TargetPlane; mitk::PointSet::Pointer m_Projection; mitk::PointSet::Pointer m_OriginalPoints; int m_SelectedInput; /** * \brief Creates an Affine Transformation from a Navigation Data Object. */ mitk::AffineTransform3D::Pointer NavigationDataToTransform(const mitk::NavigationData * nd); /** * \brief Creates an Geometry 3D Object from an AffineTransformation. */ mitk::Geometry3D::Pointer TransformToGeometry(mitk::AffineTransform3D::Pointer transform); }; } // namespace mitk #endif diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp index 7055f87860..add64852a0 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.cpp @@ -1,267 +1,286 @@ /*=================================================================== 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 "QmitkUSNavigationStepPunctuationIntervention.h" #include "ui_QmitkUSNavigationStepPunctuationIntervention.h" #include "mitkNeedleProjectionFilter.h" #include "../Widgets/QmitkZoneProgressBar.h" #include "../USNavigationMarkerPlacement.h" #include "usModuleRegistry.h" #include QmitkUSNavigationStepPunctuationIntervention::QmitkUSNavigationStepPunctuationIntervention(QWidget *parent) : QmitkUSAbstractNavigationStep(parent), m_NeedleProjectionFilter(mitk::NeedleProjectionFilter::New()), ui(new Ui::QmitkUSNavigationStepPunctuationIntervention), m_SphereSource(vtkSmartPointer::New()), m_OBBTree(vtkSmartPointer::New()), m_IntersectPoints(vtkSmartPointer::New()) { ui->setupUi(this); connect(ui->m_AddNewAblationZone, SIGNAL(clicked()), this, SLOT(OnAddAblationZoneClicked())); connect(ui->m_EnableAblationMarking, SIGNAL(clicked()), this, SLOT(OnEnableAblationZoneMarkingClicked())); connect(ui->m_AblationZoneSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnAblationZoneSizeSliderChanged(int))); ui->m_AblationZonesBox->setVisible(false); } +QmitkUSNavigationStepPunctuationIntervention::QmitkUSNavigationStepPunctuationIntervention(mitk::Point3D toolAxis, QWidget *parent) : +QmitkUSAbstractNavigationStep(parent), +m_NeedleProjectionFilter(mitk::NeedleProjectionFilter::New()), +ui(new Ui::QmitkUSNavigationStepPunctuationIntervention), +m_SphereSource(vtkSmartPointer::New()), +m_OBBTree(vtkSmartPointer::New()), +m_IntersectPoints(vtkSmartPointer::New()) +{ + m_ToolAxis.SetElement(0, (toolAxis.GetElement(0))); + m_ToolAxis.SetElement(1, (toolAxis.GetElement(1))); + m_ToolAxis.SetElement(2, (toolAxis.GetElement(2))); + m_NeedleProjectionFilter->SetToolAxisForFilter(m_ToolAxis); + ui->setupUi(this); + connect(ui->m_AddNewAblationZone, SIGNAL(clicked()), this, SLOT(OnAddAblationZoneClicked())); + connect(ui->m_EnableAblationMarking, SIGNAL(clicked()), this, SLOT(OnEnableAblationZoneMarkingClicked())); + connect(ui->m_AblationZoneSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnAblationZoneSizeSliderChanged(int))); + ui->m_AblationZonesBox->setVisible(false); +} + void QmitkUSNavigationStepPunctuationIntervention::OnEnableAblationZoneMarkingClicked() { if(ui->m_EnableAblationMarking->isChecked()) ui->m_AblationZonesBox->setVisible(true); else ui->m_AblationZonesBox->setVisible(false); } void QmitkUSNavigationStepPunctuationIntervention::OnAblationZoneSizeSliderChanged(int size) { int id = ui->m_AblationZonesList->currentRow(); if (id!=-1) {emit AblationZoneChanged(id,size);} -} +}// void QmitkUSNavigationStepPunctuationIntervention::OnAddAblationZoneClicked() { QListWidgetItem* newItem = new QListWidgetItem("Ablation Zone (initial size: " + QString::number(ui->m_AblationZoneSizeSlider->value()) + " mm)", ui->m_AblationZonesList); newItem->setSelected(true); emit AddAblationZoneClicked(ui->m_AblationZoneSizeSlider->value()); } QmitkUSNavigationStepPunctuationIntervention::~QmitkUSNavigationStepPunctuationIntervention() { mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(false); if ( dataStorage.IsNotNull() ) { // remove needle path from data storage if it is there mitk::DataNode::Pointer node = this->GetNamedDerivedNode ("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); if ( node.IsNotNull() ) { dataStorage->Remove(node); } } delete ui; } bool QmitkUSNavigationStepPunctuationIntervention::OnStartStep() { // create node for Needle Projection mitk::DataNode::Pointer node = this->GetNamedDerivedNodeAndCreate ("Needle Path", QmitkUSAbstractNavigationStep::DATANAME_BASENODE); node->SetData(m_NeedleProjectionFilter->GetProjection()); node->SetBoolProperty("show contour", true); return true; } bool QmitkUSNavigationStepPunctuationIntervention::OnRestartStep() { return this->OnActivateStep(); } bool QmitkUSNavigationStepPunctuationIntervention::OnFinishStep() { mitk::DataNode::Pointer finishPunctionResult = mitk::DataNode::New(); finishPunctionResult->SetName("PunctionResult"); mitk::Point3D needlePos = m_NeedleProjectionFilter->GetOutput(0)->GetPosition(); mitk::Quaternion needleRot = m_NeedleProjectionFilter->GetOutput(0)->GetOrientation(); finishPunctionResult->SetProperty("USNavigation::TipPositionEnd", mitk::Point3dProperty::New(needlePos)); MITK_INFO("USNavigationLogging") << "Instrument tip at end: " <ClearZones(); mitk::DataStorage::Pointer dataStorage = this->GetDataStorage(); // add progress bars for risk zone nodes m_ZoneNodes = dataStorage->GetDerivations(dataStorage->GetNamedNode(USNavigationMarkerPlacement::DATANAME_ZONES)); // add zones to the widgets for risk structures for (mitk::DataStorage::SetOfObjects::ConstIterator it = m_ZoneNodes->Begin(); it != m_ZoneNodes->End(); ++it) { ui->riskStructuresRangeWidget->AddZone(it->Value()); float rgb[3]; it->Value()->GetColor(rgb); mitk::Color color; color.SetRed(rgb[0]); color.SetGreen(rgb[1]); color.SetBlue(rgb[2]); m_OldColors[it->Value()] = color; } m_NeedleProjectionFilter->SelectInput(0); return true; } void QmitkUSNavigationStepPunctuationIntervention::OnUpdate() { // get navigation data source and make sure that it is not null mitk::NavigationDataSource::Pointer navigationDataSource = this->GetCombinedModality()->GetNavigationDataSource(); if ( navigationDataSource.IsNull() ) { MITK_ERROR("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepPunctuationIntervention") << "Navigation Data Source of Combined Modality must not be null."; mitkThrow() << "Navigation Data Source of Combined Modality must not be null."; } // update body marker this->UpdateBodyMarkerStatus(navigationDataSource->GetOutput(1)); // update critical structures this->UpdateCriticalStructures(navigationDataSource->GetOutput(0),m_NeedleProjectionFilter->GetProjection()); //Update Distance to US image mitk::Point3D point1 = m_NeedleProjectionFilter->GetProjection()->GetPoint(0); mitk::Point3D point2 = m_NeedleProjectionFilter->GetProjection()->GetPoint(1); double distance = point1.EuclideanDistanceTo(point2); ui->m_DistanceToUSPlane->setText(QString::number(distance) + " mm"); } void QmitkUSNavigationStepPunctuationIntervention::OnSettingsChanged(const itk::SmartPointer settingsNode) { if ( settingsNode.IsNull() ) { return; } } QString QmitkUSNavigationStepPunctuationIntervention::GetTitle() { return "Computer-assisted Intervention"; } bool QmitkUSNavigationStepPunctuationIntervention::GetIsRestartable() { return false; } QmitkUSNavigationStepPunctuationIntervention::FilterVector QmitkUSNavigationStepPunctuationIntervention::GetFilter() { return FilterVector(1, m_NeedleProjectionFilter.GetPointer()); } void QmitkUSNavigationStepPunctuationIntervention::OnSetCombinedModality() { mitk::USCombinedModality::Pointer combinedModality = this->GetCombinedModality(false); if ( combinedModality.IsNotNull() ) { // set calibration of the combined modality to the needle projection filter mitk::AffineTransform3D::Pointer calibration = combinedModality->GetCalibration(); if ( calibration.IsNotNull() ) { m_NeedleProjectionFilter->SetTargetPlane(calibration); } } } void QmitkUSNavigationStepPunctuationIntervention::ClearZones() { ui->riskStructuresRangeWidget->ClearZones(); } void QmitkUSNavigationStepPunctuationIntervention::UpdateBodyMarkerStatus(mitk::NavigationData::Pointer bodyMarker) { if ( bodyMarker.IsNull() ) { MITK_ERROR("QmitkUSAbstractNavigationStep")("QmitkUSNavigationStepPunctuationIntervention") << "Current Navigation Data for body marker of Combined Modality must not be null."; mitkThrow() << "Current Navigation Data for body marker of Combined Modality must not be null."; } bool valid = bodyMarker->IsDataValid(); // update body marker status label if (valid) { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is inside the tracking volume."); } else { ui->bodyMarkerTrackingStatusLabel->setStyleSheet( "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey"); ui->bodyMarkerTrackingStatusLabel->setText("Body marker is not inside the tracking volume."); } ui->riskStructuresRangeGroupBox->setEnabled(valid); } void QmitkUSNavigationStepPunctuationIntervention::UpdateCriticalStructures(mitk::NavigationData::Pointer needle, mitk::PointSet::Pointer path) { // update the distances for the risk structures widget ui->riskStructuresRangeWidget->UpdateDistancesToNeedlePosition(needle); //iterate through all zones for (mitk::DataStorage::SetOfObjects::ConstIterator it = m_ZoneNodes->Begin(); it != m_ZoneNodes->End(); ++it) { mitk::DataNode::Pointer currentNode = it->Value(); //get center point and radius float radius = -1; mitk::Point3D center; currentNode->GetFloatProperty("zone.size", radius); center = currentNode->GetData()->GetGeometry()->GetIndexToWorldTransform()->GetTranslation(); mitk::Point3D point0 = path->GetPoint(0); mitk::Point3D point1 = path->GetPoint(1); if (CheckSphereLineIntersection(center,radius,point0,point1)) {currentNode->SetColor(mitk::IGTColor_WARNING);} else {currentNode->SetColor(m_OldColors[currentNode]);} } } bool QmitkUSNavigationStepPunctuationIntervention::CheckSphereLineIntersection(mitk::Point3D& sphereOrigin, float& sphereRadius, mitk::Point3D& lineStart, mitk::Point3D& lineEnd) { double center[3] = {sphereOrigin[0],sphereOrigin[1],sphereOrigin[2]}; m_SphereSource->SetCenter(center); m_SphereSource->SetRadius(sphereRadius); m_SphereSource->Update(); m_OBBTree->SetDataSet(m_SphereSource->GetOutput()); m_OBBTree->BuildLocator(); double lineP0[3] = {lineStart[0], lineStart[1], lineStart[2]}; double lineP1[3] = {lineEnd[0], lineEnd[1], lineEnd[2]}; m_OBBTree->IntersectWithLine(lineP0, lineP1, m_IntersectPoints, nullptr); if (m_IntersectPoints->GetNumberOfPoints() > 0) {return true;} else {return false;} } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h index cf948c6cea..9c6e54b87f 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h @@ -1,117 +1,119 @@ /*=================================================================== 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 QMITKUSNAVIGATIONSTEPPUNCTUATIONINTERVENTION_H #define QMITKUSNAVIGATIONSTEPPUNCTUATIONINTERVENTION_H #include "QmitkUSAbstractNavigationStep.h" #include #include #include #include #include namespace mitk { class DataNode; class NeedleProjectionFilter; class NodeDisplacementFilter; class USNavigationGrabCutSegmentationUpdateFilter; class USNavigationTargetUpdateFilter; class USNavigationTargetOcclusionFilter; class USPointMarkInteractor; class LookupTableProperty; class Surface; } namespace Ui { class QmitkUSNavigationStepPunctuationIntervention; } class QmitkZoneProgressBar; /** * \brief Navigations step for the actual punctuation intervention. * The needle path is projected onto the image plane and the distances to all * risk structures are displayed in the widget. * * The risk structures are expected to be in the data storage under * DATANAME_BASENODE -> DATANAME_ZONES. They should contain a property named * "zone.size" and it is assumed that they are spherical. */ class QmitkUSNavigationStepPunctuationIntervention : public QmitkUSAbstractNavigationStep { Q_OBJECT public: explicit QmitkUSNavigationStepPunctuationIntervention(QWidget *parent = 0); + explicit QmitkUSNavigationStepPunctuationIntervention(mitk::Point3D toolAxis, QWidget *parent = 0); ~QmitkUSNavigationStepPunctuationIntervention(); virtual bool OnStartStep(); virtual bool OnRestartStep(); virtual bool OnFinishStep(); virtual bool OnActivateStep(); virtual void OnUpdate(); virtual void OnSettingsChanged(const itk::SmartPointer); virtual QString GetTitle(); virtual bool GetIsRestartable(); virtual FilterVector GetFilter(); signals: void AddAblationZoneClicked(int); void AblationZoneChanged(int,int); protected slots: void OnAddAblationZoneClicked(); void OnEnableAblationZoneMarkingClicked(); void OnAblationZoneSizeSliderChanged(int size); protected: virtual void OnSetCombinedModality(); void ClearZones(); void UpdateBodyMarkerStatus(mitk::NavigationData::Pointer bodyMarker); /** Updates the critical structures which means that the distance to the needle tip is updated and also the color changes to red if the path projection intersects the critical structure. */ void UpdateCriticalStructures(mitk::NavigationData::Pointer needle, mitk::PointSet::Pointer path); /** Checks if the given line intersects the given sphere. */ bool CheckSphereLineIntersection(mitk::Point3D& sphereOrigin, float& sphereRadius, mitk::Point3D& lineStart, mitk::Point3D& lineEnd); mitk::DataStorage::SetOfObjects::ConstPointer m_ZoneNodes; /** * \brief Creates a Pointset that projects the needle's path */ itk::SmartPointer m_NeedleProjectionFilter; + mitk::Point3D m_ToolAxis; std::map m_OldColors; //stores the original color of the critical structrue nodes //some help variables for the CheckSphereLineIntersection()-Method vtkSmartPointer m_SphereSource; vtkSmartPointer m_OBBTree; vtkSmartPointer m_IntersectPoints; private: Ui::QmitkUSNavigationStepPunctuationIntervention *ui; }; #endif // QMITKUSNAVIGATIONSTEPPUNCTUATIONINTERVENTION_H diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/USNavigationMarkerPlacement.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/USNavigationMarkerPlacement.cpp index a7876c2677..380c84b225 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/USNavigationMarkerPlacement.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/USNavigationMarkerPlacement.cpp @@ -1,738 +1,809 @@ /*=================================================================== 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 "USNavigationMarkerPlacement.h" #include "ui_USNavigationMarkerPlacement.h" #include "NavigationStepWidgets/QmitkUSNavigationStepCombinedModality.h" #include "NavigationStepWidgets/QmitkUSNavigationStepMarkerIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPlacementPlanning.h" #include "NavigationStepWidgets/QmitkUSNavigationStepPunctuationIntervention.h" #include "NavigationStepWidgets/QmitkUSNavigationStepTumourSelection.h" #include "NavigationStepWidgets/QmitkUSNavigationStepZoneMarking.h" #include "SettingsWidgets/QmitkUSNavigationCombinedSettingsWidget.h" #include "mitkIRenderingManager.h" #include "mitkNodeDisplacementFilter.h" #include "mitkUSCombinedModality.h" #include #include "IO/mitkUSNavigationExperimentLogging.h" #include "IO/mitkUSNavigationStepTimer.h" #include #include #include #include #include #include #include "QmitkRenderWindow.h" #include "QmitkStdMultiWidget.h" #include "QmitkStdMultiWidgetEditor.h" #include "mitkLayoutAnnotationRenderer.h" // scene serialization #include #include #include #include #include const std::string USNavigationMarkerPlacement::VIEW_ID = "org.mitk.views.usmarkerplacement"; const char *USNavigationMarkerPlacement::DATANAME_TUMOUR = "Tumour"; const char *USNavigationMarkerPlacement::DATANAME_TARGETSURFACE = "Target Surface"; const char *USNavigationMarkerPlacement::DATANAME_ZONES = "Zones"; const char *USNavigationMarkerPlacement::DATANAME_TARGETS = "Targets"; const char *USNavigationMarkerPlacement::DATANAME_TARGETS_PATHS = "Target Paths"; const char *USNavigationMarkerPlacement::DATANAME_REACHED_TARGETS = "Reached Targets"; USNavigationMarkerPlacement::USNavigationMarkerPlacement() : m_Parent(nullptr), m_UpdateTimer(new QTimer(this)), m_ImageAndNavigationDataLoggingTimer(new QTimer(this)), m_StdMultiWidget(0), m_ReinitAlreadyDone(false), m_IsExperimentRunning(false), m_NavigationStepTimer(mitk::USNavigationStepTimer::New()), m_ExperimentLogging(mitk::USNavigationExperimentLogging::New()), m_AblationZonesDisplacementFilter(mitk::NodeDisplacementFilter::New()), m_IconRunning(QPixmap(":/USNavigation/record.png")), m_IconNotRunning(QPixmap(":/USNavigation/record-gray.png")), m_USImageLoggingFilter(mitk::USImageLoggingFilter::New()), m_NavigationDataRecorder(mitk::NavigationDataRecorder::New()), m_SceneNumber(1), m_WarnOverlay(mitk::TextAnnotation2D::New()), m_ListenerDeviceChanged(this, &USNavigationMarkerPlacement::OnCombinedModalityPropertyChanged), m_NeedleIndex(0), m_MarkerIndex(1), ui(new Ui::USNavigationMarkerPlacement) { connect(m_UpdateTimer, SIGNAL(timeout()), this, SLOT(OnTimeout())); connect( m_ImageAndNavigationDataLoggingTimer, SIGNAL(timeout()), this, SLOT(OnImageAndNavigationDataLoggingTimeout())); // scale running (and not running) icon the specific height m_IconRunning = m_IconRunning.scaledToHeight(20, Qt::SmoothTransformation); m_IconNotRunning = m_IconNotRunning.scaledToHeight(20, Qt::SmoothTransformation); // set prefix for experiment logging (only keys with this prefix are taken // into consideration m_ExperimentLogging->SetKeyPrefix("USNavigation::"); m_UpdateTimer->start(33); // every 33 Milliseconds = 30 Frames/Second } USNavigationMarkerPlacement::~USNavigationMarkerPlacement() { // remove listener for ultrasound device changes if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } // remove listener for ultrasound device changes if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } delete ui; } void USNavigationMarkerPlacement::OnChangeAblationZone(int id, int newSize) { if ((static_cast(m_AblationZonesVector.size()) < id) || (id < 0)) { return; } MITK_INFO << "Ablation Zone " << id << " changed, new size: " << newSize; // create a vtk sphere with given radius vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(newSize / 2); vtkData->SetCenter(0, 0, 0); vtkData->SetPhiResolution(20); vtkData->SetThetaResolution(20); vtkData->Update(); mitk::Surface::Pointer zoneSurface = dynamic_cast(m_AblationZonesVector.at(id)->GetData()); zoneSurface->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); } void USNavigationMarkerPlacement::OnAddAblationZone(int size) { m_AblationZonesDisplacementFilter->SetInitialReferencePose( m_CombinedModality->GetNavigationDataSource()->GetOutput(m_MarkerIndex)); mitk::DataNode::Pointer NewAblationZone = mitk::DataNode::New(); mitk::Point3D origin = m_CombinedModality->GetNavigationDataSource()->GetOutput(m_NeedleIndex)->GetPosition(); MITK_INFO("USNavigationLogging") << "Ablation Zone Added, initial size: " << size << ", origin: " << origin; mitk::Surface::Pointer zone = mitk::Surface::New(); // create a vtk sphere with given radius vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(size / 2); vtkData->SetCenter(0, 0, 0); vtkData->SetPhiResolution(20); vtkData->SetThetaResolution(20); vtkData->Update(); zone->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); // set vtk sphere and origin to data node (origin must be set // again, because of the new sphere set as data) NewAblationZone->SetData(zone); NewAblationZone->GetData()->GetGeometry()->SetOrigin(origin); mitk::Color SphereColor = mitk::Color(); // default color SphereColor[0] = 102; SphereColor[1] = 0; SphereColor[2] = 204; NewAblationZone->SetColor(SphereColor); NewAblationZone->SetOpacity(0.3); // set name of zone std::stringstream name; name << "Ablation Zone" << m_AblationZonesVector.size(); NewAblationZone->SetName(name.str()); // add zone to filter m_AblationZonesDisplacementFilter->AddNode(NewAblationZone); m_AblationZonesVector.push_back(NewAblationZone); this->GetDataStorage()->Add(NewAblationZone); } void USNavigationMarkerPlacement::CreateQtPartControl(QWidget *parent) { m_Parent = parent; ui->setupUi(parent); connect(ui->navigationProcessWidget, SIGNAL(SignalCombinedModalityChanged(itk::SmartPointer)), this, SLOT(OnCombinedModalityChanged(itk::SmartPointer))); connect(ui->navigationProcessWidget, SIGNAL(SignalSettingsChanged(itk::SmartPointer)), this, SLOT(OnSettingsChanged(itk::SmartPointer))); connect(ui->navigationProcessWidget, SIGNAL(SignalActiveNavigationStepChanged(int)), this, SLOT(OnActiveNavigationStepChanged(int))); connect(ui->startExperimentButton, SIGNAL(clicked()), this, SLOT(OnStartExperiment())); connect(ui->finishExperimentButton, SIGNAL(clicked()), this, SLOT(OnFinishExperiment())); + connect(ui->m_enableNavigationLayout, SIGNAL(clicked()), this, SLOT(OnChangeLayoutClicked())); connect(ui->navigationProcessWidget, SIGNAL(SignalIntermediateResult(const itk::SmartPointer)), this, SLOT(OnIntermediateResultProduced(const itk::SmartPointer))); ui->navigationProcessWidget->SetDataStorage(this->GetDataStorage()); // indicate that no experiment is running at start ui->runningLabel->setPixmap(m_IconNotRunning); ui->navigationProcessWidget->SetSettingsWidget(new QmitkUSNavigationCombinedSettingsWidget(m_Parent)); } void USNavigationMarkerPlacement::OnCombinedModalityPropertyChanged(const std::string &key, const std::string &) { if (key == mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH) { m_ReinitAlreadyDone = false; this->ReinitOnImage(); if (m_CombinedModality.IsNotNull() && !m_CombinedModality->GetIsCalibratedForCurrentStatus()) { mitk::LayoutAnnotationRenderer::AddAnnotation( m_WarnOverlay.GetPointer(), "stdmulti.widget1", mitk::LayoutAnnotationRenderer::TopLeft); MITK_WARN << "No calibration available for the selected ultrasound image depth."; } } } + +void USNavigationMarkerPlacement::SetToolAxisMarkerPlacement() +{ + m_NavigationDataSource = m_CombinedModality->GetNavigationDataSource(); + m_ToolAxis.SetElement(0, 0); + m_ToolAxis.SetElement(1, 0); + m_ToolAxis.SetElement(2, 1); + if (m_NavigationDataSource.IsNull()) + { + MITK_WARN << "Cannot retrieve tool axis as tracking source is null."; + } + else + { + us::ModuleContext* context = us::GetModuleContext(); + std::string id = m_NavigationDataSource->US_PROPKEY_ID; + std::string filter = "(" + mitk::NavigationToolStorage::US_PROPKEY_SOURCE_ID + "=" + id + ")"; + // Get Storage + std::vector > refs = context->GetServiceReferences(); + m_CurrentStorage = context->GetService(refs.front()); + if (m_CurrentStorage.IsNull()) + { + MITK_WARN << "Found an invalid storage object!"; + } + if (m_CurrentStorage->GetToolCount() != m_NavigationDataSource->GetNumberOfOutputs()) //there is something wrong with the storage + { + MITK_WARN << "Found a tool storage, but it has not the same number of tools like the NavigationDataSource. This storage won't be used because it isn't the right one."; + m_CurrentStorage = NULL; + } + + //getting the first tool in the tool storage, assuming this is the needle + mitk::NavigationTool::Pointer needle; + needle = m_CurrentStorage->GetTool(0); + + m_ToolAxis.SetElement(0, (needle->GetToolAxis().GetElement(0))); + m_ToolAxis.SetElement(1, (needle->GetToolAxis().GetElement(1))); + m_ToolAxis.SetElement(2, (needle->GetToolAxis().GetElement(2))); + } +} + + void USNavigationMarkerPlacement::SetFocus() { this->ReinitOnImage(); } void USNavigationMarkerPlacement::OnTimeout() { if (!m_StdMultiWidget) { // try to get the standard multi widget if it couldn't be got before mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); // if there is a standard multi widget now, disable the level window and // change the layout to 2D up and 3d down if (multiWidgetEditor) { m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); if (m_StdMultiWidget) { m_StdMultiWidget->DisableStandardLevelWindow(); m_StdMultiWidget->changeLayoutTo2DUpAnd3DDown(); } } this->CreateOverlays(); } if (m_CombinedModality.IsNotNull() && !this->m_CombinedModality->GetIsFreezed()) // if the combined modality is freezed: do nothing { ui->navigationProcessWidget->UpdateNavigationProgress(); m_AblationZonesDisplacementFilter->Update(); // update the 3D window only every fourth time to speed up the rendering (at least in 2D) this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS); // make sure that a reinit was performed on the image this->ReinitOnImage(); } } +void USNavigationMarkerPlacement::OnEnableNavigationLayout() +{ + MITK_INFO << "Navigation Layout"; + // try to get the standard multi widget if it couldn't be got before + mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); + + QmitkStdMultiWidgetEditor *multiWidgetEditor = dynamic_cast(renderWindow); + + // if there is a standard multi widget now, disable the level window and + // change the layout to 2D up and 3d down + if (multiWidgetEditor) + { + m_StdMultiWidget = multiWidgetEditor->GetStdMultiWidget(); + if (m_StdMultiWidget) + { + m_StdMultiWidget->DisableStandardLevelWindow(); + m_StdMultiWidget->changeLayoutTo2DUpAnd3DDown(); + this->GetDataStorage()->GetNamedNode("stdmulti.widget1.plane")->SetVisibility(false); + this->GetDataStorage()->GetNamedNode("stdmulti.widget3.plane")->SetVisibility(false); + } + } +} + void USNavigationMarkerPlacement::OnResetStandardLayout() { - MITK_INFO << "Resetting Layout"; //reset render windows mitk::DataNode::Pointer widget1 = this->GetDataStorage()->GetNamedNode("stdmulti.widget1.plane"); if (widget1.IsNotNull()) { widget1->SetVisibility(true); } mitk::DataNode::Pointer widget3 = this->GetDataStorage()->GetNamedNode("stdmulti.widget3.plane"); if (widget3.IsNotNull()) { widget3->SetVisibility(true); } m_StdMultiWidget->changeLayoutToDefault(); } void USNavigationMarkerPlacement::OnChangeLayoutClicked() { if (ui->m_enableNavigationLayout->isChecked()) OnEnableNavigationLayout(); else OnResetStandardLayout(); } void USNavigationMarkerPlacement::OnImageAndNavigationDataLoggingTimeout() { // update filter for logging navigation data and ultrasound images if (m_CombinedModality.IsNotNull()) { m_NavigationDataRecorder->Update(); // get last messages for logging filer and store them std::vector messages = m_LoggingBackend.GetNavigationMessages(); std::string composedMessage = ""; for (std::size_t i = 0; i < messages.size(); i++) { composedMessage += messages.at(i); } m_USImageLoggingFilter->AddMessageToCurrentImage(composedMessage); m_LoggingBackend.ClearNavigationMessages(); // update logging filter m_USImageLoggingFilter->Update(); } } void USNavigationMarkerPlacement::OnStartExperiment() { // get name for the experiment by a QInputDialog bool ok; if (m_ExperimentName.isEmpty()) { // default: current date m_ExperimentName = QString::number(QDateTime::currentDateTime().date().year()) + "_" + QString::number(QDateTime::currentDateTime().date().month()) + "_" + QString::number(QDateTime::currentDateTime().date().day()) + "_experiment_" + QString::number(QDateTime::currentDateTime().time().hour()) + "." + QString::number(QDateTime::currentDateTime().time().minute()); } m_ExperimentName = QInputDialog::getText( m_Parent, QString("Experiment Name"), QString("Name of the Experiment"), QLineEdit::Normal, m_ExperimentName, &ok); MITK_INFO("USNavigationLogging") << "Experiment started: " << m_ExperimentName.toStdString(); if (ok && !m_ExperimentName.isEmpty()) { // display error message and call the function recursivly if a directory // with the given name already exists QDir experimentResultsDir(m_ResultsDirectory + QDir::separator() + m_ExperimentName); if (experimentResultsDir.exists()) { QMessageBox::critical( m_Parent, "Results Directory Exists", "The result directory already exists.\nPlease choose an other name."); this->OnStartExperiment(); } else { QDir(m_ResultsDirectory).mkdir(m_ExperimentName); m_ExperimentResultsSubDirectory = m_ResultsDirectory + QDir::separator() + m_ExperimentName; // experiment is running now ui->runningLabel->setPixmap(m_IconRunning); ui->navigationProcessWidget->EnableInteraction(true); // (re)start timer for navigation step durations m_NavigationStepTimer->Reset(); m_NavigationStepTimer->SetOutputFileName( QString(m_ExperimentResultsSubDirectory + QDir::separator() + QString("durations.cvs")).toStdString()); m_NavigationStepTimer->SetActiveIndex(0, m_NavigationSteps.at(0)->GetTitle().toStdString()); ui->finishExperimentButton->setEnabled(true); ui->startExperimentButton->setDisabled(true); // initialize and register logging backend QString loggingFilename = m_ExperimentResultsSubDirectory + QDir::separator() + "logging.txt"; m_LoggingBackend.SetOutputFileName(loggingFilename.toStdString()); mbilog::RegisterBackend(&m_LoggingBackend); // initialize and start navigation data recorder form xml recording m_NavigationDataRecorder->StartRecording(); m_IsExperimentRunning = true; m_ImageAndNavigationDataLoggingTimer->start(1000); // (re)start experiment logging and set output file name m_ExperimentLogging->Reset(); m_ExperimentLogging->SetFileName( QString(m_ExperimentResultsSubDirectory + QDir::separator() + "experiment-logging.xml").toStdString()); } } } void USNavigationMarkerPlacement::OnFinishExperiment() { this->WaitCursorOn(); MITK_INFO("USNavigationLogging") << "Experiment finished!"; MITK_INFO("USNavigationLogging") << "Position/Orientation of needle tip: " << (dynamic_cast(m_CombinedModality->GetTrackingDevice()->GetOutput(0)))->GetPosition(); MITK_INFO("USNavigationLogging") << "Position of target: " << m_TargetNodeDisplacementFilter->GetRawDisplacementNavigationData(0)->GetPosition(); MITK_INFO("USNavigationLogging") << "Total duration: " << m_NavigationStepTimer->GetTotalDuration(); ui->navigationProcessWidget->FinishCurrentNavigationStep(); m_ImageAndNavigationDataLoggingTimer->stop(); ui->runningLabel->setPixmap(m_IconNotRunning); ui->navigationProcessWidget->EnableInteraction(false); m_NavigationStepTimer->Stop(); // make sure that the navigation process will be start from beginning at the // next experiment ui->navigationProcessWidget->ResetNavigationProcess(); ui->finishExperimentButton->setDisabled(true); ui->startExperimentButton->setEnabled(true); MITK_INFO("USNavigationLogging") << "Writing logging data to " << m_ExperimentResultsSubDirectory.toStdString(); // save ultrasound images to the file system QDir(m_ExperimentResultsSubDirectory).mkdir("ImageStream"); m_USImageLoggingFilter->Update(); m_USImageLoggingFilter->SetImageFilesExtension(".jpg"); m_USImageLoggingFilter->SaveImages( QString(m_ExperimentResultsSubDirectory + QDir::separator() + "ImageStream" + QDir::separator()).toStdString()); m_USImageLoggingFilter = mitk::USImageLoggingFilter::New(); m_NavigationDataRecorder->StopRecording(); // Write data to csv and xml file mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.xml").toStdString().c_str())); mitk::IOUtil::Save( m_NavigationDataRecorder->GetNavigationDataSet(), (QString(m_ExperimentResultsSubDirectory + QDir::separator() + "navigation-data.csv").toStdString().c_str())); // write logged navigation data messages to separate file std::stringstream csvNavigationMessagesFilename; csvNavigationMessagesFilename << m_ExperimentResultsSubDirectory.toStdString() << QDir::separator().toLatin1() << "CSVNavigationMessagesLogFile.csv"; MITK_INFO("USNavigationLogging") << "Writing logged navigation messages to separate csv file: " << csvNavigationMessagesFilename.str(); m_LoggingBackend.WriteCSVFileWithNavigationMessages(csvNavigationMessagesFilename.str()); mbilog::UnregisterBackend(&m_LoggingBackend); m_IsExperimentRunning = false; m_ImageAndNavigationDataLoggingTimer->stop(); m_CombinedModality = 0; // reset scene number for next experiment m_SceneNumber = 1; this->WaitCursorOff(); MITK_INFO("USNavigationLogging") << "Finished!"; } void USNavigationMarkerPlacement::OnCombinedModalityChanged( itk::SmartPointer combinedModality) { // remove old listener for ultrasound device changes if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->RemovePropertyChangedListener(m_ListenerDeviceChanged); } m_CombinedModality = combinedModality; m_ReinitAlreadyDone = false; // add a listener for ultrasound device changes if (m_CombinedModality.IsNotNull() && m_CombinedModality->GetUltrasoundDevice().IsNotNull()) { m_CombinedModality->GetUltrasoundDevice()->AddPropertyChangedListener(m_ListenerDeviceChanged); } // update navigation data recorder for using the new combined modality mitk::NavigationDataSource::Pointer navigationDataSource = combinedModality->GetNavigationDataSource(); m_NavigationDataRecorder->ConnectTo(navigationDataSource); m_NavigationDataRecorder->ResetRecording(); - // TODO check for correct connection - // for (unsigned int n = 0; n < navigationDataSource->GetNumberOfIndexedOutputs(); ++n) - // { - // m_NavigationDataRecorder->AddNavigationData(navigationDataSource->GetOutput(n)); - // } - - // update ultrasound image logging filter for using the new combined modality - mitk::USDevice::Pointer ultrasoundImageSource = combinedModality->GetUltrasoundDevice(); - for (unsigned int n = 0; n < ultrasoundImageSource->GetNumberOfIndexedOutputs(); ++n) - { - m_USImageLoggingFilter->SetInput(n, ultrasoundImageSource->GetOutput(n)); - } + //upate stored tool axis for current tool + this->SetToolAxisMarkerPlacement(); + //store new tool axis + QmitkUSNavigationStepPunctuationIntervention* stepIntervention = + new QmitkUSNavigationStepPunctuationIntervention(m_ToolAxis, m_Parent); + m_NavigationSteps.pop_back(); + m_NavigationSteps.push_back(stepIntervention); + + // TODO check for correct connection + // for (unsigned int n = 0; n < navigationDataSource->GetNumberOfIndexedOutputs(); ++n) + // { + // m_NavigationDataRecorder->AddNavigationData(navigationDataSource->GetOutput(n)); + // } + + // update ultrasound image logging filter for using the new combined modality + mitk::USDevice::Pointer ultrasoundImageSource = combinedModality->GetUltrasoundDevice(); + for (unsigned int n = 0; n < ultrasoundImageSource->GetNumberOfIndexedOutputs(); ++n) + { + m_USImageLoggingFilter->SetInput(n, ultrasoundImageSource->GetOutput(n)); + } - // update ablation zone filter for using the new combined modality - for (unsigned int n = 0; n < navigationDataSource->GetNumberOfIndexedOutputs(); ++n) - { - m_AblationZonesDisplacementFilter->SetInput(n, navigationDataSource->GetOutput(n)); - } - m_AblationZonesDisplacementFilter->SelectInput(m_MarkerIndex); + // update ablation zone filter for using the new combined modality + for (unsigned int n = 0; n < navigationDataSource->GetNumberOfIndexedOutputs(); ++n) + { + m_AblationZonesDisplacementFilter->SetInput(n, navigationDataSource->GetOutput(n)); + } + m_AblationZonesDisplacementFilter->SelectInput(m_MarkerIndex); - // make sure that a reinit is done for the new images - this->ReinitOnImage(); + // make sure that a reinit is done for the new images + this->ReinitOnImage(); } void USNavigationMarkerPlacement::OnSettingsChanged(itk::SmartPointer settings) { std::string applicationName; if (!settings->GetStringProperty("settings.application", applicationName)) { // set default application if the string property is not available applicationName = "Marker Placement"; } // create navigation step widgets according to the selected application if (applicationName != m_CurrentApplicationName) { m_CurrentApplicationName = applicationName; QmitkUSNavigationProcessWidget::NavigationStepVector navigationSteps; if (applicationName == "Puncture") { QmitkUSNavigationStepCombinedModality* stepCombinedModality = new QmitkUSNavigationStepCombinedModality(m_Parent); QmitkUSNavigationStepTumourSelection* stepTumourSelection = new QmitkUSNavigationStepTumourSelection(m_Parent); stepTumourSelection->SetTargetSelectionOptional(true); m_TargetNodeDisplacementFilter = stepTumourSelection->GetTumourNodeDisplacementFilter(); QmitkUSNavigationStepZoneMarking* stepZoneMarking = new QmitkUSNavigationStepZoneMarking(m_Parent); QmitkUSNavigationStepPunctuationIntervention* stepIntervention = new QmitkUSNavigationStepPunctuationIntervention(m_Parent); connect(stepIntervention, SIGNAL(AddAblationZoneClicked(int)), this, SLOT(OnAddAblationZone(int))); connect(stepIntervention, SIGNAL(AblationZoneChanged(int, int)), this, SLOT(OnChangeAblationZone(int, int))); m_NavigationStepNames = std::vector(); navigationSteps.push_back(stepCombinedModality); m_NavigationStepNames.push_back("Combined Modality Initialization"); navigationSteps.push_back(stepTumourSelection); m_NavigationStepNames.push_back("Target Selection"); navigationSteps.push_back(stepZoneMarking); m_NavigationStepNames.push_back("Critical Structure Marking"); navigationSteps.push_back(stepIntervention); m_NavigationStepNames.push_back("Intervention"); } else if (applicationName == "Marker Placement") { QmitkUSNavigationStepCombinedModality *stepCombinedModality = new QmitkUSNavigationStepCombinedModality(m_Parent); QmitkUSNavigationStepTumourSelection *stepTumourSelection = new QmitkUSNavigationStepTumourSelection(m_Parent); m_TargetNodeDisplacementFilter = stepTumourSelection->GetTumourNodeDisplacementFilter(); QmitkUSNavigationStepZoneMarking *stepZoneMarking = new QmitkUSNavigationStepZoneMarking(m_Parent); QmitkUSNavigationStepPlacementPlanning *stepPlacementPlanning = new QmitkUSNavigationStepPlacementPlanning(m_Parent); QmitkUSNavigationStepMarkerIntervention *stepMarkerIntervention = new QmitkUSNavigationStepMarkerIntervention(m_Parent); m_NavigationStepNames = std::vector(); navigationSteps.push_back(stepCombinedModality); m_NavigationStepNames.push_back("Combined Modality Initialization"); navigationSteps.push_back(stepTumourSelection); m_NavigationStepNames.push_back("Target Selection"); navigationSteps.push_back(stepZoneMarking); m_NavigationStepNames.push_back("Critical Structure Marking"); navigationSteps.push_back(stepPlacementPlanning); m_NavigationStepNames.push_back("Placement Planning"); navigationSteps.push_back(stepMarkerIntervention); m_NavigationStepNames.push_back("Marker Intervention"); } // set navigation step widgets to the process widget ui->navigationProcessWidget->SetNavigationSteps(navigationSteps); for (QmitkUSNavigationProcessWidget::NavigationStepIterator it = m_NavigationSteps.begin(); it != m_NavigationSteps.end(); ++it) { delete *it; } m_NavigationSteps.clear(); m_NavigationSteps = navigationSteps; } // initialize gui according to the experiment mode setting bool experimentMode = false; settings->GetBoolProperty("settings.experiment-mode", experimentMode); ui->startExperimentButton->setVisible(experimentMode); ui->finishExperimentButton->setVisible(experimentMode); ui->runningLabel->setVisible(experimentMode); if (experimentMode && !m_IsExperimentRunning) { ui->navigationProcessWidget->ResetNavigationProcess(); ui->navigationProcessWidget->EnableInteraction(false); ui->runningLabel->setPixmap(m_IconNotRunning); } else if (!experimentMode) { if (m_IsExperimentRunning) { this->OnFinishExperiment(); } ui->navigationProcessWidget->EnableInteraction(true); } // get the results directory from the settings and use home directory if // there is no results directory configured std::string resultsDirectory; if (settings->GetStringProperty("settings.experiment-results-directory", resultsDirectory)) { m_ResultsDirectory = QString::fromStdString(resultsDirectory); } else { m_ResultsDirectory = QDir::homePath(); } // make sure that the results directory exists QDir resultsDirectoryQDir = QDir(m_ResultsDirectory); if (!resultsDirectoryQDir.exists()) { resultsDirectoryQDir.mkpath(m_ResultsDirectory); } MITK_INFO << "Results Directory: " << m_ResultsDirectory.toStdString(); } void USNavigationMarkerPlacement::OnActiveNavigationStepChanged(int index) { // update navigation step timer each time the active navigation step changes m_NavigationStepTimer->SetActiveIndex(index, m_NavigationSteps.at(index)->GetTitle().toStdString()); if (static_cast(m_NavigationStepNames.size()) <= index) { MITK_INFO("USNavigationLogging") << "Someting went wrong: unknown navigation step!"; } else { MITK_INFO("USNavigationLogging") << "Navigation step finished/changed, next step: " << this->m_NavigationStepNames.at(index).toStdString() << "; duration until now: " << m_NavigationStepTimer->GetTotalDuration(); } } void USNavigationMarkerPlacement::OnIntermediateResultProduced(const itk::SmartPointer resultsNode) { // intermediate results only matter during an experiment if (!m_IsExperimentRunning) { return; } this->WaitCursorOn(); // set results node to the experiment logging (for saving contents to the // file system) m_ExperimentLogging->SetResult(resultsNode); std::string resultsName; if (!resultsNode->GetName(resultsName)) { MITK_WARN << "Could not get name of current results node."; return; } // save the mitk scene std::string scenefile = QString(m_ExperimentResultsSubDirectory + QDir::separator() + QString("Scene %1 - ").arg(m_SceneNumber++, 2, 10, QChar('0')) + QString::fromStdString(resultsName).replace(":", "_") + ".mitk") .toStdString(); MITK_INFO << "Saving Scene File: " << scenefile; mitk::SceneIO::Pointer sceneIO = mitk::SceneIO::New(); mitk::NodePredicateNot::Pointer isNotHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); mitk::DataStorage::SetOfObjects::ConstPointer nodesToBeSaved = this->GetDataStorage()->GetSubset(isNotHelperObject); this->Convert2DImagesTo3D(nodesToBeSaved); sceneIO->SaveScene(nodesToBeSaved, this->GetDataStorage(), scenefile); this->WaitCursorOff(); } void USNavigationMarkerPlacement::ReinitOnImage() { if (!m_ReinitAlreadyDone && m_CombinedModality.IsNotNull()) { // make sure that the output is already calibrated correctly // (if the zoom level was changed recently) m_CombinedModality->Modified(); m_CombinedModality->Update(); mitk::Image::Pointer image = m_CombinedModality->GetOutput(); if (image.IsNotNull() && image->IsInitialized()) { // make a reinit on the ultrasound image mitk::IRenderWindowPart *renderWindow = this->GetRenderWindowPart(); if (renderWindow != NULL && image->GetTimeGeometry()->IsValid()) { renderWindow->GetRenderingManager()->InitializeViews( image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); renderWindow->GetRenderingManager()->RequestUpdateAll(); } this->RequestRenderWindowUpdate(); m_ReinitAlreadyDone = true; } } } void USNavigationMarkerPlacement::Convert2DImagesTo3D(mitk::DataStorage::SetOfObjects::ConstPointer nodes) { for (mitk::DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); ++it) { if (it->Value()->GetData() && strcmp(it->Value()->GetData()->GetNameOfClass(), "Image") == 0) { // convert image to 3d image if it is 2d at the moment mitk::Image::Pointer image = dynamic_cast(it->Value()->GetData()); if (image.IsNotNull() && image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable()) { mitk::Convert2Dto3DImageFilter::Pointer convert2DTo3DImageFilter = mitk::Convert2Dto3DImageFilter::New(); convert2DTo3DImageFilter->SetInput(image); convert2DTo3DImageFilter->Update(); it->Value()->SetData(convert2DTo3DImageFilter->GetOutput()); } } } } void USNavigationMarkerPlacement::CreateOverlays() { // initialize warning overlay (and do not display it, yet) m_WarnOverlay->SetText("Warning: No calibration available for current depth."); // set position and font size for the text overlay // (nonesense postition as a layouter is used, but it ignored // the overlay without setting a position here) mitk::Point2D overlayPosition; overlayPosition.SetElement(0, -50.0f); overlayPosition.SetElement(1, -50.0f); m_WarnOverlay->SetPosition2D(overlayPosition); m_WarnOverlay->SetFontSize(22); m_WarnOverlay->SetColor(1, 0, 0); // overlay should be red } diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/USNavigationMarkerPlacement.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/USNavigationMarkerPlacement.h index 94b51b06f9..550c100edf 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/USNavigationMarkerPlacement.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/USNavigationMarkerPlacement.h @@ -1,190 +1,206 @@ /*=================================================================== 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 USNAVIGATIONMARKERPLACEMENT_H #define USNAVIGATIONMARKERPLACEMENT_H #include #include "IO/mitkUSNavigationLoggingBackend.h" #include "Widgets/QmitkUSNavigationProcessWidget.h" #include "mitkNavigationDataRecorder.h" #include "mitkNodeDisplacementFilter.h" #include "mitkUSImageLoggingFilter.h" #include #include #include +#include namespace itk { template class SmartPointer; } namespace mitk { class USNavigationStepTimer; class USNavigationExperimentLogging; } namespace Ui { class USNavigationMarkerPlacement; } class QmitkUSAbstractNavigationStep; class QmitkStdMultiWidget; class QTimer; class QSignalMapper; /** * \brief View for navigated marker placement using the combined modality. * This view utilizes the QmitkUSNavigationProcessWidget to do the navigation * process. It can be switched between widgets for marker placement and widgets * for punctuation. * * An experiment mode allows for logging results, durations and the ultrasound * images. */ class USNavigationMarkerPlacement : public QmitkAbstractView { Q_OBJECT protected slots: /** * \brief Called periodically to update the rendering. * The standard multi widget is changed to fit the navigation process once it * is available and a reinit on the ultrasound image is done for a new image * node. */ void OnTimeout(); /** * \brief Called periodically during an experiment for logging the ultrasound images. */ void OnImageAndNavigationDataLoggingTimeout(); /** * \brief Initializes anything neccessary for an experiment. * The user is asked for a directory for storing the results and the logging * is started. */ void OnStartExperiment(); /** * \brief Stops logging and saves everything to the file system. */ void OnFinishExperiment(); void OnCombinedModalityChanged(itk::SmartPointer); /** * \brief Switches the navigation step widgets if the navigation application was changed. */ void OnSettingsChanged(itk::SmartPointer); /** * \brief Updates the timer for the navigation steps durations every time the active navigation step changes. */ void OnActiveNavigationStepChanged(int); /** * \brief The data node is given to the experiment logging and scene is saved to the file system. */ void OnIntermediateResultProduced(const itk::SmartPointer); void OnAddAblationZone(int size); + void OnEnableNavigationLayout(); + + void OnResetStandardLayout(); + + void OnChangeLayoutClicked(); + void OnChangeAblationZone(int id, int newSize); public: static const char *DATANAME_TUMOUR; static const char *DATANAME_TARGETSURFACE; static const char *DATANAME_ZONES; static const char *DATANAME_TARGETS; static const char *DATANAME_TARGETS_PATHS; static const char *DATANAME_REACHED_TARGETS; explicit USNavigationMarkerPlacement(); ~USNavigationMarkerPlacement(); virtual void CreateQtPartControl(QWidget *parent); static const std::string VIEW_ID; void OnCombinedModalityPropertyChanged(const std::string &, const std::string &); + /** + * \returns the point defining the needle axis in the tool storage + */ + void SetToolAxisMarkerPlacement(); + mitk::Point3D m_ToolAxis; protected: /** * \brief A reinit on the ultrasound image is performed every time the view gets the focus. */ virtual void SetFocus(); /** * \brief Helper function which performs a reinit on the ultrasound image. */ void ReinitOnImage(); /** * \brief Helper function for being able to serialize the 2d ultrasound image. */ void Convert2DImagesTo3D(mitk::DataStorage::SetOfObjects::ConstPointer nodes); void CreateOverlays(); QWidget *m_Parent; QmitkUSNavigationProcessWidget::NavigationStepVector m_NavigationSteps; QTimer *m_UpdateTimer; QTimer *m_ImageAndNavigationDataLoggingTimer; QmitkStdMultiWidget *m_StdMultiWidget; itk::SmartPointer m_CombinedModality; bool m_ReinitAlreadyDone; bool m_IsExperimentRunning; std::string m_CurrentApplicationName; itk::SmartPointer m_NavigationStepTimer; itk::SmartPointer m_ExperimentLogging; QPixmap m_IconRunning; QPixmap m_IconNotRunning; QString m_ResultsDirectory; QString m_ExperimentName; QString m_ExperimentResultsSubDirectory; std::vector m_NavigationStepNames; // stores the names of the navigation steps which are currently used (for logging purposes) mitk::USNavigationLoggingBackend m_LoggingBackend; mitk::USImageLoggingFilter::Pointer m_USImageLoggingFilter; mitk::NavigationDataRecorder::Pointer m_NavigationDataRecorder; // records navigation data files mitk::NodeDisplacementFilter::Pointer m_TargetNodeDisplacementFilter; mitk::NodeDisplacementFilter::Pointer m_AblationZonesDisplacementFilter; std::vector m_AblationZonesVector; int m_NeedleIndex; int m_MarkerIndex; int m_SceneNumber; itk::SmartPointer m_WarnOverlay; + //To get tool storage + mitk::NavigationDataSource::Pointer m_NavigationDataSource; + mitk::NavigationToolStorage::Pointer m_CurrentStorage; + private: mitk::MessageDelegate2 m_ListenerDeviceChanged; Ui::USNavigationMarkerPlacement *ui; }; #endif // USNAVIGATIONMARKERPLACEMENT_H diff --git a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/OpenIGTLinkExample.cpp b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/OpenIGTLinkExample.cpp index 9803942ff4..0c35dfb245 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/OpenIGTLinkExample.cpp +++ b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/OpenIGTLinkExample.cpp @@ -1,242 +1,242 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkRenderWindow.h" // Qt #include // mitk #include #include #include #include #include // vtk #include // #include "OpenIGTLinkExample.h" //igtl #include "igtlStringMessage.h" #include "igtlTrackingDataMessage.h" const std::string OpenIGTLinkExample::VIEW_ID = "org.mitk.views.OpenIGTLinkExample"; void OpenIGTLinkExample::SetFocus() { } OpenIGTLinkExample::~OpenIGTLinkExample() { this->DestroyPipeline(); if (m_IGTLDeviceSource.IsNotNull()) { m_IGTLDeviceSource->UnRegisterMicroservice(); } } void OpenIGTLinkExample::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); // connect the widget items with the methods connect( m_Controls.butStart, SIGNAL(clicked()), this, SLOT(Start()) ); connect( &m_Timer, SIGNAL(timeout()), this, SLOT(UpdatePipeline())); //create a new OpenIGTLinkExample Client m_IGTLClient = mitk::IGTLClient::New(false); m_IGTLClient->SetName("OIGTL Example Client Device"); //create a new OpenIGTLinkExample Device source m_IGTLDeviceSource = mitk::IGTLDeviceSource::New(); //set the client as the source for the device source m_IGTLDeviceSource->SetIGTLDevice(m_IGTLClient); m_IGTLDeviceSource->RegisterAsMicroservice(); } void OpenIGTLinkExample::CreatePipeline() { //create a filter that converts OpenIGTLinkExample messages into navigation data m_IGTLMsgToNavDataFilter = mitk::IGTLMessageToNavigationDataFilter::New(); //create a visualization filter m_VisFilter = mitk::NavigationDataObjectVisualizationFilter::New(); //we expect a tracking data message with three tools. Since we cannot change //the outputs at runtime we have to set it manually. m_IGTLMsgToNavDataFilter->SetNumberOfExpectedOutputs(m_Controls.channelSpinBox->value()); //connect the filters with each other //the OpenIGTLinkExample messages will be passed to the first filter that converts //it to navigation data, then it is passed to the visualization filter that //will visualize the transformation m_IGTLMsgToNavDataFilter->ConnectTo(m_IGTLDeviceSource); m_VisFilter->ConnectTo(m_IGTLMsgToNavDataFilter); //create an object that will be moved respectively to the navigation data for (size_t i = 0; i < m_IGTLMsgToNavDataFilter->GetNumberOfIndexedOutputs(); i++) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString name("DemoNode IGTLProviderExmpl T"); name.append(QString::number(i)); newNode->SetName(name.toStdString()); //create small sphere and use it as surface mitk::Surface::Pointer mySphere = mitk::Surface::New(); vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(2.0f); vtkData->SetCenter(0.0, 0.0, 0.0); vtkData->Update(); mySphere->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); newNode->SetData(mySphere); m_VisFilter->SetRepresentationObject(i, mySphere); m_DemoNodes.append(newNode); } this->ResizeBoundingBox(); } void OpenIGTLinkExample::DestroyPipeline() { m_VisFilter = nullptr; foreach(mitk::DataNode::Pointer node, m_DemoNodes) { this->GetDataStorage()->Remove(node); } this->m_DemoNodes.clear(); } void OpenIGTLinkExample::Start() { if (this->m_Controls.butStart->text().contains("Start Pipeline")) { static bool isFirstTime = true; if (isFirstTime) { //Setup the pipeline this->CreatePipeline(); isFirstTime = false; } m_Timer.setInterval(this->m_Controls.visualizationUpdateRateSpinBox->value()); m_Timer.start(); //this->m_Controls.visualizationUpdateRateSpinBox->setEnabled(true); this->m_Controls.butStart->setText("Stop Pipeline"); } else { m_Timer.stop(); igtl::StopTrackingDataMessage::Pointer stopStreaming = igtl::StopTrackingDataMessage::New(); - this->m_IGTLClient->SendMessage(stopStreaming.GetPointer()); + this->m_IGTLClient->SendMessage(mitk::IGTLMessage::New((igtl::MessageBase::Pointer) stopStreaming)); this->m_Controls.butStart->setText("Start Pipeline"); //this->m_Controls.visualizationUpdateRateSpinBox->setEnabled(false); } } void OpenIGTLinkExample::UpdatePipeline() { if (this->m_Controls.visualizeCheckBox->isChecked()) { //update the pipeline m_VisFilter->Update(); ////update the boundings //mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); //Update rendering mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { //no visualization so we just update this filter m_IGTLMsgToNavDataFilter->Update(); //record a timestamp if the output is new //static double previousTimestamp; //double curTimestamp = m_IGTLMsgToNavDataFilter->GetOutput()->GetIGTTimeStamp(); //if (previousTimestamp != curTimestamp) static mitk::NavigationData::Pointer previousND = mitk::NavigationData::New(); mitk::NavigationData* curND = m_IGTLMsgToNavDataFilter->GetOutput(); //std::cout << "9: igt timestamp: " << curND->GetIGTTimeStamp() << std::endl; //std::cout << "9: timestamp: " << curND->GetTimeStamp() << std::endl; if ( !mitk::Equal( *(previousND.GetPointer()), *curND ) ) { //previousTimestamp = curTimestamp; previousND->Graft(curND); } } //check if the timer interval changed static int previousValue = 0; int currentValue = this->m_Controls.visualizationUpdateRateSpinBox->value(); if (previousValue != currentValue) { m_Timer.setInterval(currentValue); previousValue = currentValue; } } /** * \brief To initialize the scene to the bounding box of all visible objects */ void OpenIGTLinkExample::ResizeBoundingBox() { // get all nodes mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetAll(); mitk::TimeGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs); if (bounds.IsNull()) { return; } //expand the bounding box in case the instruments are all at one position mitk::Point3D center = bounds->GetCenterInWorld(); mitk::Geometry3D::BoundsArrayType extended_bounds = bounds->GetGeometryForTimeStep(0)->GetBounds(); for (unsigned int i = 0; i < 3; ++i) { if (bounds->GetExtentInWorld(i) < 500) { // extend the bounding box extended_bounds[i * 2] = center[i] - 500 / 2.0; extended_bounds[i * 2 + 1] = center[i] + 500 / 2.0; } } //set the extended bounds bounds->GetGeometryForTimeStep(0)->SetBounds(extended_bounds); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeViews(bounds); } diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/IGTNavigationToolCalibration.cpp b/Plugins/org.mitk.gui.qt.igttracking/src/internal/IGTNavigationToolCalibration.cpp index 21d1cfcc86..2780806cb0 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/IGTNavigationToolCalibration.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/IGTNavigationToolCalibration.cpp @@ -1,636 +1,636 @@ /*=================================================================== 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 // Blueberry #include #include // Qmitk #include "IGTNavigationToolCalibration.h" // mitk #include #include #include #include #include #include #include // Qt #include #include //vtk #include const std::string IGTNavigationToolCalibration::VIEW_ID = "org.mitk.views.igtnavigationtoolcalibration"; IGTNavigationToolCalibration::IGTNavigationToolCalibration() {} IGTNavigationToolCalibration::~IGTNavigationToolCalibration() { //The following code is required due to a bug in the point list widget. //If this is removed, MITK crashes when closing the view: m_Controls.m_RegistrationLandmarkWidget->SetPointSetNode(nullptr); m_Controls.m_CalibrationLandmarkWidget->SetPointSetNode(nullptr); } void IGTNavigationToolCalibration::SetFocus() { } void IGTNavigationToolCalibration::OnToolCalibrationMethodChanged(int index) { //if pivot calibration (3) or manual(0) is chosen only calibration pointer is needed if (index == 0 || index == 3) { - if (!CheckInitialization(FALSE)) { + if (!CheckInitialization(false)) { return; } } else{ if (!CheckInitialization()) { return; } } UpdateManualToolTipCalibrationView(); m_Controls.m_CalibrationMethodsWidget->setCurrentIndex(index); m_IndexCurrentCalibrationMethod = index; } void IGTNavigationToolCalibration::CreateQtPartControl(QWidget *parent) { //initialize manual tool editing widget m_ManualToolTipEditWidget = new QmitkNavigationToolCreationAdvancedWidget(parent); m_ManualToolTipEditWidget->setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); m_ManualToolTipEditWidget->setWindowTitle("Edit Tool Tip Manually"); m_ManualToolTipEditWidget->setModal(false); m_ManualToolTipEditWidget->SetDataStorage(this->GetDataStorage()); m_TrackingTimer = new QTimer(this); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); connect(m_Controls.m_SetToolToCalibrate, SIGNAL(clicked()), this, SLOT(SetToolToCalibrate())); connect(m_Controls.m_SetPointer, SIGNAL(clicked()), this, SLOT(SetCalibrationPointer())); connect(m_TrackingTimer, SIGNAL(timeout()), this, SLOT(UpdateTrackingTimer())); connect(m_Controls.m_AddLandmark, SIGNAL(clicked()), this, SLOT(AddLandmark())); connect(m_Controls.m_SaveCalibratedTool, SIGNAL(clicked()), this, SLOT(SaveCalibratedTool())); connect(m_Controls.m_AddPivotPose, SIGNAL(clicked()), this, SLOT(OnAddPivotPose())); connect(m_Controls.m_ComputePivot, SIGNAL(clicked()), this, SLOT(OnComputePivot())); connect(m_Controls.m_UseComputedPivotPoint, SIGNAL(clicked()), this, SLOT(OnUseComputedPivotPoint())); connect(m_Controls.m_StartEditTooltipManually, SIGNAL(clicked()), this, SLOT(OnStartManualToolTipCalibration())); connect((QObject*)(m_ManualToolTipEditWidget), SIGNAL(RetrieveDataForManualToolTipManipulation()), this, SLOT(OnRetrieveDataForManualTooltipManipulation())); connect((QObject*)(m_ManualToolTipEditWidget), SIGNAL(DialogCloseRequested()), this, SLOT(OnProcessManualTooltipEditDialogCloseRequest())); connect(m_Controls.m_CalibrationMethodComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnToolCalibrationMethodChanged(int))); connect((QObject*)(m_Controls.m_RunCalibrationButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnRunSingleRefToolCalibrationClicked())); connect((QObject*)(m_Controls.m_CollectNavigationDataButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnLoginSingleRefToolNavigationDataClicked())); connect((QObject*)(m_Controls.m_SetNewToolTipPosButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnSetNewToolTipPosButtonClicked())); m_IDToolToCalibrate = -1; m_IDCalibrationPointer = -1; m_IndexCurrentCalibrationMethod = -1; m_OnLoginSingleRefToolNavigationDataClicked = false; m_NumberOfNavigationDataCounter = 0; m_NumberOfNavigationData = -1; //for pivot calibration m_OnAddPivotPoseClicked = false; PivotCount = 0; m_PivotPoses = std::vector(); m_CalibrationLandmarks = mitk::PointSet::New(); m_CalibrationLandmarksNode = mitk::DataNode::New(); m_CalibrationLandmarksNode->SetData(m_CalibrationLandmarks); m_Controls.m_CalibrationLandmarkWidget->SetPointSetNode(m_CalibrationLandmarksNode); m_RegistrationLandmarks = mitk::PointSet::New(); m_RegistrationLandmarksNode = mitk::DataNode::New(); m_RegistrationLandmarksNode->SetData(m_RegistrationLandmarks); m_Controls.m_RegistrationLandmarkWidget->SetPointSetNode(m_RegistrationLandmarksNode); m_ToolSurfaceInToolCoordinatesDataNode = mitk::DataNode::New(); m_ToolSurfaceInToolCoordinatesDataNode->SetName("ToolSurface(ToolCoordinates)"); m_LoggedNavigationDataDifferences = std::vector< mitk::NavigationData::Pointer >(); } void IGTNavigationToolCalibration::OnRunSingleRefToolCalibrationClicked() { if (!CheckInitialization()) { return; } mitk::NavigationData::Pointer ToolTipTransform = mitk::NavigationData::New(); if (m_Controls.m_CalibratePosition->isChecked()) { //1: Compute mean translational offset vector m_ResultOffsetVector.Fill(0); for (std::vector::iterator vecIter = m_LoggedNavigationDataOffsets.begin(); vecIter != m_LoggedNavigationDataOffsets.end(); vecIter++) { m_ResultOffsetVector[0] = m_ResultOffsetVector[0] + (*vecIter)[0]; m_ResultOffsetVector[1] = m_ResultOffsetVector[1] + (*vecIter)[1]; m_ResultOffsetVector[2] = m_ResultOffsetVector[2] + (*vecIter)[2]; } m_ResultOffsetVector[0] = m_ResultOffsetVector[0] / m_LoggedNavigationDataOffsets.size(); m_ResultOffsetVector[1] = m_ResultOffsetVector[1] / m_LoggedNavigationDataOffsets.size(); m_ResultOffsetVector[2] = m_ResultOffsetVector[2] / m_LoggedNavigationDataOffsets.size(); this->m_Controls.m_ResultOfCalibration->setText( QString("x: ") + QString(QString::number(m_ResultOffsetVector[0], 103, 3)) + QString("; y: ") + (QString::number(m_ResultOffsetVector[1], 103, 3)) + QString("; z: ") + (QString::number(m_ResultOffsetVector[2], 103, 3))); ToolTipTransform->SetPosition(m_ResultOffsetVector); } if (m_Controls.m_CalibrateOrientation->isChecked()) { //2: Compute mean orientation mitk::Quaternion meanOrientation; std::vector allOrientations = std::vector (); for (int i = 0; i < m_LoggedNavigationDataDifferences.size(); i++) { allOrientations.push_back(m_LoggedNavigationDataDifferences.at(i)->GetOrientation()); } meanOrientation = mitk::QuaternionAveraging::CalcAverage(allOrientations); this->m_Controls.m_ResultOfCalibrationOrientation->setText( QString("qx: ") + QString(QString::number(meanOrientation.x(), 103, 3)) + QString("; qy: ") + (QString::number(meanOrientation.y(), 103, 3)) + QString("; qz: ") + (QString::number(meanOrientation.z(), 103, 3)) + QString("; qr: ") + (QString::number(meanOrientation.r(), 103, 3))); ToolTipTransform->SetOrientation(meanOrientation); } MITK_INFO << "Computed calibration: "; MITK_INFO << "Translation Vector: " << ToolTipTransform->GetPosition(); MITK_INFO << "Quaternion: (" << ToolTipTransform->GetOrientation() << ")"; MITK_INFO << "Euler Angles [rad]: (" << ToolTipTransform->GetOrientation().rotation_euler_angles() << ")"; MITK_INFO << "Matrix:"; vnl_matrix_fixed rotMatrix = ToolTipTransform->GetOrientation().rotation_matrix_transpose(); MITK_INFO << rotMatrix[0][0] << " " << rotMatrix[0][1] << " " << rotMatrix[0][2] << std::endl; MITK_INFO << rotMatrix[1][0] << " " << rotMatrix[1][1] << " " << rotMatrix[1][2] << std::endl; MITK_INFO << rotMatrix[2][0] << " " << rotMatrix[2][1] << " " << rotMatrix[2][2] << std::endl; //3: write everything into the final tool tip transform and save it as member (it will be written to the tool later on) mitk::NavigationData::Pointer ToolTipInTrackingCoordinates = mitk::NavigationData::New(); ToolTipInTrackingCoordinates->Compose(ToolTipTransform); ToolTipInTrackingCoordinates->Compose(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)); ShowToolTipPreview(ToolTipInTrackingCoordinates); m_Controls.m_SetNewToolTipPosButton->setEnabled(true); m_ComputedToolTipTransformation = ToolTipTransform; } void IGTNavigationToolCalibration::OnLoginSingleRefToolNavigationDataClicked() { if (!CheckInitialization()) { return; } m_OnLoginSingleRefToolNavigationDataClicked = true; m_Controls.m_CollectNavigationDataButton->setEnabled(false); m_NumberOfNavigationData = m_Controls.m_NumberOfNavigationDataToCollect->value(); MITK_INFO << "Collecting " << m_NumberOfNavigationData << " NavigationData ... " << endl; } void IGTNavigationToolCalibration::LoginSingleRefToolNavigationData() { if (!CheckInitialization()) { return; } if (m_NumberOfNavigationDataCounter < m_NumberOfNavigationData) { //update label text QString labelText = "Collecting Data: " + QString::number(m_NumberOfNavigationDataCounter); m_Controls.m_CollectionStatus->setText(labelText); mitk::NavigationData::Pointer referenceTool = m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer); mitk::NavigationData::Pointer toolToCalibrate = m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate); //compute difference: // differenceND = toolToCalibrate^-1 * referenceTool mitk::NavigationData::Pointer differenceND = mitk::NavigationData::New(); differenceND->Compose(referenceTool); differenceND->Compose(toolToCalibrate->GetInverse()); //inverse mode... if (m_Controls.m_InvertQuaternions->isChecked()) { // negate identity matrix to directly show parameters that will set up in NDI 6D Software Architect differenceND = differenceND->GetInverse(); } //save difference in member m_LoggedNavigationDataOffsets.push_back(differenceND->GetPosition()); m_LoggedNavigationDataDifferences.push_back(differenceND); m_NumberOfNavigationDataCounter++; } if (m_NumberOfNavigationDataCounter == m_NumberOfNavigationData) { m_NumberOfNavigationDataCounter = 0; m_OnLoginSingleRefToolNavigationDataClicked = false; m_Controls.m_CollectNavigationDataButton->setEnabled(true); m_Controls.m_RunCalibrationButton->setEnabled(true); MITK_INFO << "Collecting " << m_NumberOfNavigationData << " NavigationData ... Finished" << endl; QString labelText = "Collected " + QString::number(m_NumberOfNavigationData) + " data samples!"; m_Controls.m_CollectionStatus->setText(labelText); } } void IGTNavigationToolCalibration::OnSetNewToolTipPosButtonClicked() { ApplyToolTipTransform(m_ComputedToolTipTransformation); RemoveToolTipPreview(); } void IGTNavigationToolCalibration::ClearOldPivot() { mitk::NavigationData::Pointer tempND = mitk::NavigationData::New(); this->ApplyToolTipTransform(tempND); UpdateManualToolTipCalibrationView(); m_ManualToolTipEditWidget->hide(); this->GetDataStorage()->Remove(m_ToolSurfaceInToolCoordinatesDataNode); } void IGTNavigationToolCalibration::OnAddPivotPose() { ClearOldPivot(); //When the collect Poses Button is Clicked m_OnAddPivotPoseClicked = true; m_NumberOfNavigationData = m_Controls.m_PosesToCollect->value(); } void IGTNavigationToolCalibration::AddPivotPose() { //Save the poses to be used in computation if (PivotCount < m_NumberOfNavigationData) { mitk::NavigationData::Pointer currentPose = mitk::NavigationData::New(); currentPose->Graft(m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_IDToolToCalibrate)); m_PivotPoses.push_back(currentPose); m_Controls.m_PoseNumber->setText(QString::number(m_PivotPoses.size())); PivotCount++; } if (PivotCount == m_NumberOfNavigationData) { m_OnAddPivotPoseClicked = false; } } void IGTNavigationToolCalibration::OnComputePivot() { mitk::PivotCalibration::Pointer myPivotCalibration = mitk::PivotCalibration::New(); for (int i = 0; i < this->m_PivotPoses.size(); i++) { myPivotCalibration->AddNavigationData(m_PivotPoses.at(i)); } QString resultString; if (myPivotCalibration->ComputePivotResult()) { mitk::NavigationData::Pointer markerTransformationTrackingCoordinates = m_PivotPoses.at(0); //Get computed pivot transfromation in tool coordinates mitk::NavigationData::Pointer ToolTipToTool = mitk::NavigationData::New(); ToolTipToTool->SetPosition(myPivotCalibration->GetResultPivotPoint()); ToolTipToTool->SetOrientation(myPivotCalibration->GetResultPivotRotation()); mitk::NavigationData::Pointer TrackerToTool = mitk::NavigationData::New(); TrackerToTool->SetOrientation(markerTransformationTrackingCoordinates->GetOrientation()); TrackerToTool->SetPosition(markerTransformationTrackingCoordinates->GetPosition()); TrackerToTool->Compose(ToolTipToTool); // Compute pivot point in relation to marker transformation for preview mitk::NavigationData::Pointer ToolTipToTracker = mitk::NavigationData::New(); ToolTipToTracker->Compose(ToolTipToTool); ToolTipToTracker->Compose(markerTransformationTrackingCoordinates); //add the preview node to the data storage ShowToolTipPreview(ToolTipToTracker); //parse result string resultString = QString("Pivot computation succeeded!\n") + QString("RMS Error: ") + QString::number(myPivotCalibration->GetResultRMSError()) + QString("\n") + QString("Pivot Point: ") + QString::number(myPivotCalibration->GetResultPivotPoint()[0]) + ";" + QString::number(myPivotCalibration->GetResultPivotPoint()[1]) + ";" + QString::number(myPivotCalibration->GetResultPivotPoint()[2]) + QString("\n") + QString("Pivot Rotation: ") + QString::number(myPivotCalibration->GetResultPivotRotation()[0]) + ";" + QString::number(myPivotCalibration->GetResultPivotRotation()[1]) + ";" + QString::number(myPivotCalibration->GetResultPivotRotation()[2]) + ";" + QString::number(myPivotCalibration->GetResultPivotRotation()[3]) + QString("\n"); //finally: save results to member variable m_ComputedToolTipTransformation = ToolTipToTool; //enable button to use the computed point with the tool m_Controls.m_UseComputedPivotPoint->setEnabled(true); } else { resultString = "Pivot computation failed!"; } MITK_INFO << resultString.toStdString().c_str(); m_Controls.m_ResultText->setText(resultString); } void IGTNavigationToolCalibration::UpdatePivotCount() { PivotCount = 0; while (!m_PivotPoses.empty()) { m_PivotPoses.pop_back(); } m_Controls.m_PoseNumber->setText(QString::number(PivotCount)); } void IGTNavigationToolCalibration::OnUseComputedPivotPoint() { RemoveToolTipPreview(); QString resultString = QString("Pivoted tool tip transformation was written to the tool ") + m_ToolToCalibrate->GetToolName().c_str(); ApplyToolTipTransform(m_ComputedToolTipTransformation, resultString.toStdString()); m_Controls.m_ResultText->setText(resultString); UpdatePivotCount(); } void IGTNavigationToolCalibration::ApplyToolTipTransform(mitk::NavigationData::Pointer ToolTipTransformInToolCoordinates, std::string message) { if (!CheckInitialization(false)) { return; } //Update tool in tool storage m_ToolToCalibrate->SetToolTipPosition(ToolTipTransformInToolCoordinates->GetPosition()); m_ToolToCalibrate->SetToolTipOrientation(ToolTipTransformInToolCoordinates->GetOrientation()); //And also update tracking device, so the transform is directly used mitk::TrackingDeviceSource::Pointer trackingDeviceSource; try { trackingDeviceSource = dynamic_cast(m_NavigationDataSourceOfToolToCalibrate.GetPointer()); mitk::TrackingTool::Pointer TrackingToolToCalibrate = trackingDeviceSource->GetTrackingDevice()->GetTool(m_IDToolToCalibrate); TrackingToolToCalibrate->SetToolTip(ToolTipTransformInToolCoordinates->GetPosition(), ToolTipTransformInToolCoordinates->GetOrientation()); } catch (std::exception& e) { MITK_ERROR << "Error while trying to set the tool tip to the running tracking device. Aborting! (" << e.what() << ")"; } MITK_INFO << message; } void IGTNavigationToolCalibration::ShowToolTipPreview(mitk::NavigationData::Pointer ToolTipInTrackingCoordinates) { mitk::DataNode::Pointer m_ToolTipPointPreview = mitk::DataNode::New(); m_ToolTipPointPreview->SetName("Modified Tool Tip Preview"); mitk::Color blue; blue.SetBlue(1); m_ToolTipPointPreview->SetColor(blue); mitk::Surface::Pointer mySphere = mitk::Surface::New(); vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(3.0f); vtkData->SetCenter(0.0, 0.0, 0.0); vtkData->Update(); mySphere->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); m_ToolTipPointPreview->SetData(mySphere); m_ToolTipPointPreview->GetData()->GetGeometry()->SetIndexToWorldTransform(ToolTipInTrackingCoordinates->GetAffineTransform3D()); this->GetDataStorage()->Add(m_ToolTipPointPreview); } void IGTNavigationToolCalibration::RemoveToolTipPreview() { this->GetDataStorage()->Remove(m_ToolTipPointPreview.GetPointer()); } void IGTNavigationToolCalibration::UpdateManualToolTipCalibrationView() { if (m_ToolToCalibrate.IsNull()) { return; } //parse human readable transformation data and display it std::stringstream translation; std::stringstream orientation; translation << m_ToolToCalibrate->GetToolTipPosition(); orientation << "Quaternion: (" << m_ToolToCalibrate->GetToolTipOrientation() << ")" << std::endl; orientation << std::endl; orientation << "Euler Angles [rad]: (" << m_ToolToCalibrate->GetToolTipOrientation().rotation_euler_angles() << ")" << std::endl; orientation << std::endl; orientation << "Matrix:" << std::endl; vnl_matrix_fixed rotMatrix = m_ToolToCalibrate->GetToolTipOrientation().rotation_matrix_transpose(); orientation << rotMatrix[0][0] << " " << rotMatrix[0][1] << " " << rotMatrix[0][2] << std::endl; orientation << rotMatrix[1][0] << " " << rotMatrix[1][1] << " " << rotMatrix[1][2] << std::endl; orientation << rotMatrix[2][0] << " " << rotMatrix[2][1] << " " << rotMatrix[2][2] << std::endl; m_Controls.m_ManualCurrentTranslation->setText(translation.str().c_str()); m_Controls.m_ManualCurrentOrientation->setPlainText(orientation.str().c_str()); } void IGTNavigationToolCalibration::OnStartManualToolTipCalibration() { if (!CheckInitialization(false)) { return; } m_ManualToolTipEditWidget->SetToolTipSurface(false, m_ToolToCalibrate->GetDataNode()); m_ManualToolTipEditWidget->show(); m_ManualToolTipEditWidget->SetDefaultTooltip(m_ToolToCalibrate->GetToolTipTransform()); m_ManualToolTipEditWidget->ReInitialize(); } void IGTNavigationToolCalibration::OnRetrieveDataForManualTooltipManipulation() { this->GetDataStorage()->Add(m_ToolSurfaceInToolCoordinatesDataNode); m_ManualToolTipEditWidget->SetToolTipSurface(false, m_ToolSurfaceInToolCoordinatesDataNode); } void IGTNavigationToolCalibration::OnProcessManualTooltipEditDialogCloseRequest() { mitk::NavigationData::Pointer tempND = mitk::NavigationData::New(m_ManualToolTipEditWidget->GetManipulatedToolTip()); this->ApplyToolTipTransform(tempND); UpdateManualToolTipCalibrationView(); m_ManualToolTipEditWidget->hide(); this->GetDataStorage()->Remove(m_ToolSurfaceInToolCoordinatesDataNode); } void IGTNavigationToolCalibration::SetToolToCalibrate() { m_IDToolToCalibrate = m_Controls.m_SelectionWidget->GetSelectedToolID(); m_ToolToCalibrate = m_Controls.m_SelectionWidget->GetSelectedNavigationTool(); if (m_IDToolToCalibrate == -1) //no valid tool to calibrate { m_Controls.m_CalToolLabel->setText(""); m_Controls.m_StatusWidgetToolToCalibrate->RemoveStatusLabels(); m_TrackingTimer->stop(); } else { m_NavigationDataSourceOfToolToCalibrate = m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource(); m_Controls.m_CalToolLabel->setText(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)->GetName()); //initialize widget m_Controls.m_StatusWidgetToolToCalibrate->RemoveStatusLabels(); m_Controls.m_StatusWidgetToolToCalibrate->SetShowPositions(true); m_Controls.m_StatusWidgetToolToCalibrate->SetTextAlignment(Qt::AlignLeft); m_Controls.m_StatusWidgetToolToCalibrate->AddNavigationData(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)); m_Controls.m_StatusWidgetToolToCalibrate->ShowStatusLabels(); //initialize manual tool tip calibration view UpdateManualToolTipCalibrationView(); //save tool surface in tool coordinates for further editing mitk::Surface::Pointer ToolSurface = dynamic_cast(m_ToolToCalibrate->GetDataNode()->GetData())->Clone(); m_ToolSurfaceInToolCoordinatesDataNode->SetData(ToolSurface); m_ToolSurfaceInToolCoordinatesDataNode->GetData()->GetGeometry()->SetIdentity(); //start updating timer for status widgets, etc. if (!m_TrackingTimer->isActive()) m_TrackingTimer->start(100); } } void IGTNavigationToolCalibration::SetCalibrationPointer() { m_IDCalibrationPointer = m_Controls.m_SelectionWidget->GetSelectedToolID(); m_NavigationDataSourceOfCalibrationPointer = m_Controls.m_SelectionWidget->GetSelectedNavigationDataSource(); if (m_IDCalibrationPointer == -1) { m_Controls.m_PointerLabel->setText(""); m_Controls.m_StatusWidgetCalibrationPointer->RemoveStatusLabels(); m_TrackingTimer->stop(); } else { m_Controls.m_PointerLabel->setText(m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer)->GetName()); //initialize widget m_Controls.m_StatusWidgetCalibrationPointer->RemoveStatusLabels(); m_Controls.m_StatusWidgetCalibrationPointer->SetShowPositions(true); m_Controls.m_StatusWidgetCalibrationPointer->SetTextAlignment(Qt::AlignLeft); m_Controls.m_StatusWidgetCalibrationPointer->AddNavigationData(m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer)); m_Controls.m_StatusWidgetCalibrationPointer->ShowStatusLabels(); if (!m_TrackingTimer->isActive()) m_TrackingTimer->start(100); } } void IGTNavigationToolCalibration::UpdateOffsetCoordinates() { if (m_NavigationDataSourceOfCalibrationPointer.IsNull() || m_NavigationDataSourceOfToolToCalibrate.IsNull()) { return; } mitk::NavigationData::Pointer referenceToolND = m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer); mitk::NavigationData::Pointer toolToCalibrateND = m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate); if (referenceToolND->IsDataValid() && toolToCalibrateND->IsDataValid()) { //computation: difference between both tools (in tool coordinates) //differenceND = toolToCalibrateND^-1 * referenceToolND mitk::NavigationData::Pointer differenceND = mitk::NavigationData::New(); differenceND->Compose(referenceToolND); differenceND->Compose(toolToCalibrateND->GetInverse()); //display this orientation in the UI m_Controls.m_OffsetCoordinates->setText( QString("x: ") + QString(QString::number(differenceND->GetPosition()[0], 103, 3)) + QString("; y: ") + (QString::number(differenceND->GetPosition()[1], 103, 3)) + QString("; z: ") + (QString::number(differenceND->GetPosition()[2], 103, 3))); m_Controls.m_OrientationOffsetCoordinates->setText( QString("qx: ") + QString(QString::number(differenceND->GetOrientation().x(), 103, 3)) + QString("; qy: ") + (QString::number(differenceND->GetOrientation().y(), 103, 3)) + QString("; qz: ") + (QString::number(differenceND->GetOrientation().z(), 103, 3)) + QString("; qr: ") + (QString::number(differenceND->GetOrientation().r(), 103, 3))); //also update preview if active if (m_ToolTipPointPreview.IsNotNull()) //NOT WORKING! TODO: fix or remove! { mitk::NavigationData::Pointer ToolTipTransform = mitk::NavigationData::New(); ToolTipTransform->SetPosition(m_ResultOffsetVector); mitk::NavigationData::Pointer ToolTipInTrackingCoordinates = mitk::NavigationData::New(); //maybe store as for better peformance... ToolTipInTrackingCoordinates->Compose(m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate)); ToolTipInTrackingCoordinates->Compose(ToolTipTransform); m_ToolTipPointPreview->GetData()->GetGeometry()->SetIndexToWorldTransform(ToolTipInTrackingCoordinates->GetAffineTransform3D()); } } } void IGTNavigationToolCalibration::UpdateTrackingTimer() { m_Controls.m_StatusWidgetToolToCalibrate->Refresh(); m_Controls.m_StatusWidgetCalibrationPointer->Refresh(); if (m_OnLoginSingleRefToolNavigationDataClicked) LoginSingleRefToolNavigationData(); if (m_OnAddPivotPoseClicked) AddPivotPose(); // 1 == Single Reference Calibration Method if (m_IndexCurrentCalibrationMethod == 1) UpdateOffsetCoordinates(); } void IGTNavigationToolCalibration::AddLandmark() { if (!CheckInitialization()) { return; } mitk::NavigationData::Pointer navDataTool = m_NavigationDataSourceOfToolToCalibrate->GetOutput(m_IDToolToCalibrate); mitk::Point3D landmark = m_NavigationDataSourceOfCalibrationPointer->GetOutput(m_IDCalibrationPointer)->GetPosition(); //convert to itk transform itk::Vector translation; for (int k = 0; k < 3; k++) translation[k] = navDataTool->GetPosition()[k]; itk::Matrix rotation; for (int k = 0; k < 3; k++) for (int l = 0; l < 3; l++) rotation[k][l] = navDataTool->GetOrientation().rotation_matrix_transpose()[k][l]; rotation = rotation.GetTranspose(); itk::Vector landmarkItk; landmarkItk[0] = landmark[0]; landmarkItk[1] = landmark[1]; landmarkItk[2] = landmark[2]; //compute landmark in tool coordinates itk::Matrix rotationInverse; for (int k = 0; k < 3; k++) for (int l = 0; l < 3; l++) rotationInverse[k][l] = rotation.GetInverse()[k][l]; landmarkItk = rotationInverse * (landmarkItk - translation); //convert back and add landmark to pointset landmark[0] = landmarkItk[0]; landmark[1] = landmarkItk[1]; landmark[2] = landmarkItk[2]; m_RegistrationLandmarks->InsertPoint(m_RegistrationLandmarks->GetSize(), landmark); } void IGTNavigationToolCalibration::SaveCalibratedTool() { if (m_ToolToCalibrate.IsNotNull()) { mitk::NavigationTool::Pointer calibratedTool = m_ToolToCalibrate; calibratedTool->SetToolCalibrationLandmarks(this->m_CalibrationLandmarks); calibratedTool->SetToolRegistrationLandmarks(this->m_RegistrationLandmarks); mitk::NavigationToolWriter::Pointer myWriter = mitk::NavigationToolWriter::New(); std::string filename = QFileDialog::getSaveFileName(nullptr,tr("Save Navigation Tool"), "/", "*.IGTTool").toUtf8().data(); filename.append(".IGTTool"); if (filename == "") return; if (myWriter->DoWrite(filename, calibratedTool)) MITK_INFO << "Saved calibrated tool to file " << filename; else MITK_WARN << "Can't write tool to file " << filename; } else { MITK_ERROR << "Did not find navigation tool storage of calibrated tool, aborting!"; } } bool IGTNavigationToolCalibration::CheckInitialization(bool CalibrationPointerRequired) { if ((m_IDToolToCalibrate == -1) || ((CalibrationPointerRequired) && (m_IDCalibrationPointer == -1) ) ) { QMessageBox msgBox; msgBox.setText("Tool to calibrate and/or calibration pointer not initialized, cannot proceed!"); msgBox.exec(); return false; } else { return true; } } diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp index 5665af9590..570df2261a 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp @@ -1,1468 +1,1460 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkMITKIGTTrackingToolboxView.h" #include "QmitkTrackingDeviceConfigurationWidget.h" // Qt #include #include #include // MITK #include #include #include #include #include #include #include //#include #include #include #include #include #include #include "mitkNDIAuroraTypeInformation.h" // vtk #include //for exceptions #include #include //for Microservice #include "mitkPluginActivator.h" #include #include #include "usServiceReference.h" const std::string QmitkMITKIGTTrackingToolboxView::VIEW_ID = "org.mitk.views.mitkigttrackingtoolbox"; QmitkMITKIGTTrackingToolboxView::QmitkMITKIGTTrackingToolboxView() : QmitkAbstractView() , m_Controls(nullptr) , m_DeviceTypeCollection(nullptr) { m_TrackingLoggingTimer = new QTimer(this); m_TrackingRenderTimer = new QTimer(this); m_TimeoutTimer = new QTimer(this); m_tracking = false; m_connected = false; m_logging = false; m_loggedFrames = 0; m_SimpleModeEnabled = false; //create filename for autosaving of tool storage QString loggingPathWithoutFilename = QString(mitk::LoggingBackend::GetLogFile().c_str()); if (!loggingPathWithoutFilename.isEmpty()) //if there already is a path for the MITK logging file use this one { //extract path from path+filename (if someone knows a better way to do this feel free to change it) int lengthOfFilename = QFileInfo(QString::fromStdString(mitk::LoggingBackend::GetLogFile())).fileName().size(); loggingPathWithoutFilename.resize(loggingPathWithoutFilename.size() - lengthOfFilename); m_AutoSaveFilename = loggingPathWithoutFilename + "TrackingToolboxAutoSave.IGTToolStorage"; } else //if not: use a temporary path from IOUtil { m_AutoSaveFilename = QString(mitk::IOUtil::GetTempPath().c_str()) + "TrackingToolboxAutoSave.IGTToolStorage"; } MITK_INFO("IGT Tracking Toolbox") << "Filename for auto saving of IGT ToolStorages: " << m_AutoSaveFilename.toStdString(); //! [Thread 1] //initialize worker thread m_WorkerThread = new QThread(); m_Worker = new QmitkMITKIGTTrackingToolboxViewWorker(); //! [Thread 1] ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { QString interfaceName = QString::fromStdString(us_service_interface_iid()); QList serviceReference = pluginContext->getServiceReferences(interfaceName); if (serviceReference.size() > 0) { m_DeviceTypeServiceReference = serviceReference.at(0); const ctkServiceReference& r = serviceReference.at(0); m_DeviceTypeCollection = pluginContext->getService(r); } else { MITK_INFO << "No Tracking Device Collection!"; } } } QmitkMITKIGTTrackingToolboxView::~QmitkMITKIGTTrackingToolboxView() { this->StoreUISettings(); m_TrackingLoggingTimer->stop(); m_TrackingRenderTimer->stop(); m_TimeoutTimer->stop(); delete m_TrackingLoggingTimer; delete m_TrackingRenderTimer; delete m_TimeoutTimer; try { //! [Thread 2] // wait for thread to finish m_WorkerThread->terminate(); m_WorkerThread->wait(); //clean up worker thread if (m_WorkerThread) { delete m_WorkerThread; } if (m_Worker) { delete m_Worker; } //! [Thread 2] //remove the tracking volume this->GetDataStorage()->Remove(m_TrackingVolumeNode); //unregister microservices if (m_toolStorage) { m_toolStorage->UnRegisterMicroservice(); } if (m_TrackingDeviceSource) { m_TrackingDeviceSource->UnRegisterMicroservice(); } if (m_IGTLMessageProvider.IsNotNull()){ m_IGTLMessageProvider->UnRegisterMicroservice(); } } catch (std::exception& e) { MITK_WARN << "Unexpected exception during clean up of tracking toolbox view: " << e.what(); } catch (...) { MITK_WARN << "Unexpected unknown error during clean up of tracking toolbox view!"; } //store tool storage and UI settings for persistence this->AutoSaveToolStorage(); this->StoreUISettings(); m_DeviceTypeCollection = nullptr; mitk::PluginActivator::GetContext()->ungetService(m_DeviceTypeServiceReference); } void QmitkMITKIGTTrackingToolboxView::CreateQtPartControl(QWidget *parent) { // build up qt view, unless already done if (!m_Controls) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkMITKIGTTrackingToolboxViewControls; m_Controls->setupUi(parent); //create connections connect(m_Controls->m_LoadTools, SIGNAL(clicked()), this, SLOT(OnLoadTools())); connect(m_Controls->m_ConnectDisconnectButton, SIGNAL(clicked()), this, SLOT(OnConnectDisconnect())); connect(m_Controls->m_StartStopTrackingButton, SIGNAL(clicked()), this, SLOT(OnStartStopTracking())); connect(m_Controls->m_ConnectSimpleMode, SIGNAL(clicked()), this, SLOT(OnConnectDisconnect())); connect(m_Controls->m_StartTrackingSimpleMode, SIGNAL(clicked()), this, SLOT(OnStartStopTracking())); connect(m_Controls->m_FreezeUnfreezeTrackingButton, SIGNAL(clicked()), this, SLOT(OnFreezeUnfreezeTracking())); connect(m_TrackingLoggingTimer, SIGNAL(timeout()), this, SLOT(UpdateLoggingTrackingTimer())); connect(m_TrackingRenderTimer, SIGNAL(timeout()), this, SLOT(UpdateRenderTrackingTimer())); connect(m_TimeoutTimer, SIGNAL(timeout()), this, SLOT(OnTimeOut())); connect(m_Controls->m_ChooseFile, SIGNAL(clicked()), this, SLOT(OnChooseFileClicked())); connect(m_Controls->m_StartLogging, SIGNAL(clicked()), this, SLOT(StartLogging())); connect(m_Controls->m_StopLogging, SIGNAL(clicked()), this, SLOT(StopLogging())); connect(m_Controls->m_VolumeSelectionBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(OnTrackingVolumeChanged(QString))); connect(m_Controls->m_ShowTrackingVolume, SIGNAL(clicked()), this, SLOT(OnShowTrackingVolumeChanged())); connect(m_Controls->m_AutoDetectTools, SIGNAL(clicked()), this, SLOT(OnAutoDetectTools())); connect(m_Controls->m_ResetTools, SIGNAL(clicked()), this, SLOT(OnResetTools())); connect(m_Controls->m_AddSingleTool, SIGNAL(clicked()), this, SLOT(OnAddSingleTool())); connect(m_Controls->m_NavigationToolCreationWidget, SIGNAL(NavigationToolFinished()), this, SLOT(OnAddSingleToolFinished())); connect(m_Controls->m_NavigationToolCreationWidget, SIGNAL(Canceled()), this, SLOT(OnAddSingleToolCanceled())); connect(m_Controls->m_csvFormat, SIGNAL(clicked()), this, SLOT(OnToggleFileExtension())); connect(m_Controls->m_xmlFormat, SIGNAL(clicked()), this, SLOT(OnToggleFileExtension())); connect(m_Controls->m_UseDifferentUpdateRates, SIGNAL(clicked()), this, SLOT(OnToggleDifferentUpdateRates())); connect(m_Controls->m_RenderUpdateRate, SIGNAL(valueChanged(int)), this, SLOT(OnChangeRenderUpdateRate())); connect(m_Controls->m_DisableAllTimers, SIGNAL(stateChanged(int)), this, SLOT(EnableDisableTimerButtons(int))); connect(m_Controls->m_advancedUI, SIGNAL(clicked()), this, SLOT(OnToggleAdvancedSimpleMode())); connect(m_Controls->m_simpleUI, SIGNAL(clicked()), this, SLOT(OnToggleAdvancedSimpleMode())); //connections for the tracking device configuration widget connect(m_Controls->m_configurationWidget, SIGNAL(TrackingDeviceSelectionChanged()), this, SLOT(OnTrackingDeviceChanged())); //! [Thread 3] //connect worker thread connect(m_Worker, SIGNAL(AutoDetectToolsFinished(bool, QString)), this, SLOT(OnAutoDetectToolsFinished(bool, QString))); connect(m_Worker, SIGNAL(ConnectDeviceFinished(bool, QString)), this, SLOT(OnConnectFinished(bool, QString))); connect(m_Worker, SIGNAL(StartTrackingFinished(bool, QString)), this, SLOT(OnStartTrackingFinished(bool, QString))); connect(m_Worker, SIGNAL(StopTrackingFinished(bool, QString)), this, SLOT(OnStopTrackingFinished(bool, QString))); connect(m_Worker, SIGNAL(DisconnectDeviceFinished(bool, QString)), this, SLOT(OnDisconnectFinished(bool, QString))); connect(m_WorkerThread, SIGNAL(started()), m_Worker, SLOT(ThreadFunc())); //move the worker to the thread m_Worker->moveToThread(m_WorkerThread); //! [Thread 3] //initialize widgets m_Controls->m_TrackingToolsStatusWidget->SetShowPositions(true); m_Controls->m_TrackingToolsStatusWidget->SetTextAlignment(Qt::AlignLeft); m_Controls->m_simpleWidget->setVisible(false); //initialize tracking volume node m_TrackingVolumeNode = mitk::DataNode::New(); m_TrackingVolumeNode->SetName("TrackingVolume"); m_TrackingVolumeNode->SetBoolProperty("Backface Culling", true); mitk::Color red; red.SetRed(1); m_TrackingVolumeNode->SetColor(red); //initialize buttons - m_Controls->m_AutoDetectTools->setVisible(false); //only visible if tracking device is Aurora + m_Controls->m_AutoDetectTools->setVisible(false); //only visible if supported by tracking device m_Controls->m_StartStopTrackingButton->setEnabled(false); m_Controls->m_StartTrackingSimpleMode->setEnabled(false); m_Controls->m_FreezeUnfreezeTrackingButton->setEnabled(false); //initialize warning labels m_Controls->m_renderWarningLabel->setVisible(false); m_Controls->m_TrackingFrozenLabel->setVisible(false); //Update List of available models for selected tool. std::vector Compatibles; if ((m_Controls == nullptr) || //check all these stuff for nullptr, latterly this causes crashes from time to time (m_Controls->m_configurationWidget == nullptr) || (m_Controls->m_configurationWidget->GetTrackingDevice().IsNull())) { MITK_ERROR << "Couldn't get current tracking device or an object is nullptr, something went wrong!"; return; } else { Compatibles = m_DeviceTypeCollection->GetDeviceDataForLine(m_Controls->m_configurationWidget->GetTrackingDevice()->GetType()); } m_Controls->m_VolumeSelectionBox->clear(); for (std::size_t i = 0; i < Compatibles.size(); i++) { m_Controls->m_VolumeSelectionBox->addItem(Compatibles[i].Model.c_str()); } //initialize tool storage m_toolStorage = mitk::NavigationToolStorage::New(GetDataStorage()); m_toolStorage->SetName("TrackingToolbox Default Storage"); m_toolStorage->RegisterAsMicroservice("no tracking device"); //set home directory as default path for logfile m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(QDir::homePath()) + QDir::separator() + "logfile.csv"); //tracking device may be changed already by the persistence of the //QmitkTrackingDeciveConfigurationWidget this->OnTrackingDeviceChanged(); this->LoadUISettings(); //add tracking volume node only to data storage this->GetDataStorage()->Add(m_TrackingVolumeNode); if (!m_Controls->m_ShowTrackingVolume->isChecked()) m_TrackingVolumeNode->SetOpacity(0.0); else m_TrackingVolumeNode->SetOpacity(0.25); //Update List of available models for selected tool. m_Controls->m_VolumeSelectionBox->clear(); for (std::size_t i = 0; i < Compatibles.size(); i++) { m_Controls->m_VolumeSelectionBox->addItem(Compatibles[i].Model.c_str()); } } } void QmitkMITKIGTTrackingToolboxView::SetFocus() { m_Controls->m_configurationWidget->setFocus(); } void QmitkMITKIGTTrackingToolboxView::OnLoadTools() { //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Tool Storage"), "/", tr("Tool Storage Files (*.IGTToolStorage)")); if (filename.isNull()) return; //read tool storage from disk std::string errorMessage = ""; mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(GetDataStorage()); // try-catch block for exceptions try { this->ReplaceCurrentToolStorage(myDeserializer->Deserialize(filename.toStdString()), filename.toStdString()); } catch (mitk::IGTException) { std::string errormessage = "Error during loading the tool storage file. Please only load tool storage files created with the NavigationToolManager view."; QMessageBox::warning(nullptr, "Tool Storage Loading Error", errormessage.c_str()); return; } if (m_toolStorage->isEmpty()) { errorMessage = myDeserializer->GetErrorMessage(); MessageBox(errorMessage); return; } //update label UpdateToolStorageLabel(filename); //update tool preview m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); //save filename for persistent storage m_ToolStorageFilename = filename; } void QmitkMITKIGTTrackingToolboxView::OnResetTools() { this->ReplaceCurrentToolStorage(mitk::NavigationToolStorage::New(GetDataStorage()), "TrackingToolbox Default Storage"); m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); QString toolLabel = QString(""); m_Controls->m_toolLabel->setText(toolLabel); m_ToolStorageFilename = ""; } void QmitkMITKIGTTrackingToolboxView::OnStartStopTracking() { if (!m_connected) { MITK_WARN << "Can't start tracking if no device is connected. Aborting"; return; } if (m_tracking) { OnStopTracking(); } else { OnStartTracking(); } } void QmitkMITKIGTTrackingToolboxView::OnFreezeUnfreezeTracking() { if (m_Controls->m_FreezeUnfreezeTrackingButton->text() == "Freeze Tracking") { m_TrackingDeviceSource->Freeze(); m_Controls->m_FreezeUnfreezeTrackingButton->setText("Unfreeze Tracking"); m_Controls->m_TrackingFrozenLabel->setVisible(true); } else if (m_Controls->m_FreezeUnfreezeTrackingButton->text() == "Unfreeze Tracking") { m_TrackingDeviceSource->UnFreeze(); m_Controls->m_FreezeUnfreezeTrackingButton->setText("Freeze Tracking"); m_Controls->m_TrackingFrozenLabel->setVisible(false); } } void QmitkMITKIGTTrackingToolboxView::OnConnectDisconnect() { if (m_connected) { OnDisconnect(); } else { OnConnect(); } } void QmitkMITKIGTTrackingToolboxView::OnConnect() { MITK_INFO << "Connect Clicked"; //check if everything is ready to start tracking if (this->m_toolStorage.IsNull()) { MessageBox("Error: No Tools Loaded Yet!"); return; } else if (this->m_toolStorage->GetToolCount() == 0) { MessageBox("Error: No Way To Track Without Tools!"); return; } //parse tracking device data mitk::TrackingDeviceData data = mitk::UnspecifiedTrackingTypeInformation::GetDeviceDataUnspecified(); QString qstr = m_Controls->m_VolumeSelectionBox->currentText(); if ((!qstr.isNull()) || (!qstr.isEmpty())) { std::string str = qstr.toStdString(); data = m_DeviceTypeCollection->GetDeviceDataByName(str); //Data will be set later, after device generation } //! [Thread 4] //initialize worker thread m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eConnectDevice); m_Worker->SetTrackingDevice(this->m_Controls->m_configurationWidget->GetTrackingDevice()); m_Worker->SetInverseMode(m_Controls->m_InverseMode->isChecked()); m_Worker->SetNavigationToolStorage(this->m_toolStorage); m_Worker->SetTrackingDeviceData(data); //start worker thread m_WorkerThread->start(); //! [Thread 4] //disable buttons this->m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::EnableDisableTimerButtons(int enable) { bool enableBool = enable; m_Controls->m_UpdateRateOptionsGroupBox->setEnabled(!enableBool); m_Controls->m_renderWarningLabel->setVisible(enableBool); } void QmitkMITKIGTTrackingToolboxView::OnConnectFinished(bool success, QString errorMessage) { m_WorkerThread->quit(); m_WorkerThread->wait(); //enable buttons this->m_Controls->m_MainWidget->setEnabled(true); if (!success) { MITK_WARN << errorMessage.toStdString(); MessageBox(errorMessage.toStdString()); return; } //! [Thread 6] //get data from worker thread m_TrackingDeviceSource = m_Worker->GetTrackingDeviceSource(); m_TrackingDeviceData = m_Worker->GetTrackingDeviceData(); m_ToolVisualizationFilter = m_Worker->GetToolVisualizationFilter(); //! [Thread 6] //enable/disable Buttons DisableOptionsButtons(); DisableTrackingConfigurationButtons(); m_Controls->m_TrackingControlLabel->setText("Status: connected"); m_Controls->m_ConnectDisconnectButton->setText("Disconnect"); m_Controls->m_ConnectSimpleMode->setText("Disconnect"); m_Controls->m_StartStopTrackingButton->setEnabled(true); m_Controls->m_StartTrackingSimpleMode->setEnabled(true); m_connected = true; } void QmitkMITKIGTTrackingToolboxView::OnDisconnect() { m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eDisconnectDevice); m_WorkerThread->start(); m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::OnDisconnectFinished(bool success, QString errorMessage) { m_WorkerThread->quit(); m_WorkerThread->wait(); m_Controls->m_MainWidget->setEnabled(true); if (!success) { MITK_WARN << errorMessage.toStdString(); MessageBox(errorMessage.toStdString()); return; } //enable/disable Buttons m_Controls->m_StartStopTrackingButton->setEnabled(false); m_Controls->m_StartTrackingSimpleMode->setEnabled(false); EnableOptionsButtons(); EnableTrackingConfigurationButtons(); m_Controls->m_TrackingControlLabel->setText("Status: disconnected"); m_Controls->m_ConnectDisconnectButton->setText("Connect"); m_Controls->m_ConnectSimpleMode->setText("Connect"); m_Controls->m_FreezeUnfreezeTrackingButton->setText("Freeze Tracking"); m_Controls->m_TrackingFrozenLabel->setVisible(false); m_connected = false; } void QmitkMITKIGTTrackingToolboxView::OnStartTracking() { //show tracking volume this->OnTrackingVolumeChanged(m_Controls->m_VolumeSelectionBox->currentText()); //Reset the view to a defined start. Do it here and not in OnStartTrackingFinished, to give other tracking devices the chance to reset the view to a different direction. this->GlobalReinit(); m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eStartTracking); m_WorkerThread->start(); this->m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::OnStartTrackingFinished(bool success, QString errorMessage) { //! [Thread 5] m_WorkerThread->quit(); m_WorkerThread->wait(); //! [Thread 5] this->m_Controls->m_MainWidget->setEnabled(true); if (!success) { MessageBox(errorMessage.toStdString()); MITK_WARN << errorMessage.toStdString(); return; } if (!(m_Controls->m_DisableAllTimers->isChecked())) { if (m_Controls->m_UseDifferentUpdateRates->isChecked()) { if (m_Controls->m_RenderUpdateRate->value() != 0) m_TrackingRenderTimer->start(1000 / (m_Controls->m_RenderUpdateRate->value())); m_TrackingLoggingTimer->start(1000 / (m_Controls->m_LogUpdateRate->value())); } else { m_TrackingRenderTimer->start(1000 / (m_Controls->m_UpdateRate->value())); m_TrackingLoggingTimer->start(1000 / (m_Controls->m_UpdateRate->value())); } } m_Controls->m_TrackingControlLabel->setText("Status: tracking"); //connect the tool visualization widget for (std::size_t i = 0; i < m_TrackingDeviceSource->GetNumberOfOutputs(); i++) { m_Controls->m_TrackingToolsStatusWidget->AddNavigationData(m_TrackingDeviceSource->GetOutput(i)); } m_Controls->m_TrackingToolsStatusWidget->ShowStatusLabels(); if (m_Controls->m_ShowToolQuaternions->isChecked()) { m_Controls->m_TrackingToolsStatusWidget->SetShowQuaternions(true); } else { m_Controls->m_TrackingToolsStatusWidget->SetShowQuaternions(false); } //if activated enable open IGT link microservice if (m_Controls->m_EnableOpenIGTLinkMicroService->isChecked()) { //create convertion filter m_IGTLConversionFilter = mitk::NavigationDataToIGTLMessageFilter::New(); m_IGTLConversionFilter->SetName("IGT Tracking Toolbox"); + QString dataModeSelection = this->m_Controls->m_OpenIGTLinkDataFormat->currentText(); + if (dataModeSelection == "TDATA") + {m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendTDataMsg);} + else if (dataModeSelection == "TRANSFORM") + {m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendTransMsg);} + else if (dataModeSelection == "QTDATA") + {m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendQTDataMsg);} + else if (dataModeSelection == "POSITION") + {m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendQTransMsg);} m_IGTLConversionFilter->ConnectTo(m_ToolVisualizationFilter); - m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendTDataMsg); m_IGTLConversionFilter->RegisterAsMicroservice(); + //create server and message provider m_IGTLServer = mitk::IGTLServer::New(false); m_IGTLServer->SetName("Tracking Toolbox IGTL Server"); m_IGTLMessageProvider = mitk::IGTLMessageProvider::New(); m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer); m_IGTLMessageProvider->RegisterAsMicroservice(); } m_tracking = true; m_Controls->m_ConnectDisconnectButton->setEnabled(false); m_Controls->m_StartStopTrackingButton->setText("Stop Tracking"); m_Controls->m_StartTrackingSimpleMode->setText("Stop\nTracking"); m_Controls->m_FreezeUnfreezeTrackingButton->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::OnStopTracking() { if (!m_tracking) return; m_TrackingRenderTimer->stop(); m_TrackingLoggingTimer->stop(); m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eStopTracking); m_WorkerThread->start(); m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::OnStopTrackingFinished(bool success, QString errorMessage) { m_WorkerThread->quit(); m_WorkerThread->wait(); m_Controls->m_MainWidget->setEnabled(true); if (!success) { MessageBox(errorMessage.toStdString()); MITK_WARN << errorMessage.toStdString(); return; } m_Controls->m_TrackingControlLabel->setText("Status: connected"); if (m_logging) StopLogging(); m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); m_tracking = false; m_Controls->m_StartStopTrackingButton->setText("Start Tracking"); m_Controls->m_StartTrackingSimpleMode->setText("Start\nTracking"); m_Controls->m_ConnectDisconnectButton->setEnabled(true); m_Controls->m_FreezeUnfreezeTrackingButton->setEnabled(false); //unregister open IGT link micro service if (m_Controls->m_EnableOpenIGTLinkMicroService->isChecked()) { m_IGTLConversionFilter->UnRegisterMicroservice(); m_IGTLMessageProvider->UnRegisterMicroservice(); } } void QmitkMITKIGTTrackingToolboxView::OnTrackingDeviceChanged() { mitk::TrackingDeviceType Type; if (m_Controls->m_configurationWidget->GetTrackingDevice().IsNotNull()) { Type = m_Controls->m_configurationWidget->GetTrackingDevice()->GetType(); //enable controls because device is valid m_Controls->m_TrackingToolsGoupBox->setEnabled(true); m_Controls->m_TrackingControlsGroupBox->setEnabled(true); } else { Type = mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); MessageBox("Error: This tracking device is not included in this project. Please make sure that the device is installed and activated in your MITK build."); m_Controls->m_TrackingToolsGoupBox->setEnabled(false); m_Controls->m_TrackingControlsGroupBox->setEnabled(false); return; } // Code to enable/disable device specific buttons if (m_Controls->m_configurationWidget->GetTrackingDevice()->AutoDetectToolsAvailable()) { m_Controls->m_AutoDetectTools->setVisible(true); } else { m_Controls->m_AutoDetectTools->setVisible(false); } if (Type == mitk::NDIAuroraTypeInformation::GetTrackingDeviceName()) //Aurora { m_Controls->m_AddSingleTool->setEnabled(false);} else //other trackers { m_Controls->m_AddSingleTool->setEnabled(true); } // Code to select appropriate tracking volume for current type std::vector Compatibles = m_DeviceTypeCollection->GetDeviceDataForLine(Type); m_Controls->m_VolumeSelectionBox->clear(); for (std::size_t i = 0; i < Compatibles.size(); i++) { m_Controls->m_VolumeSelectionBox->addItem(Compatibles[i].Model.c_str()); } } void QmitkMITKIGTTrackingToolboxView::OnTrackingVolumeChanged(QString qstr) { if (qstr.isNull()) return; if (qstr.isEmpty()) return; mitk::TrackingVolumeGenerator::Pointer volumeGenerator = mitk::TrackingVolumeGenerator::New(); std::string str = qstr.toStdString(); mitk::TrackingDeviceData data = m_DeviceTypeCollection->GetDeviceDataByName(str); m_TrackingDeviceData = data; volumeGenerator->SetTrackingDeviceData(data); volumeGenerator->Update(); mitk::Surface::Pointer volumeSurface = volumeGenerator->GetOutput(); m_TrackingVolumeNode->SetData(volumeSurface); if (!m_Controls->m_ShowTrackingVolume->isChecked()) m_TrackingVolumeNode->SetOpacity(0.0); else m_TrackingVolumeNode->SetOpacity(0.25); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnShowTrackingVolumeChanged() { if (m_Controls->m_ShowTrackingVolume->isChecked()) { OnTrackingVolumeChanged(m_Controls->m_VolumeSelectionBox->currentText()); m_TrackingVolumeNode->SetOpacity(0.25); } else { m_TrackingVolumeNode->SetOpacity(0.0); } } void QmitkMITKIGTTrackingToolboxView::OnAutoDetectTools() { if (m_Controls->m_configurationWidget->GetTrackingDevice()->AutoDetectToolsAvailable()) { DisableTrackingConfigurationButtons(); m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eAutoDetectTools); m_Worker->SetTrackingDevice(m_Controls->m_configurationWidget->GetTrackingDevice().GetPointer()); m_Worker->SetDataStorage(this->GetDataStorage()); m_WorkerThread->start(); m_TimeoutTimer->start(5000); //disable controls until worker thread is finished this->m_Controls->m_MainWidget->setEnabled(false); } } void QmitkMITKIGTTrackingToolboxView::OnAutoDetectToolsFinished(bool success, QString errorMessage) { m_TimeoutTimer->stop(); m_WorkerThread->quit(); m_WorkerThread->wait(); //enable controls again this->m_Controls->m_MainWidget->setEnabled(true); EnableTrackingConfigurationButtons(); if (!success) { MITK_WARN << errorMessage.toStdString(); MessageBox(errorMessage.toStdString()); EnableTrackingConfigurationButtons(); return; } mitk::NavigationToolStorage::Pointer autoDetectedStorage = m_Worker->GetNavigationToolStorage(); //save detected tools this->ReplaceCurrentToolStorage(autoDetectedStorage, "Autodetected NDI Aurora Storage"); //auto save the new storage to hard disc (for persistence) AutoSaveToolStorage(); //update label QString toolLabel = QString("Loaded Tools: ") + QString::number(m_toolStorage->GetToolCount()) + " Tools (Auto Detected)"; m_Controls->m_toolLabel->setText(toolLabel); //update tool preview m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); EnableTrackingConfigurationButtons(); //print a logging message about the detected tools switch (m_toolStorage->GetToolCount()) { case 0: MITK_INFO("IGT Tracking Toolbox") << "Found no tools. Empty ToolStorage was autosaved to " << m_ToolStorageFilename.toStdString(); break; case 1: MITK_INFO("IGT Tracking Toolbox") << "Found one tool. ToolStorage was autosaved to " << m_ToolStorageFilename.toStdString(); break; default: MITK_INFO("IGT Tracking Toolbox") << "Found " << m_toolStorage->GetToolCount() << " tools. ToolStorage was autosaved to " << m_ToolStorageFilename.toStdString(); } } void QmitkMITKIGTTrackingToolboxView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkMITKIGTTrackingToolboxView::UpdateRenderTrackingTimer() { //update filter m_ToolVisualizationFilter->Update(); MITK_DEBUG << "Number of outputs ToolVisualizationFilter: " << m_ToolVisualizationFilter->GetNumberOfIndexedOutputs(); MITK_DEBUG << "Number of inputs ToolVisualizationFilter: " << m_ToolVisualizationFilter->GetNumberOfIndexedInputs(); //update tool colors to show tool status for (unsigned int i = 0; i < m_ToolVisualizationFilter->GetNumberOfIndexedOutputs(); i++) { mitk::NavigationData::Pointer currentTool = m_ToolVisualizationFilter->GetOutput(i); if (currentTool->IsDataValid()) { this->m_toolStorage->GetTool(i)->GetDataNode()->SetColor(mitk::IGTColor_VALID); } else { this->m_toolStorage->GetTool(i)->GetDataNode()->SetColor(mitk::IGTColor_WARNING); } } //refresh view and status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_Controls->m_TrackingToolsStatusWidget->Refresh(); - - //code to better isolate bug 17713, could be removed when bug 17713 is fixed - static int i = 0; - static mitk::Point3D lastPositionTool1 = m_ToolVisualizationFilter->GetOutput(0)->GetPosition(); - static itk::TimeStamp lastTimeStamp = m_ToolVisualizationFilter->GetOutput(0)->GetTimeStamp(); - i++; - //every 20 frames: check if tracking is frozen - if (i > 20) - { - i = 0; - if (m_ToolVisualizationFilter->GetOutput(0)->IsDataValid()) - { - if (mitk::Equal(lastPositionTool1, m_ToolVisualizationFilter->GetOutput(0)->GetPosition(), 0.000000001, false) - && m_Controls->m_configurationWidget->GetTrackingDevice()->GetType() != "Da Vinci") - { - MITK_WARN << "Seems as tracking (of at least tool 1) is frozen which means that bug 17713 occurred. Restart tracking might help."; - //display further information to find the bug - MITK_WARN << "Timestamp of current navigation data: " << m_ToolVisualizationFilter->GetOutput(0)->GetTimeStamp(); - MITK_WARN << "Timestamp of last navigation data (which holds the same values): " << lastTimeStamp; - } - lastPositionTool1 = m_ToolVisualizationFilter->GetOutput(0)->GetPosition(); - lastTimeStamp = m_ToolVisualizationFilter->GetOutput(0)->GetTimeStamp(); - } - } } void QmitkMITKIGTTrackingToolboxView::UpdateLoggingTrackingTimer() { //update logging if (m_logging) { this->m_loggingFilter->Update(); m_loggedFrames = this->m_loggingFilter->GetNumberOfRecordedSteps(); this->m_Controls->m_LoggedFramesLabel->setText("Logged Frames: " + QString::number(m_loggedFrames)); //check if logging stopped automatically if ((m_loggedFrames > 1) && (!m_loggingFilter->GetRecording())){ StopLogging(); } } //refresh status widget m_Controls->m_TrackingToolsStatusWidget->Refresh(); } void QmitkMITKIGTTrackingToolboxView::OnChooseFileClicked() { QDir currentPath = QFileInfo(m_Controls->m_LoggingFileName->text()).dir(); // if no path was selected (QDir would select current working dir then) or the // selected path does not exist -> use home directory if (currentPath == QDir() || !currentPath.exists()) { currentPath = QDir(QDir::homePath()); } QString filename = QFileDialog::getSaveFileName(nullptr, tr("Choose Logging File"), currentPath.absolutePath(), "*.*"); if (filename == "") return; this->m_Controls->m_LoggingFileName->setText(filename); this->OnToggleFileExtension(); } // bug-16470: toggle file extension after clicking on radio button void QmitkMITKIGTTrackingToolboxView::OnToggleFileExtension() { QString currentInputText = this->m_Controls->m_LoggingFileName->text(); QString currentFile = QFileInfo(currentInputText).baseName(); QDir currentPath = QFileInfo(currentInputText).dir(); if (currentFile.isEmpty()) { currentFile = "logfile"; } // Setting currentPath to default home path when currentPath is empty or it does not exist if (currentPath == QDir() || !currentPath.exists()) { currentPath = QDir::homePath(); } // check if csv radio button is clicked if (this->m_Controls->m_csvFormat->isChecked()) { // you needn't add a seperator to the input text when currentpath is the rootpath if (currentPath.isRoot()) { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + currentFile + ".csv"); } else { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + QDir::separator() + currentFile + ".csv"); } } // check if xml radio button is clicked else if (this->m_Controls->m_xmlFormat->isChecked()) { // you needn't add a seperator to the input text when currentpath is the rootpath if (currentPath.isRoot()) { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + currentFile + ".xml"); } else { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + QDir::separator() + currentFile + ".xml"); } } } void QmitkMITKIGTTrackingToolboxView::OnToggleAdvancedSimpleMode() { if (m_SimpleModeEnabled) { m_Controls->m_simpleWidget->setVisible(false); m_Controls->m_MainWidget->setVisible(true); m_Controls->m_simpleUI->setChecked(false); m_SimpleModeEnabled = false; } else { m_Controls->m_simpleWidget->setVisible(true); m_Controls->m_MainWidget->setVisible(false); m_SimpleModeEnabled = true; } } void QmitkMITKIGTTrackingToolboxView::OnToggleDifferentUpdateRates() { if (m_Controls->m_UseDifferentUpdateRates->isChecked()) { if (m_Controls->m_RenderUpdateRate->value() == 0) m_Controls->m_renderWarningLabel->setVisible(true); else m_Controls->m_renderWarningLabel->setVisible(false); m_Controls->m_UpdateRate->setEnabled(false); m_Controls->m_OptionsUpdateRateLabel->setEnabled(false); m_Controls->m_RenderUpdateRate->setEnabled(true); m_Controls->m_OptionsRenderUpdateRateLabel->setEnabled(true); m_Controls->m_LogUpdateRate->setEnabled(true); m_Controls->m_OptionsLogUpdateRateLabel->setEnabled(true); } else { m_Controls->m_renderWarningLabel->setVisible(false); m_Controls->m_UpdateRate->setEnabled(true); m_Controls->m_OptionsUpdateRateLabel->setEnabled(true); m_Controls->m_RenderUpdateRate->setEnabled(false); m_Controls->m_OptionsRenderUpdateRateLabel->setEnabled(false); m_Controls->m_LogUpdateRate->setEnabled(false); m_Controls->m_OptionsLogUpdateRateLabel->setEnabled(false); } } void QmitkMITKIGTTrackingToolboxView::OnChangeRenderUpdateRate() { if (m_Controls->m_RenderUpdateRate->value() == 0) m_Controls->m_renderWarningLabel->setVisible(true); else m_Controls->m_renderWarningLabel->setVisible(false); } void QmitkMITKIGTTrackingToolboxView::StartLogging() { if (m_ToolVisualizationFilter.IsNull()) { MessageBox("Cannot activate logging without a connected device. Configure and connect a tracking device first."); return; } if (!m_logging) { //initialize logging filter m_loggingFilter = mitk::NavigationDataRecorder::New(); + m_loggingFilter->SetRecordOnlyValidData(m_Controls->m_SkipInvalidData->isChecked()); m_loggingFilter->ConnectTo(m_ToolVisualizationFilter); if (m_Controls->m_LoggingLimit->isChecked()){ m_loggingFilter->SetRecordCountLimit(m_Controls->m_LoggedFramesLimit->value()); } //start filter with try-catch block for exceptions try { m_loggingFilter->StartRecording(); } catch (mitk::IGTException) { std::string errormessage = "Error during start recording. Recorder already started recording?"; QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str()); m_loggingFilter->StopRecording(); return; } //update labels / logging variables this->m_Controls->m_LoggingLabel->setText("Logging ON"); this->m_Controls->m_LoggedFramesLabel->setText("Logged Frames: 0"); m_loggedFrames = 0; m_logging = true; DisableLoggingButtons(); } } void QmitkMITKIGTTrackingToolboxView::StopLogging() { if (m_logging) { //stop logging m_loggingFilter->StopRecording(); m_logging = false; //update GUI this->m_Controls->m_LoggingLabel->setText("Logging OFF"); EnableLoggingButtons(); //write the results to a file if (m_Controls->m_csvFormat->isChecked() || m_Controls->m_xmlFormat->isChecked()) mitk::IOUtil::Save(m_loggingFilter->GetNavigationDataSet(), this->m_Controls->m_LoggingFileName->text().toStdString()); } } void QmitkMITKIGTTrackingToolboxView::OnAddSingleTool() { QString Identifier = "Tool#"; QString Name = "NewTool"; if (m_toolStorage.IsNotNull()) { Identifier += QString::number(m_toolStorage->GetToolCount()); Name += QString::number(m_toolStorage->GetToolCount()); } else { Identifier += "0"; Name += "0"; } m_Controls->m_NavigationToolCreationWidget->Initialize(GetDataStorage(), Identifier.toStdString(), Name.toStdString()); m_Controls->m_NavigationToolCreationWidget->SetTrackingDeviceType(m_Controls->m_configurationWidget->GetTrackingDevice()->GetType(), false); m_Controls->m_TrackingToolsWidget->setCurrentIndex(1); //disable tracking volume during tool editing lastTrackingVolumeState = m_Controls->m_ShowTrackingVolume->isChecked(); if (lastTrackingVolumeState) m_Controls->m_ShowTrackingVolume->click(); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnAddSingleToolFinished() { m_Controls->m_TrackingToolsWidget->setCurrentIndex(0); if (this->m_toolStorage.IsNull()) { //this shouldn't happen! MITK_WARN << "No ToolStorage available, cannot add tool, aborting!"; return; } m_toolStorage->AddTool(m_Controls->m_NavigationToolCreationWidget->GetCreatedTool()); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); m_Controls->m_toolLabel->setText(""); //auto save current storage for persistence MITK_INFO << "Auto saving manually added tools for persistence."; AutoSaveToolStorage(); //enable tracking volume again if (lastTrackingVolumeState) m_Controls->m_ShowTrackingVolume->click(); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnAddSingleToolCanceled() { m_Controls->m_TrackingToolsWidget->setCurrentIndex(0); //enable tracking volume again if (lastTrackingVolumeState) m_Controls->m_ShowTrackingVolume->click(); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::GlobalReinit() { // get all nodes that have not set "includeInBoundingBox" to false mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetSubset(pred); // calculate bounding geometry of these nodes mitk::TimeGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs, "visible"); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeViews(bounds); } void QmitkMITKIGTTrackingToolboxView::DisableLoggingButtons() { m_Controls->m_StartLogging->setEnabled(false); m_Controls->m_LoggingFileName->setEnabled(false); m_Controls->m_ChooseFile->setEnabled(false); m_Controls->m_LoggingLimit->setEnabled(false); m_Controls->m_LoggedFramesLimit->setEnabled(false); m_Controls->m_csvFormat->setEnabled(false); m_Controls->m_xmlFormat->setEnabled(false); + m_Controls->m_SkipInvalidData->setEnabled(false); m_Controls->m_StopLogging->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::EnableLoggingButtons() { m_Controls->m_StartLogging->setEnabled(true); m_Controls->m_LoggingFileName->setEnabled(true); m_Controls->m_ChooseFile->setEnabled(true); m_Controls->m_LoggingLimit->setEnabled(true); m_Controls->m_LoggedFramesLimit->setEnabled(true); m_Controls->m_csvFormat->setEnabled(true); m_Controls->m_xmlFormat->setEnabled(true); + m_Controls->m_SkipInvalidData->setEnabled(true); m_Controls->m_StopLogging->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::DisableOptionsButtons() { m_Controls->m_ShowTrackingVolume->setEnabled(false); m_Controls->m_UseDifferentUpdateRates->setEnabled(false); m_Controls->m_UpdateRate->setEnabled(false); m_Controls->m_OptionsUpdateRateLabel->setEnabled(false); m_Controls->m_RenderUpdateRate->setEnabled(false); m_Controls->m_OptionsRenderUpdateRateLabel->setEnabled(false); m_Controls->m_LogUpdateRate->setEnabled(false); m_Controls->m_OptionsLogUpdateRateLabel->setEnabled(false); m_Controls->m_DisableAllTimers->setEnabled(false); m_Controls->m_OtherOptionsGroupBox->setEnabled(false); + m_Controls->m_EnableOpenIGTLinkMicroService->setEnabled(false); + m_Controls->m_OpenIGTLinkDataFormat->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::EnableOptionsButtons() { m_Controls->m_ShowTrackingVolume->setEnabled(true); m_Controls->m_UseDifferentUpdateRates->setEnabled(true); m_Controls->m_DisableAllTimers->setEnabled(true); m_Controls->m_OtherOptionsGroupBox->setEnabled(true); + m_Controls->m_EnableOpenIGTLinkMicroService->setEnabled(true); + m_Controls->m_OpenIGTLinkDataFormat->setEnabled(true); OnToggleDifferentUpdateRates(); } void QmitkMITKIGTTrackingToolboxView::EnableTrackingControls() { m_Controls->m_TrackingControlsGroupBox->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::DisableTrackingControls() { m_Controls->m_TrackingControlsGroupBox->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::EnableTrackingConfigurationButtons() { m_Controls->m_AutoDetectTools->setEnabled(true); if (m_Controls->m_configurationWidget->GetTrackingDevice()->GetType() != mitk::NDIAuroraTypeInformation::GetTrackingDeviceName()) m_Controls->m_AddSingleTool->setEnabled(true); m_Controls->m_LoadTools->setEnabled(true); m_Controls->m_ResetTools->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::DisableTrackingConfigurationButtons() { m_Controls->m_AutoDetectTools->setEnabled(false); if (m_Controls->m_configurationWidget->GetTrackingDevice()->GetType() != mitk::NDIAuroraTypeInformation::GetTrackingDeviceName()) m_Controls->m_AddSingleTool->setEnabled(false); m_Controls->m_LoadTools->setEnabled(false); m_Controls->m_ResetTools->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::ReplaceCurrentToolStorage(mitk::NavigationToolStorage::Pointer newStorage, std::string newStorageName) { //first: get rid of the old one //don't reset if there is no tool storage. BugFix #17793 if (m_toolStorage.IsNotNull()){ m_toolStorage->UnLockStorage(); //only to be sure... m_toolStorage->UnRegisterMicroservice(); m_toolStorage = nullptr; } //now: replace by the new one m_toolStorage = newStorage; m_toolStorage->SetName(newStorageName); m_toolStorage->RegisterAsMicroservice("no tracking device"); } void QmitkMITKIGTTrackingToolboxView::OnTimeOut() { m_WorkerThread->terminate(); m_WorkerThread->wait(); m_TimeoutTimer->stop(); } //! [StoreUISettings] void QmitkMITKIGTTrackingToolboxView::StoreUISettings() { // persistence service does not directly work in plugins for now // -> using QSettings QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); MITK_INFO << "Store UI settings"; // set the values of some widgets and attrbutes to the QSettings settings.setValue("ShowTrackingVolume", QVariant(m_Controls->m_ShowTrackingVolume->isChecked())); settings.setValue("toolStorageFilename", QVariant(m_ToolStorageFilename)); settings.setValue("VolumeSelectionBox", QVariant(m_Controls->m_VolumeSelectionBox->currentIndex())); settings.setValue("SimpleModeEnabled", QVariant(m_SimpleModeEnabled)); settings.endGroup(); } //! [StoreUISettings] //! [LoadUISettings] void QmitkMITKIGTTrackingToolboxView::LoadUISettings() { // persistence service does not directly work in plugins for now // -> using QSettings QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); // set some widgets and attributes by the values from the QSettings m_Controls->m_ShowTrackingVolume->setChecked(settings.value("ShowTrackingVolume", true).toBool()); m_Controls->m_VolumeSelectionBox->setCurrentIndex(settings.value("VolumeSelectionBox", 0).toInt()); m_ToolStorageFilename = settings.value("toolStorageFilename", QVariant("")).toString(); if (settings.value("SimpleModeEnabled", false).toBool()) { this->OnToggleAdvancedSimpleMode(); } settings.endGroup(); //! [LoadUISettings] //! [LoadToolStorage] // try to deserialize the tool storage from the given tool storage file name if (!m_ToolStorageFilename.isEmpty()) { // try-catch block for exceptions try { mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(GetDataStorage()); m_toolStorage->UnRegisterMicroservice(); m_toolStorage = myDeserializer->Deserialize(m_ToolStorageFilename.toStdString()); m_toolStorage->RegisterAsMicroservice("no tracking device"); //update label UpdateToolStorageLabel(m_ToolStorageFilename); //update tool preview m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); } catch (mitk::IGTException) { MITK_WARN("QmitkMITKIGTTrackingToolBoxView") << "Error during restoring tools. Problems with file (" << m_ToolStorageFilename.toStdString() << "), please check the file?"; this->OnResetTools(); //if there where errors reset the tool storage to avoid problems later on } } //! [LoadToolStorage] } void QmitkMITKIGTTrackingToolboxView::UpdateToolStorageLabel(QString pathOfLoadedStorage) { QFileInfo myPath(pathOfLoadedStorage); //use this to seperate filename from path QString toolLabel = myPath.fileName(); if (toolLabel.size() > 45) //if the tool storage name is to long trimm the string { toolLabel.resize(40); toolLabel += "[...]"; } m_Controls->m_toolLabel->setText(toolLabel); } void QmitkMITKIGTTrackingToolboxView::AutoSaveToolStorage() { m_ToolStorageFilename = m_AutoSaveFilename; mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); mySerializer->Serialize(m_ToolStorageFilename.toStdString(), m_toolStorage); } void QmitkMITKIGTTrackingToolboxViewWorker::SetWorkerMethod(WorkerMethod w) { m_WorkerMethod = w; } void QmitkMITKIGTTrackingToolboxViewWorker::SetTrackingDevice(mitk::TrackingDevice::Pointer t) { m_TrackingDevice = t; } void QmitkMITKIGTTrackingToolboxViewWorker::SetDataStorage(mitk::DataStorage::Pointer d) { m_DataStorage = d; } void QmitkMITKIGTTrackingToolboxViewWorker::SetInverseMode(bool mode) { m_InverseMode = mode; } void QmitkMITKIGTTrackingToolboxViewWorker::SetTrackingDeviceData(mitk::TrackingDeviceData d) { m_TrackingDeviceData = d; } void QmitkMITKIGTTrackingToolboxViewWorker::SetNavigationToolStorage(mitk::NavigationToolStorage::Pointer n) { m_NavigationToolStorage = n; } //! [Thread 7] void QmitkMITKIGTTrackingToolboxViewWorker::ThreadFunc() { switch (m_WorkerMethod) { case eAutoDetectTools: this->AutoDetectTools(); break; case eConnectDevice: this->ConnectDevice(); break; case eStartTracking: this->StartTracking(); break; case eStopTracking: this->StopTracking(); break; case eDisconnectDevice: this->DisconnectDevice(); break; default: MITK_WARN << "Undefined worker method was set ... something went wrong!"; break; } } //! [Thread 7] void QmitkMITKIGTTrackingToolboxViewWorker::AutoDetectTools() { //mitk::ProgressBar::GetInstance()->AddStepsToDo(2); mitk::NavigationToolStorage::Pointer autoDetectedStorage = mitk::NavigationToolStorage::New(m_DataStorage); try { mitk::NavigationToolStorage::Pointer tempStorage = m_TrackingDevice->AutoDetectTools(); //mitk::ProgressBar::GetInstance()->Progress(); for (int i = 0; i < tempStorage->GetToolCount(); i++) { autoDetectedStorage->AddTool(tempStorage->GetTool(i)); } } catch (mitk::Exception& e) { MITK_WARN << e.GetDescription(); //mitk::ProgressBar::GetInstance()->Reset(); emit AutoDetectToolsFinished(false, e.GetDescription()); return; } m_NavigationToolStorage = autoDetectedStorage; //::ProgressBar::GetInstance()->Progress(); emit AutoDetectToolsFinished(true, ""); } void QmitkMITKIGTTrackingToolboxViewWorker::ConnectDevice() { std::string message = ""; //mitk::ProgressBar::GetInstance()->AddStepsToDo(4); //build the IGT pipeline mitk::TrackingDevice::Pointer trackingDevice = m_TrackingDevice; trackingDevice->SetData(m_TrackingDeviceData); //set device to rotation mode transposed becaus we are working with VNL style quaternions if (m_InverseMode) { trackingDevice->SetRotationMode(mitk::TrackingDevice::RotationTransposed); } //Get Tracking Volume Data mitk::TrackingDeviceData data = m_TrackingDeviceData; //mitk::ProgressBar::GetInstance()->Progress(); //Create Navigation Data Source with the factory class mitk::TrackingDeviceSourceConfigurator::Pointer myTrackingDeviceSourceFactory = mitk::TrackingDeviceSourceConfigurator::New(m_NavigationToolStorage, trackingDevice); m_TrackingDeviceSource = myTrackingDeviceSourceFactory->CreateTrackingDeviceSource(m_ToolVisualizationFilter); //mitk::ProgressBar::GetInstance()->Progress(); if (m_TrackingDeviceSource.IsNull()) { message = std::string("Cannot connect to device: ") + myTrackingDeviceSourceFactory->GetErrorMessage(); emit ConnectDeviceFinished(false, QString(message.c_str())); return; } //set filter to rotation mode transposed becaus we are working with VNL style quaternions if (m_InverseMode) m_ToolVisualizationFilter->SetRotationMode(mitk::NavigationDataObjectVisualizationFilter::RotationTransposed); //First check if the created object is valid if (m_TrackingDeviceSource.IsNull()) { message = myTrackingDeviceSourceFactory->GetErrorMessage(); emit ConnectDeviceFinished(false, QString(message.c_str())); return; } MITK_INFO << "Number of tools: " << m_TrackingDeviceSource->GetNumberOfOutputs(); //mitk::ProgressBar::GetInstance()->Progress(); //The tools are maybe reordered after initialization, e.g. in case of auto-detected tools of NDI Aurora mitk::NavigationToolStorage::Pointer toolsInNewOrder = myTrackingDeviceSourceFactory->GetUpdatedNavigationToolStorage(); if ((toolsInNewOrder.IsNotNull()) && (toolsInNewOrder->GetToolCount() > 0)) { //so delete the old tools in wrong order and add them in the right order //we cannot simply replace the tool storage because the new storage is //not correctly initialized with the right data storage /* m_NavigationToolStorage->DeleteAllTools(); for (int i=0; i < toolsInNewOrder->GetToolCount(); i++) {m_NavigationToolStorage->AddTool(toolsInNewOrder->GetTool(i));} This was replaced and thereby fixed Bug 18318 DeleteAllTools() is not Threadsafe! */ for (int i = 0; i < toolsInNewOrder->GetToolCount(); i++) { m_NavigationToolStorage->AssignToolNumber(toolsInNewOrder->GetTool(i)->GetIdentifier(), i); } } //mitk::ProgressBar::GetInstance()->Progress(); //connect to device try { m_TrackingDeviceSource->Connect(); //mitk::ProgressBar::GetInstance()->Reset(); //Microservice registration: m_TrackingDeviceSource->RegisterAsMicroservice(); m_NavigationToolStorage->UnRegisterMicroservice(); m_NavigationToolStorage->RegisterAsMicroservice(m_TrackingDeviceSource->GetMicroserviceID()); m_NavigationToolStorage->LockStorage(); } catch (...) //todo: change to mitk::IGTException { message = "Error on connecting the tracking device."; emit ConnectDeviceFinished(false, QString(message.c_str())); return; } emit ConnectDeviceFinished(true, QString(message.c_str())); //mitk::ProgressBar::GetInstance()->Reset(); } void QmitkMITKIGTTrackingToolboxViewWorker::StartTracking() { QString errorMessage = ""; try { m_TrackingDeviceSource->StartTracking(); } catch (...) //todo: change to mitk::IGTException { errorMessage += "Error while starting the tracking device!"; emit StartTrackingFinished(false, errorMessage); return; } //remember the original colors of the tools m_OriginalColors = std::map(); for (int i = 0; i < this->m_NavigationToolStorage->GetToolCount(); i++) { mitk::DataNode::Pointer currentToolNode = m_NavigationToolStorage->GetTool(i)->GetDataNode(); float c[3]; currentToolNode->GetColor(c); mitk::Color color; color.SetRed(c[0]); color.SetGreen(c[1]); color.SetBlue(c[2]); m_OriginalColors[currentToolNode] = color; } emit StartTrackingFinished(true, errorMessage); } void QmitkMITKIGTTrackingToolboxViewWorker::StopTracking() { //stop tracking try { m_TrackingDeviceSource->StopTracking(); } catch (mitk::Exception& e) { emit StopTrackingFinished(false, e.GetDescription()); } //restore the original colors of the tools for (int i = 0; i < this->m_NavigationToolStorage->GetToolCount(); i++) { mitk::DataNode::Pointer currentToolNode = m_NavigationToolStorage->GetTool(i)->GetDataNode(); if (m_OriginalColors.find(currentToolNode) == m_OriginalColors.end()) { MITK_WARN << "Cannot restore original color of tool " << m_NavigationToolStorage->GetTool(i)->GetToolName(); } else { currentToolNode->SetColor(m_OriginalColors[currentToolNode]); } } //emit signal emit StopTrackingFinished(true, ""); } void QmitkMITKIGTTrackingToolboxViewWorker::DisconnectDevice() { try { if (m_TrackingDeviceSource->IsTracking()) { m_TrackingDeviceSource->StopTracking(); } m_TrackingDeviceSource->Disconnect(); m_TrackingDeviceSource->UnRegisterMicroservice(); m_NavigationToolStorage->UnLockStorage(); } catch (mitk::Exception& e) { emit DisconnectDeviceFinished(false, e.GetDescription()); } emit DisconnectDeviceFinished(true, ""); } diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui index 80774c501b..46a7777220 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui @@ -1,889 +1,936 @@ QmitkMITKIGTTrackingToolboxViewControls 0 0 370 - 747 + 723 0 0 QmitkTemplate 0 Tracking 0 0 0 0 16777215 280 0 0 6 75 true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Tracking Tools</span></p></body></html> 0 0 ToolStorage: <none> Qt::Horizontal 40 20 200 80 Qt::Horizontal 13 49 120 0 Auto Detection 120 0 Add Single Tool 120 0 Load Tool Storage 120 0 Reset <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Tracking Control</span></p></body></html> Status: disconnected Qt::Horizontal 40 20 142 0 Connect Qt::Horizontal 40 20 142 0 Start Tracking Qt::Horizontal 40 20 <html><head/><body><p><span style=" color:#ff0000;">Tracking Frozen!</span></p></body></html> true 142 0 Freeze Tracking Qt::Vertical 20 40 Options Disable All Timers true <html><head/><body><p align="right"><span style=" color:#ff0000;">Rendering Disabled!</span></p></body></html> Qt::AutoText Update Rate Options Update Rate [per second] Qt::Horizontal 40 20 100 10 Use different Render and Log Update Rates false Render Update Rate [fps] Qt::Horizontal 40 20 false 0 100 10 false Log Update Rate [per second] Qt::Horizontal 40 20 false 1 120 10 60 Tracking Volume Options true Show Tracking Volume true Select Model: - + - Other Options + Open IGT Link - + - + - Show Tool Quaternions + Enable Open IGT Link MicroService + + + true - + - Enable Open IGT Link MicroService + Select Open IGT Link Data Format: - - true + + + + + + + TRANSFORM + + + + + QTDATA + + + + + TDATA + + + + + POSITION + + + + + + + + + + + Other Options + + + + + + Show Tool Quaternions Simple UI Caution, only for backward compatibility: Inverse mode (Quaternions are stored inverse) Qt::Vertical 20 600 Logging Filename: Choose File Limit Number Of Logged Frames: Qt::Horizontal 40 20 1 9999 300 CSV format true XML format + + + + Skip invalid data + + + Logging Status Logging OFF Logged Frames: 0 Qt::Horizontal 40 20 Start Logging Stop Logging Qt::Vertical 20 40 70 50 Connect 70 50 Start Tracking Qt::Horizontal 40 20 70 50 Advanced Mode Qt::Vertical 20 40 QmitkTrackingDeviceConfigurationWidget QWidget
QmitkTrackingDeviceConfigurationWidget.h
1
QmitkToolTrackingStatusWidget QWidget
QmitkToolTrackingStatusWidget.h
1
QmitkNavigationToolCreationWidget QWidget
QmitkNavigationToolCreationWidget.h
1
diff --git a/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManager.cpp b/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManager.cpp index 72397c9036..29dc0c5b06 100644 --- a/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManager.cpp +++ b/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManager.cpp @@ -1,84 +1,100 @@ /*=================================================================== 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. ===================================================================*/ // Blueberry #include #include // #include "OpenIGTLinkManager.h" const std::string OpenIGTLinkManager::VIEW_ID = "org.mitk.views.openigtlinkmanager"; OpenIGTLinkManager::OpenIGTLinkManager() : QmitkAbstractView() { } OpenIGTLinkManager::~OpenIGTLinkManager() { for(unsigned int i=0; i < m_AllSourcesHandledByThisWidget.size(); i++) m_AllSourcesHandledByThisWidget.at(i)->UnRegisterMicroservice(); } void OpenIGTLinkManager::SetFocus() { } void OpenIGTLinkManager::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); // create GUI widgets from the Qt Designer's .ui file // connect( (QObject*)(m_Controls.m_SourceManagerWidget), // SIGNAL(NewSourceAdded(mitk::IGTLDeviceSource::Pointer, std::string)), // this, // SLOT(NewSourceByWidget(mitk::IGTLDeviceSource::Pointer,std::string)) ); connect( (QObject*)(m_Controls.m_SourceListWidget), SIGNAL(IGTLDeviceSourceSelected(mitk::IGTLDeviceSource::Pointer)), this, SLOT(SourceSelected(mitk::IGTLDeviceSource::Pointer)) ); + connect(m_Controls.checkBoxLogMessages, SIGNAL(clicked()), this, SLOT(LogMessagesClicked())); + + logMessages = m_Controls.checkBoxLogMessages->isChecked(); } void OpenIGTLinkManager::NewSourceByWidget( mitk::IGTLDeviceSource::Pointer source,std::string /*sourceName*/) { source->RegisterAsMicroservice(/*sourceName*/); m_AllSourcesHandledByThisWidget.push_back(source); } +void OpenIGTLinkManager::LogMessagesClicked() +{ + logMessages = m_Controls.checkBoxLogMessages->isChecked(); + if(m_CurrentIGTLDevice.IsNotNull()) + m_CurrentIGTLDevice->SetLogMessages(logMessages); + else + MITK_WARN << "Logging information not passed down to Message Provider."; +} + void OpenIGTLinkManager::SourceSelected( mitk::IGTLDeviceSource::Pointer source) { if (source.IsNull()) //no source selected { //reset everything return; } + m_CurrentIGTLDevice = source->GetIGTLDevice(); + m_CurrentIGTLDevice->SetLogMessages(logMessages); this->m_Controls.m_SourceManagerWidget->LoadSource(source); //check if the current selected source is also a message provider - mitk::IGTLMessageProvider::Pointer msgProvider = + mitk::IGTLMessageProvider::Pointer currentMsgProvider = mitk::IGTLMessageProvider::New(); - msgProvider = dynamic_cast(source.GetPointer()); - this->m_Controls.m_StreamManagerWidget->LoadSource(msgProvider); + currentMsgProvider = dynamic_cast(source.GetPointer()); + if(currentMsgProvider.IsNull()) + return; + this->m_Controls.m_StreamManagerWidget->LoadSource(currentMsgProvider); } diff --git a/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManager.h b/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManager.h index 0c418b5150..6e5765f4a4 100644 --- a/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManager.h +++ b/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManager.h @@ -1,71 +1,76 @@ /*=================================================================== 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 OpenIGTLinkManager_h #define OpenIGTLinkManager_h #include #include #include "ui_OpenIGTLinkManagerControls.h" #include "mitkIGTLClient.h" #include "mitkIGTLDeviceSource.h" /** \brief OpenIGTLinkManager \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkAbstractView \ingroup ${plugin_target}_internal */ class OpenIGTLinkManager : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; OpenIGTLinkManager(); virtual ~OpenIGTLinkManager(); public slots: void NewSourceByWidget(mitk::IGTLDeviceSource::Pointer source, std::string); void SourceSelected(mitk::IGTLDeviceSource::Pointer source); + void LogMessagesClicked(); protected: virtual void CreateQtPartControl(QWidget *parent) override; virtual void SetFocus() override; void CreatePipeline(); void DestroyPipeline(); Ui::OpenIGTLinkManagerControls m_Controls; /** Someone needs to hold the smart pointers of new sources, otherwise the * objects will be lost although they are listed as microservice. */ std::vector m_AllSourcesHandledByThisWidget; + + bool logMessages; + + mitk::IGTLDevice::Pointer m_CurrentIGTLDevice; }; #endif // OpenIGTLinkManager_h diff --git a/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManagerControls.ui b/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManagerControls.ui index c112355b49..e83ddbb914 100644 --- a/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManagerControls.ui +++ b/Plugins/org.mitk.gui.qt.openigtlink/src/internal/OpenIGTLinkManagerControls.ui @@ -1,98 +1,105 @@ OpenIGTLinkManagerControls 0 0 668 392 0 0 QmitkTemplate 12 75 true Select OpenIGTLink device source: 12 75 true Manage device: + + + + Log incoming / outgoing messages + + + 12 75 true Manage streams of selected device source: QmitkIGTLDeviceSourceSelectionWidget QTextEdit
QmitkIGTLDeviceSourceSelectionWidget.h
QmitkIGTLDeviceSourceManagementWidget QWidget
QmitkIGTLDeviceSourceManagementWidget.h
1
QmitkIGTLStreamingManagementWidget QWidget
QmitkIGTLStreamingManagementWidget.h
1