diff --git a/Modules/IGT/IGTFilters/mitkCameraVisualization.cpp b/Modules/IGT/IGTFilters/mitkCameraVisualization.cpp index 48223a34e0..669fc82a73 100644 --- a/Modules/IGT/IGTFilters/mitkCameraVisualization.cpp +++ b/Modules/IGT/IGTFilters/mitkCameraVisualization.cpp @@ -1,140 +1,142 @@ /*=================================================================== 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 "mitkCameraVisualization.h" #include "vtkCamera.h" #include "mitkPropertyList.h" #include "mitkProperties.h" mitk::CameraVisualization::CameraVisualization(): NavigationDataToNavigationDataFilter(), m_Renderer(NULL), m_FocalLength(10.0) { // initialize members m_DirectionOfProjectionInToolCoordinates[0] = 0; m_DirectionOfProjectionInToolCoordinates[1] = 0; m_DirectionOfProjectionInToolCoordinates[2] = -1; m_ViewUpInToolCoordinates[0] = 1; m_ViewUpInToolCoordinates[1] = 0; m_ViewUpInToolCoordinates[2] = 0; } mitk::CameraVisualization::~CameraVisualization() { } void mitk::CameraVisualization::GenerateData() { // check if renderer was set if (m_Renderer.IsNull()) itkExceptionMacro(<< "Renderer was not properly set"); /* update outputs with tracking data from tools */ unsigned int numberOfInputs = this->GetNumberOfInputs(); for (unsigned int i = 0; i < numberOfInputs ; ++i) { mitk::NavigationData* output = this->GetOutput(i); assert(output); const mitk::NavigationData* input = this->GetInput(i); assert(input); if (input->IsDataValid() == false) { continue; } output->Graft(input); // First, copy all information from input to output } const NavigationData* navigationData = this->GetInput(); // get position from NavigationData to move the camera to this position Point3D cameraPosition = navigationData->GetPosition(); //calculate the transform from the quaternions static itk::QuaternionRigidTransform::Pointer quatTransform = itk::QuaternionRigidTransform::New(); mitk::NavigationData::OrientationType orientation = navigationData->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 datatype. 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); + //mitk::TransferMatrix(quatTransform->GetMatrix(), m); + m = navigationData->GetOrientation().rotation_matrix_transpose(); + Vector3D directionOfProjection = m*m_DirectionOfProjectionInToolCoordinates; directionOfProjection.Normalize(); Point3D focalPoint = cameraPosition + m_FocalLength*directionOfProjection; // compute current view up vector Vector3D viewUp = m*m_ViewUpInToolCoordinates; m_Renderer->GetVtkRenderer()->GetActiveCamera()->SetPosition(cameraPosition[0],cameraPosition[1],cameraPosition[2]); m_Renderer->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(focalPoint[0],focalPoint[1],focalPoint[2]); m_Renderer->GetVtkRenderer()->GetActiveCamera()->SetViewUp(viewUp[0],viewUp[1],viewUp[2]); m_Renderer->GetVtkRenderer()->ResetCameraClippingRange(); m_Renderer->RequestUpdate(); } void mitk::CameraVisualization::SetRenderer(mitk::BaseRenderer* renderer) { m_Renderer = renderer; } const mitk::BaseRenderer* mitk::CameraVisualization::GetRenderer() { return m_Renderer; } void mitk::CameraVisualization::SetParameters( const mitk::PropertyList* p ) { if (p == NULL) return; mitk::Vector3D doP; if (p->GetPropertyValue("CameraVisualization_DirectionOfProjectionInToolCoordinates", doP) == true) // search for DirectionOfProjectionInToolCoordinates parameter this->SetDirectionOfProjectionInToolCoordinates(doP); // apply if found; mitk::Vector3D vUp; if (p->GetPropertyValue("CameraVisualization_ViewUpInToolCoordinates", vUp) == true) // search for ViewUpInToolCoordinates parameter this->SetViewUpInToolCoordinates(vUp); // apply if found; float fL; if (p->GetPropertyValue("CameraVisualization_FocalLength", fL) == true) // search for FocalLength parameter this->SetFocalLength(fL); // apply if found; float vA; if (p->GetPropertyValue("CameraVisualization_ViewAngle", vA) == true) // search for ViewAngle parameter this->SetFocalLength(vA); // apply if found; } mitk::PropertyList::ConstPointer mitk::CameraVisualization::GetParameters() const { mitk::PropertyList::Pointer p = mitk::PropertyList::New(); p->SetProperty("CameraVisualization_DirectionOfProjectionInToolCoordinates", mitk::Vector3DProperty::New(this->GetDirectionOfProjectionInToolCoordinates())); // store DirectionOfProjectionInToolCoordinates parameter p->SetProperty("CameraVisualization_ViewUpInToolCoordinates", mitk::Vector3DProperty::New(this->GetViewUpInToolCoordinates())); // store ViewUpInToolCoordinates parameter p->SetProperty("CameraVisualization_FocalLength", mitk::Vector3DProperty::New(this->GetFocalLength())); // store FocalLength parameter return mitk::PropertyList::ConstPointer(p); } diff --git a/Modules/IGT/IGTFilters/mitkNavigationDataObjectVisualizationFilter.cpp b/Modules/IGT/IGTFilters/mitkNavigationDataObjectVisualizationFilter.cpp index 3c88d8500a..7b2ff03235 100644 --- a/Modules/IGT/IGTFilters/mitkNavigationDataObjectVisualizationFilter.cpp +++ b/Modules/IGT/IGTFilters/mitkNavigationDataObjectVisualizationFilter.cpp @@ -1,219 +1,265 @@ /*=================================================================== 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 "mitkNavigationDataObjectVisualizationFilter.h" #include "mitkDataStorage.h" mitk::NavigationDataObjectVisualizationFilter::NavigationDataObjectVisualizationFilter() : NavigationDataToNavigationDataFilter(), -m_RepresentationList(), m_TransformPosition(), m_TransformOrientation() +m_RepresentationList(), m_TransformPosition(), m_TransformOrientation(), m_RotationMode(RotationStandard) { } mitk::NavigationDataObjectVisualizationFilter::~NavigationDataObjectVisualizationFilter() { m_RepresentationList.clear(); + m_OffsetList.clear(); } const mitk::BaseData* mitk::NavigationDataObjectVisualizationFilter::GetRepresentationObject(unsigned int idx) { //if (idx >= this->GetNumberOfInputs()) // return NULL; //const NavigationData* nd = this->GetInput(idx); //if (nd == NULL) // return NULL; RepresentationPointerMap::const_iterator iter = m_RepresentationList.find(idx); if (iter != m_RepresentationList.end()) return iter->second; return NULL; } +mitk::AffineTransform3D::Pointer mitk::NavigationDataObjectVisualizationFilter::GetOffset(int index) +{ + OffsetPointerMap::const_iterator iter = m_OffsetList.find(index); + if (iter != m_OffsetList.end()) + return iter->second; + return NULL; +} + void mitk::NavigationDataObjectVisualizationFilter::SetRepresentationObject(unsigned int idx, BaseData* data) { //if (idx >= this->GetNumberOfInputs()) // return false; //const NavigationData* nd = this->GetInput(idx); //if (nd == NULL || data == NULL) // return false; m_RepresentationList[idx] = RepresentationPointer(data); //std::pair returnEl; //pair for returning the result //returnEl = m_RepresentationList.insert( RepresentationPointerMap::value_type(nd, data) ); //insert the given elements //return returnEl.second; // return if insert was successful } +void mitk::NavigationDataObjectVisualizationFilter::SetOffset(int index, mitk::AffineTransform3D::Pointer offset) +{ +m_OffsetList[index] = offset; +} + + +void mitk::NavigationDataObjectVisualizationFilter::SetRotationMode(RotationMode r) +{ + m_RotationMode = r; +} + void mitk::NavigationDataObjectVisualizationFilter::GenerateData() { /*get each input, lookup the associated BaseData and transfer the data*/ DataObjectPointerArray inputs = this->GetInputs(); //get all inputs for (unsigned int index=0; index < inputs.size(); index++) { //get the needed variables const mitk::NavigationData* nd = this->GetInput(index); assert(nd); mitk::NavigationData* output = this->GetOutput(index); assert(output); //check if the data is valid if (!nd->IsDataValid()) { output->SetDataValid(false); continue; } output->Graft(nd); // copy all information from input to output const mitk::BaseData* data = this->GetRepresentationObject(index); if (data == NULL) { itkWarningMacro("NavigationDataObjectVisualizationFilter: Wrong/No BaseData associated with input."); return; } //get the transform from data mitk::AffineTransform3D::Pointer affineTransform = data->GetGeometry()->GetIndexToWorldTransform(); if (affineTransform.IsNull()) { //replace with mitk standard output itkWarningMacro("NavigationDataObjectVisualizationFilter: AffineTransform IndexToWorldTransform not initialized!"); return; } + //check for offset + mitk::AffineTransform3D::Pointer offset = this->GetOffset(index); + //store the current scaling to set it after transformation mitk::Vector3D spacing = data->GetGeometry()->GetSpacing(); //clear spacing of data to be able to set it again afterwards ScalarType scale[] = {1.0, 1.0, 1.0}; data->GetGeometry()->SetSpacing(scale); /*now bring quaternion to affineTransform by using vnl_Quaternion*/ affineTransform->SetIdentity(); - if (this->GetTransformOrientation(index) == true) { - //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); + + //convert quaternion to rotation matrix depending on the rotation mode + if(m_RotationMode == RotationStandard) + { + //calculate the transform from the quaternions + static itk::QuaternionRigidTransform::Pointer quatTransform = itk::QuaternionRigidTransform::New(); + // 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(); + mitk::TransferMatrix(quatTransform->GetMatrix(), m); + } + else if(m_RotationMode == RotationTransposed) + { + vnl_matrix_fixed rot = orientation.rotation_matrix_transpose(); + for(int i=0; i<3; i++) for (int j=0; j<3; j++) m[i][j] = rot[i][j]; + } affineTransform->SetMatrix(m); + } if (this->GetTransformPosition(index) == true) { ///*set the offset by convert from itkPoint to itkVector and setting offset of transform*/ mitk::Vector3D pos; pos.Set_vnl_vector(nd->GetPosition().Get_vnl_vector()); affineTransform->SetOffset(pos); } affineTransform->Modified(); + + //set the transform to data - data->GetGeometry()->SetIndexToWorldTransform(affineTransform); + if(offset.IsNotNull()) //first use offset if there is one. + { + mitk::AffineTransform3D::Pointer overallTransform = mitk::AffineTransform3D::New(); + overallTransform->SetIdentity(); + overallTransform->Compose(offset); + overallTransform->Compose(affineTransform); + data->GetGeometry()->SetIndexToWorldTransform(overallTransform); + } + else + { + data->GetGeometry()->SetIndexToWorldTransform(affineTransform); + } + //set the original spacing to keep scaling of the geometrical object data->GetGeometry()->SetSpacing(spacing); data->GetGeometry()->TransferItkToVtkTransform(); // update VTK Transform for rendering too data->GetGeometry()->Modified(); data->Modified(); output->SetDataValid(true); // operation was successful, therefore data of output is valid. } } void mitk::NavigationDataObjectVisualizationFilter::SetTransformPosition( unsigned int index, bool applyTransform ) { itkDebugMacro("setting TransformPosition for index " << index << " to " << applyTransform); BooleanInputMap::const_iterator it = this->m_TransformPosition.find(index); if ((it != this->m_TransformPosition.end()) && (it->second == applyTransform)) return; this->m_TransformPosition[index] = applyTransform; - this->Modified(); \ + this->Modified(); } bool mitk::NavigationDataObjectVisualizationFilter::GetTransformPosition( unsigned int index ) const { itkDebugMacro("returning TransformPosition for index " << index); BooleanInputMap::const_iterator it = this->m_TransformPosition.find(index); if (it != this->m_TransformPosition.end()) return it->second; else return true; // default to true } void mitk::NavigationDataObjectVisualizationFilter::TransformPositionOn( unsigned int index ) { this->SetTransformPosition(index, true); } void mitk::NavigationDataObjectVisualizationFilter::TransformPositionOff( unsigned int index ) { this->SetTransformPosition(index, false); } void mitk::NavigationDataObjectVisualizationFilter::SetTransformOrientation( unsigned int index, bool applyTransform ) { itkDebugMacro("setting TransformOrientation for index " << index << " to " << applyTransform); BooleanInputMap::const_iterator it = this->m_TransformOrientation.find(index); if ((it != this->m_TransformOrientation.end()) && (it->second == applyTransform)) return; this->m_TransformOrientation[index] = applyTransform; this->Modified(); \ } bool mitk::NavigationDataObjectVisualizationFilter::GetTransformOrientation( unsigned int index ) const { itkDebugMacro("returning TransformOrientation for index " << index); BooleanInputMap::const_iterator it = this->m_TransformOrientation.find(index); if (it != this->m_TransformOrientation.end()) return it->second; else return true; // default to true } void mitk::NavigationDataObjectVisualizationFilter::TransformOrientationOn( unsigned int index ) { this->SetTransformOrientation(index, true); } void mitk::NavigationDataObjectVisualizationFilter::TransformOrientationOff( unsigned int index ) { this->SetTransformOrientation(index, false); } diff --git a/Modules/IGT/IGTFilters/mitkNavigationDataObjectVisualizationFilter.h b/Modules/IGT/IGTFilters/mitkNavigationDataObjectVisualizationFilter.h index 10cc79b66b..e9023b2e81 100644 --- a/Modules/IGT/IGTFilters/mitkNavigationDataObjectVisualizationFilter.h +++ b/Modules/IGT/IGTFilters/mitkNavigationDataObjectVisualizationFilter.h @@ -1,119 +1,154 @@ /*=================================================================== 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 MITKNAVIGATIONDATAOBJECTVISUALIZATIONFILTER_H_HEADER_INCLUDED_ #define MITKNAVIGATIONDATAOBJECTVISUALIZATIONFILTER_H_HEADER_INCLUDED_ #include "mitkNavigationDataToNavigationDataFilter.h" #include "mitkNavigationData.h" #include "mitkBaseData.h" namespace mitk { /** * \brief Class that reads NavigationData from input and transfers the information to the geometry of the associated BaseData * * Derived from NavigationDataToNavigationDataFilter * * \ingroup IGT */ class MitkIGT_EXPORT NavigationDataObjectVisualizationFilter : public NavigationDataToNavigationDataFilter { public: mitkClassMacro(NavigationDataObjectVisualizationFilter, NavigationDataToNavigationDataFilter); itkNewMacro(Self); + /** Defines the rotation modes of this tracking device which results in different representations + * of quaternions. + * + * - Standard: normal representation, rawdata from the device is not changed (DEFAULT) + * + * - Transposed: the rotation is stored transposed, which is (by mistake!) expected by some older MITK classes due + * to an ambigious method naming in VNL. + * + * CAUTION: The rotation mode can only be changed for backward compatibility of old WRONG code. + * PLEASE DO NOT CHANGE THE ROTATION MODE UNLESS YOU ARE KNOWING EXACTLY WHAT YOU ARE DOING! + * + * use SetRotationMode to change the mode. + */ + enum RotationMode {RotationStandard, RotationTransposed}; + /** * \brief Smart Pointer type to a BaseData. */ typedef BaseData::ConstPointer RepresentationPointer; /** * \brief STL map of index to BaseData . Using map to be able to set non continuous indices */ typedef std::map RepresentationPointerMap; /** * \brief Size type of an std::vector */ typedef RepresentationPointerMap::size_type RepresentationPointerMapSizeType; /** * \brief Set the representation object of the input * * \param data The BaseData to be associated to the index * \param index the index with which data will be associated */ void SetRepresentationObject(unsigned int index, BaseData* data); /** * \brief Get the representation object associated with the index idx * * \param idx the corresponding input number with which the BaseData is associated * \return Returns the desired BaseData if it exists for the given input; Returns NULL * if no BaseData was found. */ const BaseData* GetRepresentationObject(unsigned int idx); virtual void SetTransformPosition(unsigned int index, bool applyTransform); ///< if set to true, the filter will use the position part of the input navigation data at the given index to transform the representation object. If set to false, it will not. If no value is set, it defaults to true. virtual bool GetTransformPosition(unsigned int index) const; ///< returns whether position part of the input navigation data at the given index is used for the transformation of the representation object. virtual void TransformPositionOn(unsigned int index); ///< sets the TransformPosition flag to true for the given index virtual void TransformPositionOff(unsigned int index); ///< sets the TransformPosition flag to false for the given index virtual void SetTransformOrientation(unsigned int index, bool applyTransform); ///< if set to true, the filter will use the orientation part of the input navigation data at the given index to transform the representation object. If set to false, it will not. If no value is set, it defaults to true. virtual bool GetTransformOrientation(unsigned int index) const; ///< returns whether orientation part of the input navigation data at the given index is used for the transformation of the representation object. virtual void TransformOrientationOn(unsigned int index); ///< sets the TransformOrientation flag to true for the given index virtual void TransformOrientationOff(unsigned int index); ///< sets the TransformOrientation flag to false for the given index + /** @brief Defines an offset for a representation object. This offset is applied before the object is visualized. + * If no offset is given, no offset will be used. To deactivate the offset just set it to NULL. + */ + void SetOffset(int index, mitk::AffineTransform3D::Pointer offset); + + /** Sets the rotation mode of this class. See documentation of enum RotationMode for details + * on the different modes. + * CAUTION: The rotation mode can only be changed for backward compatibility of old WRONG code. + * PLEASE DO NOT CHANGE THE ROTATION MODE UNLESS YOU ARE KNOWING EXACTLY WHAT YOU ARE DOING! + */ + virtual void SetRotationMode(RotationMode r); + + /** @return Returns the offset of a represenation object. Returns NULL if there is no offset. */ + mitk::AffineTransform3D::Pointer GetOffset(int index); + /** *\brief Get the number of added BaseData associated to NavigationData * \return Returns the size of the internal map */ RepresentationPointerMapSizeType GetNumberOfToolRepresentations() const { return m_RepresentationList.size(); } /* * \brief Transfer the information from the input to the associated BaseData */ virtual void GenerateData(); protected: typedef std::map BooleanInputMap; + typedef std::map OffsetPointerMap; /** * \brief Constructor **/ NavigationDataObjectVisualizationFilter(); /** * \brief Destructor **/ ~NavigationDataObjectVisualizationFilter(); /** * \brief An array of the BaseData which represent the tools. */ RepresentationPointerMap m_RepresentationList; BooleanInputMap m_TransformPosition; ///< if set to true, the filter will use the position part of the input navigation data at the given index for the calculation of the transform. If no entry for the index exists, it defaults to true. BooleanInputMap m_TransformOrientation; ///< if set to true, the filter will use the orientation part of the input navigation data at the given index for the calculation of the transform. If no entry for the index exists, it defaults to true. + OffsetPointerMap m_OffsetList; + + private: + RotationMode m_RotationMode; ///< defines the rotation mode Standard or Transposed, Standard is default }; } // namespace mitk #endif /* MITKNAVIGATIONDATAOBJECTVISUALIZATIONFILTER_H_HEADER_INCLUDED_ */ diff --git a/Modules/IGT/IGTTrackingDevices/mitkNDIProtocol.cpp b/Modules/IGT/IGTTrackingDevices/mitkNDIProtocol.cpp index 8d910ebac8..9d6b7f2fa9 100644 --- a/Modules/IGT/IGTTrackingDevices/mitkNDIProtocol.cpp +++ b/Modules/IGT/IGTTrackingDevices/mitkNDIProtocol.cpp @@ -1,1872 +1,1882 @@ /*=================================================================== 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 "mitkNDIProtocol.h" #include "mitkNDITrackingDevice.h" #include #include #include #include #include mitk::NDIProtocol::NDIProtocol() : itk::Object(), m_TrackingDevice(NULL), m_UseCRC(true) { } mitk::NDIProtocol::~NDIProtocol() { } mitk::NDIErrorCode mitk::NDIProtocol::COMM(mitk::SerialCommunication::BaudRate baudRate , mitk::SerialCommunication::DataBits dataBits, mitk::SerialCommunication::Parity parity, mitk::SerialCommunication::StopBits stopBits, mitk::SerialCommunication::HardwareHandshake hardwareHandshake) { /* Build parameter string */ std::string param; switch (baudRate) { case mitk::SerialCommunication::BaudRate14400: param += "1"; break; case mitk::SerialCommunication::BaudRate19200: param += "2"; break; case mitk::SerialCommunication::BaudRate38400: param += "3"; break; case mitk::SerialCommunication::BaudRate57600: param += "4"; break; case mitk::SerialCommunication::BaudRate115200: param += "5"; break; case mitk::SerialCommunication::BaudRate9600: default: // assume 9600 Baud as default param += "0"; break; } switch (dataBits) { case mitk::SerialCommunication::DataBits7: param += "1"; break; case mitk::SerialCommunication::DataBits8: default: // set 8 data bits as default param += "0"; break; } switch (parity) { case mitk::SerialCommunication::Odd: param += "1"; break; case mitk::SerialCommunication::Even: param += "2"; break; case mitk::SerialCommunication::None: default: // set no parity as default param += "0"; break; } switch (stopBits) { case mitk::SerialCommunication::StopBits2: param += "1"; break; case mitk::SerialCommunication::StopBits1: default: // set 1 stop bit as default param += "0"; break; } switch (hardwareHandshake) { case mitk::SerialCommunication::HardwareHandshakeOn: param += "1"; break; case mitk::SerialCommunication::HardwareHandshakeOff: default: // set no hardware handshake as default param += "0"; break; } return GenericCommand("COMM", ¶m); } mitk::NDIErrorCode mitk::NDIProtocol::INIT() { return GenericCommand("INIT"); } mitk::NDIErrorCode mitk::NDIProtocol::DSTART() { return GenericCommand("DSTART"); } mitk::NDIErrorCode mitk::NDIProtocol::DSTOP() { return GenericCommand("DSTOP"); } mitk::NDIErrorCode mitk::NDIProtocol::IRINIT() { return GenericCommand("IRINIT"); } mitk::NDIErrorCode mitk::NDIProtocol::IRCHK(bool* IRdetected) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = "IRCHK:0001"; // command string format 1: with crc else fullcommand = "IRCHK 0001"; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } /* wait for the trackingsystem to process the command */ itksys::SystemTools::Delay(100); /* read and parse the reply from tracking device */ // the reply for IRCHK can be either Infrared Source Information or ERROR## // because we use the simple reply format, the answer will be only one char: // "0" - no IR detected // "1" - IR detected std::string reply; char b; m_TrackingDevice->ReceiveByte(&b);// read the first byte reply = b; if ((b == '0') || (b == '1')) // normal answer { /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code { if ( b == '0') *IRdetected = false; else *IRdetected = true; returnValue = NDIOKAY; } else // return error in CRC { returnValue = NDICRCERROR; *IRdetected = false; // IRdetected is only valid if return code of this function is NDIOKAY } } else if (b =='E') // expect ERROR## { std::string errorstring; m_TrackingDevice->Receive(&errorstring, 4); // read the remaining 4 characters of ERROR reply += errorstring; static const std::string error("ERROR"); if (error.compare(0, 5, reply) == 0) // check for "ERROR" { std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code /* perform CRC checking */ reply += errorcode; // build complete reply string std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else returnValue = NDICRCERROR; // return error in CRC } } else // something else, that we do not expect returnValue = NDIUNEXPECTEDREPLY; /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PHSR(PHSRQueryType queryType, std::string* portHandles) { NDIErrorCode returnValue = NDIUNKNOWNERROR; if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string command; char stringQueryType[3]; sprintf(stringQueryType, "%02X", queryType);// convert numerical queryType to string in hexadecimal format if (m_UseCRC == true) command = std::string("PHSR:") + std::string(stringQueryType); else //if (m_UseCRC != true) command = std::string("PHSR ") + std::string(stringQueryType); // command string format 2: without crc returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } itksys::SystemTools::Delay(100); std::string reply; m_TrackingDevice->Receive(&reply, 2); // read first 2 characters of reply ("Number of Handles" as a 2 digit hexadecimal number) static const std::string error("ERROR"); if (error.compare(0, 2, reply) == 0) // check for "ERROR" (compare for "ER" because we can not be sure that the reply is more than 2 characters (in case of 0 port handles returned) { std::string ror; m_TrackingDevice->Receive(&ror, 3); // read rest of ERROR (=> "ROR") reply += ror; // build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // No error, expect number of handles as a 2 character hexadecimal value { unsigned int numberOfHandles = 0; // convert the hexadecimal string representation to a numerical using a stringstream std::stringstream s; s << reply; s >> numberOfHandles; if (numberOfHandles > 16) // there can not be more than 16 handles ToDo: exact maximum number depend on tracking device and firmware revision. these data could be read with VER and used here { returnValue = NDIUNKNOWNERROR; } else { std::string handleInformation; portHandles->clear(); for (unsigned int i = 0; i < numberOfHandles; i++) // read 5 characters for each handle and extract port handle { m_TrackingDevice->Receive(&handleInformation, 5); *portHandles += handleInformation.substr(0, 2); // Append the port handle to the portHandles string reply += handleInformation; // build complete reply string for crc checking } /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return okay returnValue = NDIOKAY; else // return error in CRC returnValue = NDICRCERROR; } } /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PHRQ(std::string* portHandle) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking device if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string command; if (m_UseCRC == true) command = "PHRQ:*********1****"; // command string format 1: with crc else command = "PHRQ *********1****"; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } itksys::SystemTools::Delay(100); // give the tracking device some time to process the command std::string reply; m_TrackingDevice->Receive(&reply, 2); // read first 2 characters of reply ("Number of Handles" as a 2 digit hexadecimal number) static const std::string error("ERROR"); if (error.compare(0, 2, reply) == 0) // check for "ERROR" (compare for "ER" because we can not be sure that the reply is more than 2 characters (in case of 0 port handles returned) { std::string ror; m_TrackingDevice->Receive(&ror, 3); // read rest of ERROR (=> "ROR") reply += ror; // build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // No error, expect port handle as a 2 character hexadecimal value { *portHandle = reply; // assign the port handle to the return string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return okay returnValue = NDIOKAY; else // else return error in CRC returnValue = NDICRCERROR; } /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PVWR(std::string* portHandle, const unsigned char* sromData, unsigned int sromDataLength) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; if (sromDataLength > 1024) return SROMFILETOOLARGE; if (sromDataLength == 0) return SROMFILETOOSMALL; /* build send commands */ std::string basecommand; if (m_UseCRC == true) basecommand = "PVWR:"; // command string format 1: with crc else basecommand = "PVWR "; // command string format 2: without crc std::string hexSROMData; hexSROMData.reserve(2 * sromDataLength); char hexcharacter[20]; // 7 bytes should be enough (in send loop) for (unsigned int i = 0; i < sromDataLength; i++) { sprintf(hexcharacter, "%02X", sromData[i]); // convert srom byte to string in hexadecimal format //hexSROMData += "12"; hexSROMData += hexcharacter; // append hex string to srom data in hex format } /* data must be written in chunks of 64 byte (128 hex characters). To ensure 64 byte chunks the last chunk must be padded with 00 */ unsigned int zerosToPad = 128 - (hexSROMData.size() % 128); // hexSROMData must be a multiple of 128 if (zerosToPad > 0) hexSROMData.append(zerosToPad, '0'); /* now we have all the data, send it in 128 character chunks */ std::string fullcommand; for (unsigned int j = 0; j < hexSROMData.size(); j += 128) { sprintf(hexcharacter, "%s%04X", portHandle->c_str(), j/2); // build the first two parameters: PortHandle and SROM device adress (not in hex characters, but in bytes) fullcommand = basecommand + hexcharacter + hexSROMData.substr(j, 128); // build complete command string returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); // send command itksys::SystemTools::Delay(50); // Wait for trackingsystem to process the data if (returnValue != NDIOKAY) // check for send error break; returnValue = this->ParseOkayError(); // parse answer if (returnValue != NDIOKAY) // check for error returned from tracking device break; } /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PINIT(std::string* portHandle) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = std::string("PINIT:") + *portHandle; // command string format 1: with crc else fullcommand = std::string("PINIT ") + *portHandle; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } /* wait for the trackingsystem to process the command */ itksys::SystemTools::Delay(100); std::string reply; m_TrackingDevice->Receive(&reply, 4); // read first 4 characters of reply /* Parse reply from tracking device */ static const std::string okay("OKAYA896"); // OKAY is static, so we can perform a static crc check static const std::string error("ERROR"); static const std::string warning("WARNING7423"); // WARNING has a static crc too if (okay.compare(0, 4, reply) == 0) // check for "OKAY": compare first 4 characters from okay with reply { // OKAY was found, now check the CRC16 too m_TrackingDevice->Receive(&reply, 4); // read 4 hexadecimal characters for CRC16 if (okay.compare(4, 4, reply, 0, 4) == 0) // first 4 from new reply should match last 4 from okay returnValue = NDIOKAY; else returnValue = NDICRCERROR; } else if (warning.compare(0, 4, reply) == 0) // check for "WARNING" { // WARN was found, now check remaining characters and CRC16 m_TrackingDevice->Receive(&reply, 4); // read 4 hexadecimal characters for CRC16 if (warning.compare(4, 7, reply, 0, 7) == 0) // first 7 from new reply should match last 7 from okay returnValue = NDIWARNING; else returnValue = NDICRCERROR; } else if (error.compare(0, 4, reply) == 0) // check for "ERRO" { char b; // The ERROR reply is not static, so we can not use a static crc check. m_TrackingDevice->ReceiveByte(&b); // read next character ("R" from ERROR) reply += b; // to build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // else it is something else, that we do not expect returnValue = NDIUNEXPECTEDREPLY; //read cr carriage return char b; m_TrackingDevice->ReceiveByte(&b); /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PENA(std::string* portHandle, TrackingPriority prio) { std::string param; if (portHandle != NULL) param = *portHandle + (char) prio; else param = ""; return this->GenericCommand("PENA", ¶m); } mitk::NDIErrorCode mitk::NDIProtocol::PHINF(std::string portHandle, std::string* portInfo) { std::string command; if (m_UseCRC) command = "PHINF:" + portHandle; else command = "PHINF " + portHandle; mitk::NDIErrorCode returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue==NDIOKAY) { m_TrackingDevice->ClearReceiveBuffer(); m_TrackingDevice->Receive(portInfo, 33); m_TrackingDevice->ClearReceiveBuffer(); } else m_TrackingDevice->ClearReceiveBuffer(); return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::PDIS(std::string* portHandle) { return this->GenericCommand("PDIS", portHandle); } mitk::NDIErrorCode mitk::NDIProtocol::PHF(std::string* portHandle) { return this->GenericCommand("PHF", portHandle); } mitk::NDIErrorCode mitk::NDIProtocol::IRATE(IlluminationActivationRate rate) { std::string param; switch (rate) { case Hz60: param = "2"; break; case Hz30: param = "1"; break; case Hz20: default: param = "0"; break; } return this->GenericCommand("IRATE", ¶m); } mitk::NDIErrorCode mitk::NDIProtocol::BEEP(unsigned char count) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; std::string p; if ((count >= 1) && (count <= 9)) p = (count + '0'); // convert the number count to a character representation else return NDICOMMANDPARAMETEROUTOFRANGE; /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = "BEEP:" + p; // command string format 1: with crc else fullcommand = "BEEP " + p; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } /* wait for the trackingsystem to process the command */ itksys::SystemTools::Delay(100); std::string reply; char b; m_TrackingDevice->ReceiveByte(&b); // read the first byte reply = b; if ((b == '0') || (b == '1')) // normal answer { /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = NDIOKAY; else // return error in CRC returnValue = NDICRCERROR; } else if (b =='E') // expect ERROR## { std::string errorstring; m_TrackingDevice->Receive(&errorstring, 4); // read the remaining 4 characters of ERROR reply += errorstring; static const std::string error("ERROR"); if (error.compare(0, 5, reply) == 0) // check for "ERROR" { std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code /* perform CRC checking */ reply += errorcode; // build complete reply string std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else returnValue = NDICRCERROR; // return error in CRC } } else // something else, that we do not expect returnValue = NDIUNEXPECTEDREPLY; /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::TSTART(bool resetFrameCounter) { std::string param = "80"; if (resetFrameCounter == true) return this->GenericCommand("TSTART", ¶m); else return this->GenericCommand("TSTART"); } mitk::NDIErrorCode mitk::NDIProtocol::TSTOP() { return this->GenericCommand("TSTOP"); } mitk::NDIErrorCode mitk::NDIProtocol::PSOUT(std::string portHandle, std::string state) { std::string param = portHandle + state; return this->GenericCommand("PSOUT", ¶m); } mitk::NDIErrorCode mitk::NDIProtocol::TX(bool trackIndividualMarkers, MarkerPointContainerType* markerPositions) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking device if(trackIndividualMarkers) markerPositions->clear(); if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string fullcommand; if (trackIndividualMarkers) { if (m_UseCRC == true) fullcommand = "TX:1001"; // command string format 1: with crc else fullcommand = "TX 1001"; // command string format 2: without crc } else { if (m_UseCRC == true) fullcommand = "TX:"; // command string format 1: with crc else fullcommand = "TX "; // command string format 2: without crc } returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) { /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } /* read number of handles returned */ std::string reply; std::string s; m_TrackingDevice->Receive(&reply, 2); // read first 2 characters of reply (error or number of handles returned) //printf("%d",reply); static const std::string error("ERROR"); if (error.compare(0, 2, reply) == 0) { m_TrackingDevice->Receive(&s, 3); // read next characters ("ROR" from ERROR) reply += s; // to build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code { returnValue = this->GetErrorCode(&errorcode); } else // return error in CRC { returnValue = NDICRCERROR; } } else // transformation data is returned { /* parse number of handles from first 2 characters */ std::stringstream converter; unsigned int numberOfHandles = 0; converter << std::hex << reply; // insert reply into stringstream converter >> numberOfHandles; // extract number of handles as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); /* read and parse transformation data for each handle */ for (unsigned int i = 0; i < numberOfHandles; i++) // for each handle { /* Read port handle */ m_TrackingDevice->Receive(&s, 2); // read port handle reply += s; // build complete command string NDIPassiveTool::Pointer tool = m_TrackingDevice->GetInternalTool(s); // get tool object for that handle if (tool.IsNull()) { returnValue = UNKNOWNHANDLERETURNED; break; // if we do not know the handle, we can not assume anything about the remaining data, so we better abort (we could read up to the next LF) } /* Parse reply from tracking device */ static const std::string missing("MISSING"); static const std::string disabled("DISABLED"); static const std::string unoccupied("UNOCCUPIED"); m_TrackingDevice->Receive(&s, 6); // read next 6 characters: either an error message or part of the transformation data reply += s; // build complete command string if (missing.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'missing'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 18); // after 'missin', 1 character for 'g', 8 characters for port status, 8 characters for frame number and one for line feed are send reply += s; // build complete command string } else if (disabled.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'disabled'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 3); // read last characters of disabled plus 8 characters for port status, 8 characters for frame number and one for line feed reply += s; // build complete command string } else if (unoccupied.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'unoccupied'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 21); // read remaining characters of UNOCCUPIED reply += s; // build complete command string } else // transformation data { /* define local copies */ signed int number = 0; float localPos[3] = {0.0, 0.0, 0.0}; float localQuat[4] = {0.0, 0.0, 0.0, 0.0}; float localError = 0.0; unsigned long localPortStatus = 0; unsigned int localFrameNumber = 0; /* read and parse the four 6 character quaternion values */ //std::cout << "s = " << s << std::endl; converter << std::dec << s; // insert string with first number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); //std::cout << "number = " << number << std::endl; localQuat[0] = number / 10000.0; // the value is send with an implied decimal point with 4 digits to the right for (unsigned int i = 1; i < 4; i++)// read the next 3 numbers { m_TrackingDevice->Receive(&s, 6); // read the next number reply += s; // build complete command string converter << std::dec << s; // insert string with first number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localQuat[i] = number / 10000.0; // the value is send with an implied decimal point with 4 digits to the right } /* read and parse the three 7 character translation values */ for (unsigned int i = 0; i < 3; i++) { m_TrackingDevice->Receive(&s, 7); // read the next position vector number reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localPos[i] = number / 100.0; // the value is send with an implied decimal point with 2 digits to the right } /* read and parse 6 character error value */ m_TrackingDevice->Receive(&s, 6); // read the error value reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract the number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localError = number / 10000.0; // the error value is send with an implied decimal point with 4 digits to the right /* read and parse 8 character port status */ m_TrackingDevice->Receive(&s, 8); // read the port status value reply += s; // build complete command string converter << std::hex << s; // insert string into stringstream converter >> localPortStatus; // extract the number as unsigned long converter.clear(); // converter must be cleared to be reused converter.str(""); /* read and parse 8 character frame number as hexadecimal */ m_TrackingDevice->Receive(&s, 8); // read the frame number value reply += s; // build complete command string converter << std::hex << s; // insert string with hex value encoded number into stringstream converter >> localFrameNumber; // extract the number as unsigned long converter.clear(); // converter must be cleared to be reused converter.str(""); /* copy local values to the tool */ mitk::Quaternion orientation(localQuat[1], localQuat[2], localQuat[3], localQuat[0]); + + //If the rotation mode is vnlTransposed we have to transpose the quaternion + if (m_TrackingDevice->GetRotationMode() == mitk::NDITrackingDevice::RotationTransposed) + { + orientation[0] *= -1; //qx + orientation[1] *= -1; //qy + orientation[2] *= -1; //qz + //qr is not inverted + } + tool->SetOrientation(orientation); mitk::Point3D position; position[0] = localPos[0]; position[1] = localPos[1]; position[2] = localPos[2]; tool->SetPosition(position); tool->SetTrackingError(localError); tool->SetErrorMessage(""); tool->SetDataValid(true); m_TrackingDevice->Receive(&s, 1); // read the line feed character, that terminates each handle data reply += s; // build complete command string } } // for //Read Reply Option 1000 data if(trackIndividualMarkers) { /* parse number of markers from first 2 characters */ m_TrackingDevice->Receive(&s, 2); reply += s; unsigned int numberOfMarkers = 0; converter << std::hex << s; // insert reply into stringstream converter >> numberOfMarkers; // extract number of markers as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); unsigned int oovReplySize = (unsigned int)ceil((double)numberOfMarkers/4.0); unsigned int nbMarkersInVolume = 0; char c; // parse oov data to find out how many marker positions were recorded for (unsigned int i = 0; i < oovReplySize; i++) { m_TrackingDevice->ReceiveByte(&c); reply += c; nbMarkersInVolume += ByteToNbBitsOn(c); } nbMarkersInVolume = numberOfMarkers-nbMarkersInVolume; /* read and parse position data for each marker */ for (unsigned int i = 0; i < nbMarkersInVolume; i++) { /* define local copies */ signed int number = 0; MarkerPointType markerPosition; /* read and parse the three 7 character translation values */ for (unsigned int i = 0; i < 3; i++) { m_TrackingDevice->Receive(&s, 7); // read the next position vector number reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); markerPosition[i] = number / 100.0; // the value is send with an implied decimal point with 2 digits to the right } markerPositions->push_back(markerPosition); } // end for all markers } //END read Reply Option 1000 data /* Read System Status */ m_TrackingDevice->Receive(&s, 4); // read system status reply += s; // build complete command string /* now the reply string is complete, perform crc checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return okay { returnValue = NDIOKAY; } else // return error in CRC { returnValue = NDICRCERROR; /* Invalidate all tools because the received data contained an error */ m_TrackingDevice->InvalidateAll(); if(trackIndividualMarkers) markerPositions->clear(); } } // else /* cleanup and return */ m_TrackingDevice->Receive(&s, 1); // read the last linde feed (because the tracking system device is sometimes to slow to send it before we clear the buffer. In this case, the LF would remain in the receive buffer and be read as the first character of the next command m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::TX1000(MarkerPointContainerType* markerPositions) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem markerPositions->clear(); if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = "TX:1001"; // command string format 1: with crc else fullcommand = "TX 1001"; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); /* read number of handles returned */ std::string reply; std::string s; m_TrackingDevice->Receive(&reply, 2); // read first 2 characters of reply (error or number of handles returned) static const std::string error("ERROR"); if (error.compare(0, 2, reply) == 0) { m_TrackingDevice->Receive(&s, 3); // read next characters ("ROR" from ERROR) reply += s; // to build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code { returnValue = this->GetErrorCode(&errorcode); } else // return error in CRC { returnValue = NDICRCERROR; } } else // transformation data is returned { /* parse number of handles from first 2 characters */ std::stringstream converter; unsigned int numberOfHandles = 0; converter << std::hex << reply; // insert reply into stringstream converter >> numberOfHandles; // extract number of handles as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); /* read and parse transformation data for each handle */ for (unsigned int i = 0; i < numberOfHandles; i++) // for each handle { /* Read port handle */ m_TrackingDevice->Receive(&s, 2); // read port handle reply += s; // build complete command string NDIPassiveTool::Pointer tool = m_TrackingDevice->GetInternalTool(s); // get tool object for that handle if (tool.IsNull()) { returnValue = UNKNOWNHANDLERETURNED; break; // if we do not know the handle, we can not assume anything about the remaining data, so we better abort (we could read up to the next LF) } /* Parse reply from tracking device */ static const std::string missing("MISSING"); static const std::string disabled("DISABLED"); static const std::string unoccupied("UNOCCUPIED"); m_TrackingDevice->Receive(&s, 6); // read next 6 characters: either an error message or part of the transformation data reply += s; // build complete command string if (missing.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'missing'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 18); // after 'missin', 1 character for 'g', 8 characters for port status, 8 characters for frame number and one for line feed are send reply += s; // build complete command string } else if (disabled.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'disabled'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 19); // read last characters of disabled plus 8 characters for port status, 8 characters for frame number and one for line feed reply += s; // build complete command string } else if (unoccupied.compare(0, 6, s) == 0) { tool->SetErrorMessage("Tool is reported as 'unoccupied'."); tool->SetDataValid(false); m_TrackingDevice->Receive(&s, 21); // read remaining characters of UNOCCUPIED reply += s; // build complete command string } else // transformation data { /* define local copies */ signed int number = 0; float localPos[3] = {0.0, 0.0, 0.0}; float localQuat[4] = {0.0, 0.0, 0.0, 0.0}; float localError = 0.0; unsigned long localPortStatus = 0; unsigned int localFrameNumber = 0; /* read and parse the four 6 character quaternion values */ //std::cout << "s = " << s << std::endl; converter << std::dec << s; // insert string with first number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); //std::cout << "number = " << number << std::endl; localQuat[0] = number / 10000.0; // the value is send with an implied decimal point with 4 digits to the right for (unsigned int i = 1; i < 4; i++)// read the next 3 numbers { m_TrackingDevice->Receive(&s, 6); // read the next number reply += s; // build complete command string converter << std::dec << s; // insert string with first number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localQuat[i] = number / 10000.0; // the value is send with an implied decimal point with 4 digits to the right } /* read and parse the three 7 character translation values */ for (unsigned int i = 0; i < 3; i++) { m_TrackingDevice->Receive(&s, 7); // read the next position vector number reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localPos[i] = number / 100.0; // the value is send with an implied decimal point with 2 digits to the right } /* read and parse 6 character error value */ m_TrackingDevice->Receive(&s, 6); // read the error value reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract the number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); localError = number / 10000.0; // the error value is send with an implied decimal point with 4 digits to the right /* read and parse 8 character port status */ m_TrackingDevice->Receive(&s, 8); // read the port status value reply += s; // build complete command string converter << std::hex << s; // insert string into stringstream converter >> localPortStatus; // extract the number as unsigned long converter.clear(); // converter must be cleared to be reused converter.str(""); /* read and parse 8 character frame number as hexadecimal */ m_TrackingDevice->Receive(&s, 8); // read the frame number value reply += s; // build complete command string converter << std::hex << s; // insert string with hex value encoded number into stringstream converter >> localFrameNumber; // extract the number as unsigned long converter.clear(); // converter must be cleared to be reused converter.str(""); /* copy local values to the tool */ mitk::Quaternion orientation(localQuat[1], localQuat[2], localQuat[3], localQuat[0]); tool->SetOrientation(orientation); mitk::Point3D position; position[0] = localPos[0]; position[1] = localPos[1]; position[2] = localPos[2]; tool->SetPosition(position); tool->SetTrackingError(localError); tool->SetErrorMessage(""); tool->SetDataValid(true); m_TrackingDevice->Receive(&s, 1); // read the line feed character, that terminates each handle data reply += s; // build complete command string } } //Read Reply Option 1000 data /* parse number of markers from first 2 characters */ m_TrackingDevice->Receive(&s, 2); reply += s; unsigned int numberOfMarkers = 0; converter << std::hex << s; // insert reply into stringstream converter >> numberOfMarkers; // extract number of markers as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); unsigned int oovReplySize = (unsigned int)ceil((double)numberOfMarkers/4.0); unsigned int nbMarkersInVolume = 0; char c; // parse oov data to find out how many marker positions were recorded for (unsigned int i = 0; i < oovReplySize; i++) { m_TrackingDevice->ReceiveByte(&c); reply += c; nbMarkersInVolume += ByteToNbBitsOn(c); } nbMarkersInVolume = numberOfMarkers-nbMarkersInVolume; /* read and parse position data for each marker */ for (unsigned int i = 0; i < nbMarkersInVolume; i++) { /* define local copies */ signed int number = 0; MarkerPointType markerPosition; /* read and parse the three 7 character translation values */ for (unsigned int i = 0; i < 3; i++) { m_TrackingDevice->Receive(&s, 7); // read the next position vector number reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract first number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); markerPosition[i] = number / 100.0; // the value is send with an implied decimal point with 2 digits to the right } markerPositions->push_back(markerPosition); } // end for all markers //m_TrackingDevice->Receive(&s, 1); // read the line feed character, that terminates each handle data //reply += s; // build complete command string // //END read Reply Option 1000 data m_TrackingDevice->Receive(&s, 4); // read system status reply += s; // build complete command string /* now the reply string is complete, perform crc checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return okay { returnValue = NDIOKAY; } else // return error in CRC { returnValue = NDICRCERROR; /* Invalidate all tools because the received data contained an error */ markerPositions->clear(); m_TrackingDevice->InvalidateAll(); } } // else /* cleanup and return */ m_TrackingDevice->Receive(&s, 1); // read the last linde feed (because the tracking system device is sometimes to slow to send it before we clear the buffer. In this case, the LF would remain in the receive buffer and be read as the first character of the next command m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::BX() { std::cout << "BX() not implemented yet, using TX() instead." << std::endl; return this->TX(); } mitk::NDIErrorCode mitk::NDIProtocol::VER(mitk::TrackingDeviceType& t) { if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking system /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = "VER:4"; // command string format 1: with crc else fullcommand = "VER 4"; // command string format 2: without crc returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) { /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } /* read number of handles returned */ std::string reply; m_TrackingDevice->Receive(&reply, 5); // read first 5 characters of reply (error beginning of version information) static const std::string error("ERROR"); if (error.compare(0, 6, reply) == 0) // ERROR case { std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // no error, valid reply { std::string s; m_TrackingDevice->ReceiveLine(&s); // read until first LF character reply += s; std::string upperCaseReply; upperCaseReply.resize(reply.size()); std::transform (reply.begin(), reply.end(), upperCaseReply.begin(), toupper); // convert reply to uppercase to ease finding if (upperCaseReply.find("POLARIS") != std::string::npos) t = mitk::NDIPolaris; else if (upperCaseReply.find("AURORA") != std::string::npos) t = mitk::NDIAurora; else t = mitk::TrackingSystemNotSpecified; // check for "VICRA", "SPECTRA", "ACCEDO" /* do not check for remaining reply, do not check for CRC, just delete remaining reply */ itksys::SystemTools::Delay(500); // wait until reply should be finished m_TrackingDevice->ClearReceiveBuffer(); returnValue = NDIOKAY; } return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::POS3D(MarkerPointContainerType* markerPositions) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) { return TRACKINGDEVICENOTSET; } if (markerPositions == NULL) { std::cout << "ERROR: markerPositions==NULL" << std::endl; return NDIUNKNOWNERROR; } markerPositions->clear(); // empty point container /* try to obtain a porthandle */ if (m_TrackingDevice->GetToolCount() == 0) { std::cout << "ERROR: no tools present" << std::endl; return NDIUNKNOWNERROR; } const TrackingTool* t = m_TrackingDevice->GetTool(static_cast(0)); const NDIPassiveTool* t2 = dynamic_cast(t); if (t2 == NULL) { std::cout << "ERROR: no tool present" << std::endl; return NDIUNKNOWNERROR; } std::string portHandle = t2->GetPortHandle(); if (portHandle.size() == 0) { std::cout << "ERROR: no port handle" << std::endl; return NDIUNKNOWNERROR; } /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = "3D:" + portHandle + "5"; // command string format 1: with crc else fullcommand = "3D " + portHandle + "5"; // command string format 2: without crc m_TrackingDevice->ClearReceiveBuffer(); returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); /* read number of markers returned */ std::string reply; std::string s; mitk::NDIErrorCode receivevalue = m_TrackingDevice->Receive(&reply, 3); // read first 3 characters of reply (error or number of markers returned) if(receivevalue != NDIOKAY) { std::cout << "ERROR: receive_value != NDIOKAY" << std::endl; return receivevalue; } static const std::string error("ERROR"); if (error.compare(0, 3, reply) == 0) { m_TrackingDevice->Receive(&s, 2); // read next characters ("OR" from ERROR) reply += s; // to build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code { returnValue = this->GetErrorCode(&errorcode); } else // return error in CRC { returnValue = NDICRCERROR; } } else // transformation data is returned { signed int number = 0; //float localPos[3] = {0.0, 0.0, 0.0}; MarkerPointType p; float lineSeparation = 0.0; /* parse number of markers from first 3 characters */ std::stringstream converter; unsigned int numberOfMarkers = 0; converter << std::dec << reply; // insert reply into stringstream converter >> numberOfMarkers; // extract number of handles as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); /* read and parse 3D data for each marker */ for (unsigned int markerID = 0; markerID < numberOfMarkers; markerID++) // for each marker { m_TrackingDevice->Receive(&s, 1); // read line feed reply += s; // build complete command string /* read and parse the three 9 character translation values */ for (unsigned int i = 0; i < 3; i++) { receivevalue = m_TrackingDevice->Receive(&s, 9); // read the next position vector number if(receivevalue != NDIOKAY) { markerPositions->clear(); std::cout << "ERROR: receive_value != NDIOKAY" << std::endl; return receivevalue; } reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract the number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); p[i] = number / 10000.0; // the value is send with an implied decimal point with 4 digits to the right } /* read and parse 4 character line separation value */ receivevalue = m_TrackingDevice->Receive(&s, 4); // read the line separation value if(receivevalue != NDIOKAY) { markerPositions->clear(); std::cout << "ERROR: receive_value != NDIOKAY" << std::endl; return receivevalue; } reply += s; // build complete command string converter << std::dec << s; // insert string with number into stringstream converter >> number; // extract the number as integer converter.clear(); // converter must be cleared to be reused converter.str(""); lineSeparation = number / 100.0; // the line separation value is send with an implied decimal point with 2 digits to the right /* read and parse 1 character out of volume value */ receivevalue = m_TrackingDevice->Receive(&s, 1); // read the port status value if(receivevalue != NDIOKAY) { markerPositions->clear(); std::cout << std::endl << std::endl << std::endl << "ERROR: POS3D != NDIOKAY" << std::endl; return receivevalue; } reply += s; // build complete command string /* store the marker positions in the point container */ markerPositions->push_back(p); } //std::cout << "INFO: Found " << markerPositions->size() << " markers." << std::endl; /* now the reply string is complete, perform crc checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return okay { returnValue = NDIOKAY; } else // return error in CRC { returnValue = NDICRCERROR; std::cout << "ERROR: receive_value != NDIOKAY" << std::endl; /* delete all marker positions because the received data contained an error */ markerPositions->clear(); } } // else /* cleanup and return */ m_TrackingDevice->Receive(&s, 1); // read the last linde feed (because the tracking system device is sometimes to slow to send it before we clear the buffer. In this case, the LF would remain in the receive buffer and be read as the first character of the next command m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::GenericCommand(const std::string command, const std::string* parameter) { NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from trackingsystem if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; std::string p; if (parameter != NULL) p = *parameter; else p = ""; /* send command */ std::string fullcommand; if (m_UseCRC == true) fullcommand = command + ":" + p; // command string format 1: with crc else fullcommand = command + " " + p; // command string format 2: without crc m_TrackingDevice->ClearReceiveBuffer(); // This is a workaround for a linux specific issue: // after sending the TSTART command and expecting an "okay" there are some unexpected bytes left in the buffer. // this issue is explained in bug 11825 returnValue = m_TrackingDevice->Send(&fullcommand, m_UseCRC); if (returnValue != NDIOKAY) // check for send error { m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove any reply return returnValue; } /* wait for the trackingsystem to process the command */ itksys::SystemTools::Delay(100); /* read and parse the reply from tracking device */ // the reply for a generic command can be OKAY or ERROR## // so we can use the generic parse method for these replies this->ParseOkayError(); return returnValue; } unsigned int mitk::NDIProtocol::ByteToNbBitsOn(char& c) const { if(c == '0') return 0; else if (c == '1' || c == '2' || c == '4' || c == '8') return 1; else if (c == '3' || c == '5' || c == '9' || c == '6' || c == 'A' || c == 'C') return 2; else if (c == '7' || c == 'B' || c == 'D' || c == 'E') return 3; else if (c == 'F') return 4; else return 0; } mitk::NDIErrorCode mitk::NDIProtocol::ParseOkayError() { NDIErrorCode returnValue = NDIUNKNOWNERROR; /* read reply from tracking device */ // the reply is expected to be OKAY or ERROR## // define reply strings std::string reply; m_TrackingDevice->Receive(&reply, 4); // read first 4 characters of reply /* Parse reply from tracking device */ static const std::string okay("OKAYA896"); // OKAY is static, so we can perform a static crc check static const std::string error("ERROR"); if (okay.compare(0, 4, reply) == 0) // check for "OKAY": compare first 4 characters from okay with reply { // OKAY was found, now check the CRC16 too m_TrackingDevice->Receive(&reply, 4); // read 4 hexadecimal characters for CRC16 if (okay.compare(4, 4, reply, 0, 4) == 0) // first 4 from new reply should match last 4 from okay returnValue = NDIOKAY; else returnValue = NDICRCERROR; } else if (error.compare(0, 4, reply) == 0) // check for "ERRO" { char b; // The ERROR reply is not static, so we can not use a static crc check. m_TrackingDevice->ReceiveByte(&b); // read next character ("R" from ERROR) reply += b; // to build complete reply string std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // something else, that we do not expect returnValue = NDIUNEXPECTEDREPLY; /* cleanup and return */ char b; m_TrackingDevice->ReceiveByte(&b); // read CR character m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::GetErrorCode(const std::string* input) { if (input->compare("01") == 0) return NDIINVALIDCOMMAND; else if (input->compare("02") == 0) return NDICOMMANDTOOLONG; else if (input->compare("03") == 0) return NDICOMMANDTOOSHORT; else if (input->compare("04") == 0) return NDICRCDOESNOTMATCH; else if (input->compare("05") == 0) return NDITIMEOUT; else if (input->compare("06") == 0) return NDIUNABLETOSETNEWCOMMPARAMETERS; else if (input->compare("07") == 0) return NDIINCORRECTNUMBEROFPARAMETERS; else if (input->compare("08") == 0) return NDIINVALIDPORTHANDLE; else if (input->compare("09") == 0) return NDIINVALIDTRACKINGPRIORITY; else if (input->compare("0A") == 0) return NDIINVALIDLED; else if (input->compare("0B") == 0) return NDIINVALIDLEDSTATE; else if (input->compare("0C") == 0) return NDICOMMANDINVALIDINCURRENTMODE; else if (input->compare("0D") == 0) return NDINOTOOLFORPORT; else if (input->compare("0E") == 0) return NDIPORTNOTINITIALIZED; // ... else if (input->compare("10") == 0) return NDISYSTEMNOTINITIALIZED; else if (input->compare("11") == 0) return NDIUNABLETOSTOPTRACKING; else if (input->compare("12") == 0) return NDIUNABLETOSTARTTRACKING; else if (input->compare("13") == 0) return NDIINITIALIZATIONFAILED; else if (input->compare("14") == 0) return NDIINVALIDVOLUMEPARAMETERS; else if (input->compare("16") == 0) return NDICANTSTARTDIAGNOSTICMODE; else if (input->compare("1B") == 0) return NDICANTINITIRDIAGNOSTICS; else if (input->compare("1F") == 0) return NDIFAILURETOWRITESROM; else if (input->compare("22") == 0) return NDIENABLEDTOOLSNOTSUPPORTED; else if (input->compare("23") == 0) return NDICOMMANDPARAMETEROUTOFRANGE; else if (input->compare("2A") == 0) return NDINOMEMORYAVAILABLE; else if (input->compare("2B") == 0) return NDIPORTHANDLENOTALLOCATED; else if (input->compare("2C") == 0) return NDIPORTHASBECOMEUNOCCUPIED; else if (input->compare("2D") == 0) return NDIOUTOFHANDLES; else if (input->compare("2E") == 0) return NDIINCOMPATIBLEFIRMWAREVERSIONS; else if (input->compare("2F") == 0) return NDIINVALIDPORTDESCRIPTION; else if (input->compare("32") == 0) return NDIINVALIDOPERATIONFORDEVICE; // ... else return NDIUNKNOWNERROR; } mitk::NDIErrorCode mitk::NDIProtocol::APIREV(std::string* revision) { if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking system /* send command */ std::string command; if (m_UseCRC) command = "APIREV:"; else command = "APIREV "; returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue != NDIOKAY) { /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } //wait for tracking system to compute the output //itksys::SystemTools::Delay(100); /* read number of handles returned */ std::string reply; m_TrackingDevice->Receive(&reply, 5); //look for ERROR // read first 5 characters of reply (error beginning of version information) static const std::string error("ERROR"); if (error.compare(0, 6, reply) == 0) // ERROR case { std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // no error, valid reply: expect something like: D.001.00450D4 (.. { std::string s; m_TrackingDevice->Receive(&s, 4); // read further reply += s; /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = NDIOKAY; else // return error in CRC returnValue = NDICRCERROR; } *revision = reply; m_TrackingDevice->ClearReceiveBuffer(); return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::SFLIST(std::string* info) { if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking system /* send command */ std::string command; if (m_UseCRC) command = "SFLIST:03"; else command = "SFLIST 03"; returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue != NDIOKAY) { /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } /* read number of handles returned */ std::string reply; m_TrackingDevice->Receive(&reply, 5); //look for "ERROR" static const std::string error("ERROR"); if (error.compare(0,6,reply) == 0) // ERROR case { std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else // no error, valid reply: expect numbers of devices in hex, and then info of each featured tracking volume { /* parse number of volumes from first character in hex */ std::stringstream converter; unsigned int numberOfVolumes = 0; converter << std::hex << reply[0]; // insert reply into stringstream converter >> numberOfVolumes; // extract number of handles as unsigned byte converter.clear(); // converter must be cleared to be reused converter.str(""); //reply currently contains the first 5 elements if (numberOfVolumes>0) { //for each featured volume for (unsigned int i = 0; iReceive(&s, 69);// 69 characters to get all dimensions plus two characters at the end: one reserved and one for metal resistance. reply += s; currentVolume += s; } else { //read to the end of the line from the last volume //(needed here, because if only one volume is supported, //then there is no lineending before CRC checksum std::string l; m_TrackingDevice->ReceiveLine(&l); reply += l; std::string s; m_TrackingDevice->Receive(&s, 73); //need total of 73 bytes for a volume reply += s; currentVolume += s; } //analyze volume here static const std::string standard = "0"; static const std::string pyramid = "4"; static const std::string spectraPyramid = "5"; static const std::string vicraVolume = "7"; static const std::string cube = "9"; static const std::string dome = "A"; if (currentVolume.compare(0,1,standard)==0) MITK_INFO<<"Standard volume supported \n"; else if (currentVolume.compare(0,1,pyramid)==0) MITK_INFO<<"Pyramid volume supported \n"; else if (currentVolume.compare(0,1,spectraPyramid)==0) MITK_INFO<<"Spectra pyramid volume supported \n"; else if (currentVolume.compare(0,1,vicraVolume)==0) MITK_INFO<<"Vicra volume supported \n"; else if (currentVolume.compare(0,1,cube)==0) MITK_INFO<<"Cube volume supported \n"; else if (currentVolume.compare(0,1,dome)==0) MITK_INFO<<"Dome volume supported \n"; else MITK_INFO<<"Message not understood!\n"; } } /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = NDIOKAY; else // return error in CRC returnValue = NDICRCERROR; } *info = reply; m_TrackingDevice->ClearReceiveBuffer(); return returnValue; } mitk::NDIErrorCode mitk::NDIProtocol::VSEL(mitk::NDITrackingVolume volume) { if (m_TrackingDevice == NULL) return TRACKINGDEVICENOTSET; NDIErrorCode returnValue = NDIUNKNOWNERROR; // return code for this function. Will be set according to reply from tracking system //get information about the order of volumes from tracking device. Then choose the number needed for VSEL by the output and parameter "device" unsigned int numberOfVolumes; mitk::NDITrackingDevice::NDITrackingVolumeContainerType volumes; mitk::NDITrackingDevice::TrackingVolumeDimensionType volumesDimensions; if (!m_TrackingDevice->GetSupportedVolumes(&numberOfVolumes, &volumes, &volumesDimensions)) return returnValue; //interested in volumes(!) if (volumes.empty()) return returnValue; //with the order within volumes we can define our needed parameter for VSEL //find the index where volumes[n] == device unsigned int index = 1; //the index for VSEL starts at 1 mitk::NDITrackingDevice::NDITrackingVolumeContainerType::iterator it = volumes.begin(); while (it != volumes.end()) { if ((*it) == volume) break; it++, index++; } if (it == volumes.end() || index > numberOfVolumes) //not found / volume not supported return NDIINVALIDOPERATIONFORDEVICE; //index now contains the information on which position the desired volume is situated /* send command */ std::string command; if (m_UseCRC) command = "VSEL:"; else command = "VSEL "; //add index to command std::stringstream s; s << index; command += s.str(); returnValue = m_TrackingDevice->Send(&command, m_UseCRC); if (returnValue != NDIOKAY) { /* cleanup and return */ m_TrackingDevice->ClearReceiveBuffer(); // flush the buffer to remove the remaining carriage return or unknown/unexpected reply return returnValue; } /* read number of handles returned */ std::string reply; m_TrackingDevice->Receive(&reply, 4); //look for "ERROR" or "OKAY" static const std::string error("ERRO"); if (error.compare(reply) == 0) // ERROR case { std::string s; m_TrackingDevice->Receive(&s, 1); //get the last "R" in "ERROR" reply += s; std::string errorcode; m_TrackingDevice->Receive(&errorcode, 2); // now read 2 bytes error code reply += errorcode; // build complete reply string /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = this->GetErrorCode(&errorcode); else // return error in CRC returnValue = NDICRCERROR; } else { /* perform CRC checking */ std::string expectedCRC = m_TrackingDevice->CalcCRC(&reply); // calculate crc for received reply string std::string readCRC; // read attached crc value m_TrackingDevice->Receive(&readCRC, 4); // CRC16 is 2 bytes long, which is transmitted as 4 hexadecimal digits if (expectedCRC == readCRC) // if the read CRC is correct, return normal error code returnValue = NDIOKAY; else // return error in CRC returnValue = NDICRCERROR; } m_TrackingDevice->ClearReceiveBuffer(); return returnValue; } diff --git a/Modules/IGT/IGTTrackingDevices/mitkNDITrackingDevice.cpp b/Modules/IGT/IGTTrackingDevices/mitkNDITrackingDevice.cpp index 92221dc306..cd4c9a57b3 100644 --- a/Modules/IGT/IGTTrackingDevices/mitkNDITrackingDevice.cpp +++ b/Modules/IGT/IGTTrackingDevices/mitkNDITrackingDevice.cpp @@ -1,1321 +1,1325 @@ /*=================================================================== 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 "mitkNDITrackingDevice.h" #include "mitkIGTTimeStamp.h" #include #include #include typedef itk::MutexLockHolder MutexLockHolder; const unsigned char CR = 0xD; // == '\r' - carriage return const unsigned char LF = 0xA; // == '\n' - line feed mitk::NDITrackingDevice::NDITrackingDevice() : TrackingDevice(),m_DeviceName(""), m_PortNumber(mitk::SerialCommunication::COM5), m_BaudRate(mitk::SerialCommunication::BaudRate9600), m_DataBits(mitk::SerialCommunication::DataBits8), m_Parity(mitk::SerialCommunication::None), m_StopBits(mitk::SerialCommunication::StopBits1), m_HardwareHandshake(mitk::SerialCommunication::HardwareHandshakeOff), m_NDITrackingVolume(Standard), m_IlluminationActivationRate(Hz20), m_DataTransferMode(TX), m_6DTools(), m_ToolsMutex(NULL), m_SerialCommunication(NULL), m_SerialCommunicationMutex(NULL), m_DeviceProtocol(NULL), m_MultiThreader(NULL), m_ThreadID(0), m_OperationMode(ToolTracking6D), m_MarkerPointsMutex(NULL), m_MarkerPoints() { m_Data = mitk::DeviceDataUnspecified; m_6DTools.clear(); m_SerialCommunicationMutex = itk::FastMutexLock::New(); m_DeviceProtocol = NDIProtocol::New(); m_DeviceProtocol->SetTrackingDevice(this); m_DeviceProtocol->UseCRCOn(); m_MultiThreader = itk::MultiThreader::New(); m_ToolsMutex = itk::FastMutexLock::New(); m_MarkerPointsMutex = itk::FastMutexLock::New(); m_MarkerPoints.reserve(50); // a maximum of 50 marker positions can be reported by the tracking device } bool mitk::NDITrackingDevice::UpdateTool(mitk::TrackingTool* tool) { if (this->GetState() != Setup) { mitk::NDIPassiveTool* ndiTool = dynamic_cast(tool); if (ndiTool == NULL) return false; std::string portHandle = ndiTool->GetPortHandle(); //return false if the SROM Data has not been set if (ndiTool->GetSROMData() == NULL) return false; NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->PVWR(&portHandle, ndiTool->GetSROMData(), ndiTool->GetSROMDataLength()); if (returnvalue != NDIOKAY) return false; returnvalue = m_DeviceProtocol->PINIT(&portHandle); if (returnvalue != NDIOKAY) return false; returnvalue = m_DeviceProtocol->PENA(&portHandle, ndiTool->GetTrackingPriority()); // Enable tool if (returnvalue != NDIOKAY) return false; return true; } else { return false; } } +void mitk::NDITrackingDevice::SetRotationMode(RotationMode r) +{ + m_RotationMode = r; +} mitk::NDITrackingDevice::~NDITrackingDevice() { /* stop tracking and disconnect from tracking device */ if (GetState() == Tracking) { this->StopTracking(); } if (GetState() == Ready) { this->CloseConnection(); } /* cleanup tracking thread */ if ((m_ThreadID != 0) && (m_MultiThreader.IsNotNull())) { m_MultiThreader->TerminateThread(m_ThreadID); } m_MultiThreader = NULL; /* free serial communication interface */ if (m_SerialCommunication.IsNotNull()) { m_SerialCommunication->ClearReceiveBuffer(); m_SerialCommunication->ClearSendBuffer(); m_SerialCommunication->CloseConnection(); m_SerialCommunication = NULL; } } void mitk::NDITrackingDevice::SetPortNumber(const PortNumber _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting PortNumber to " << _arg); if (this->m_PortNumber != _arg) { this->m_PortNumber = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetDeviceName(std::string _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting eviceName to " << _arg); if (this->m_DeviceName != _arg) { this->m_DeviceName = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetBaudRate(const BaudRate _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting BaudRate to " << _arg); if (this->m_BaudRate != _arg) { this->m_BaudRate = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetDataBits(const DataBits _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting DataBits to " << _arg); if (this->m_DataBits != _arg) { this->m_DataBits = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetParity(const Parity _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting Parity to " << _arg); if (this->m_Parity != _arg) { this->m_Parity = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetStopBits(const StopBits _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting StopBits to " << _arg); if (this->m_StopBits != _arg) { this->m_StopBits = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetHardwareHandshake(const HardwareHandshake _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting HardwareHandshake to " << _arg); if (this->m_HardwareHandshake != _arg) { this->m_HardwareHandshake = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetIlluminationActivationRate(const IlluminationActivationRate _arg) { if (this->GetState() == Tracking) return; itkDebugMacro("setting IlluminationActivationRate to " << _arg); if (this->m_IlluminationActivationRate != _arg) { this->m_IlluminationActivationRate = _arg; this->Modified(); if (this->GetState() == Ready) // if the connection to the tracking system is established, send the new rate to the tracking device too m_DeviceProtocol->IRATE(this->m_IlluminationActivationRate); } } void mitk::NDITrackingDevice::SetDataTransferMode(const DataTransferMode _arg) { itkDebugMacro("setting DataTransferMode to " << _arg); if (this->m_DataTransferMode != _arg) { this->m_DataTransferMode = _arg; this->Modified(); } } mitk::NDIErrorCode mitk::NDITrackingDevice::Send(const std::string* input, bool addCRC) { if (input == NULL) return SERIALSENDERROR; std::string message; if (addCRC == true) message = *input + CalcCRC(input) + std::string(1, CR); else message = *input + std::string(1, CR); //unsigned int messageLength = message.length() + 1; // +1 for CR // Clear send buffer this->ClearSendBuffer(); // Send the date to the device MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex long returnvalue = m_SerialCommunication->Send(message); if (returnvalue == 0) return SERIALSENDERROR; else return NDIOKAY; } mitk::NDIErrorCode mitk::NDITrackingDevice::Receive(std::string* answer, unsigned int numberOfBytes) { if (answer == NULL) return SERIALRECEIVEERROR; MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex long returnvalue = m_SerialCommunication->Receive(*answer, numberOfBytes); // never read more bytes than the device has send, the function will block until enough bytes are send... if (returnvalue == 0) return SERIALRECEIVEERROR; else return NDIOKAY; } mitk::NDIErrorCode mitk::NDITrackingDevice::ReceiveByte(char* answer) { if (answer == NULL) return SERIALRECEIVEERROR; std::string m; MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex long returnvalue = m_SerialCommunication->Receive(m, 1); if ((returnvalue == 0) ||(m.size() != 1)) return SERIALRECEIVEERROR; *answer = m.at(0); return NDIOKAY; } mitk::NDIErrorCode mitk::NDITrackingDevice::ReceiveLine(std::string* answer) { if (answer == NULL) return SERIALRECEIVEERROR; std::string m; MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex do { long returnvalue = m_SerialCommunication->Receive(m, 1); if ((returnvalue == 0) ||(m.size() != 1)) return SERIALRECEIVEERROR; *answer += m; } while (m.at(0) != LF); return NDIOKAY; } void mitk::NDITrackingDevice::ClearSendBuffer() { MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex m_SerialCommunication->ClearSendBuffer(); } void mitk::NDITrackingDevice::ClearReceiveBuffer() { MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex m_SerialCommunication->ClearReceiveBuffer(); } const std::string mitk::NDITrackingDevice::CalcCRC(const std::string* input) { if (input == NULL) return ""; /* the crc16 calculation code is taken from the NDI API guide example code section */ static int oddparity[16] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}; unsigned int data; // copy of the input string's current character unsigned int crcValue = 0; // the crc value is stored here unsigned int* puCRC16 = &crcValue; // the algorithm uses a pointer to crcValue, so it's easier to provide that than to change the algorithm for (unsigned int i = 0; i < input->length(); i++) { data = (*input)[i]; data = (data ^ (*(puCRC16) & 0xff)) & 0xff; *puCRC16 >>= 8; if (oddparity[data & 0x0f] ^ oddparity[data >> 4]) { *(puCRC16) ^= 0xc001; } data <<= 6; *puCRC16 ^= data; data <<= 1; *puCRC16 ^= data; } // crcValue contains now the CRC16 value. Convert it to a string and return it char returnvalue[13]; sprintf(returnvalue,"%04X", crcValue); // 4 hexadecimal digit with uppercase format return std::string(returnvalue); } bool mitk::NDITrackingDevice::OpenConnection() { //this->m_ModeMutex->Lock(); if (this->GetState() != Setup) { this->SetErrorMessage("Can only try to open the connection if in setup mode"); return false; } // m_SerialCommunication = mitk::SerialCommunication::New(); /* init local com port to standard com settings for a NDI tracking device: 9600 baud, 8 data bits, no parity, 1 stop bit, no hardware handshake */ if (m_DeviceName.empty()) m_SerialCommunication->SetPortNumber(m_PortNumber); else m_SerialCommunication->SetDeviceName(m_DeviceName); m_SerialCommunication->SetBaudRate(mitk::SerialCommunication::BaudRate9600); m_SerialCommunication->SetDataBits(mitk::SerialCommunication::DataBits8); m_SerialCommunication->SetParity(mitk::SerialCommunication::None); m_SerialCommunication->SetStopBits(mitk::SerialCommunication::StopBits1); m_SerialCommunication->SetSendTimeout(5000); m_SerialCommunication->SetReceiveTimeout(5000); if (m_SerialCommunication->OpenConnection() == 0) // 0 == ERROR_VALUE { this->SetErrorMessage("Can not open serial port"); m_SerialCommunication->CloseConnection(); m_SerialCommunication = NULL; return false; } /* Reset Tracking device by sending a serial break for 500ms */ m_SerialCommunication->SendBreak(400); /* Read answer from tracking device (RESETBE6F) */ static const std::string reset("RESETBE6F\r"); std::string answer = ""; this->Receive(&answer, reset.length()); // read answer (should be RESETBE6F) this->ClearReceiveBuffer(); // flush the receive buffer of all remaining data (carriage return, strings other than reset if (reset.compare(answer) != 0) // check for RESETBE6F { this->SetErrorMessage("Hardware Reset of tracking device did not work"); if (m_SerialCommunication.IsNotNull()) { m_SerialCommunication->CloseConnection(); m_SerialCommunication = NULL; } return false; } /* Now the tracking device is reset, start initialization */ NDIErrorCode returnvalue; /* set device com settings to new values and wait for the device to change them */ returnvalue = m_DeviceProtocol->COMM(m_BaudRate, m_DataBits, m_Parity, m_StopBits, m_HardwareHandshake); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not set comm settings in trackingdevice"); return false; } //after changing COMM wait at least 100ms according to NDI Api documentation page 31 itksys::SystemTools::Delay(500); /* now change local com settings accordingly */ m_SerialCommunication->CloseConnection(); m_SerialCommunication->SetBaudRate(m_BaudRate); m_SerialCommunication->SetDataBits(m_DataBits); m_SerialCommunication->SetParity(m_Parity); m_SerialCommunication->SetStopBits(m_StopBits); m_SerialCommunication->SetHardwareHandshake(m_HardwareHandshake); m_SerialCommunication->SetSendTimeout(5000); m_SerialCommunication->SetReceiveTimeout(5000); m_SerialCommunication->OpenConnection(); /* initialize the tracking device */ returnvalue = m_DeviceProtocol->INIT(); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not initialize the tracking device"); return false; } if (this->GetType() == mitk::TrackingSystemNotSpecified) // if the type of tracking device is not specified, try to query the connected device { mitk::TrackingDeviceType deviceType; returnvalue = m_DeviceProtocol->VER(deviceType); if ((returnvalue != NDIOKAY) || (deviceType == mitk::TrackingSystemNotSpecified)) { this->SetErrorMessage("Could not determine tracking device type. Please set manually and try again."); return false; } this->SetType(deviceType); } /**** Optional Polaris specific code, Work in progress // start diagnostic mode returnvalue = m_DeviceProtocol->DSTART(); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not start diagnostic mode"); return false; } else // we are in diagnostic mode { // initialize extensive IR checking returnvalue = m_DeviceProtocol->IRINIT(); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not initialize intense infrared light checking"); return false; } bool intenseIR = false; returnvalue = m_DeviceProtocol->IRCHK(&intenseIR); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not execute intense infrared light checking"); return false; } if (intenseIR == true) // do something - warn the user, raise exception, write to protocol or similar std::cout << "Warning: Intense infrared light detected. Accurate tracking will probably not be possible.\n"; // stop diagnictic mode returnvalue = m_DeviceProtocol->DSTOP(); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not stop diagnostic mode"); return false; } } *** end of optional polaris code ***/ /** * now add tools to the tracking system **/ /* First, check if the tracking device has port handles that need to be freed and free them */ returnvalue = FreePortHandles(); // non-critical, therefore no error handling /** * POLARIS: initialize the tools that were added manually **/ { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex std::string portHandle; Tool6DContainerType::iterator endIt = m_6DTools.end(); for(Tool6DContainerType::iterator it = m_6DTools.begin(); it != endIt; ++it) { /* get a port handle for the tool */ returnvalue = m_DeviceProtocol->PHRQ(&portHandle); if (returnvalue == NDIOKAY) { (*it)->SetPortHandle(portHandle.c_str()); /* now write the SROM file of the tool to the tracking system using PVWR */ if (this->m_Data.Line == NDIPolaris) { returnvalue = m_DeviceProtocol->PVWR(&portHandle, (*it)->GetSROMData(), (*it)->GetSROMDataLength()); if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not write SROM file for tool '") + (*it)->GetToolName() + std::string("' to tracking device")).c_str()); return false; } returnvalue = m_DeviceProtocol->PINIT(&portHandle); if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not initialize tool '") + (*it)->GetToolName()).c_str()); return false; } if ((*it)->IsEnabled() == true) { returnvalue = m_DeviceProtocol->PENA(&portHandle, (*it)->GetTrackingPriority()); // Enable tool if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not enable port '") + portHandle + std::string("' for tool '")+ (*it)->GetToolName() + std::string("'")).c_str()); return false; } } } } } } // end of toolsmutexlockholder scope /* check for wired tools and add them too */ if (this->DiscoverWiredTools() == false) // query the tracking device for wired tools and add them to our tool list return false; // \TODO: could we continue anyways? /*POLARIS: set the illuminator activation rate */ if (this->m_Data.Line == NDIPolaris) { returnvalue = m_DeviceProtocol->IRATE(this->m_IlluminationActivationRate); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not set the illuminator activation rate"); return false; } } /* finish - now all tools should be added, initialized and enabled, so that tracking can be started */ this->SetState(Ready); this->SetErrorMessage(""); return true; } bool mitk::NDITrackingDevice::InitializeWiredTools() { NDIErrorCode returnvalue; std::string portHandle; returnvalue = m_DeviceProtocol->PHSR(OCCUPIED, &portHandle); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not obtain a list of port handles that are connected"); return false; // ToDo: Is this a fatal error? } /* if there are port handles that need to be initialized, initialize them. Furthermore instantiate tools for each handle that has no tool yet. */ std::string ph; for (unsigned int i = 0; i < portHandle.size(); i += 2) { ph = portHandle.substr(i, 2); mitk::NDIPassiveTool* pt = this->GetInternalTool(ph); if ( pt == NULL) // if we don't have a tool, something is wrong. Tools should be discovered first by calling DiscoverWiredTools() continue; if (pt->GetSROMData() == NULL) continue; returnvalue = m_DeviceProtocol->PVWR(&ph, pt->GetSROMData(), pt->GetSROMDataLength()); if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not write SROM file for tool '") + pt->GetToolName() + std::string("' to tracking device")).c_str()); return false; } returnvalue = m_DeviceProtocol->PINIT(&ph); if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not initialize tool '") + pt->GetToolName()).c_str()); return false; } if (pt->IsEnabled() == true) { returnvalue = m_DeviceProtocol->PENA(&ph, pt->GetTrackingPriority()); // Enable tool if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not enable port '") + portHandle + std::string("' for tool '")+ pt->GetToolName() + std::string("'")).c_str()); return false; } } } return true; } mitk::TrackingDeviceType mitk::NDITrackingDevice::TestConnection() { if (this->GetState() != Setup) { return mitk::TrackingSystemNotSpecified; } m_SerialCommunication = mitk::SerialCommunication::New(); //m_DeviceProtocol = mitk::NDIProtocol::New(); //m_DeviceProtocol->SetTrackingDevice(this); //m_DeviceProtocol->UseCRCOn(); /* init local com port to standard com settings for a NDI tracking device: 9600 baud, 8 data bits, no parity, 1 stop bit, no hardware handshake */ if (m_DeviceName.empty()) m_SerialCommunication->SetPortNumber(m_PortNumber); else m_SerialCommunication->SetDeviceName(m_DeviceName); m_SerialCommunication->SetBaudRate(mitk::SerialCommunication::BaudRate9600); m_SerialCommunication->SetDataBits(mitk::SerialCommunication::DataBits8); m_SerialCommunication->SetParity(mitk::SerialCommunication::None); m_SerialCommunication->SetStopBits(mitk::SerialCommunication::StopBits1); m_SerialCommunication->SetSendTimeout(5000); m_SerialCommunication->SetReceiveTimeout(5000); if (m_SerialCommunication->OpenConnection() == 0) // error { m_SerialCommunication = NULL; return mitk::TrackingSystemNotSpecified; } /* Reset Tracking device by sending a serial break for 500ms */ m_SerialCommunication->SendBreak(400); /* Read answer from tracking device (RESETBE6F) */ static const std::string reset("RESETBE6F\r"); std::string answer = ""; this->Receive(&answer, reset.length()); // read answer (should be RESETBE6F) this->ClearReceiveBuffer(); // flush the receive buffer of all remaining data (carriage return, strings other than reset if (reset.compare(answer) != 0) // check for RESETBE6F { this->SetErrorMessage("Hardware Reset of tracking device did not work"); m_SerialCommunication->CloseConnection(); m_SerialCommunication = NULL; return mitk::TrackingSystemNotSpecified; } /* Now the tracking device is reset, start initialization */ NDIErrorCode returnvalue; /* initialize the tracking device */ //returnvalue = m_DeviceProtocol->INIT(); //if (returnvalue != NDIOKAY) //{ // this->SetErrorMessage("Could not initialize the tracking device"); // return mitk::TrackingSystemNotSpecified; //} mitk::TrackingDeviceType deviceType; returnvalue = m_DeviceProtocol->VER(deviceType); if ((returnvalue != NDIOKAY) || (deviceType == mitk::TrackingSystemNotSpecified)) { m_SerialCommunication = NULL; return mitk::TrackingSystemNotSpecified; } m_SerialCommunication = NULL; return deviceType; } bool mitk::NDITrackingDevice::CloseConnection() { if (this->GetState() != Setup) { //init before closing to force the field generator from aurora to switch itself off m_DeviceProtocol->INIT(); /* close the serial connection */ m_SerialCommunication->CloseConnection(); /* invalidate all tools */ this->InvalidateAll(); /* return to setup mode */ this->SetState(Setup); this->SetErrorMessage(""); m_SerialCommunication = NULL; } return true; } ITK_THREAD_RETURN_TYPE mitk::NDITrackingDevice::ThreadStartTracking(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } NDITrackingDevice *trackingDevice = (NDITrackingDevice*)pInfo->UserData; if (trackingDevice != NULL) { if (trackingDevice->GetOperationMode() == ToolTracking6D) trackingDevice->TrackTools(); // call TrackTools() from the original object else if (trackingDevice->GetOperationMode() == MarkerTracking3D) trackingDevice->TrackMarkerPositions(); // call TrackMarkerPositions() from the original object else if (trackingDevice->GetOperationMode() == ToolTracking5D) trackingDevice->TrackMarkerPositions(); // call TrackMarkerPositions() from the original object else if (trackingDevice->GetOperationMode() == HybridTracking) { trackingDevice->TrackToolsAndMarkers(); } } trackingDevice->m_ThreadID = 0; // erase thread id, now that this thread will end. return ITK_THREAD_RETURN_VALUE; } bool mitk::NDITrackingDevice::StartTracking() { if (this->GetState() != Ready) return false; 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(); m_TrackingFinishedMutex->Unlock(); // transfer the execution rights to tracking thread m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartTracking, this); // start a new thread that executes the TrackTools() method mitk::IGTTimeStamp::GetInstance()->Start(this); return true; } void mitk::NDITrackingDevice::TrackTools() { if (this->GetState() != Tracking) return; NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->TSTART(); if (returnvalue != NDIOKAY) return; /* 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)) { if (this->m_DataTransferMode == TX) { returnvalue = this->m_DeviceProtocol->TX(); if (!((returnvalue == NDIOKAY) || (returnvalue == NDICRCERROR) || (returnvalue == NDICRCDOESNOTMATCH))) // right now, do not stop on crc errors break; } else { returnvalue = this->m_DeviceProtocol->BX(); if (returnvalue != NDIOKAY) break; } /* Update the local copy of m_StopTracking */ this->m_StopTrackingMutex->Lock(); localStopTracking = m_StopTracking; this->m_StopTrackingMutex->Unlock(); } /* StopTracking was called, thus the mode should be changed back to Ready now that the tracking loop has ended. */ returnvalue = m_DeviceProtocol->TSTOP(); if (returnvalue != NDIOKAY) { /* insert error handling/notification here */ ; // how can this thread tell the application, that an error has occurred? } return; // returning from this function (and ThreadStartTracking()) this will end the thread and transfer control back to main thread by releasing trackingFinishedLockHolder } void mitk::NDITrackingDevice::TrackMarkerPositions() { if (m_OperationMode == ToolTracking6D) return; if (this->GetState() != Tracking) return; NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->DSTART(); // Start Diagnostic Mode if (returnvalue != NDIOKAY) return; 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)) { m_MarkerPointsMutex->Lock(); // lock points data structure returnvalue = this->m_DeviceProtocol->POS3D(&m_MarkerPoints); // update points data structure with new position data from tracking device m_MarkerPointsMutex->Unlock(); if (!((returnvalue == NDIOKAY) || (returnvalue == NDICRCERROR) || (returnvalue == NDICRCDOESNOTMATCH))) // right now, do not stop on crc errors { std::cout << "Error in POS3D: could not read data. Possibly no markers present." << std::endl; } /* Update the local copy of m_StopTracking */ this->m_StopTrackingMutex->Lock(); localStopTracking = m_StopTracking; this->m_StopTrackingMutex->Unlock(); itksys::SystemTools::Delay(1); } /* StopTracking was called, thus the mode should be changed back to Ready now that the tracking loop has ended. */ returnvalue = m_DeviceProtocol->DSTOP(); if (returnvalue != NDIOKAY) return; // how can this thread tell the application, that an error has occured? this->SetState(Ready); return; // returning from this function (and ThreadStartTracking()) this will end the thread } void mitk::NDITrackingDevice::TrackToolsAndMarkers() { if (m_OperationMode != HybridTracking) return; NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->TSTART(); // Start Diagnostic Mode if (returnvalue != NDIOKAY) return; 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)) { m_MarkerPointsMutex->Lock(); // lock points data structure returnvalue = this->m_DeviceProtocol->TX(true, &m_MarkerPoints); // update points data structure with new position data from tracking device m_MarkerPointsMutex->Unlock(); if (!((returnvalue == NDIOKAY) || (returnvalue == NDICRCERROR) || (returnvalue == NDICRCDOESNOTMATCH))) // right now, do not stop on crc errors { std::cout << "Error in TX: could not read data. Possibly no markers present." << std::endl; } /* Update the local copy of m_StopTracking */ this->m_StopTrackingMutex->Lock(); localStopTracking = m_StopTracking; this->m_StopTrackingMutex->Unlock(); } /* StopTracking was called, thus the mode should be changed back to Ready now that the tracking loop has ended. */ returnvalue = m_DeviceProtocol->TSTOP(); if (returnvalue != NDIOKAY) return; // how can this thread tell the application, that an error has occurred? this->SetState(Ready); return; // returning from this function (and ThreadStartTracking()) this will end the thread } mitk::TrackingTool* mitk::NDITrackingDevice::GetTool(unsigned int toolNumber) const { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex if (toolNumber < m_6DTools.size()) return m_6DTools.at(toolNumber); return NULL; } mitk::TrackingTool* mitk::NDITrackingDevice::GetToolByName(std::string name) const { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex Tool6DContainerType::const_iterator end = m_6DTools.end(); for (Tool6DContainerType::const_iterator iterator = m_6DTools.begin(); iterator != end; ++iterator) if (name.compare((*iterator)->GetToolName()) == 0) return *iterator; return NULL; } mitk::NDIPassiveTool* mitk::NDITrackingDevice::GetInternalTool(std::string portHandle) { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex Tool6DContainerType::iterator end = m_6DTools.end(); for (Tool6DContainerType::iterator iterator = m_6DTools.begin(); iterator != end; ++iterator) if (portHandle.compare((*iterator)->GetPortHandle()) == 0) return *iterator; return NULL; } unsigned int mitk::NDITrackingDevice::GetToolCount() const { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex return m_6DTools.size(); } bool mitk::NDITrackingDevice::Beep(unsigned char count) { if (this->GetState() != Setup) { return (m_DeviceProtocol->BEEP(count) == NDIOKAY); } else { return false; } } mitk::TrackingTool* mitk::NDITrackingDevice::AddTool( const char* toolName, const char* fileName, TrackingPriority p /*= NDIPassiveTool::Dynamic*/ ) { mitk::NDIPassiveTool::Pointer t = mitk::NDIPassiveTool::New(); if (t->LoadSROMFile(fileName) == false) return NULL; t->SetToolName(toolName); t->SetTrackingPriority(p); if (this->InternalAddTool(t) == false) return NULL; return t.GetPointer(); } bool mitk::NDITrackingDevice::InternalAddTool(mitk::NDIPassiveTool* tool) { if (tool == NULL) return false; NDIPassiveTool::Pointer p = tool; /* if the connection to the tracking device is already established, add the new tool to the device now */ if (this->GetState() == Ready) { /* get a port handle for the tool */ std::string newPortHandle; NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->PHRQ(&newPortHandle); if (returnvalue == NDIOKAY) { p->SetPortHandle(newPortHandle.c_str()); /* now write the SROM file of the tool to the tracking system using PVWR */ returnvalue = m_DeviceProtocol->PVWR(&newPortHandle, p->GetSROMData(), p->GetSROMDataLength()); if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not write SROM file for tool '") + p->GetToolName() + std::string("' to tracking device")).c_str()); return false; } /* initialize the port handle */ returnvalue = m_DeviceProtocol->PINIT(&newPortHandle); if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not initialize port '") + newPortHandle + std::string("' for tool '")+ p->GetToolName() + std::string("'")).c_str()); return false; } /* enable the port handle */ if (p->IsEnabled() == true) { returnvalue = m_DeviceProtocol->PENA(&newPortHandle, p->GetTrackingPriority()); // Enable tool if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not enable port '") + newPortHandle + std::string("' for tool '")+ p->GetToolName() + std::string("'")).c_str()); return false; } } } /* now that the tool is added to the device, add it to list too */ m_ToolsMutex->Lock(); this->m_6DTools.push_back(p); m_ToolsMutex->Unlock(); this->Modified(); return true; } else if (this->GetState() == Setup) { /* In Setup mode, we only add it to the list, so that OpenConnection() can add it later */ m_ToolsMutex->Lock(); this->m_6DTools.push_back(p); m_ToolsMutex->Unlock(); this->Modified(); return true; } else // in Tracking mode, no tools can be added return false; } bool mitk::NDITrackingDevice::RemoveTool(mitk::TrackingTool* tool) { mitk::NDIPassiveTool* ndiTool = dynamic_cast(tool); if (ndiTool == NULL) return false; std::string portHandle = ndiTool->GetPortHandle(); /* a valid portHandle has length 2. If a valid handle exists, the tool is already added to the tracking device, so we have to remove it there if the connection to the tracking device has already been established. */ if ((portHandle.length() == 2) && (this->GetState() == Ready)) // do not remove a tool in tracking mode { NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->PHF(&portHandle); if (returnvalue != NDIOKAY) return false; /* Now that the tool is removed from the tracking device, remove it from our tool list too */ MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex (scope is inside the if-block Tool6DContainerType::iterator end = m_6DTools.end(); for (Tool6DContainerType::iterator iterator = m_6DTools.begin(); iterator != end; ++iterator) { if (iterator->GetPointer() == ndiTool) { m_6DTools.erase(iterator); this->Modified(); return true; } } return false; } else if (this->GetState() == Setup) // in Setup Mode, we are not connected to the tracking device, so we can just remove the tool from the tool list { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex Tool6DContainerType::iterator end = m_6DTools.end(); for (Tool6DContainerType::iterator iterator = m_6DTools.begin(); iterator != end; ++iterator) { if ((*iterator).GetPointer() == ndiTool) { m_6DTools.erase(iterator); this->Modified(); return true; } } return false; } return false; } void mitk::NDITrackingDevice::InvalidateAll() { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex Tool6DContainerType::iterator end = m_6DTools.end(); for (Tool6DContainerType::iterator iterator = m_6DTools.begin(); iterator != end; ++iterator) (*iterator)->SetDataValid(false); } bool mitk::NDITrackingDevice::SetOperationMode(OperationMode mode) { if (GetState() == Tracking) return false; m_OperationMode = mode; return true; } mitk::OperationMode mitk::NDITrackingDevice::GetOperationMode() { return m_OperationMode; } bool mitk::NDITrackingDevice::GetMarkerPositions(MarkerPointContainerType* markerpositions) { m_MarkerPointsMutex->Lock(); *markerpositions = m_MarkerPoints; // copy the internal vector to the one provided m_MarkerPointsMutex->Unlock(); return (markerpositions->size() != 0) ; } bool mitk::NDITrackingDevice::DiscoverWiredTools() { /* First, check for disconnected tools and remove them */ this->FreePortHandles(); /* check for new tools, add and initialize them */ NDIErrorCode returnvalue; std::string portHandle; returnvalue = m_DeviceProtocol->PHSR(OCCUPIED, &portHandle); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not obtain a list of port handles that are connected"); return false; // ToDo: Is this a fatal error? } /* if there are port handles that need to be initialized, initialize them. Furthermore instantiate tools for each handle that has no tool yet. */ std::string ph; /* we need to remember the ports which are occupied to be able to readout the serial numbers of the connected tools later */ std::vector occupiedPorts = std::vector(); int numberOfToolsAtStart = this->GetToolCount(); //also remember the number of tools at start to identify the automatically detected tools later for (unsigned int i = 0; i < portHandle.size(); i += 2) { ph = portHandle.substr(i, 2); if (this->GetInternalTool(ph) != NULL) // if we already have a tool with this handle continue; // then skip the initialization //instantiate an object for each tool that is connected mitk::NDIPassiveTool::Pointer newTool = mitk::NDIPassiveTool::New(); newTool->SetPortHandle(ph.c_str()); newTool->SetTrackingPriority(mitk::NDIPassiveTool::Dynamic); //set a name for identification newTool->SetToolName((std::string("Port ") + ph).c_str()); returnvalue = m_DeviceProtocol->PINIT(&ph); if (returnvalue != NDIINITIALIZATIONFAILED) //if the initialization failed (AURORA) it can not be enabled. A srom file will have to be specified manually first. Still return true to be able to continue { if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not initialize port '") + ph + std::string("' for tool '")+ newTool->GetToolName() + std::string("'")).c_str()); return false; } /* enable the port handle */ returnvalue = m_DeviceProtocol->PENA(&ph, newTool->GetTrackingPriority()); // Enable tool if (returnvalue != NDIOKAY) { this->SetErrorMessage((std::string("Could not enable port '") + ph + std::string("' for tool '")+ newTool->GetToolName() + std::string("'")).c_str()); return false; } } //we have to temporarily unlock m_ModeMutex here to avoid a deadlock with another lock inside InternalAddTool() if (this->InternalAddTool(newTool) == false) this->SetErrorMessage("Error while adding new tool"); else occupiedPorts.push_back(i); } // after initialization readout serial numbers of automatically detected tools for (unsigned int i = 0; i < occupiedPorts.size(); i++) { ph = portHandle.substr(occupiedPorts.at(i), 2); std::string portInfo; NDIErrorCode returnvaluePort = m_DeviceProtocol->PHINF(ph, &portInfo); if ((returnvaluePort==NDIOKAY) && (portInfo.size()>31)) dynamic_cast(this->GetTool(i+numberOfToolsAtStart))->SetSerialNumber(portInfo.substr(23,8)); itksys::SystemTools::Delay(10); } return true; } mitk::NDIErrorCode mitk::NDITrackingDevice::FreePortHandles() { /* first search for port handles that need to be freed: e.g. because of a reset of the tracking system */ NDIErrorCode returnvalue = NDIOKAY; std::string portHandle; returnvalue = m_DeviceProtocol->PHSR(FREED, &portHandle); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not obtain a list of port handles that need to be freed"); return returnvalue; // ToDo: Is this a fatal error? } /* if there are port handles that need to be freed, free them */ if (portHandle.empty() == true) return returnvalue; std::string ph; for (unsigned int i = 0; i < portHandle.size(); i += 2) { ph = portHandle.substr(i, 2); mitk::NDIPassiveTool* t = this->GetInternalTool(ph); if (t != NULL) // if we have a tool for the port handle that needs to be freed { if (this->RemoveTool(t) == false) // remove it (this will free the port too) returnvalue = NDIERROR; } else // we don't have a tool, the port handle exists only in the tracking device { returnvalue = m_DeviceProtocol->PHF(&ph); // free it there // What to do if port handle could not be freed? This seems to be a non critical error if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not free all port handles"); // return false; // could not free all Handles } } } return returnvalue; } int mitk::NDITrackingDevice::GetMajorFirmwareRevisionNumber() { std::string revision; if (m_DeviceProtocol->APIREV(&revision) != mitk::NDIOKAY || revision.empty() || (revision.size() != 9) ) { this->SetErrorMessage("Could not receive firmware revision number!"); return 0; } const std::string majrevno = revision.substr(2,3); //cut out "004" from "D.004.001" return std::atoi(majrevno.c_str()); } const char* mitk::NDITrackingDevice::GetFirmwareRevisionNumber() { static std::string revision; if (m_DeviceProtocol->APIREV(&revision) != mitk::NDIOKAY || revision.empty() || (revision.size() != 9) ) { this->SetErrorMessage("Could not receive firmware revision number!"); revision = ""; return revision.c_str(); } return revision.c_str(); } bool mitk::NDITrackingDevice::GetSupportedVolumes(unsigned int* numberOfVolumes, mitk::NDITrackingDevice::NDITrackingVolumeContainerType* volumes, mitk::NDITrackingDevice::TrackingVolumeDimensionType* volumesDimensions) { if (numberOfVolumes == NULL || volumes == NULL || volumesDimensions == NULL) return false; static std::string info; if (m_DeviceProtocol->SFLIST(&info) != mitk::NDIOKAY || info.empty()) { this->SetErrorMessage("Could not receive tracking volume information of tracking system!"); return false; } /*info contains the following: (+n times:) */ (*numberOfVolumes) = (unsigned int) std::atoi(info.substr(0,1).c_str()); for (unsigned int i=0; i<(*numberOfVolumes); i++) { //e.g. for cube: "9-025000+025000-025000+025000-055000-005000+000000+000000+000000+00000011" //for dome: "A+005000+048000+005000+066000+000000+000000+000000+000000+000000+00000011" std::string::size_type offset, end; offset = (i*73)+1; end = 73+(i*73); std::string currentVolume = info.substr(offset, end);//i=0: from 1 to 73 characters; i=1: from 75 to 148 char; // if i>0 then we have a return statement infront if (i>0) currentVolume = currentVolume.substr(1, currentVolume.size()); std::string standard = "0"; std::string pyramid = "4"; std::string spectraPyramid = "5"; std::string vicraVolume = "7"; std::string cube = "9"; std::string dome = "A"; if (currentVolume.compare(0,1,standard)==0) volumes->push_back(mitk::Standard); if (currentVolume.compare(0,1,pyramid)==0) volumes->push_back(mitk::Pyramid); if (currentVolume.compare(0,1,spectraPyramid)==0) volumes->push_back(mitk::SpectraPyramid); if (currentVolume.compare(0,1,vicraVolume)==0) volumes->push_back(mitk::VicraVolume); else if (currentVolume.compare(0,1,cube)==0) volumes->push_back(mitk::Cube);//alias cube else if (currentVolume.compare(0,1,dome)==0) volumes->push_back(mitk::Dome); //fill volumesDimensions for (unsigned int index = 0; index < 10; index++) { std::string::size_type offD, endD; offD = 1+(index*7); //7 digits per dimension and the first is the type of volume endD = offD+7; int dimension = std::atoi(currentVolume.substr(offD, endD).c_str()); dimension /= 100; //given in mm. 7 digits are xxxx.xx according to NDI //strange, the last two digits (11) also for the metal flag get read also... volumesDimensions->push_back(dimension); } } return true; } bool mitk::NDITrackingDevice::SetVolume(NDITrackingVolume volume) { if (m_DeviceProtocol->VSEL(volume) != mitk::NDIOKAY) { this->SetErrorMessage("Could not set volume!"); return false; } return true; } diff --git a/Modules/IGT/IGTTrackingDevices/mitkNDITrackingDevice.h b/Modules/IGT/IGTTrackingDevices/mitkNDITrackingDevice.h index d1b13fc466..bd2729925f 100644 --- a/Modules/IGT/IGTTrackingDevices/mitkNDITrackingDevice.h +++ b/Modules/IGT/IGTTrackingDevices/mitkNDITrackingDevice.h @@ -1,305 +1,311 @@ /*=================================================================== 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 MITKNDITRACKINGDEVICE_H_HEADER_INCLUDED_C1C2FCD2 #define MITKNDITRACKINGDEVICE_H_HEADER_INCLUDED_C1C2FCD2 #include "mitkTrackingDevice.h" #include #include #include "itkFastMutexLock.h" #include #include "mitkTrackingTypes.h" #include "mitkNDIProtocol.h" #include "mitkNDIPassiveTool.h" #include "mitkSerialCommunication.h" namespace mitk { class NDIProtocol; /** Documentation * \brief superclass for specific NDI tracking Devices that use serial communication. * * implements the TrackingDevice interface for NDI tracking devices (POLARIS, AURORA) * * \ingroup IGT */ class MitkIGT_EXPORT NDITrackingDevice : public TrackingDevice { friend class NDIProtocol; public: typedef std::vector Tool6DContainerType; ///< List of 6D tools of the correct type for this tracking device typedef std::vector TrackingVolumeDimensionType; ///< List of the supported tracking volume dimensions. typedef mitk::TrackingDeviceType NDITrackingDeviceType; ///< This enumeration includes the two types of NDI tracking devices (Polaris, Aurora). typedef std::vector NDITrackingVolumeContainerType; ///< vector of tracking volumes typedef mitk::SerialCommunication::PortNumber PortNumber; ///< Port number of the serial connection typedef mitk::SerialCommunication::BaudRate BaudRate; ///< Baud rate of the serial connection typedef mitk::SerialCommunication::DataBits DataBits; ///< Number of data bits used in the serial connection typedef mitk::SerialCommunication::Parity Parity; ///< Parity mode used in the serial connection typedef mitk::SerialCommunication::StopBits StopBits; ///< Number of stop bits used in the serial connection typedef mitk::SerialCommunication::HardwareHandshake HardwareHandshake; ///< Hardware handshake mode of the serial connection typedef mitk::NDIPassiveTool::TrackingPriority TrackingPriority; ///< Tracking priority used for tracking a tool mitkClassMacro(NDITrackingDevice, TrackingDevice); itkNewMacro(Self); /** * \brief Set the type of the NDI Tracking Device because it can not jet handle this itself */ //itkSetMacro(Type, TrackingDeviceType); + /** * \brief initialize the connection to the tracking device * * OpenConnection() establishes the connection to the tracking device by: * - initializing the serial port with the given parameters (port number, baud rate, ...) * - connection to the tracking device * - initializing the device * - initializing all manually added passive tools (user supplied srom file) * - initializing active tools that are connected to the tracking device */ virtual bool OpenConnection(); /** * \brief Closes the connection * * CloseConnection() resets the tracking device, invalidates all tools and then closes the serial port. */ virtual bool CloseConnection(); bool InitializeWiredTools(); + /** Sets the rotation mode of this class. See documentation of enum RotationMode for details + * on the different modes. + */ + virtual void SetRotationMode(RotationMode r); + /** * \brief TestConnection() tries to connect to a NDI tracking device on the current port/device and returns which device it has found * * TestConnection() tries to connect to a NDI tracking device on the current port/device. * \return It returns the type of the device that * answers at the port/device or mitk::TrackingSystemNotSpecified if no NDI tracking device is available at that port */ virtual mitk::TrackingDeviceType TestConnection(); /** * \brief retrieves all wired tools from the tracking device * * This method queries the tracking device for all wired tools, initializes them and creates TrackingTool representation objects * for them * \return true if no error occured, false if an error occured. Check GetErrorMessage() in case of error. */ bool DiscoverWiredTools(); /** * \brief Start the tracking. * * A new thread is created, which continuously reads the position and orientation information of each tool and stores them inside the tools. * Depending on the current operation mode (see SetOperationMode()), either the 6D tools (ToolTracking6D), 5D tools (ToolTracking5D), * 3D marker positions (MarkerTracking3D) or both 6D tools and 3D markers (HybridTracking) are updated. * Call StopTracking() to stop the tracking thread. */ virtual bool StartTracking(); /** * \brief return the tool with index toolNumber */ virtual TrackingTool* GetTool(unsigned int toolNumber) const; virtual mitk::TrackingTool* GetToolByName(std::string name) const; /** * \brief return current number of tools */ virtual unsigned int GetToolCount() const; /** * \brief Create a passive 6D tool with toolName and fileName and add it to the list of tools * * This method will create a new NDIPassiveTool object, load the SROM file fileName, * set the tool name toolName and the tracking priority p and then add * it to the list of tools. It returns a pointer of type mitk::TrackingTool to the tool * that can be used to read tracking data from it. * This is the only way to add tools to NDITrackingDevice. * * \warning adding tools is not possible in tracking mode, only in setup and ready. */ mitk::TrackingTool* AddTool(const char* toolName, const char* fileName, TrackingPriority p = NDIPassiveTool::Dynamic); /** * \brief Remove a passive 6D tool from the list of tracked tools. * * \warning removing tools is not possible in tracking mode, only in setup and ready modes. */ virtual bool RemoveTool(TrackingTool* tool); /** * \brief reloads the srom file and reinitializes the tool */ virtual bool UpdateTool(mitk::TrackingTool* tool); virtual void SetPortNumber(const PortNumber _arg); ///< set port number for serial communication itkGetConstMacro(PortNumber, PortNumber); ///< returns the port number for serial communication virtual void SetDeviceName(std::string _arg); ///< set device name (e.g. COM1, /dev/ttyUSB0). If this is set, PortNumber will be ignored itkGetStringMacro(DeviceName); ///< returns the device name for serial communication virtual void SetBaudRate(const BaudRate _arg); ///< set baud rate for serial communication itkGetConstMacro(BaudRate, BaudRate); ///< returns the baud rate for serial communication virtual void SetDataBits(const DataBits _arg); ///< set number of data bits itkGetConstMacro(DataBits, DataBits); ///< returns the data bits for serial communication virtual void SetParity(const Parity _arg); ///< set parity mode itkGetConstMacro(Parity, Parity); ///< returns the parity mode virtual void SetStopBits(const StopBits _arg); ///< set number of stop bits itkGetConstMacro(StopBits, StopBits); ///< returns the number of stop bits virtual void SetHardwareHandshake(const HardwareHandshake _arg); ///< set use hardware handshake for serial communication itkGetConstMacro(HardwareHandshake, HardwareHandshake); ///< returns the hardware handshake setting virtual void SetIlluminationActivationRate(const IlluminationActivationRate _arg); ///< set activation rate of IR illumator for polaris itkGetConstMacro(IlluminationActivationRate, IlluminationActivationRate); ///< returns the activation rate of IR illumator for polaris virtual void SetDataTransferMode(const DataTransferMode _arg); ///< set data transfer mode to text (TX) or binary (BX). \warning: only TX is supportet at the moment itkGetConstMacro(DataTransferMode, DataTransferMode); ///< returns the data transfer mode virtual bool Beep(unsigned char count); ///< Beep the tracking device 1 to 9 times NDIErrorCode GetErrorCode(const std::string* input); ///< returns the error code for a string that contains an error code in hexadecimal format virtual bool SetOperationMode(OperationMode mode); ///< set operation mode to 6D tool tracking, 3D marker tracking or 6D&3D hybrid tracking (see OperationMode) virtual OperationMode GetOperationMode(); ///< get current operation mode /** * \brief Get 3D marker positions (operation mode must be set to MarkerTracking3D or HybridTracking) */ virtual bool GetMarkerPositions(MarkerPointContainerType* markerpositions); /** * \brief Get major revision number from tracking device * should not be called directly after starting to track **/ virtual int GetMajorFirmwareRevisionNumber(); /** * \brief Get revision number from tracking device as string * should not be called directly after starting to track **/ virtual const char* GetFirmwareRevisionNumber(); /** * \brief Get number of supported tracking volumes, a vector containing the supported volumes and * a vector containing the signed dimensions in mm. For each volume 10 boundaries are stored in the order of * the supported volumes (see AURORA API GUIDE: SFLIST p.54). **/ virtual bool GetSupportedVolumes(unsigned int* numberOfVolumes, NDITrackingVolumeContainerType* volumes, TrackingVolumeDimensionType* volumesDimensions); /** * \brief Sets the desired tracking volume. Returns true if the volume type could be set. Usage: ndiTracker->SetVolume(mitk::Dome); **/ virtual bool SetVolume(NDITrackingVolume volume); protected: /** * \brief Add a passive 6D tool to the list of tracked tools. This method is used by AddTool * * \warning adding tools is not possible in tracking mode, only in setup and ready. */ virtual bool InternalAddTool(NDIPassiveTool* tool); /* Methods for NDIProtocol friend class */ virtual void InvalidateAll(); ///< invalidate all tools NDIPassiveTool* GetInternalTool(std::string portHandle); ///< returns the tool object that has been assigned the port handle or NULL if no tool can be found /** * \brief free all port handles that need to be freed * * This method retrieves a list of all port handles that need to be freed (e.g. tool got disconnected) * and frees the handles at the tracking device and it removes the tools from the internal tool list * \warning This method can remove TrackingTools from the tool list! After calling this method, GetTool(i) could return * a different tool, because tool indices could have changed. * \return returns NDIOKAY if everything was sucessfull, returns an error code otherwise */ NDIErrorCode FreePortHandles(); NDIErrorCode Send(const std::string* message, bool addCRC = true); ///< Send message to tracking device NDIErrorCode Receive(std::string* answer, unsigned int numberOfBytes); ///< receive numberOfBytes bytes from tracking device NDIErrorCode ReceiveByte(char* answer); ///< lightweight receive function, that reads just one byte NDIErrorCode ReceiveLine(std::string* answer); ///< receive characters until the first LF (The LF is included in the answer string) void ClearSendBuffer(); ///< empty send buffer of serial communication interface void ClearReceiveBuffer(); ///< empty receive buffer of serial communication interface const std::string CalcCRC(const std::string* input); ///< returns the CRC16 for input as a std::string public://TODO /** * \brief TrackTools() continuously polls serial interface for new 6d tool positions until StopTracking is called. * * Continuously tracks the 6D position of all tools until StopTracking() is called. * This function is executed by the tracking thread (through StartTracking() and ThreadStartTracking()). * It should not be called directly. */ virtual void TrackTools(); /** * \brief continuously polls serial interface for new 3D marker positions until StopTracking is called. * * Continuously tracks the 3D position of all markers until StopTracking() is called. * This function is executed by the tracking thread (through StartTracking() and ThreadStartTracking()). * It should not be called directly. */ virtual void TrackMarkerPositions(); /** * \brief continuously polls serial interface for new 3D marker positions and 6D tool positions until StopTracking is called. * * Continuously tracks the 3D position of all markers and the 6D position of all tools until StopTracking() is called. * This function is executed by the tracking thread (through StartTracking() and ThreadStartTracking()). * It should not be called directly. */ virtual void TrackToolsAndMarkers(); /** * \brief static start method for the tracking thread. */ static ITK_THREAD_RETURN_TYPE ThreadStartTracking(void* data); protected: NDITrackingDevice(); ///< Constructor virtual ~NDITrackingDevice(); ///< Destructor std::string m_DeviceName;///< Device Name PortNumber m_PortNumber; ///< COM Port Number BaudRate m_BaudRate; ///< COM Port Baud Rate DataBits m_DataBits; ///< Number of Data Bits per token Parity m_Parity; ///< Parity mode for communication StopBits m_StopBits; ///< number of stop bits per token HardwareHandshake m_HardwareHandshake; ///< use hardware handshake for serial port connection NDITrackingVolume m_NDITrackingVolume; ///< which tracking volume is currently used (if device supports multiple volumes) (\warning This parameter is not used yet) IlluminationActivationRate m_IlluminationActivationRate; ///< update rate of IR illuminator for Polaris DataTransferMode m_DataTransferMode; ///< use TX (text) or BX (binary) (\warning currently, only TX mode is supported) Tool6DContainerType m_6DTools; ///< list of 6D tools itk::FastMutexLock::Pointer m_ToolsMutex; ///< mutex for coordinated access of tool container mitk::SerialCommunication::Pointer m_SerialCommunication; ///< serial communication interface itk::FastMutexLock::Pointer m_SerialCommunicationMutex; ///< mutex for coordinated access of serial communication interface NDIProtocol::Pointer m_DeviceProtocol; ///< create and parse NDI protocol strings itk::MultiThreader::Pointer m_MultiThreader; ///< creates tracking thread that continuously polls serial interface for new tracking data int m_ThreadID; ///< ID of tracking thread OperationMode m_OperationMode; ///< tracking mode (6D tool tracking, 3D marker tracking,...) itk::FastMutexLock::Pointer m_MarkerPointsMutex; ///< mutex for marker point data container MarkerPointContainerType m_MarkerPoints; ///< container for markers (3D point tracking mode) }; } // namespace mitk #endif /* MITKNDITRACKINGDEVICE_H_HEADER_INCLUDED_C1C2FCD2 */ diff --git a/Modules/IGT/IGTTrackingDevices/mitkTrackingDevice.cpp b/Modules/IGT/IGTTrackingDevices/mitkTrackingDevice.cpp index 1a67441b11..a87164501f 100644 --- a/Modules/IGT/IGTTrackingDevices/mitkTrackingDevice.cpp +++ b/Modules/IGT/IGTTrackingDevices/mitkTrackingDevice.cpp @@ -1,108 +1,113 @@ /*=================================================================== 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 "mitkTrackingDevice.h" #include "mitkIGTTimeStamp.h" #include "mitkTrackingTool.h" #include typedef itk::MutexLockHolder MutexLockHolder; mitk::TrackingDevice::TrackingDevice() : m_Data(mitk::DeviceDataUnspecified), m_State(mitk::TrackingDevice::Setup), - m_StopTracking(false), m_ErrorMessage("") + m_StopTracking(false), m_ErrorMessage(""), + m_RotationMode(mitk::TrackingDevice::RotationStandard) { m_StopTrackingMutex = itk::FastMutexLock::New(); m_StateMutex = itk::FastMutexLock::New(); m_TrackingFinishedMutex = itk::FastMutexLock::New(); m_TrackingFinishedMutex->Lock(); // execution rights are owned by the application thread at the beginning } mitk::TrackingDevice::~TrackingDevice() { } mitk::TrackingDevice::TrackingDeviceState mitk::TrackingDevice::GetState() const { MutexLockHolder lock(*m_StateMutex); return m_State; } void mitk::TrackingDevice::SetState( TrackingDeviceState state ) { itkDebugMacro("setting m_State to " << state); MutexLockHolder lock(*m_StateMutex); // lock and unlock the mutex if (m_State == state) { return; } m_State = state; this->Modified(); } +void mitk::TrackingDevice::SetRotationMode(RotationMode r) +{ + MITK_WARN << "Rotation mode switching is not implemented for this device. Leaving it at mitk::TrackingDevice::RotationStandard"; +} mitk::TrackingDeviceType mitk::TrackingDevice::GetType() const{ return m_Data.Line; } void mitk::TrackingDevice::SetType(mitk::TrackingDeviceType deviceType){ m_Data = mitk::GetFirstCompatibleDeviceDataForLine(deviceType); } mitk::TrackingDeviceData mitk::TrackingDevice::GetData() const{ return m_Data; } void mitk::TrackingDevice::SetData(mitk::TrackingDeviceData data){ m_Data = data; } bool mitk::TrackingDevice::StopTracking() { if (this->GetState() == Tracking) // Only if the object is in the correct state { m_StopTrackingMutex->Lock(); // m_StopTracking is used by two threads, so we have to ensure correct thread handling m_StopTracking = true; m_StopTrackingMutex->Unlock(); //we have to wait here that the other thread recognizes the STOP-command and executes it m_TrackingFinishedMutex->Lock(); mitk::IGTTimeStamp::GetInstance()->Stop(this); // notify realtime clock // StopTracking was called, thus the mode should be changed back // to Ready now that the tracking loop has ended. this->SetState(Ready); } return true; } mitk::TrackingTool* mitk::TrackingDevice::GetToolByName( std::string name ) const { unsigned int toolCount = this->GetToolCount(); for (unsigned int i = 0; i < toolCount; ++i) if (name == this->GetTool(i)->GetToolName()) return this->GetTool(i); return NULL; } diff --git a/Modules/IGT/IGTTrackingDevices/mitkTrackingDevice.h b/Modules/IGT/IGTTrackingDevices/mitkTrackingDevice.h index aad6aea613..09c2af6bd8 100644 --- a/Modules/IGT/IGTTrackingDevices/mitkTrackingDevice.h +++ b/Modules/IGT/IGTTrackingDevices/mitkTrackingDevice.h @@ -1,149 +1,178 @@ /*=================================================================== 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 MITKTRACKINGDEVICE_H_HEADER_INCLUDED_C1C2FCD2 #define MITKTRACKINGDEVICE_H_HEADER_INCLUDED_C1C2FCD2 #include #include "itkObject.h" #include "mitkCommon.h" #include "mitkTrackingTypes.h" #include "itkFastMutexLock.h" namespace mitk { class TrackingTool; // interface for a tool that can be tracked by the TrackingDevice /**Documentation * \brief Interface for all Tracking Devices * * Defines the methods that are common for all tracking devices. * * \ingroup IGT */ class MitkIGT_EXPORT TrackingDevice : public itk::Object { public: mitkClassMacro(TrackingDevice, itk::Object); + /** Defines the rotation modes of this tracking device which results in different representations + * of quaternions. + * + * - Standard: normal representation, rawdata from the device is not changed (DEFAULT) + * + * - Transposed: the rotation is stored transposed, which is (by mistake!) expected by some older MITK classes due + * to an ambigious method naming in VNL. + * + * CAUTION: The rotation mode can only be changed for backward compatibility of old WRONG code. + * PLEASE DO NOT CHANGE THE ROTATION MODE UNLESS YOU ARE KNOWING EXACTLY WHAT YOU ARE DOING! + * + * use SetRotationMode to change the mode. + */ + enum RotationMode {RotationStandard, RotationTransposed}; + enum TrackingDeviceState {Setup, Ready, Tracking}; ///< Type for state variable. The trackingdevice is always in one of these states /** * \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 tracking is * not running (e.g. object is in Ready state) */ virtual bool CloseConnection() = 0; ///< Closes the connection with the device /** * \brief start retrieving tracking data from the device. * * This may only be called after the connection to the device has been established * with a call to OpenConnection() (E.g. object is in Ready mode). This will change the * object state from Ready to Tracking */ virtual bool StartTracking() = 0; /** * \brief stop retrieving tracking data from the device. * stop retrieving tracking data from the device. * This may only be called after StartTracking was called * (e.g. the object is in Tracking mode). * This will change the object state from Tracking to Ready. */ virtual bool StopTracking(); /** * \brief Return tool with index toolNumber * * tools are numbered from 0 to GetToolCount() - 1. */ virtual TrackingTool* GetTool(unsigned int toolNumber) const = 0; /** * \brief Returns the tool with the given tool name * * Note: subclasses can and should implement optimized versions of this method * \return the given tool or NULL if no tool with that name exists */ virtual mitk::TrackingTool* GetToolByName(std::string name) const; /** * \brief Returns number of tracking tools */ virtual unsigned int GetToolCount() const = 0; + /** Sets the rotation mode of this class. See documentation of enum RotationMode for details + * on the different modes. This method has to be implemented in a deriving class to become + * functional / if different rotation modes should be supported. + * CAUTION: The rotation mode can only be changed for backward compatibility of old WRONG code. + * PLEASE DO NOT CHANGE THE ROTATION MODE UNLESS YOU ARE KNOWING EXACTLY WHAT YOU ARE DOING! + */ + virtual void SetRotationMode(RotationMode r); + + /** @return Returns the rotation mode of this class. See documentation of enum + * RotationMode for details on the different modes. + */ + itkGetConstMacro(RotationMode,RotationMode); + /** * \brief return current error message */ itkGetStringMacro(ErrorMessage); /** * \brief return current object state (Setup, Ready or Tracking) */ TrackingDeviceState GetState() const; /** * \brief Deprecated! Use the more specific getDeviceData instead. return device type identifier */ TrackingDeviceType GetType() const; /** * \brief Deprecated! Use the more specific setDeviceData instead. set device type */ void SetType(TrackingDeviceType type); /** * \brief return device data */ TrackingDeviceData GetData() const; /** * \brief set device type */ void SetData(TrackingDeviceData data); protected: /** * \brief set error message */ itkSetStringMacro(ErrorMessage); /** * \brief change object state */ void SetState(TrackingDeviceState state); TrackingDevice(); virtual ~TrackingDevice(); TrackingDeviceData m_Data; ///< current device Data TrackingDeviceState m_State; ///< current object state (Setup, Ready or Tracking) bool m_StopTracking; ///< signal stop to tracking thread itk::FastMutexLock::Pointer m_StopTrackingMutex; ///< mutex to control access to m_StopTracking itk::FastMutexLock::Pointer m_TrackingFinishedMutex; ///< mutex to manage control flow of StopTracking() itk::FastMutexLock::Pointer m_StateMutex; ///< mutex to control access to m_State std::string m_ErrorMessage; ///< current error message + RotationMode m_RotationMode; ///< defines the rotation mode Standard or Transposed, Standard is default }; } // namespace mitk #endif /* MITKTRACKINGDEVICE_H_HEADER_INCLUDED_C1C2FCD2 */ diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationDataSourceSelectionWidget.cpp b/Modules/IGTUI/Qmitk/QmitkNavigationDataSourceSelectionWidget.cpp index 1b39a416e2..9ba1f78280 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationDataSourceSelectionWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkNavigationDataSourceSelectionWidget.cpp @@ -1,124 +1,128 @@ /*=================================================================== 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 "QmitkNavigationDataSourceSelectionWidget.h" //mitk headers #include #include +#include "usServiceReference.h" QmitkNavigationDataSourceSelectionWidget::QmitkNavigationDataSourceSelectionWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Controls = NULL; CreateQtPartControl(this); CreateConnections(); } QmitkNavigationDataSourceSelectionWidget::~QmitkNavigationDataSourceSelectionWidget() { } void QmitkNavigationDataSourceSelectionWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkNavigationDataSourceSelectionWidgetControls; m_Controls->setupUi(parent); std::string empty = ""; m_Controls->m_NaviagationDataSourceWidget->Initialize(mitk::NavigationDataSource::US_PROPKEY_DEVICENAME,empty); } } void QmitkNavigationDataSourceSelectionWidget::CreateConnections() { if ( m_Controls ) { - connect( (QObject*)(m_Controls->m_NaviagationDataSourceWidget), SIGNAL(ServiceSelectionChanged(mitk::ServiceReference)), this, SLOT(NavigationDataSourceSelected(mitk::ServiceReference)) ); + connect( (QObject*)(m_Controls->m_NaviagationDataSourceWidget), SIGNAL(ServiceSelectionChanged(us::ServiceReferenceU)), this, SLOT(NavigationDataSourceSelected(us::ServiceReferenceU)) ); } } -void QmitkNavigationDataSourceSelectionWidget::NavigationDataSourceSelected(us::ServiceReference s) +void QmitkNavigationDataSourceSelectionWidget::NavigationDataSourceSelected(us::ServiceReferenceU s) { if (!s) //no device selected { //reset everything m_CurrentSource = NULL; m_CurrentStorage = NULL; + emit NavigationDataSourceSelected(m_CurrentSource); return; } // Get Source us::ModuleContext* context = us::GetModuleContext(); - m_CurrentSource = context->GetService(s); + m_CurrentSource = context->GetService(s); std::string id = s.GetProperty(mitk::NavigationDataSource::US_PROPKEY_ID).ToString(); //Fill tool list for(std::size_t i = 0; i < m_CurrentSource->GetNumberOfOutputs(); i++) {new QListWidgetItem(tr(m_CurrentSource->GetOutput(i)->GetName()), m_Controls->m_ToolView);} // Create Filter for ToolStorage std::string filter = "("+ mitk::NavigationToolStorage::US_PROPKEY_SOURCE_ID + "=" + id + ")"; // Get Storage std::vector > refs = context->GetServiceReferences(filter); if (refs.empty()) return; //no storage was found m_CurrentStorage = context->GetService(refs.front()); if (m_CurrentStorage.IsNull()) { MITK_WARN << "Found an invalid storage object!"; return; } if (m_CurrentStorage->GetToolCount() != m_CurrentSource->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; } + + emit NavigationDataSourceSelected(m_CurrentSource); } mitk::NavigationDataSource::Pointer QmitkNavigationDataSourceSelectionWidget::GetSelectedNavigationDataSource() { return this->m_CurrentSource; } int QmitkNavigationDataSourceSelectionWidget::GetSelectedToolID() { return this->m_Controls->m_ToolView->currentIndex().row(); } mitk::NavigationTool::Pointer QmitkNavigationDataSourceSelectionWidget::GetSelectedNavigationTool() { if (this->m_CurrentStorage.IsNull()) return NULL; if (m_Controls->m_ToolView->currentIndex().row() >= m_CurrentStorage->GetToolCount()) return NULL; return this->m_CurrentStorage->GetTool(m_Controls->m_ToolView->currentIndex().row()); } mitk::NavigationToolStorage::Pointer QmitkNavigationDataSourceSelectionWidget::GetNavigationToolStorageOfSource() { return this->m_CurrentStorage; } diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationDataSourceSelectionWidget.h b/Modules/IGTUI/Qmitk/QmitkNavigationDataSourceSelectionWidget.h index 765b2a1718..da26578795 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationDataSourceSelectionWidget.h +++ b/Modules/IGTUI/Qmitk/QmitkNavigationDataSourceSelectionWidget.h @@ -1,89 +1,93 @@ /*=================================================================== 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 QmitkNavigationDataSourceSelectionWidget_H #define QmitkNavigationDataSourceSelectionWidget_H //QT headers #include //mitk headers #include "MitkIGTUIExports.h" #include #include #include //ui header #include "ui_QmitkNavigationDataSourceSelectionWidgetControls.h" /** Documentation: * \brief This widget allows the user to select a NavigationDataSource. Tools of this Source are also shown and the user can select one of these tools. * \ingroup IGTUI */ class MitkIGTUI_EXPORT QmitkNavigationDataSourceSelectionWidget : public QWidget { Q_OBJECT public: static const std::string VIEW_ID; QmitkNavigationDataSourceSelectionWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); ~QmitkNavigationDataSourceSelectionWidget(); /** @return Returns the currently selected NavigationDataSource. Returns null if no source is selected at the moment. */ mitk::NavigationDataSource::Pointer GetSelectedNavigationDataSource(); /** @return Returns the ID of the currently selected tool. You can get the corresponding NavigationData when calling GetOutput(id) * on the source object. Returns -1 if there is no tool selected. */ int GetSelectedToolID(); /** @return Returns the NavigationTool of the current selected tool if a NavigationToolStorage is available. Returns NULL if * there is no storage available or if no tool is selected. */ mitk::NavigationTool::Pointer GetSelectedNavigationTool(); /** @return Returns the NavigationToolStorage of the currently selected NavigationDataSource. Returns NULL if there is no * source selected or if the source has no NavigationToolStorage assigned. */ mitk::NavigationToolStorage::Pointer GetNavigationToolStorageOfSource(); signals: + /** @brief This signal is emitted when a new navigation data source is selected. + * @param n Holds the new selected navigation data source. Is null if the old source is deselected and no new source is selected. + */ + void NavigationDataSourceSelected(mitk::NavigationDataSource::Pointer n); protected slots: - void NavigationDataSourceSelected(us::ServiceReference s); + void NavigationDataSourceSelected(us::ServiceReferenceU s); protected: /// \brief Creation of the connections virtual void CreateConnections(); virtual void CreateQtPartControl(QWidget *parent); Ui::QmitkNavigationDataSourceSelectionWidgetControls* m_Controls; mitk::NavigationToolStorage::Pointer m_CurrentStorage; mitk::NavigationDataSource::Pointer m_CurrentSource; }; #endif diff --git a/Modules/IGTUI/Qmitk/QmitkTrackingDeviceConfigurationWidget.cpp b/Modules/IGTUI/Qmitk/QmitkTrackingDeviceConfigurationWidget.cpp index 76167a15c9..91f9981729 100644 --- a/Modules/IGTUI/Qmitk/QmitkTrackingDeviceConfigurationWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkTrackingDeviceConfigurationWidget.cpp @@ -1,482 +1,494 @@ /*=================================================================== 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 "QmitkTrackingDeviceConfigurationWidget.h" #include #include #include #include #include #include #include #include const std::string QmitkTrackingDeviceConfigurationWidget::VIEW_ID = "org.mitk.views.trackingdeviceconfigurationwidget"; QmitkTrackingDeviceConfigurationWidget::QmitkTrackingDeviceConfigurationWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Controls = NULL; CreateQtPartControl(this); CreateConnections(); m_MTCalibrationFile = ""; //reset a few things ResetOutput(); AddOutput("
NDI Polaris selected"); this->m_TrackingDeviceConfigurated = false; m_AdvancedUserControl = true; } void QmitkTrackingDeviceConfigurationWidget::SetGUIStyle(QmitkTrackingDeviceConfigurationWidget::Style style) { switch(style) { case QmitkTrackingDeviceConfigurationWidget::SIMPLE: //move all UI elements to an empty dummy layout //m_Controls->dummyLayout->addItem(m_Controls->mainLayout); m_Controls->dummyLayout->addWidget(m_Controls->widget_title_label); m_Controls->dummyLayout->addWidget(m_Controls->choose_tracking_device_label); m_Controls->dummyLayout->addWidget(m_Controls->polaris_label); m_Controls->dummyLayout->addWidget( m_Controls->aurora_label); m_Controls->dummyLayout->addWidget(m_Controls->aurora_label); m_Controls->dummyLayout->addWidget(m_Controls->microntracker_label); m_Controls->dummyLayout->addWidget(m_Controls->m_testConnectionMicronTracker); m_Controls->dummyLayout->addWidget(m_Controls->m_outputTextMicronTracker); m_Controls->dummyLayout->addWidget(m_Controls->m_outputTextAurora); m_Controls->dummyLayout->addWidget(m_Controls->m_testConnectionAurora); m_Controls->dummyLayout->addWidget(m_Controls->m_outputTextPolaris); m_Controls->dummyLayout->addWidget(m_Controls->m_testConnectionPolaris); m_Controls->dummyLayout->addWidget(m_Controls->m_polarisTrackingModeBox); m_Controls->dummyLayout->addWidget(m_Controls->m_finishedLine); m_Controls->dummyLayout->addWidget(m_Controls->line); m_Controls->dummyLayout->addWidget(m_Controls->configuration_finished_label); m_Controls->dummyLayout->addItem(m_Controls->horizontalLayout_4); m_Controls->mainLayout->removeItem(m_Controls->horizontalLayout_4); m_Controls->dummyLayout->addWidget(m_Controls->configuration_finished_label); m_Controls->dummyLayout->addItem(m_Controls->verticalSpacer_2); m_Controls->verticalLayout_3->removeItem(m_Controls->verticalSpacer_2); m_Controls->dummyLayout->addItem(m_Controls->horizontalSpacer_9); m_Controls->horizontalLayout_9->removeItem(m_Controls->horizontalSpacer_9); m_Controls->dummyLayout->addItem(m_Controls->horizontalSpacer_3); m_Controls->horizontalLayout_11->removeItem(m_Controls->horizontalSpacer_3); m_Controls->dummyLayout->addItem(m_Controls->verticalSpacer_3); m_Controls->verticalLayout_7->removeItem(m_Controls->verticalSpacer_3); m_Controls->dummyLayout->addItem(m_Controls->verticalSpacer_4); m_Controls->verticalLayout_10->removeItem(m_Controls->verticalSpacer_4); m_Controls->dummyLayout->addItem(m_Controls->horizontalSpacer_10); m_Controls->verticalLayout_10->removeItem(m_Controls->horizontalSpacer_10); //set height to min m_Controls->m_outputTextPolaris->setMinimumHeight(0); m_Controls->m_outputTextPolaris->setMaximumHeight(0); m_Controls->m_outputTextMicronTracker->setMinimumHeight(0); m_Controls->m_outputTextMicronTracker->setMaximumHeight(0); m_Controls->m_outputTextAurora->setMinimumHeight(0); m_Controls->m_outputTextAurora->setMaximumHeight(0); m_Controls->m_finishedButton->setMinimumHeight(0); m_Controls->m_finishedButton->setMaximumHeight(0); m_Controls->m_resetButton->setMinimumHeight(0); m_Controls->m_resetButton->setMaximumHeight(0); //set the height of the tracking device combo box m_Controls->m_trackingDeviceChooser->setMinimumHeight(50); //move back the used elemets to the main layout m_Controls->simpleLayout->addWidget(m_Controls->m_trackingDeviceChooser); m_Controls->simpleLayout->addWidget(m_Controls->m_TrackingSystemWidget); m_Controls->mainWidget->setCurrentIndex(1); this->setMaximumHeight(150); this->EnableAdvancedUserControl(false); break; case QmitkTrackingDeviceConfigurationWidget::ADVANCED: //default at the moment => start settings are advanced break; } } QmitkTrackingDeviceConfigurationWidget::~QmitkTrackingDeviceConfigurationWidget() { } void QmitkTrackingDeviceConfigurationWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkTrackingDeviceConfigurationWidgetControls; m_Controls->setupUi(parent); } } void QmitkTrackingDeviceConfigurationWidget::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_trackingDeviceChooser), SIGNAL(currentIndexChanged(int)), this, SLOT(TrackingDeviceChanged()) ); connect( (QObject*)(m_Controls->m_testConnectionPolaris), SIGNAL(clicked()), this, SLOT(TestConnection()) ); connect( (QObject*)(m_Controls->m_testConnectionAurora), SIGNAL(clicked()), this, SLOT(TestConnection()) ); connect( (QObject*)(m_Controls->m_testConnectionMicronTracker), SIGNAL(clicked()), this, SLOT(TestConnection()) ); connect( (QObject*)(m_Controls->m_resetButton), SIGNAL(clicked()), this, SLOT(ResetByUser()) ); connect( (QObject*)(m_Controls->m_finishedButton), SIGNAL(clicked()), this, SLOT(Finished()) ); connect( (QObject*)(m_Controls->m_AutoScanPolaris), SIGNAL(clicked()), this, SLOT(AutoScanPorts()) ); connect( (QObject*)(m_Controls->m_AutoScanAurora), SIGNAL(clicked()), this, SLOT(AutoScanPorts()) ); connect( (QObject*)(m_Controls->m_SetMTCalibrationFile), SIGNAL(clicked()), this, SLOT(SetMTCalibrationFileClicked()) ); //set a few UI components depending on Windows / Linux #ifdef WIN32 m_Controls->portTypeLabelPolaris->setVisible(false); m_Controls->portTypePolaris->setVisible(false); m_Controls->portTypeLabelAurora->setVisible(false); m_Controls->portTypeAurora->setVisible(false); #else m_Controls->comPortLabelAurora->setText("Port Nr:"); m_Controls->m_comPortLabelPolaris->setText("Port Nr:"); m_Controls->m_portSpinBoxAurora->setPrefix(""); m_Controls->m_portSpinBoxPolaris->setPrefix(""); #endif //disable unused UI component m_Controls->m_polarisTrackingModeBox->setVisible(false); //don't delete this component, because it is used in the MBI part of MITK } } void QmitkTrackingDeviceConfigurationWidget::TrackingDeviceChanged() { //show the correspondig widget m_Controls->m_TrackingSystemWidget->setCurrentIndex(m_Controls->m_trackingDeviceChooser->currentIndex()); //the new trackingdevice is not configurated yet m_TrackingDeviceConfigurated = false; //reset output ResetOutput(); //print output and do further initializations if (m_Controls->m_trackingDeviceChooser->currentIndex()==0)//NDI Polaris { AddOutput("
NDI Polaris selected"); } else if (m_Controls->m_trackingDeviceChooser->currentIndex()==1) //NDI Aurora { AddOutput("
NDI Aurora selected"); } else if (m_Controls->m_trackingDeviceChooser->currentIndex()==2) //ClaronTechnology MicronTracker 2 { AddOutput("
Microntracker selected"); if (!mitk::ClaronTrackingDevice::New()->IsMicronTrackerInstalled()) { AddOutput("
ERROR: not installed!"); } else if (this->m_MTCalibrationFile == "") //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())); } } emit TrackingDeviceSelectionChanged(); } void QmitkTrackingDeviceConfigurationWidget::EnableUserReset(bool enable) { if (enable) m_Controls->m_resetButton->setVisible(true); else m_Controls->m_resetButton->setVisible(false); } void QmitkTrackingDeviceConfigurationWidget::TestConnection() { this->setEnabled(false); //#### Step 1: construct a tracking device: mitk::TrackingDevice::Pointer testTrackingDevice = ConstructTrackingDevice(); //#### Step 2: test connection and start tracking, generate output AddOutput("
testing connection
..."); +bool connectionSuccess = false; +bool trackingSuccess = false; if (testTrackingDevice->OpenConnection()) { - AddOutput(" OK"); + //try start/stop tracking AddOutput("
testing tracking
..."); - if (testTrackingDevice->StartTracking()) - { - AddOutput(" OK"); - if (!testTrackingDevice->StopTracking())AddOutput("
ERROR while stop tracking
"); - } - else AddOutput(" ERROR!"); - if (!testTrackingDevice->CloseConnection())AddOutput("
ERROR while closing connection
"); + if (testTrackingDevice->StartTracking()) {if (testTrackingDevice->StopTracking()) {trackingSuccess = true;}} + + //try close connection + if (testTrackingDevice->CloseConnection()) {connectionSuccess = true;} } -else AddOutput(" ERROR!"); + +if (connectionSuccess && trackingSuccess) + { + AddOutput("OK"); + } +else + { + AddOutput("ERROR!"); + if(!connectionSuccess) + {MITK_WARN << "Error while connecting to device: " << testTrackingDevice->GetErrorMessage();} + else if(!trackingSuccess) + {MITK_WARN << "Error while start tracking to device: " << testTrackingDevice->GetErrorMessage();} + } + this->setEnabled(true); } void QmitkTrackingDeviceConfigurationWidget::Finished() { m_TrackingDevice = ConstructTrackingDevice(); m_Controls->m_TrackingSystemWidget->setEnabled(false); m_Controls->m_trackingDeviceChooser->setEnabled(false); m_Controls->choose_tracking_device_label->setEnabled(false); m_Controls->configuration_finished_label->setText("\n\n

Configuration finished

"); this->m_TrackingDeviceConfigurated = true; emit TrackingDeviceConfigurationFinished(); } void QmitkTrackingDeviceConfigurationWidget::Reset() { m_TrackingDevice = NULL; m_Controls->m_TrackingSystemWidget->setEnabled(true); m_Controls->m_trackingDeviceChooser->setEnabled(true); m_Controls->choose_tracking_device_label->setEnabled(true); m_Controls->configuration_finished_label->setText("\n\n

Press \"Finished\" to confirm configuration

"); this->m_TrackingDeviceConfigurated = false; emit TrackingDeviceConfigurationReseted(); } void QmitkTrackingDeviceConfigurationWidget::ResetByUser() { Reset(); } void QmitkTrackingDeviceConfigurationWidget::AutoScanPorts() { this->setEnabled(false); AddOutput("
Scanning..."); QString result = "
Found Devices:"; int resultSize = result.size(); //remember size of result: if it stays the same no device were found #ifdef WIN32 QString devName; for (unsigned int i = 1; i < 20; ++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" mitk::TrackingDeviceType scannedPort = ScanPort(devName); switch (scannedPort) { case mitk::NDIPolaris: result += "
" + devName + ": " + "NDI Polaris"; m_Controls->m_portSpinBoxPolaris->setValue(i); break; case mitk::NDIAurora: result += "
" + devName + ": " + "NDI Aurora"; m_Controls->m_portSpinBoxAurora->setValue(i); break; } } #else //linux systems for(unsigned int i = 1; i < 6; ++i) { QString devName = QString("/dev/ttyS%1").arg(i); mitk::TrackingDeviceType scannedPort = ScanPort(devName); switch (scannedPort) { case mitk::NDIPolaris: result += "
" + devName + ": " + "NDI Polaris"; m_Controls->m_portSpinBoxPolaris->setValue(i); m_Controls->portTypePolaris->setCurrentIndex(1); break; case mitk::NDIAurora: result += "
" + devName + ": " + "NDI Aurora"; m_Controls->m_portSpinBoxAurora->setValue(i); m_Controls->portTypeAurora->setCurrentIndex(1); break; } } for(unsigned int i = 0; i <7; ++i) { QString devName = QString("/dev/ttyUSB%1").arg(i); mitk::TrackingDeviceType scannedPort = ScanPort(devName); switch (scannedPort) { case mitk::NDIPolaris: result += "
" + devName + ": " + "NDI Polaris"; m_Controls->m_portSpinBoxPolaris->setValue(i); m_Controls->portTypePolaris->setCurrentIndex(0); break; case mitk::NDIAurora: result += "
" + devName + ": " + "NDI Aurora"; m_Controls->m_portSpinBoxAurora->setValue(i); m_Controls->portTypeAurora->setCurrentIndex(0); break; } } #endif if ( result.size() == resultSize) result += "
none"; AddOutput(result.toStdString()); this->setEnabled(true); } void QmitkTrackingDeviceConfigurationWidget::SetMTCalibrationFileClicked() { std::string filename = QFileDialog::getOpenFileName(NULL,tr("Open Calibration File"), "/", "*.*").toAscii().data(); if (filename=="") {return;} else { m_MTCalibrationFile = filename; Poco::Path myPath = Poco::Path(m_MTCalibrationFile.c_str()); m_Controls->m_MTCalibrationFile->setText("Calibration File: " + QString(myPath.getFileName().c_str())); } } //######################### internal help methods ####################################### void QmitkTrackingDeviceConfigurationWidget::ResetOutput() { m_output.str(""); m_output <<"output:"; m_Controls->m_outputTextAurora->setHtml(QString(m_output.str().c_str())); m_Controls->m_outputTextPolaris->setHtml(QString(m_output.str().c_str())); m_Controls->m_outputTextMicronTracker->setHtml(QString(m_output.str().c_str())); } void QmitkTrackingDeviceConfigurationWidget::AddOutput(std::string s) { //print output m_output << s; m_Controls->m_outputTextAurora->setHtml(QString(m_output.str().c_str())); m_Controls->m_outputTextPolaris->setHtml(QString(m_output.str().c_str())); m_Controls->m_outputTextMicronTracker->setHtml(QString(m_output.str().c_str())); m_Controls->m_outputTextPolaris->verticalScrollBar()->setValue(m_Controls->m_outputTextPolaris->verticalScrollBar()->maximum()); m_Controls->m_outputTextAurora->verticalScrollBar()->setValue(m_Controls->m_outputTextAurora->verticalScrollBar()->maximum()); m_Controls->m_outputTextMicronTracker->verticalScrollBar()->setValue(m_Controls->m_outputTextMicronTracker->verticalScrollBar()->maximum()); repaint(); } mitk::TrackingDevice::Pointer QmitkTrackingDeviceConfigurationWidget::ConstructTrackingDevice() { mitk::TrackingDevice::Pointer returnValue; //#### Step 1: configure tracking device: if (m_Controls->m_trackingDeviceChooser->currentIndex()==0)//NDI Polaris { if(m_Controls->m_radioPolaris5D->isChecked()) //5D Tracking { //not yet in the open source part so we'll only get NULL here. returnValue = ConfigureNDI5DTrackingDevice(); } else //6D Tracking { returnValue = ConfigureNDI6DTrackingDevice(); returnValue->SetType(mitk::NDIPolaris); } } else if (m_Controls->m_trackingDeviceChooser->currentIndex()==1)//NDI Aurora { returnValue = ConfigureNDI6DTrackingDevice(); returnValue->SetType(mitk::NDIAurora); } else if (m_Controls->m_trackingDeviceChooser->currentIndex()==2)//ClaronTechnology MicronTracker 2 { mitk::ClaronTrackingDevice::Pointer newDevice = mitk::ClaronTrackingDevice::New(); if(this->m_MTCalibrationFile=="") AddOutput("
Warning: Calibration file is not set!"); else { //extract path from calibration file and set the calibration dir of the device std::string path = itksys::SystemTools::GetFilenamePath(m_MTCalibrationFile); newDevice->SetCalibrationDir(path); } returnValue = newDevice; } return returnValue; } mitk::TrackingDevice::Pointer QmitkTrackingDeviceConfigurationWidget::ConfigureNDI5DTrackingDevice() { return NULL; } mitk::TrackingDevice::Pointer QmitkTrackingDeviceConfigurationWidget::ConfigureNDI6DTrackingDevice() { mitk::NDITrackingDevice::Pointer tempTrackingDevice = mitk::NDITrackingDevice::New(); //get port int port = 0; if (m_Controls->m_trackingDeviceChooser->currentIndex()==1) port = m_Controls->m_portSpinBoxAurora->value(); else port = m_Controls->m_portSpinBoxPolaris->value(); //build prefix (depends on linux/win) QString prefix = ""; #ifdef WIN32 prefix ="COM"; tempTrackingDevice->SetPortNumber(static_cast(port)); //also set the com port for compatibility #else if (m_Controls->m_trackingDeviceChooser->currentIndex()==1) //Aurora prefix = m_Controls->portTypeAurora->currentText(); else //Polaris prefix = m_Controls->portTypePolaris->currentText(); #endif //build port name string QString portName = prefix + QString::number(port); tempTrackingDevice->SetDeviceName(portName.toStdString()); //set the port name tempTrackingDevice->SetBaudRate(mitk::SerialCommunication::BaudRate115200);//set baud rate mitk::TrackingDevice::Pointer returnValue = static_cast(tempTrackingDevice); return returnValue; } mitk::TrackingDevice::Pointer QmitkTrackingDeviceConfigurationWidget::GetTrackingDevice() { if (!m_AdvancedUserControl) m_TrackingDevice = ConstructTrackingDevice(); return this->m_TrackingDevice; } bool QmitkTrackingDeviceConfigurationWidget::GetTrackingDeviceConfigured() { return this->m_TrackingDeviceConfigurated; } void QmitkTrackingDeviceConfigurationWidget::ConfigurationFinished() { Finished(); } void QmitkTrackingDeviceConfigurationWidget::EnableAdvancedUserControl(bool enable) { m_AdvancedUserControl = enable; m_Controls->configuration_finished_label->setVisible(enable); m_Controls->m_finishedLine->setVisible(enable); m_Controls->m_resetButton->setVisible(enable); m_Controls->m_finishedButton->setVisible(enable); } mitk::TrackingDeviceType QmitkTrackingDeviceConfigurationWidget::ScanPort(QString port) { mitk::NDITrackingDevice::Pointer tracker = mitk::NDITrackingDevice::New(); tracker->SetDeviceName(port.toStdString()); return tracker->TestConnection(); } diff --git a/Plugins/org.mitk.gui.qt.igtexamples/CMakeLists.txt b/Plugins/org.mitk.gui.qt.igtexamples/CMakeLists.txt index 4b6474cfa4..6bd7508243 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.igtexamples/CMakeLists.txt @@ -1,9 +1,9 @@ # The project name must correspond to the directory name of your plug-in # and must not contain periods. project(org_mitk_gui_qt_igtexamples) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE IGTEXAMPLES_EXPORT EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDENCIES QmitkExt MitkIGT MitkIGTUI + MODULE_DEPENDENCIES QmitkExt MitkIGT MitkIGTUI mitkCameraCalibration ) \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp index d086227608..af866e01e5 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp +++ b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.cpp @@ -1,1042 +1,898 @@ /*=================================================================== 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 "QmitkIGTTrackingLabView.h" #include "QmitkStdMultiWidget.h" #include #include #include #include #include #include #include #include +#include +#include +#include #include #include #include #include +#include +#include +#include // Qt #include #include +// vtk +#include + const std::string QmitkIGTTrackingLabView::VIEW_ID = "org.mitk.views.igttrackinglab"; QmitkIGTTrackingLabView::QmitkIGTTrackingLabView() : QmitkFunctionality() ,m_Source(NULL) -,m_FiducialRegistrationFilter(NULL) ,m_PermanentRegistrationFilter(NULL) ,m_Visualizer(NULL) ,m_VirtualView(NULL) ,m_PSRecordingPointSet(NULL) ,m_RegistrationTrackingFiducialsName("Tracking Fiducials") ,m_RegistrationImageFiducialsName("Image Fiducials") ,m_PointSetRecordingDataNodeName("Recorded Points") ,m_PointSetRecording(false) +,m_PermanentRegistration(false) +,m_CameraView(false) ,m_ImageFiducialsDataNode(NULL) ,m_TrackerFiducialsDataNode(NULL) ,m_PermanentRegistrationSourcePoints(NULL) { //[-1;0;0] for WOLF_6D bronchoscope m_DirectionOfProjectionVector[0]=0; m_DirectionOfProjectionVector[1]=0; m_DirectionOfProjectionVector[2]=-1;} QmitkIGTTrackingLabView::~QmitkIGTTrackingLabView() { + if (m_Timer->isActive()) m_Timer->stop(); } void QmitkIGTTrackingLabView::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); - m_ToolBox = new QToolBox(parent); - m_Controls.m_VBoxLayout->addWidget(m_ToolBox); - + m_ToolBox = m_Controls.m_ToolBox; this->CreateBundleWidgets( parent ); this->CreateConnections(); } void QmitkIGTTrackingLabView::CreateBundleWidgets( QWidget* parent ) { - // configuration widget - m_NDIConfigWidget = new QmitkNDIConfigurationWidget(parent); - m_NDIConfigWidget->SetToolTypes(QStringList () << "Instrument" << "Fiducial" << "Skinmarker" << "Unknown" ); - - m_ToolBox->addItem(m_NDIConfigWidget, "Configuration"); - - - // registration widget - m_RegistrationWidget = new QmitkFiducialRegistrationWidget(parent); + //initialize registration widget + m_RegistrationWidget = m_Controls.m_RegistrationWidget; m_RegistrationWidget->HideStaticRegistrationRadioButton(true); m_RegistrationWidget->HideContinousRegistrationRadioButton(true); m_RegistrationWidget->HideUseICPRegistrationCheckbox(true); - - m_ToolBox->addItem(m_RegistrationWidget, "Initial Registration"); - - // permanent registration widget - m_PermanentRegistrationToolSelectionWidget = new QmitkToolSelectionWidget(parent); - m_PermanentRegistrationToolSelectionWidget->SetCheckboxtText("Use this tool for permanent registration"); - - m_ToolBox->addItem(m_PermanentRegistrationToolSelectionWidget, "Permanent Registration"); - - // pointset recording - m_ToolBox->addItem(this->CreatePointSetRecordingWidget(parent), "PointSet Recording"); - - // virtual view - m_VirtualViewToolSelectionWidget = new QmitkToolSelectionWidget(parent); - m_VirtualViewToolSelectionWidget->SetCheckboxtText("Enable Virtual Camera"); - - m_ToolBox->addItem(m_VirtualViewToolSelectionWidget, "Virtual Camera"); - - // tracking status - m_ToolStatusWidget = new QmitkToolTrackingStatusWidget( parent ); - m_Controls.m_VBoxLayout->addWidget(m_ToolStatusWidget); - - // update timer - m_RenderingTimerWidget = new QmitkUpdateTimerWidget( parent ); - m_RenderingTimerWidget->SetPurposeLabelText(QString("Navigation")); - m_RenderingTimerWidget->SetTimerInterval( 50 ); // set rendering timer at 20Hz (updating every 50msec) - - m_Controls.m_VBoxLayout->addWidget(m_RenderingTimerWidget); } void QmitkIGTTrackingLabView::CreateConnections() { + m_Timer = new QTimer(this); + connect(m_Timer, SIGNAL(timeout()), this, SLOT(UpdateTimer())); connect( m_ToolBox, SIGNAL(currentChanged(int)), this, SLOT(OnToolBoxCurrentChanged(int)) ); - - //connect( m_NDIConfigWidget, SIGNAL(Connected()), m_RenderingTimerWidget, SLOT(EnableWidget()) ); - connect( m_NDIConfigWidget, SIGNAL(Disconnected()), this, SLOT(OnTrackerDisconnected()) ); - connect( m_NDIConfigWidget, SIGNAL(Connected()), this, SLOT(OnSetupNavigation()) ); - connect( m_NDIConfigWidget, SIGNAL(SignalToolNameChanged(int, QString)), this, SLOT(OnChangeToolName(int, QString)) ); - connect( m_NDIConfigWidget, SIGNAL(SignalLoadTool(int, mitk::DataNode::Pointer)), this, SLOT(OnToolLoaded(int, mitk::DataNode::Pointer)) ); - connect( m_NDIConfigWidget, SIGNAL(ToolsAdded(QStringList)), this, SLOT(OnToolsAdded(QStringList)) ); - connect( m_NDIConfigWidget, SIGNAL(RepresentationChanged( int ,mitk::Surface::Pointer )), this, SLOT(ChangeToolRepresentation( int, mitk::Surface::Pointer ))); - + connect( m_Controls.m_UsePermanentRegistrationToggle, SIGNAL(toggled(bool)), this, SLOT(OnPermanentRegistration(bool)) ); + connect( m_Controls.m_TrackingDeviceSelectionWidget, SIGNAL(NavigationDataSourceSelected(mitk::NavigationDataSource::Pointer)), this, SLOT(OnSetupNavigation()) ); + connect( m_Controls.m_UseAsPointerButton, SIGNAL(clicked()), this, SLOT(OnInstrumentSelected()) ); + connect( m_Controls.m_UseAsObjectmarkerButton, SIGNAL(clicked()), this, SLOT(OnObjectmarkerSelected()) ); connect( m_RegistrationWidget, SIGNAL(AddedTrackingFiducial()), this, SLOT(OnAddRegistrationTrackingFiducial()) ); connect( m_RegistrationWidget, SIGNAL(PerformFiducialRegistration()), this, SLOT(OnRegisterFiducials()) ); + connect( m_Controls.m_PointSetRecordCheckBox, SIGNAL(toggled(bool)), this, SLOT(OnPointSetRecording(bool)) ); + connect( m_Controls.m_ActivateNeedleView, SIGNAL(toggled(bool)), this, SLOT(OnVirtualCamera(bool)) ); - connect( m_RenderingTimerWidget, SIGNAL(Started()), this, SLOT(OnStartNavigation()) ); - connect( m_RenderingTimerWidget, SIGNAL(Stopped()), this, SLOT(OnStopNavigation()) ); - - connect( m_VirtualViewToolSelectionWidget, SIGNAL(SignalUseTool(int, bool)), this, SLOT(OnVirtualCamera(int, bool))); + //start timer + m_Timer->start(30); - connect( m_PermanentRegistrationToolSelectionWidget, SIGNAL(SignalUseTool(int, bool)), this, SLOT(OnPermanentRegistration(int, bool)) ); + //initialize Combo Boxes + m_Controls.m_ObjectComboBox->SetDataStorage(this->GetDataStorage()); + m_Controls.m_ObjectComboBox->SetAutoSelectNewItems(false); + m_Controls.m_ObjectComboBox->SetPredicate(mitk::NodePredicateDataType::New("Surface")); + m_Controls.m_ImageComboBox->SetDataStorage(this->GetDataStorage()); + m_Controls.m_ImageComboBox->SetAutoSelectNewItems(false); + m_Controls.m_ImageComboBox->SetPredicate(mitk::NodePredicateDataType::New("Image")); } - -void QmitkIGTTrackingLabView::OnAddRegistrationTrackingFiducial() +void QmitkIGTTrackingLabView::UpdateTimer() { - - mitk::DataStorage* ds = this->GetDefaultDataStorage(); // check if DataStorage available - if(ds == NULL) - throw std::invalid_argument("DataStorage is not available"); - - if (m_FiducialRegistrationFilter.IsNull()) + if (m_PermanentRegistration && m_PermanentRegistrationFilter.IsNotNull()) { - std::string message( "IGT Pipeline is not ready. Please 'Start Navigation' before adding points"); - QMessageBox::warning(NULL, "Adding Fiducials not possible", message.c_str()); - return; + mitk::Transform::Pointer ObjectMarkerCurrentTransform = mitk::Transform::New(m_ObjectmarkerNavigationData); + if(IsTransformDifferenceHigh(ObjectMarkerCurrentTransform, m_ObjectmarkerNavigationDataLastUpdate)) + { + m_ObjectmarkerNavigationDataLastUpdate = mitk::Transform::New(m_ObjectmarkerNavigationData); + m_PermanentRegistrationFilter->Update(); + //if(m_Controls.m_SurfaceActive->isChecked()) + //{ + // mitk::Transform::Pointer newTransform = mitk::Transform::New(); + // newTransform->Concatenate(m_T_MarkerRel); + // newTransform->Concatenate(ObjectMarkerCurrentTransform); + // this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(newTransform->GetAffineTransform3D()); + //} + + //if(m_Controls.m_ImageActive->isChecked()) + //{ + // mitk::AffineTransform3D::Pointer newTransform = mitk::AffineTransform3D::New(); + // newTransform->SetIdentity(); + // newTransform->Compose(m_T_ImageGeo); + // newTransform->Compose(m_T_MarkerRel->GetAffineTransform3D()); + // newTransform->Compose(ObjectMarkerCurrentTransform->GetAffineTransform3D()); + // this->m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(newTransform); + //} + } } - if (m_FiducialRegistrationFilter->GetNumberOfOutputs() < 1 || m_FiducialRegistrationFilter->GetNumberOfInputs() < 1) - { - std::string message("There are no tracking instruments! Please add an instrument first!"); - QMessageBox::warning(NULL, "Adding Fiducials not possible", message.c_str()); - return; - } + if (m_CameraView && m_VirtualView.IsNotNull()) {m_VirtualView->Update();} - if (m_FiducialRegistrationFilter->GetInput()->IsDataValid() == false) - { - std::string message("instrument can currently not be tracked. Please make sure that the instrument is visible to the tracker"); - QMessageBox::warning(NULL, "Adding Fiducials not possible", message.c_str()); - return; + if(m_PointSetRecording && m_PSRecordingPointSet.IsNotNull()) + { + int size = m_PSRecordingPointSet->GetSize(); + mitk::NavigationData::Pointer nd = m_PointSetRecordingNavigationData; + + if(size > 0) + { + mitk::Point3D p = m_PSRecordingPointSet->GetPoint(size-1); + if(p.EuclideanDistanceTo(nd->GetPosition()) > (double) m_Controls.m_PSRecordingSpinBox->value()) + m_PSRecordingPointSet->InsertPoint(size, nd->GetPosition()); + } + else + m_PSRecordingPointSet->InsertPoint(size, nd->GetPosition()); + } } - mitk::NavigationData::Pointer nd = m_Source->GetOutput(); + +void QmitkIGTTrackingLabView::OnAddRegistrationTrackingFiducial() +{ + mitk::NavigationData::Pointer nd = m_InstrumentNavigationData; if( nd.IsNull() || !nd->IsDataValid()) + { QMessageBox::warning( 0, "Invalid tracking data", "Navigation data is not available or invalid!", QMessageBox::Ok ); - - // in case the tracker fiducials datanode has been renamed or removed - //if(trackerFiducialsPS.IsNull()) - //{ - // mitk::DataNode::Pointer trackerFiducialsDN = mitk::DataNode::New(); - // trackerFiducialsDN->SetName(m_RegistrationTrackingFiducialsName); - // trackerFiducialsPS = mitk::PointSet::New(); - // trackerFiducialsDN->SetData(trackerFiducialsPS); - // m_RegistrationWidget->SetTrackerFiducialsNode(trackerFiducialsDN); - //} - - + return; + } if(m_TrackerFiducialsDataNode.IsNotNull() && m_TrackerFiducialsDataNode->GetData() != NULL) { mitk::PointSet::Pointer ps = dynamic_cast(m_TrackerFiducialsDataNode->GetData()); ps->InsertPoint(ps->GetSize(), nd->GetPosition()); } else QMessageBox::warning(NULL, "IGTSurfaceTracker: Error", "Can not access Tracker Fiducials. Adding fiducial not possible!"); +} + +void QmitkIGTTrackingLabView::OnInstrumentSelected() +{ + if (m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource().IsNotNull()) + { + m_InstrumentNavigationData = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedToolID()); + } + else + { + m_Controls.m_PointerNameLabel->setText(""); + return; + } + + if (m_InstrumentNavigationData.IsNotNull()) + { + m_Controls.m_PointerNameLabel->setText(m_InstrumentNavigationData->GetName()); + } + else + { + m_Controls.m_PointerNameLabel->setText(""); + } +} + +void QmitkIGTTrackingLabView::OnObjectmarkerSelected() +{ +if (m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource().IsNotNull()) + { + m_ObjectmarkerNavigationData = m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_TrackingDeviceSelectionWidget->GetSelectedToolID()); + } + else + { + m_Controls.m_ObjectmarkerNameLabel->setText(""); + return; + } + if (m_ObjectmarkerNavigationData.IsNotNull()) + { + m_Controls.m_ObjectmarkerNameLabel->setText(m_ObjectmarkerNavigationData->GetName()); + } + else + { + m_Controls.m_ObjectmarkerNameLabel->setText(""); + } } void QmitkIGTTrackingLabView::OnSetupNavigation() { + MITK_INFO << "SetupNavigationCalled"; if(m_Source.IsNotNull()) if(m_Source->IsTracking()) return; mitk::DataStorage* ds = this->GetDefaultDataStorage(); if(ds == NULL) { QMessageBox::warning(NULL, "IGTSurfaceTracker: Error", "can not access DataStorage. Navigation not possible"); return; } // Building up the filter pipeline try { this->SetupIGTPipeline(); } catch(std::exception& e) { QMessageBox::warning(NULL, QString("IGTSurfaceTracker: Error"), QString("Error while building the IGT-Pipeline: %1").arg(e.what())); this->DestroyIGTPipeline(); // destroy the pipeline if building is incomplete return; } catch(...) { QMessageBox::warning(NULL, QString("IGTSurfaceTracker: Error"), QString("Error while building the IGT-Pipeline")); this->DestroyIGTPipeline(); return; } } void QmitkIGTTrackingLabView::SetupIGTPipeline() { - mitk::DataStorage* ds = this->GetDefaultDataStorage(); // check if DataStorage is available - if(ds == NULL) - throw std::invalid_argument("DataStorage is not available"); - - mitk::TrackingDevice::Pointer tracker = m_NDIConfigWidget->GetTracker(); // get current tracker from configuration widget - if(tracker.IsNull()) // check if tracker is valid - throw std::invalid_argument("tracking device is NULL!"); - - m_Source = mitk::TrackingDeviceSource::New(); // create new source for the IGT-Pipeline - m_Source->SetTrackingDevice(tracker); // set the found tracker from the configuration widget to the source - - this->InitializeFilters(); // initialize all needed filters - - if(m_NDIConfigWidget->GetTracker()->GetType() == mitk::NDIAurora) - { - - for (unsigned int i=0; i < m_Source->GetNumberOfOutputs(); ++i) - { - m_FiducialRegistrationFilter->SetInput(i, m_Source->GetOutput(i)); // set input for registration filter - m_Visualizer->SetInput(i, m_FiducialRegistrationFilter->GetOutput(i)); // set input for visualization filter - } - - for(unsigned int i= 0; i < m_Visualizer->GetNumberOfOutputs(); ++i) - { - const char* toolName = tracker->GetTool(i)->GetToolName(); - - mitk::DataNode::Pointer representation = this->CreateInstrumentVisualization(this->GetDefaultDataStorage(), toolName); - m_PSRecToolSelectionComboBox->addItem(QString(toolName)); - - m_PermanentRegistrationToolSelectionWidget->AddToolName(QString(toolName)); - m_VirtualViewToolSelectionWidget->AddToolName(QString(toolName)); - - m_Visualizer->SetRepresentationObject(i, representation->GetData()); - - } - - if(m_Source->GetTrackingDevice()->GetToolCount() > 0) - m_RenderingTimerWidget->setEnabled(true); - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_ALL); - this->GlobalReinit(); - } - - // this->CreateInstrumentVisualization(ds, tracker);//create for each single connected ND a corresponding 3D representation + this->InitializeRegistration(); //initializes the registration widget } void QmitkIGTTrackingLabView::InitializeFilters() { - //1. Fiducial Registration Filters - m_FiducialRegistrationFilter = mitk::NavigationDataLandmarkTransformFilter::New(); // filter used for initial fiducial registration - - //2. Visualization Filter - m_Visualizer = mitk::NavigationDataObjectVisualizationFilter::New(); // filter to display NavigationData - - m_PermanentRegistrationFilter = mitk::NavigationDataLandmarkTransformFilter::New(); - //3. Virtual Camera - m_VirtualView = mitk::CameraVisualization::New(); // filter to update the vtk camera according to the reference navigation data - m_VirtualView->SetRenderer(mitk::BaseRenderer::GetInstance(this->GetActiveStdMultiWidget()->mitkWidget4->GetRenderWindow())); - - mitk::Vector3D viewUpInToolCoordinatesVector; - viewUpInToolCoordinatesVector[0]=1; - viewUpInToolCoordinatesVector[1]=0; - viewUpInToolCoordinatesVector[2]=0; - - m_VirtualView->SetDirectionOfProjectionInToolCoordinates(m_DirectionOfProjectionVector); - m_VirtualView->SetFocalLength(5000.0); - m_VirtualView->SetViewUpInToolCoordinates(viewUpInToolCoordinatesVector); } -void QmitkIGTTrackingLabView::OnRegisterFiducials( ) +void QmitkIGTTrackingLabView::OnRegisterFiducials() { - /* filter pipeline can only be build, if source and visualization filters exist */ - if (m_Source.IsNull() || m_Visualizer.IsNull() || m_FiducialRegistrationFilter.IsNull()) - { - QMessageBox::warning(NULL, "Registration not possible", "Navigation pipeline is not ready. Please (re)start the navigation"); - return; - } - if (m_Source->IsTracking() == false) - { - QMessageBox::warning(NULL, "Registration not possible", "Registration only possible if navigation is running"); - return; - } + //Check for initialization + if (!CheckRegistrationInitialization()) return; /* retrieve fiducials from data storage */ mitk::DataStorage* ds = this->GetDefaultDataStorage(); - - mitk::PointSet::Pointer imageFiducials = dynamic_cast(m_ImageFiducialsDataNode->GetData()); mitk::PointSet::Pointer trackerFiducials = dynamic_cast(m_TrackerFiducialsDataNode->GetData()); - //mitk::PointSet::Pointer imageFiducials = ds->GetNamedObject(m_RegistrationImageFiducialsName.c_str()); - //mitk::PointSet::Pointer trackerFiducials = ds->GetNamedObject(m_RegistrationTrackingFiducialsName.c_str()); - if (imageFiducials.IsNull() || trackerFiducials.IsNull()) - { - QMessageBox::warning(NULL, "Registration not possible", "Fiducial data objects not found. \n" - "Please set 3 or more fiducials in the image and with the tracking system.\n\n" - "Registration is not possible"); - return; - } - - unsigned int minFiducialCount = 3; // \Todo: move to view option - if ((imageFiducials->GetSize() < minFiducialCount) || (trackerFiducials->GetSize() < minFiducialCount) || (imageFiducials->GetSize() != trackerFiducials->GetSize())) - { - QMessageBox::warning(NULL, "Registration not possible", QString("Not enough fiducial pairs found. At least %1 fiducial must " - "exist for the image and the tracking system respectively.\n" - "Currently, %2 fiducials exist for the image, %3 fiducials exist for the tracking system").arg(minFiducialCount).arg(imageFiducials->GetSize()).arg(trackerFiducials->GetSize())); - return; - } - - /* now we have two PointSets with enough points to perform a landmark based transform */ - if ( m_RegistrationWidget->UseICPIsChecked() ) - m_FiducialRegistrationFilter->UseICPInitializationOn(); - else - m_FiducialRegistrationFilter->UseICPInitializationOff(); - - m_FiducialRegistrationFilter->SetSourceLandmarks(trackerFiducials); - m_FiducialRegistrationFilter->SetTargetLandmarks(imageFiducials); - - - if (m_FiducialRegistrationFilter.IsNotNull() && m_FiducialRegistrationFilter->IsInitialized()) // update registration quality display - { - QString registrationQuality = QString("%0: FRE is %1mm (Std.Dev. %2), \n" - "RMS error is %3mm,\n" - "Minimum registration error (best fitting landmark) is %4mm,\n" - "Maximum registration error (worst fitting landmark) is %5mm.") - .arg("Fiducial Registration") - .arg(m_FiducialRegistrationFilter->GetFRE(), 3, 'f', 3) - .arg(m_FiducialRegistrationFilter->GetFREStdDev(), 3, 'f', 3) - .arg(m_FiducialRegistrationFilter->GetRMSError(), 3, 'f', 3) - .arg(m_FiducialRegistrationFilter->GetMinError(), 3, 'f', 3) - .arg(m_FiducialRegistrationFilter->GetMaxError(), 3, 'f', 3); - m_RegistrationWidget->SetQualityDisplayText(registrationQuality); - } - - //trackerFiducials->Clear(); - //this->GlobalReinit(); -} - - -void QmitkIGTTrackingLabView::OnTrackerDisconnected() -{ - m_RenderingTimerWidget->DisableWidget(); - this->DestroyInstrumentVisualization(this->GetDefaultDataStorage(), m_NDIConfigWidget->GetTracker()); -} - - -mitk::DataNode::Pointer QmitkIGTTrackingLabView::CreateInstrumentVisualization(mitk::DataStorage* ds, const char* toolName) -{ - //const char* toolName = tracker->GetTool(i)->GetToolName(); - mitk::DataNode::Pointer toolRepresentationNode; - toolRepresentationNode = ds->GetNamedNode(toolName); // check if node with same name already exists - - if(toolRepresentationNode.IsNotNull()) - ds->Remove(toolRepresentationNode); // remove old node with same name - - toolRepresentationNode = this->CreateConeRepresentation( toolName ); - // m_Visualizer->SetRepresentationObject(i, toolRepresentationNode->GetData()); - - ds->Add(toolRepresentationNode); // adds node to data storage - - return toolRepresentationNode; -} - - -mitk::DataNode::Pointer QmitkIGTTrackingLabView::CreateConeRepresentation( const char* label ) -{ - - //new data - mitk::Cone::Pointer activeToolData = mitk::Cone::New(); - vtkConeSource* vtkData = vtkConeSource::New(); - - vtkData->SetRadius(7.5); - vtkData->SetHeight(15.0); - vtkData->SetDirection(m_DirectionOfProjectionVector[0],m_DirectionOfProjectionVector[1],m_DirectionOfProjectionVector[2]); - vtkData->SetCenter(0.0, 0.0, 7.5); - vtkData->SetResolution(20); - vtkData->CappingOn(); - vtkData->Update(); - activeToolData->SetVtkPolyData(vtkData->GetOutput()); - vtkData->Delete(); - - //new node - mitk::DataNode::Pointer coneNode = mitk::DataNode::New(); - coneNode->SetData(activeToolData); - coneNode->GetPropertyList()->SetProperty("name", mitk::StringProperty::New( label )); - coneNode->GetPropertyList()->SetProperty("layer", mitk::IntProperty::New(0)); - coneNode->GetPropertyList()->SetProperty("visible", mitk::BoolProperty::New(true)); - coneNode->SetColor(1.0,0.0,0.0); - coneNode->SetOpacity(0.85); - coneNode->Modified(); - - return coneNode; -} - -void QmitkIGTTrackingLabView::DestroyIGTPipeline() -{ - if(m_Source.IsNotNull()) - { - m_Source->StopTracking(); - m_Source->Disconnect(); - m_Source = NULL; - } - m_FiducialRegistrationFilter = NULL; - m_PermanentRegistrationFilter = NULL; - m_Visualizer = NULL; - m_VirtualView = NULL; -} - -void QmitkIGTTrackingLabView::OnChangeToolName(int index, QString name) -{ - if(m_Source.IsNull()) - return; - - mitk::DataStorage* ds = this->GetDefaultDataStorage(); - if(ds == NULL) + //convert point sets to vtk poly data + vtkSmartPointer sourcePoints = vtkSmartPointer::New(); + vtkSmartPointer targetPoints = vtkSmartPointer::New(); + for (int i=0; iGetSize(); i++) { - QMessageBox::warning(NULL,"DataStorage Access Error", "Could not access DataStorage. Tool Name can not be changed!"); - return; + double point[3] = {imageFiducials->GetPoint(i)[0],imageFiducials->GetPoint(i)[1],imageFiducials->GetPoint(i)[2]}; + sourcePoints->InsertNextPoint(point); + double point_targets[3] = {trackerFiducials->GetPoint(i)[0],trackerFiducials->GetPoint(i)[1],trackerFiducials->GetPoint(i)[2]}; + targetPoints->InsertNextPoint(point_targets); } - mitk::NavigationData::Pointer tempND = m_Source->GetOutput(index); - if(tempND.IsNull()) - return; - - const char* oldName = tempND->GetName(); - - mitk::DataNode::Pointer tempNode = ds->GetNamedNode(oldName); - - if(tempNode.IsNotNull()) + //compute transform + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->SetSourceLandmarks(sourcePoints); + transform->SetTargetLandmarks(targetPoints); + transform->SetModeToRigidBody(); + transform->Modified(); + transform->Update(); + + //compute FRE + double FRE = 0; + for(unsigned int i = 0; i < imageFiducials->GetSize(); i++) { - tempNode->SetName(name.toStdString().c_str()); - tempND->SetName(name.toStdString().c_str()); + itk::Point transformed = transform->TransformPoint(imageFiducials->GetPoint(i)[0],imageFiducials->GetPoint(i)[1],imageFiducials->GetPoint(i)[2]); + double cur_error_squared = transformed.SquaredEuclideanDistanceTo(trackerFiducials->GetPoint(i)); + FRE += cur_error_squared; } - else - QMessageBox::warning(NULL, "Rename Tool Error", "Couldn't find the corresponding tool for changing it's name!"); -} - -void QmitkIGTTrackingLabView::OnToolLoaded(int index, mitk::DataNode::Pointer toolNode) -{ - if(m_Source.IsNull() || m_Visualizer.IsNull()) - return; - - mitk::DataStorage* ds = this->GetDefaultDataStorage(); - if(ds == NULL) - { - QMessageBox::warning(NULL,"DataStorage Access Error", "Could not access DataStorage. Loaded tool representation can not be shown!"); - return; - } - - mitk::NavigationData::Pointer tempND = m_Source->GetOutput(index); - if(tempND.IsNull()) - return; - - // try to find DataNode for tool in DataStorage - const char* toolName = tempND->GetName(); - mitk::DataNode::Pointer tempNode = ds->GetNamedNode(toolName); - - if(tempNode.IsNull()) - { - tempNode = mitk::DataNode::New(); // create new node, if none was found - ds->Add(tempNode); - } - - tempNode->SetData(toolNode->GetData()); - tempNode->SetName(toolNode->GetName()); - m_PSRecToolSelectionComboBox->setItemText(index,toolNode->GetName().c_str()); - - m_VirtualViewToolSelectionWidget->ChangeToolName(index, QString(toolNode->GetName().c_str())); - m_PermanentRegistrationToolSelectionWidget->ChangeToolName(index, QString(toolNode->GetName().c_str())); - - m_Visualizer->SetRepresentationObject(index, tempNode->GetData()); - m_Visualizer->Update(); - - tempNode->Modified(); - this->GlobalReinit(); -} - -void QmitkIGTTrackingLabView::OnStartNavigation() -{ + FRE = sqrt(FRE/ (double) imageFiducials->GetSize()); + m_Controls.m_RegistrationWidget->SetQualityDisplayText("FRE: " + QString::number(FRE) + " mm"); - if(m_Source.IsNull()) - { - QMessageBox::warning(NULL, "IGTTrackingLab: Error", "can not access tracking source. Navigation not possible"); - return; - } + //convert from vtk to itk data types + itk::Matrix rotationFloat = itk::Matrix(); + itk::Vector translationFloat = itk::Vector(); + itk::Matrix rotationDouble = itk::Matrix(); + itk::Vector translationDouble = itk::Vector(); - if(!m_Source->IsTracking()) + vtkSmartPointer m = transform->GetMatrix(); + for(int k=0; k<3; k++) for(int l=0; l<3; l++) { - m_Source->StartTracking(); - - try - { - m_RenderingTimerWidget->GetTimerInterval(); - this->StartContinuousUpdate(); // start tracker with set interval - - for(unsigned int i = 0; i < m_Source->GetNumberOfOutputs(); i++) // add navigation data to bundle widgets - { - m_ToolStatusWidget->AddNavigationData(dynamic_cast(m_Source->GetOutputs().at(i).GetPointer())); - } - - m_ToolStatusWidget->ShowStatusLabels(); // show status for every tool if ND is valid or not - //m_IGTPlayerWidget->setEnabled(true); - } - catch(...) - { - //m_IGTPlayerWidget->setDisabled(true); - this->StopContinuousUpdate(); - this->DestroyIGTPipeline(); - return; - } - - m_NDIConfigWidget->EnableAddToolsButton(false); + rotationFloat[k][l] = m->GetElement(k,l); + rotationDouble[k][l] = m->GetElement(k,l); } -} - - -void QmitkIGTTrackingLabView::StopContinuousUpdate() -{ - if (this->m_RenderingTimerWidget->GetUpdateTimer() != NULL) + for(int k=0; k<3; k++) { - m_RenderingTimerWidget->StopTimer(); - disconnect( (QTimer*) m_RenderingTimerWidget->GetUpdateTimer(), SIGNAL(timeout()), this, SLOT(RenderScene()) ); // disconnect timer from RenderScene() method + translationFloat[k] = m->GetElement(k,3); + translationDouble[k] = m->GetElement(k,3); } - if(m_PointSetRecordPushButton) - m_PointSetRecordPushButton->setDisabled(true); -} - -void QmitkIGTTrackingLabView::RenderScene( ) -{ - try - { - if (m_Visualizer.IsNull() || this->GetActiveStdMultiWidget() == NULL) - return; - try - { - if(m_Source.IsNotNull() && m_Source->IsTracking()) - m_ToolStatusWidget->Refresh(); - - - - if(m_VirtualViewToolSelectionWidget->IsSelectedToolActivated()) - { - m_VirtualView->Update(); - mitk::Point3D p = m_Visualizer->GetOutput(m_VirtualViewToolSelectionWidget->GetCurrentSelectedIndex())->GetPosition(); - this->GetActiveStdMultiWidget()->MoveCrossToPosition(p); - } - - if(m_PermanentRegistrationToolSelectionWidget->IsSelectedToolActivated() && m_PermanentRegistrationToolSelectionWidget->GetCurrentSelectedIndex() >= 0 ) - { - mitk::NavigationData::Pointer permRegTool = m_Source->GetOutput((unsigned int) m_PermanentRegistrationToolSelectionWidget->GetCurrentSelectedIndex()); - - m_PermanentRegistrationFilter->SetSourceLandmarks(this->GetVirtualPointSetFromPosition(permRegTool)); - } - - if(m_PointSetRecording && m_PSRecordingPointSet.IsNotNull()) - { - int size = m_PSRecordingPointSet->GetSize(); - mitk::NavigationData::Pointer nd= m_Visualizer->GetOutput(m_PSRecToolSelectionComboBox->currentIndex()); - - if(size > 0) - { - mitk::Point3D p = m_PSRecordingPointSet->GetPoint(size-1); - if(p.EuclideanDistanceTo(nd->GetPosition()) > (double) m_PSRecordingSpinBox->value()) - m_PSRecordingPointSet->InsertPoint(size, nd->GetPosition()); - } - else - m_PSRecordingPointSet->InsertPoint(size, nd->GetPosition()); - } - } - catch(std::exception& e) + /*MITK_INFO << "MATRIX: "; + for(int k=0; k<=3; k++) { - MITK_WARN << "Exception during QmitkIGTTrackingLab::RenderScene():" << e.what() << "\n"; - } - - //if(m_VirtualViewCheckBox->isChecked()) - // mitk::RenderingManager::GetInstance()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_ALL); - ////update all Widgets - //else - - m_Visualizer->Update(); + MITK_INFO << m->GetElement(k,0) << " " << m->GetElement(k,1) << " " << m->GetElement(k,2) << " " << m->GetElement(k,3); + }*/ - mitk::RenderingManager::GetInstance()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_ALL); + //save transform + m_T_ObjectReg = mitk::Transform::New(); + m_T_ObjectReg->SetMatrix(m); + //transform surface + mitk::AffineTransform3D::Pointer newTransform = mitk::AffineTransform3D::New(); + newTransform->SetMatrix(rotationFloat); + newTransform->SetOffset(translationFloat); - } - catch (std::exception& e) - { - MITK_WARN << "RenderAll exception: " << e.what() << "\n"; - } - catch (...) + //transform surface + if(m_Controls.m_SurfaceActive->isChecked() && m_Controls.m_ObjectComboBox->GetSelectedNode().IsNotNull()) { - MITK_WARN << "RenderAll unknown exception\n"; + m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(newTransform); } -} - -void QmitkIGTTrackingLabView::StartContinuousUpdate( ) -{ - if (m_Source.IsNull() || m_Visualizer.IsNull() ) - throw std::invalid_argument("Pipeline is not set up correctly"); - if (m_RenderingTimerWidget->GetUpdateTimer() == NULL) - return; - - else + //transform ct image + if(m_Controls.m_ImageActive->isChecked() && m_Controls.m_ImageComboBox->GetSelectedNode().IsNotNull()) { - connect( (QTimer*) m_RenderingTimerWidget->GetUpdateTimer(), SIGNAL(timeout()), this, SLOT(RenderScene()) ); // connect update timer to RenderScene() method + mitk::AffineTransform3D::Pointer imageTransform = m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->GetIndexToWorldTransform(); + m_T_ImageGeo = mitk::AffineTransform3D::New(); + m_T_ImageGeo->Compose(imageTransform); + imageTransform->Compose(newTransform); + mitk::AffineTransform3D::Pointer newImageTransform = mitk::AffineTransform3D::New(); //create new image transform... setting the composed directly leads to an error + itk::Matrix rotationFloatNew = imageTransform->GetMatrix(); + itk::Vector translationFloatNew = imageTransform->GetOffset(); + newImageTransform->SetMatrix(rotationFloatNew); + newImageTransform->SetOffset(translationFloatNew); + m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(newImageTransform); + m_T_ImageReg = m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->GetIndexToWorldTransform(); } - if(m_PointSetRecordPushButton) - m_PointSetRecordPushButton->setEnabled(true); } - - -void QmitkIGTTrackingLabView::OnStopNavigation() +void QmitkIGTTrackingLabView::DestroyIGTPipeline() { - if(m_Source.IsNull()) - { - QMessageBox::warning(NULL, "IGTSurfaceTracker: Error", "can not access tracking source. Navigation not possible"); - return; - } - if(m_Source->IsTracking()) + if(m_Source.IsNotNull()) { m_Source->StopTracking(); - this->StopContinuousUpdate(); - m_ToolStatusWidget->RemoveStatusLabels(); - - m_NDIConfigWidget->EnableAddToolsButton(true); - } -} - - -void QmitkIGTTrackingLabView::OnToolsAdded(QStringList toolsList) -{ - - if(m_Source.IsNull() || m_FiducialRegistrationFilter.IsNull() || m_Visualizer.IsNull()) - return; - - m_Source->UpdateOutputInformation(); - - unsigned int nrOfOldOutputs = m_Visualizer->GetNumberOfOutputs(); - - for(unsigned int i = nrOfOldOutputs; i < m_Source->GetNumberOfOutputs(); ++i) - { - m_FiducialRegistrationFilter->SetInput(i, m_Source->GetOutput(i)); - m_Visualizer->SetInput(i, m_FiducialRegistrationFilter->GetOutput(i)); - } - - for(unsigned int j = nrOfOldOutputs; j < m_Visualizer->GetNumberOfOutputs(); ++j) - { - mitk::DataNode::Pointer representation = this->CreateInstrumentVisualization(this->GetDefaultDataStorage(), m_Source->GetTrackingDevice()->GetTool(j)->GetToolName()); - - m_PSRecToolSelectionComboBox->addItem(QString(m_Source->GetTrackingDevice()->GetTool(j)->GetToolName())); - - m_PermanentRegistrationToolSelectionWidget->AddToolName(QString(m_Source->GetTrackingDevice()->GetTool(j)->GetToolName())); - m_VirtualViewToolSelectionWidget->AddToolName(QString(m_Source->GetTrackingDevice()->GetTool(j)->GetToolName())); - - m_Visualizer->SetRepresentationObject(j, representation->GetData()); + m_Source->Disconnect(); + m_Source = NULL; } - - if(m_Source->GetTrackingDevice()->GetToolCount() > 0) - m_RenderingTimerWidget->setEnabled(true); - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_ALL); - this->GlobalReinit(); - - //mitk::RenderingManager::GetInstance()->RequestUpdateAll(mitk::RenderingManager::REQUEST_UPDATE_ALL); + m_PermanentRegistrationFilter = NULL; + m_Visualizer = NULL; + m_VirtualView = NULL; } void QmitkIGTTrackingLabView::InitializeRegistration() { mitk::DataStorage* ds = this->GetDefaultDataStorage(); if( ds == NULL ) return; m_RegistrationWidget->SetMultiWidget(this->GetActiveStdMultiWidget()); // passing multiwidget to pointsetwidget if(m_ImageFiducialsDataNode.IsNull()) { m_ImageFiducialsDataNode = mitk::DataNode::New(); mitk::PointSet::Pointer ifPS = mitk::PointSet::New(); m_ImageFiducialsDataNode->SetData(ifPS); mitk::Color color; color.Set(1.0f, 0.0f, 0.0f); m_ImageFiducialsDataNode->SetName(m_RegistrationImageFiducialsName); m_ImageFiducialsDataNode->SetColor(color); m_ImageFiducialsDataNode->SetBoolProperty( "updateDataOnRender", false ); ds->Add(m_ImageFiducialsDataNode); } m_RegistrationWidget->SetMultiWidget(this->GetActiveStdMultiWidget()); m_RegistrationWidget->SetImageFiducialsNode(m_ImageFiducialsDataNode); if(m_TrackerFiducialsDataNode.IsNull()) { m_TrackerFiducialsDataNode = mitk::DataNode::New(); mitk::PointSet::Pointer tfPS = mitk::PointSet::New(); m_TrackerFiducialsDataNode->SetData(tfPS); mitk::Color color; color.Set(0.0f, 1.0f, 0.0f); m_TrackerFiducialsDataNode->SetName(m_RegistrationTrackingFiducialsName); m_TrackerFiducialsDataNode->SetColor(color); m_TrackerFiducialsDataNode->SetBoolProperty( "updateDataOnRender", false ); ds->Add(m_TrackerFiducialsDataNode); } m_RegistrationWidget->SetTrackerFiducialsNode(m_TrackerFiducialsDataNode); } void QmitkIGTTrackingLabView::OnToolBoxCurrentChanged(const int index) { switch (index) { case RegistrationWidget: this->InitializeRegistration(); break; default: break; } } mitk::DataNode::Pointer QmitkIGTTrackingLabView::CreateRegistrationFiducialsNode( const std::string& label, const mitk::Color& color) { mitk::DataNode::Pointer fiducialsNode = mitk::DataNode::New(); mitk::PointSet::Pointer fiducialsPointSet = mitk::PointSet::New(); fiducialsNode->SetData(fiducialsPointSet); fiducialsNode->SetName( label ); fiducialsNode->SetColor( color ); fiducialsNode->SetBoolProperty( "updateDataOnRender", false ); return fiducialsNode; } void QmitkIGTTrackingLabView::ChangeToolRepresentation( int toolID , mitk::Surface::Pointer surface ) { mitk::DataStorage* ds = this->GetDefaultDataStorage(); if(ds == NULL) { QMessageBox::warning(NULL, "IGTSurfaceTracker: Error", "Can not access DataStorage. Changing tool representation not possible!"); return; } mitk::TrackingDevice::Pointer tracker = m_NDIConfigWidget->GetTracker(); if(tracker.IsNull()) { QMessageBox::warning(NULL, "IGTSurfaceTracker: Error", "Can not access Tracker. Changing tool representation not possible!"); return; } try { const char* name = tracker->GetTool(toolID)->GetToolName(); // get tool name by id mitk::DataNode::Pointer toolNode = ds->GetNamedNode(name); if(toolNode.IsNull()) return; toolNode->SetData(surface); // change surface representation of node toolNode->SetColor(0.45,0.70,0.85); //light blue like old 5D sensors toolNode->Modified(); m_Visualizer->SetRepresentationObject( toolID, toolNode->GetData()); // updating node with changed surface back in visualizer mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } catch(std::exception& e) { QMessageBox::warning(NULL, QString("IGTSurfaceTracker: Error"), QString("Can not change tool representation!").arg(e.what())); return; } } - -QWidget* QmitkIGTTrackingLabView::CreatePointSetRecordingWidget(QWidget* parent) -{ - QWidget* pointSetRecordingWidget = new QWidget(parent); - m_PSRecToolSelectionComboBox = new QComboBox(pointSetRecordingWidget); - m_PSRecordingSpinBox = new QSpinBox(pointSetRecordingWidget); - QLabel* psRecordingEpsilonDistance = new QLabel("mm (point distance)", pointSetRecordingWidget); - - // the recording button - m_PointSetRecordPushButton = new QPushButton("Start PointSet Recording", pointSetRecordingWidget); - m_PointSetRecordPushButton->setDisabled(true); - m_PointSetRecordPushButton->setIcon(QIcon(":/QmitkQmitkIGTTrackingLabView/start_rec.png")); - m_PointSetRecordPushButton->setCheckable(true); - connect( m_PointSetRecordPushButton, SIGNAL(toggled(bool)), this, SLOT(OnPointSetRecording(bool)) ); - - // distances spin - m_PSRecordingSpinBox->setValue(1); - m_PSRecordingSpinBox->setMinimum(1); - m_PSRecordingSpinBox->setMaximum(20); - - QLabel* toolSelectLabel = new QLabel("Select tool for recording:", pointSetRecordingWidget); - QGridLayout* layout = new QGridLayout(pointSetRecordingWidget); - - int row = 0; - int col = 0; - - layout->addWidget(toolSelectLabel,row,col++,1,1,Qt::AlignRight); - layout->addWidget(m_PSRecToolSelectionComboBox,row,col++,1,3,Qt::AlignLeft); - col +=2; - layout->addWidget(m_PSRecordingSpinBox,row,col++,1,1,Qt::AlignRight); - layout->addWidget(psRecordingEpsilonDistance, row, col++,1,1,Qt::AlignLeft); - - row++; - col=4; - - layout->addWidget(m_PointSetRecordPushButton,row,col++,1,2,Qt::AlignRight); - - return pointSetRecordingWidget; -} - void QmitkIGTTrackingLabView::OnPointSetRecording(bool record) { mitk::DataStorage* ds = this->GetDefaultDataStorage(); - if(ds == NULL) - return; - if(record) { + if (m_Controls.m_PointSetRecordingToolSelectionWidget->GetSelectedToolID() == -1) + { + QMessageBox::warning(NULL, "Error", "No tool selected for point set recording!"); + m_Controls.m_PointSetRecordCheckBox->setChecked(false); + return; + } + m_PointSetRecordingNavigationData = m_Controls.m_PointSetRecordingToolSelectionWidget->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_PointSetRecordingToolSelectionWidget->GetSelectedToolID()); + + //initialize point set mitk::DataNode::Pointer psRecND = ds->GetNamedNode(m_PointSetRecordingDataNodeName); if(m_PSRecordingPointSet.IsNull() || psRecND.IsNull()) { m_PSRecordingPointSet = NULL; m_PSRecordingPointSet = mitk::PointSet::New(); mitk::DataNode::Pointer dn = mitk::DataNode::New(); dn->SetName(m_PointSetRecordingDataNodeName); dn->SetColor(0.,1.,0.); dn->SetData(m_PSRecordingPointSet); ds->Add(dn); } else + { m_PSRecordingPointSet->Clear(); - + } m_PointSetRecording = true; - m_PointSetRecordPushButton->setText("Stop PointSet Recording"); - m_PSRecToolSelectionComboBox->setDisabled(true); } else { m_PointSetRecording = false; - m_PointSetRecordPushButton->setText("Start PointSet Recording"); - m_PSRecToolSelectionComboBox->setEnabled(true); - } -} - -void QmitkIGTTrackingLabView::DestroyInstrumentVisualization(mitk::DataStorage* ds, mitk::TrackingDevice::Pointer tracker) -{ - if(ds == NULL || tracker.IsNull()) - return; - - for(int i=0; i < tracker->GetToolCount(); ++i) - { - mitk::DataNode::Pointer dn = ds->GetNamedNode(tracker->GetTool(i)->GetToolName()); - - if(dn.IsNotNull()) - ds->Remove(dn); } } - -void QmitkIGTTrackingLabView::GlobalReinit() +/*void QmitkIGTTrackingLabView::GlobalReinit() { // request global reiinit 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::TimeSlicedGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs, "visible"); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeViews(bounds); //global reinit end -} +}*/ -void QmitkIGTTrackingLabView::OnVirtualCamera(int toolNr, bool on) +void QmitkIGTTrackingLabView::OnVirtualCamera(bool on) { - if(m_VirtualView.IsNull() || m_FiducialRegistrationFilter.IsNull()) +if (m_Controls.m_CameraViewSelection->GetSelectedToolID() == -1) + { + m_Controls.m_ActivateNeedleView->setChecked(false); + QMessageBox::warning(NULL, "Error", "No tool selected for camera view!"); return; + } + +if(on) + { + m_VirtualView = mitk::CameraVisualization::New(); + m_VirtualView->SetInput(m_Controls.m_CameraViewSelection->GetSelectedNavigationDataSource()->GetOutput(m_Controls.m_CameraViewSelection->GetSelectedToolID())); - if(on) - { - m_VirtualView->SetInput(m_FiducialRegistrationFilter->GetOutput(toolNr)); - this->GetActiveStdMultiWidget()->SetWidgetPlaneModeToRotation(true); - } - else - this->GetActiveStdMultiWidget()->SetWidgetPlaneModeToSlicing(true); + mitk::Vector3D viewDirection; + viewDirection[0] = (int)(m_Controls.m_NeedleViewX->isChecked()); + viewDirection[1] = (int)(m_Controls.m_NeedleViewY->isChecked()); + viewDirection[2] = (int)(m_Controls.m_NeedleViewZ->isChecked()); + if (m_Controls.m_NeedleViewInvert->isChecked()) viewDirection *= -1; + m_VirtualView->SetDirectionOfProjectionInToolCoordinates(viewDirection); + + mitk::Vector3D viewUpVector; + viewUpVector[0] = (int)(m_Controls.m_NeedleUpX->isChecked()); + viewUpVector[1] = (int)(m_Controls.m_NeedleUpY->isChecked()); + viewUpVector[2] = (int)(m_Controls.m_NeedleUpZ->isChecked()); + if (m_Controls.m_NeedleUpInvert->isChecked()) viewUpVector *= -1; + m_VirtualView->SetViewUpInToolCoordinates(viewUpVector); + + m_VirtualView->SetRenderer(this->GetActiveStdMultiWidget()->GetRenderWindow4()->GetRenderer()); + //next line: better code when this plugin is migrated to mitk::abstractview + //m_VirtualView->SetRenderer(mitk::BaseRenderer::GetInstance(this->GetRenderWindowPart()->GetRenderWindow("3d")->GetRenderWindow())); + m_CameraView = true; + + //make pointer itself invisible + m_Controls.m_CameraViewSelection->GetSelectedNavigationTool()->GetDataNode()->SetBoolProperty("visible",false); + + //disable UI elements + m_Controls.m_ViewDirectionBox->setEnabled(false); + m_Controls.m_ViewUpBox->setEnabled(false); + } +else + { + m_VirtualView = NULL; + m_CameraView = false; + m_Controls.m_CameraViewSelection->GetSelectedNavigationTool()->GetDataNode()->SetBoolProperty("visible",true); + + m_Controls.m_ViewDirectionBox->setEnabled(true); + m_Controls.m_ViewUpBox->setEnabled(true); + } } +bool QmitkIGTTrackingLabView::CheckRegistrationInitialization() +{ + mitk::DataStorage* ds = this->GetDefaultDataStorage(); + mitk::PointSet::Pointer imageFiducials = dynamic_cast(m_ImageFiducialsDataNode->GetData()); + mitk::PointSet::Pointer trackerFiducials = dynamic_cast(m_TrackerFiducialsDataNode->GetData()); + + if (m_Controls.m_SurfaceActive->isChecked() && m_Controls.m_ObjectComboBox->GetSelectedNode().IsNull()) + { + std::string warningMessage = "No surface selected for registration.\nRegistration is not possible"; + MITK_WARN << warningMessage; + QMessageBox::warning(NULL, "Registration not possible", warningMessage.c_str()); + return false; + } + + if (m_Controls.m_ImageActive->isChecked() && m_Controls.m_ImageComboBox->GetSelectedNode().IsNull()) + { + std::string warningMessage = "No image selected for registration.\nRegistration is not possible"; + MITK_WARN << warningMessage; + QMessageBox::warning(NULL, "Registration not possible", warningMessage.c_str()); + return false; + } + + if (imageFiducials.IsNull() || trackerFiducials.IsNull()) + { + std::string warningMessage = "Fiducial data objects not found. \n" + "Please set 3 or more fiducials in the image and with the tracking system.\n\n" + "Registration is not possible"; + MITK_WARN << warningMessage; + QMessageBox::warning(NULL, "Registration not possible", warningMessage.c_str()); + return false; + } + + unsigned int minFiducialCount = 3; // \Todo: move to view option + if ((imageFiducials->GetSize() < minFiducialCount) || (trackerFiducials->GetSize() < minFiducialCount) || (imageFiducials->GetSize() != trackerFiducials->GetSize())) + { + QMessageBox::warning(NULL, "Registration not possible", QString("Not enough fiducial pairs found. At least %1 fiducial must " + "exist for the image and the tracking system respectively.\n" + "Currently, %2 fiducials exist for the image, %3 fiducials exist for the tracking system").arg(minFiducialCount).arg(imageFiducials->GetSize()).arg(trackerFiducials->GetSize())); + return false; + } + + return true; +} -void QmitkIGTTrackingLabView::OnPermanentRegistration(int toolID, bool on) +bool QmitkIGTTrackingLabView::IsTransformDifferenceHigh(mitk::Transform::Pointer transformA, mitk::Transform::Pointer transformB) { - if (m_PermanentRegistrationFilter.IsNull() || m_FiducialRegistrationFilter.IsNull()) - return; + double euclideanDistanceThreshold = .8; + double angularDifferenceThreshold = .8; + + if(transformA.IsNull() || transformA.IsNull()) + {return false;} + mitk::Point3D posA,posB; + posA = transformA->GetPosition(); + posB = transformB->GetPosition(); + + + if(posA.EuclideanDistanceTo(posB) > euclideanDistanceThreshold) + {return true;} + + double returnValue; + mitk::Quaternion rotA,rotB; + rotA = transformA->GetOrientation(); + rotB = transformB->GetOrientation(); + + itk::Vector point; //caution 5D-Tools: Vector must lie in the YZ-plane for a correct result. + point[0] = 0.0; + point[1] = 0.0; + point[2] = 100000.0; + + rotA.normalize(); + rotB.normalize(); + + itk::Matrix rotMatrixA; + for(int i=0; i<3; i++) for(int j=0; j<3; j++) rotMatrixA[i][j] = rotA.rotation_matrix_transpose().transpose()[i][j]; + + itk::Matrix rotMatrixB; + for(int i=0; i<3; i++) for(int j=0; j<3; j++) rotMatrixB[i][j] = rotB.rotation_matrix_transpose().transpose()[i][j]; + + itk::Vector pt1 = rotMatrixA * point; + itk::Vector pt2 = rotMatrixB * point; + + returnValue = (pt1[0]*pt2[0]+pt1[1]*pt2[1]+pt1[2]*pt2[2]) / ( sqrt(pow(pt1[0],2.0)+pow(pt1[1],2.0)+pow(pt1[2],2.0)) * sqrt(pow(pt2[0],2.0)+pow(pt2[1],2.0)+pow(pt2[2],2.0))); + returnValue = acos(returnValue); + + if(returnValue*57.3 > angularDifferenceThreshold){return true;} + + return false; +} + +void QmitkIGTTrackingLabView::OnPermanentRegistration(bool on) +{ if(on) - { - if(m_PermanentRegistrationSourcePoints.IsNull()) - m_PermanentRegistrationSourcePoints = mitk::PointSet::New(); + { + + if(!CheckRegistrationInitialization()) + { + m_Controls.m_UsePermanentRegistrationToggle->setChecked(false); + return; + } - // interconnectiong permanent registration filter between tracking source and fiducial registration filter - for(unsigned int i=0; i < m_Source->GetNumberOfOutputs(); ++i) + //remember initial object transform to calculate the object to marker transform later on + mitk::AffineTransform3D::Pointer transform = this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->GetIndexToWorldTransform(); + vnl_matrix_fixed rotation = vnl_matrix_fixed(); + rotation[0][0] = transform->GetMatrix().GetVnlMatrix()[0][0]; + rotation[0][1] = transform->GetMatrix().GetVnlMatrix()[0][1]; + rotation[0][2] = transform->GetMatrix().GetVnlMatrix()[0][2]; + rotation[1][0] = transform->GetMatrix().GetVnlMatrix()[1][0]; + rotation[1][1] = transform->GetMatrix().GetVnlMatrix()[1][1]; + rotation[1][2] = transform->GetMatrix().GetVnlMatrix()[1][2]; + rotation[2][0] = transform->GetMatrix().GetVnlMatrix()[2][0]; + rotation[2][1] = transform->GetMatrix().GetVnlMatrix()[2][1]; + rotation[2][2] = transform->GetMatrix().GetVnlMatrix()[2][2]; + + mitk::Point3D translation; + translation[0] = transform->GetOffset()[0]; + translation[1] = transform->GetOffset()[1]; + translation[2] = transform->GetOffset()[2]; + + + mitk::Transform::Pointer T_Object = mitk::Transform::New(); + T_Object->SetPosition(translation); + T_Object->SetRotation(rotation); + + //then reset the transform because we will now start to calculate the permenent registration + this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIdentity(); + + if(m_Controls.m_ImageActive->isChecked()) + this->m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(m_T_ImageGeo); + + //create the permanent registration filter + m_PermanentRegistrationFilter = mitk::NavigationDataObjectVisualizationFilter::New(); + //set to rotation mode transposed because we are working with VNL style quaternions + m_PermanentRegistrationFilter->SetRotationMode(mitk::NavigationDataObjectVisualizationFilter::RotationTransposed); + + //first: surface (always activated) + + //connect filter to source + m_PermanentRegistrationFilter->SetInput(0,this->m_ObjectmarkerNavigationData); + + //set representation object + m_PermanentRegistrationFilter->SetRepresentationObject(0,this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()); + + //get the marker transform out of the navigation data + mitk::Transform::Pointer T_Marker = mitk::Transform::New(this->m_ObjectmarkerNavigationData); + + //compute transform from object to marker + mitk::Transform::Pointer T_MarkerRel = mitk::Transform::New(); + T_MarkerRel->Concatenate(T_Object); + T_Marker->Invert(); + T_MarkerRel->Concatenate(T_Marker); + m_T_MarkerRel = T_MarkerRel; + + //TODO: remove mitk::transform from this class and use only mitk::AffineTransform3D + //convert to AffineTransform3D + mitk::AffineTransform3D::Pointer T_MarkerRel_conv = mitk::AffineTransform3D::New(); { - m_PermanentRegistrationFilter->SetInput(i,m_Source->GetOutput(i)); - m_FiducialRegistrationFilter->SetInput(i,m_PermanentRegistrationFilter->GetOutput(i)); + itk::Matrix rotation = itk::Matrix(); + for(int i = 0; i<3; i++)for (int j=0; j<3; j ++) + rotation[i][j] = T_MarkerRel->GetVnlRotationMatrix()[i][j]; + itk::Vector translation = itk::Vector(); + for(int i = 0; i<3; i++) translation[i] = T_MarkerRel->GetPosition()[i]; + + T_MarkerRel_conv->SetMatrix(rotation); + T_MarkerRel_conv->SetOffset(translation); } - mitk::NavigationData::Pointer nd = m_Source->GetOutput((unsigned int) toolID); - m_PermanentRegistrationFilter->SetTargetLandmarks(this->GetVirtualPointSetFromPosition(nd)); - } + m_PermanentRegistrationFilter->SetOffset(0,T_MarkerRel_conv); + + //first: image (if activated) + //set interpolation mode + if (m_Controls.m_ImageActive->isChecked() && (m_Controls.m_ImageComboBox->GetSelectedNode().IsNotNull())) + { + mitk::DataNode::Pointer imageNode = this->m_Controls.m_ImageComboBox->GetSelectedNode(); + imageNode->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_LINEAR) ); + m_PermanentRegistrationFilter->SetInput(1,this->m_ObjectmarkerNavigationData); + m_PermanentRegistrationFilter->SetRepresentationObject(1,imageNode->GetData()); + + mitk::AffineTransform3D::Pointer newTransform = mitk::AffineTransform3D::New(); + newTransform->SetIdentity(); + newTransform->Compose(m_T_ImageGeo); + newTransform->Compose(T_MarkerRel_conv); + m_PermanentRegistrationFilter->SetOffset(1,newTransform); + } + //some general stuff + m_PermanentRegistration = true; + m_ObjectmarkerNavigationDataLastUpdate = mitk::Transform::New(); + + + } else - { - for(unsigned int i=0; i < m_FiducialRegistrationFilter->GetNumberOfOutputs(); ++i) - m_FiducialRegistrationFilter->SetInput(i,m_Source->GetOutput()); - } + { + //stop permanent registration + m_PermanentRegistration = false; + + //restore old registration + if(m_T_ObjectReg.IsNotNull()) + { + //convert to AffineTransform3D + //TODO: remove mitk::transform from this class and use only mitk::AffineTransform3D + mitk::AffineTransform3D::Pointer m_T_ObjectReg_conv = mitk::AffineTransform3D::New(); + itk::Matrix rotation = itk::Matrix(); + for(int i = 0; i<3; i++)for (int j=0; j<3; j ++) + rotation[i][j] = m_T_ObjectReg->GetVnlRotationMatrix()[i][j]; + itk::Vector translation = itk::Vector(); + for(int i = 0; i<3; i++) translation[i] = m_T_ObjectReg->GetPosition()[i]; + m_T_ObjectReg_conv->SetMatrix(rotation); + m_T_ObjectReg_conv->SetOffset(translation); + + this->m_Controls.m_ObjectComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(m_T_ObjectReg_conv); + } + if(m_T_ImageReg.IsNotNull()) this->m_Controls.m_ImageComboBox->GetSelectedNode()->GetData()->GetGeometry()->SetIndexToWorldTransform(m_T_ImageReg); + + //delete filter + m_PermanentRegistrationFilter = NULL; + } + } mitk::PointSet::Pointer QmitkIGTTrackingLabView::GetVirtualPointSetFromPosition(mitk::NavigationData::Pointer navigationData) { typedef itk::QuaternionRigidTransform QuaternionTransformType; mitk::NavigationData::PositionType pointA; mitk::NavigationData::PositionType pointB; mitk::NavigationData::PositionType pointC; //initializing three points with position(0|0|0) pointA.Fill(0); pointB.Fill(0); pointC.Fill(0); // changing position off all points in order to make them orthogonal pointA[0] = 1; pointB[1] = 1; pointC[2] = 1; QuaternionTransformType::Pointer quatTransform = QuaternionTransformType::New(); // orientation of NavigationData from parameter mitk::NavigationData::OrientationType quatIn = navigationData->GetOrientation(); // set orientation to quaternion transform vnl_quaternion const vnlQuatIn(quatIn.x(), quatIn.y(), quatIn.z(), quatIn.r()); quatTransform->SetRotation(vnlQuatIn); // transform each point pointA = quatTransform->TransformPoint(pointA); pointB = quatTransform->TransformPoint(pointB); pointC = quatTransform->TransformPoint(pointC); // add position data from NavigationData parameter to each point pointA[0] += navigationData->GetPosition()[0]; pointA[1] += navigationData->GetPosition()[1]; pointA[2] += navigationData->GetPosition()[2]; pointB[0] += navigationData->GetPosition()[0]; pointB[1] += navigationData->GetPosition()[1]; pointB[2] += navigationData->GetPosition()[2]; pointC[0] += navigationData->GetPosition()[0]; pointC[1] += navigationData->GetPosition()[1]; pointC[2] += navigationData->GetPosition()[2]; // insert points in source points pointset for the permanent registration landmark transform m_PermanentRegistrationSourcePoints->InsertPoint(0,pointA); m_PermanentRegistrationSourcePoints->InsertPoint(1,pointB); m_PermanentRegistrationSourcePoints->InsertPoint(2,pointC); return m_PermanentRegistrationSourcePoints; } diff --git a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.h b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.h index 4748f78813..c01c51b1c4 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.h +++ b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabView.h @@ -1,267 +1,238 @@ /*=================================================================== 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 QmitkIGTTrackingLabView_h #define QmitkIGTTrackingLabView_h #include #include #include "ui_QmitkIGTTrackingLabViewControls.h" #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include +#include class QmitkNDIConfigurationWidget; class QmitkFiducialRegistrationWidget; class QmitkUpdateTimerWidget; class QmitkToolSelectionWidget; class QmitkToolTrackingStatusWidget; /*! \brief QmitkIGTTrackingLabView \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class QmitkIGTTrackingLabView : public QmitkFunctionality { // 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; /** \brief default constructor */ QmitkIGTTrackingLabView(); /** \brief default destructor */ virtual ~QmitkIGTTrackingLabView(); virtual void CreateQtPartControl(QWidget *parent); protected slots: + + void UpdateTimer(); + /** \brief This method adds a new fiducial to the tracker fiducials PointSet. */ void OnAddRegistrationTrackingFiducial(); /** \brief This method calls the fiducial registration. */ void OnRegisterFiducials(); /** - \brief This method should be called if deconnecting the tracker. - */ - void OnTrackerDisconnected(); - /** \brief This method sets up the navigation pipeline before tracking is started. */ void OnSetupNavigation(); /** - \brief This method changes the name of a specific tool. - */ - void OnChangeToolName(int index, QString name); - /** - \brief This method creates the surface representation for a tool loaded from file. - */ - void OnToolLoaded(int index, mitk::DataNode::Pointer toolNode); - /** - \brief This method starts the navigation. - */ - void OnStartNavigation(); - /** - \brief This method stops the navigation. - */ - void OnStopNavigation(); - /** - \brief This method performs the visualisation of all NavigationDatas and performs the PointSet recording if activated. - */ - void RenderScene(); - /** - \brief This method should be called if new tools have been added to the tracking device. - */ - void OnToolsAdded(QStringList toolsList); - /** \brief This method reacts on toolbox item changes. */ void OnToolBoxCurrentChanged(int index); /** \brief This method initializes the registration for the FiducialRegistrationWidget. */ void InitializeRegistration(); /** \brief This method reacts on tool surface changes. */ void ChangeToolRepresentation( int toolID , mitk::Surface::Pointer surface ); /** \brief This method starts the PointSet recording. */ void OnPointSetRecording(bool record); /** \brief This method activates the virtual camera. */ - void OnVirtualCamera(int toolNr, bool on); + void OnVirtualCamera(bool on); /** \brief This method activates the permanent registration based on one tool's position. */ - void OnPermanentRegistration(int toolID, bool on); + void OnPermanentRegistration(bool on); + + void OnInstrumentSelected(); + + void OnObjectmarkerSelected(); + protected: enum ToolBoxElement // enums for the different ToolBox item tabs. { NDIConfigurationWidget = 0, RegistrationWidget = 1, PermanentRecording = 2, PointSetRecording = 3, VirtualCamera = 4 }; Ui::QmitkIGTTrackingLabViewControls m_Controls; /** \brief This method creates all widgets this bundle needs. */ void CreateBundleWidgets( QWidget* parent ); /** \brief This method creates the SIGNAL SLOT connections. */ void CreateConnections(); /** \brief This method sets up the filter pipeline. */ void SetupIGTPipeline(); /** \brief This method initializes all needed filters. */ void InitializeFilters(); /** \brief This method destroys the filter pipeline. */ void DestroyIGTPipeline(); - /** - \brief This method starts the continuos update of the tracking device and the rendering. - */ - void StartContinuousUpdate(); - /** - \brief This method stops the continuos update of the tracking device and the rendering. - */ - void StopContinuousUpdate(); + /** \brief This method creates a DataNode for fiducial PointSets. */ mitk::DataNode::Pointer CreateRegistrationFiducialsNode( const std::string& label, const mitk::Color& color); - /** - \brief This method creates the visualization for all connected instruments. - */ - mitk::DataNode::Pointer CreateInstrumentVisualization(mitk::DataStorage* ds, const char* toolName); // create 3D models for all connected tools - /** - \brief This method creates a DataNode of a 3D cone object. - */ - mitk::DataNode::Pointer CreateConeRepresentation(const char* label = ""); // create a 3D cone as representation for a tool - /** - \brief This method destroys the instrument visualization. - */ - void DestroyInstrumentVisualization(mitk::DataStorage* ds, mitk::TrackingDevice::Pointer tracker); - - /** - \brief This method creates a widget with all input objects needed for the PointSet recording. - */ - QWidget* CreatePointSetRecordingWidget(QWidget* parent); /** \brief This method returns a PointSet with three vritual points transformed from the position and orientation of the given NavigationData. This method is needed to calculate the source points for permanent registration from one tool's position. */ mitk::PointSet::Pointer GetVirtualPointSetFromPosition(mitk::NavigationData::Pointer navigationData); mitk::TrackingDeviceSource::Pointer m_Source; ///< source that connects to the tracking device - mitk::NavigationDataLandmarkTransformFilter::Pointer m_FiducialRegistrationFilter; ///< this filter transforms from tracking coordinates into mitk world coordinates - mitk::NavigationDataLandmarkTransformFilter::Pointer m_PermanentRegistrationFilter; ///< this filter transforms from tracking coordinates into mitk world coordinates if needed it is interconnected before the FiducialEegistrationFilter + + mitk::NavigationDataObjectVisualizationFilter::Pointer m_PermanentRegistrationFilter; ///< this filter transforms from tracking coordinates into mitk world coordinates if needed it is interconnected before the FiducialEegistrationFilter mitk::NavigationDataObjectVisualizationFilter::Pointer m_Visualizer; ///< visualization filter mitk::CameraVisualization::Pointer m_VirtualView; ///< filter to update the vtk camera according to the reference navigation data mitk::Vector3D m_DirectionOfProjectionVector;///< vector for direction of projection of instruments + bool CheckRegistrationInitialization();///< Checks if everything is initialized for registration. Gives error messages and returns false if not. + private: + QTimer* m_Timer; + QToolBox* m_ToolBox; - QComboBox* m_PSRecToolSelectionComboBox; - QSpinBox* m_PSRecordingSpinBox; - QPushButton* m_PointSetRecordPushButton; mitk::PointSet::Pointer m_PSRecordingPointSet; QmitkNDIConfigurationWidget* m_NDIConfigWidget; // tracking device configuration widget QmitkFiducialRegistrationWidget* m_RegistrationWidget; // landmark registration widget - QmitkUpdateTimerWidget* m_RenderingTimerWidget; // update timer widget for rendering and updating - QmitkToolTrackingStatusWidget* m_ToolStatusWidget; // tracking status visualizer widget std::string m_RegistrationTrackingFiducialsName; std::string m_RegistrationImageFiducialsName; std::string m_PointSetRecordingDataNodeName; bool m_PointSetRecording; + bool m_PermanentRegistration; + bool m_CameraView; mitk::DataNode::Pointer m_ImageFiducialsDataNode; mitk::DataNode::Pointer m_TrackerFiducialsDataNode; QmitkToolSelectionWidget* m_PermanentRegistrationToolSelectionWidget; QmitkToolSelectionWidget* m_VirtualViewToolSelectionWidget; mitk::NavigationData::PositionType m_TargetPosition; mitk::NavigationData::OrientationType m_PermanentRegistrationInitialOrientation; mitk::PointSet::Pointer m_PermanentRegistrationSourcePoints; + mitk::NavigationData::Pointer m_InstrumentNavigationData; + mitk::NavigationData::Pointer m_ObjectmarkerNavigationData; + mitk::NavigationData::Pointer m_PointSetRecordingNavigationData; + + mitk::Transform::Pointer m_T_MarkerRel; + mitk::Transform::Pointer m_T_ObjectReg; + mitk::AffineTransform3D::Pointer m_T_ImageReg; + mitk::AffineTransform3D::Pointer m_T_ImageGeo; + mitk::Transform::Pointer m_ObjectmarkerNavigationDataLastUpdate; + + bool IsTransformDifferenceHigh(mitk::Transform::Pointer transformA, mitk::Transform::Pointer transformB); + /** \brief This method performs GlobalReinit() for the rendering widgets. */ - void GlobalReinit(); + //void GlobalReinit(); }; #endif // QmitkIGTTrackingLabView_h diff --git a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabViewControls.ui b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabViewControls.ui index f945916514..b4b80324e5 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabViewControls.ui +++ b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/QmitkIGTTrackingLabViewControls.ui @@ -1,47 +1,581 @@ QmitkIGTTrackingLabViewControls 0 0 - 436 - 374 + 364 + 1058 0 0 QmitkTemplate - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - + + - 20 - 220 + 0 + 600 - + + 0 + + + + + 0 + 0 + 345 + 860 + + + + Configuration + + + + + + <!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:8pt; color:#ff0000;">Caution: Inverse mode is needed </span></p> +<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:8pt; color:#ff0000;">(Change in TrackingToolbox)</span></p></body></html> + + + + + + + + 0 + 150 + + + + + + + + Tool Selection + + + + + + + + Pointer: + + + + + + + Qt::Horizontal + + + + 13 + 20 + + + + + + + + <not selected> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Use selected tool + + + + + + + + + + + Objectmarker: + + + + + + + Qt::Horizontal + + + + 47 + 20 + + + + + + + + <not selected> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Use selected tool + + + + + + + + + + + + Object Selection + + + + + + + + false + + + + + + true + + + true + + + false + + + + + + + Surface: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 150 + 0 + + + + + + + + + + + + DICOM Image: + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 150 + 0 + + + + + + + + + + + + + + + 0 + 0 + 98 + 32 + + + + Initial Registration + + + + + + + + + + + 0 + 0 + 229 + 49 + + + + Permanent Registration + + + + + + Activate permanent registration + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + 0 + 200 + 99 + + + + PointSet Recording + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Point Distance [mm] + + + + + + + 1 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Point Set Recording + + + + + + + + + Qt::Vertical + + + + 20 + 779 + + + + + + + + + + 0 + 0 + 290 + 258 + + + + Camera View + + + + + + + + + Needle View Direction (in Tool Coordinates) + + + + + + + + X + + + true + + + + + + + Y + + + + + + + Z + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Invert + + + + + + + + + + View Up Vector (in Tool Coordinates) + + + + + + + + X + + + true + + + + + + + Y + + + + + + + Z + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Invert + + + + + + + + + + Activate Needle View + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 630 + + + + + + + + + + QmitkFiducialRegistrationWidget + QWidget +
QmitkFiducialRegistrationWidget.h
+ 1 +
+ + QmitkNavigationDataSourceSelectionWidget + QWidget +
QmitkNavigationDataSourceSelectionWidget.h
+ 1 +
+ + QmitkDataStorageComboBox + QComboBox +
QmitkDataStorageComboBox.h
+
+
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 aa8a4982a3..6acb333382 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp @@ -1,679 +1,687 @@ /*=================================================================== 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 "QmitkStdMultiWidget.h" // Qt #include #include // MITK #include #include #include #include #include #include #include // vtk #include //for exceptions #include #include const std::string QmitkMITKIGTTrackingToolboxView::VIEW_ID = "org.mitk.views.mitkigttrackingtoolbox"; QmitkMITKIGTTrackingToolboxView::QmitkMITKIGTTrackingToolboxView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) { m_TrackingTimer = new QTimer(this); m_tracking = false; m_logging = false; m_loggedFrames = 0; } QmitkMITKIGTTrackingToolboxView::~QmitkMITKIGTTrackingToolboxView() { //remove the tracking volume this->GetDataStorage()->Remove(m_TrackingVolumeNode); } 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_Connect, SIGNAL(clicked()), this, SLOT(OnConnect()) ); connect( m_Controls->m_Disconnect, SIGNAL(clicked()), this, SLOT(OnDisconnect()) ); connect( m_Controls->m_StartTracking, SIGNAL(clicked()), this, SLOT(OnStartTracking()) ); connect( m_Controls->m_StopTracking, SIGNAL(clicked()), this, SLOT(OnStopTracking()) ); connect( m_TrackingTimer, SIGNAL(timeout()), this, SLOT(UpdateTrackingTimer())); 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_configurationWidget, SIGNAL(TrackingDeviceSelectionChanged()), this, SLOT(OnTrackingDeviceChanged())); 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())); //initialize widgets m_Controls->m_configurationWidget->EnableAdvancedUserControl(false); m_Controls->m_TrackingToolsStatusWidget->SetShowPositions(true); m_Controls->m_TrackingToolsStatusWidget->SetTextAlignment(Qt::AlignLeft); //initialize tracking volume node m_TrackingVolumeNode = mitk::DataNode::New(); m_TrackingVolumeNode->SetName("TrackingVolume"); m_TrackingVolumeNode->SetOpacity(0.25); m_TrackingVolumeNode->SetBoolProperty("Backface Culling",true); mitk::Color red; red.SetRed(1); m_TrackingVolumeNode->SetColor(red); GetDataStorage()->Add(m_TrackingVolumeNode); //initialize buttons m_Controls->m_Connect->setEnabled(true); m_Controls->m_Disconnect->setEnabled(false); m_Controls->m_StartTracking->setEnabled(false); m_Controls->m_StopTracking->setEnabled(false); m_Controls->m_AutoDetectTools->setVisible(false); //only visible if tracking device is Aurora //Update List of available models for selected tool. std::vector Compatibles = mitk::GetDeviceDataForLine( m_Controls->m_configurationWidget->GetTrackingDevice()->GetType()); m_Controls->m_VolumeSelectionBox->clear(); for(int i = 0; i < Compatibles.size(); i++) { m_Controls->m_VolumeSelectionBox->addItem(Compatibles[i].Model.c_str()); } } } void QmitkMITKIGTTrackingToolboxView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkMITKIGTTrackingToolboxView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkMITKIGTTrackingToolboxView::OnLoadTools() { //read in filename QString filename = QFileDialog::getOpenFileName(NULL,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 { m_toolStorage = myDeserializer->Deserialize(filename.toStdString()); } catch(mitk::IGTException) { std::string errormessage = "Error during deserializing. Problems with file,please check the file?"; QMessageBox::warning(NULL, "IGTPlayer: Error", errormessage.c_str()); return; } if(m_toolStorage->isEmpty()) { errorMessage = myDeserializer->GetErrorMessage(); MessageBox(errorMessage); return; } //update label Poco::Path myPath = Poco::Path(filename.toStdString()); //use this to seperate filename from path QString toolLabel = QString("Loaded Tools: ") + QString::number(m_toolStorage->GetToolCount()) + " Tools from " + myPath.getFileName().c_str(); m_Controls->m_toolLabel->setText(toolLabel); //update tool preview m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); } void QmitkMITKIGTTrackingToolboxView::OnResetTools() { m_toolStorage = NULL; m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); QString toolLabel = QString("Loaded Tools: "); m_Controls->m_toolLabel->setText(toolLabel); } void QmitkMITKIGTTrackingToolboxView::OnConnect() { //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; } //build the IGT pipeline mitk::TrackingDevice::Pointer trackingDevice = this->m_Controls->m_configurationWidget->GetTrackingDevice(); + //set device to rotation mode transposed becaus we are working with VNL style quaternions + if(m_Controls->m_InverseMode->isChecked()) + trackingDevice->SetRotationMode(mitk::TrackingDevice::RotationTransposed); + //Get Tracking Volume Data mitk::TrackingDeviceData data = mitk::DeviceDataUnspecified; QString qstr = m_Controls->m_VolumeSelectionBox->currentText(); if ( (! qstr.isNull()) || (! qstr.isEmpty()) ) { std::string str = qstr.toStdString(); data = mitk::GetDeviceDataByName(str); //Data will be set later, after device generation } //Create Navigation Data Source with the factory class mitk::TrackingDeviceSourceConfigurator::Pointer myTrackingDeviceSourceFactory = mitk::TrackingDeviceSourceConfigurator::New(this->m_toolStorage,trackingDevice); m_TrackingDeviceSource = myTrackingDeviceSourceFactory->CreateTrackingDeviceSource(this->m_ToolVisualizationFilter); MITK_INFO << "Number of tools: " << m_TrackingDeviceSource->GetNumberOfOutputs(); + //set filter to rotation mode transposed becaus we are working with VNL style quaternions + if(m_Controls->m_InverseMode->isChecked()) + m_ToolVisualizationFilter->SetRotationMode(mitk::NavigationDataObjectVisualizationFilter::RotationTransposed); + //First check if the created object is valid if (m_TrackingDeviceSource.IsNull()) { MessageBox(myTrackingDeviceSourceFactory->GetErrorMessage()); return; } //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_toolStorage->DeleteAllTools(); for (int i=0; i < toolsInNewOrder->GetToolCount(); i++) {m_toolStorage->AddTool(toolsInNewOrder->GetTool(i));} } //connect to device try { m_TrackingDeviceSource->Connect(); //Microservice registration: m_TrackingDeviceSource->RegisterAsMicroservice(); m_toolStorage->RegisterAsMicroservice(m_TrackingDeviceSource->GetMicroserviceID()); } catch (...) //todo: change to mitk::IGTException { MessageBox("Error while starting the tracking device!"); return; } //enable/disable Buttons m_Controls->m_Disconnect->setEnabled(true); m_Controls->m_StartTracking->setEnabled(true); m_Controls->m_StopTracking->setEnabled(false); m_Controls->m_Connect->setEnabled(false); DisableOptionsButtons(); DisableTrackingConfigurationButtons(); m_Controls->m_configurationWidget->ConfigurationFinished(); m_Controls->m_TrackingControlLabel->setText("Status: connected"); } void QmitkMITKIGTTrackingToolboxView::OnDisconnect() { if (m_tracking) this->OnStopTracking(); m_TrackingDeviceSource->Disconnect(); m_TrackingDeviceSource->UnRegisterMicroservice(); //ToolStorages unregisters automatically //enable/disable Buttons m_Controls->m_Disconnect->setEnabled(false); m_Controls->m_StartTracking->setEnabled(false); m_Controls->m_StopTracking->setEnabled(false); m_Controls->m_Connect->setEnabled(true); EnableOptionsButtons(); EnableTrackingConfigurationButtons(); m_Controls->m_configurationWidget->Reset(); m_Controls->m_TrackingControlLabel->setText("Status: disconnected"); } void QmitkMITKIGTTrackingToolboxView::OnStartTracking() { try { m_TrackingDeviceSource->StartTracking(); } catch (...) //todo: change to mitk::IGTException { MessageBox("Error while starting the tracking device!"); return; } m_TrackingTimer->start(1000/(m_Controls->m_UpdateRate->value())); m_Controls->m_TrackingControlLabel->setText("Status: tracking"); //connect the tool visualization widget for(int i=0; iGetNumberOfOutputs(); 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);} //show tracking volume this->OnTrackingVolumeChanged(m_Controls->m_VolumeSelectionBox->currentText()); //enable/disable Buttons m_Controls->m_Disconnect->setEnabled(true); m_Controls->m_StartTracking->setEnabled(false); m_Controls->m_StopTracking->setEnabled(true); m_Controls->m_Connect->setEnabled(false); m_tracking = true; this->GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnStopTracking() { if (!m_tracking) return; m_TrackingTimer->stop(); m_TrackingDeviceSource->StopTracking(); 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; //enable/disable Buttons m_Controls->m_Disconnect->setEnabled(true); m_Controls->m_StartTracking->setEnabled(true); m_Controls->m_StopTracking->setEnabled(false); m_Controls->m_Connect->setEnabled(false); this->GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnTrackingDeviceChanged() { mitk::TrackingDeviceType Type = m_Controls->m_configurationWidget->GetTrackingDevice()->GetType(); // Code to enable/disable device specific buttons if (Type == mitk::NDIAurora) //Aurora { m_Controls->m_AutoDetectTools->setVisible(true); m_Controls->m_AddSingleTool->setEnabled(false); } else //Polaris or Microntracker { m_Controls->m_AutoDetectTools->setVisible(false); m_Controls->m_AddSingleTool->setEnabled(true); } // Code to select appropriate tracking volume for current type std::vector Compatibles = mitk::GetDeviceDataForLine(Type); m_Controls->m_VolumeSelectionBox->clear(); for(int 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; if (m_Controls->m_ShowTrackingVolume->isChecked()) { mitk::TrackingVolumeGenerator::Pointer volumeGenerator = mitk::TrackingVolumeGenerator::New(); std::string str = qstr.toStdString(); mitk::TrackingDeviceData data = mitk::GetDeviceDataByName(str); volumeGenerator->SetTrackingDeviceData(data); volumeGenerator->Update(); mitk::Surface::Pointer volumeSurface = volumeGenerator->GetOutput(); m_TrackingVolumeNode->SetData(volumeSurface); GlobalReinit(); } } void QmitkMITKIGTTrackingToolboxView::OnShowTrackingVolumeChanged() { if (m_Controls->m_ShowTrackingVolume->isChecked()) { OnTrackingVolumeChanged(m_Controls->m_VolumeSelectionBox->currentText()); GetDataStorage()->Add(m_TrackingVolumeNode); } else { GetDataStorage()->Remove(m_TrackingVolumeNode); GlobalReinit(); } } void QmitkMITKIGTTrackingToolboxView::OnAutoDetectTools() { if (m_Controls->m_configurationWidget->GetTrackingDevice()->GetType() == mitk::NDIAurora) { DisableTrackingConfigurationButtons(); mitk::NDITrackingDevice::Pointer currentDevice = dynamic_cast(m_Controls->m_configurationWidget->GetTrackingDevice().GetPointer()); currentDevice->OpenConnection(); currentDevice->StartTracking(); mitk::NavigationToolStorage::Pointer autoDetectedStorage = mitk::NavigationToolStorage::New(this->GetDataStorage()); for (int i=0; iGetToolCount(); i++) { //create a navigation tool with sphere as surface std::stringstream toolname; toolname << "AutoDetectedTool" << i; mitk::NavigationTool::Pointer newTool = mitk::NavigationTool::New(); newTool->SetSerialNumber(dynamic_cast(currentDevice->GetTool(i))->GetSerialNumber()); newTool->SetIdentifier(toolname.str()); newTool->SetTrackingDeviceType(mitk::NDIAurora); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); 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(); newNode->SetData(mySphere); newNode->SetName(toolname.str()); newTool->SetDataNode(newNode); autoDetectedStorage->AddTool(newTool); } //save detected tools m_toolStorage = autoDetectedStorage; //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); currentDevice->StopTracking(); currentDevice->CloseConnection(); EnableTrackingConfigurationButtons(); if (m_toolStorage->GetToolCount()>0) { //ask the user if he wants to save the detected tools QMessageBox msgBox; switch(m_toolStorage->GetToolCount()) { case 1: msgBox.setText("Found one tool!"); break; default: msgBox.setText("Found " + QString::number(m_toolStorage->GetToolCount()) + " tools!"); } msgBox.setInformativeText("Do you want to save this tools as tool storage, so you can load them again?"); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); int ret = msgBox.exec(); if (ret == 16384) //yes { //ask the user for a filename QString fileName = QFileDialog::getSaveFileName(NULL, tr("Save File"),"/",tr("*.IGTToolStorage")); //check for empty filename if(fileName == "") {return;} mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); //when Serialize method is used exceptions are thrown, need to be adapted //try-catch block for exception handling in Serializer try { mySerializer->Serialize(fileName.toStdString(),m_toolStorage); } catch(mitk::IGTException) { std::string errormessage = "Error during serialization. Please check the Zip file."; QMessageBox::warning(NULL, "IGTPlayer: Error", errormessage.c_str());} return; } else if (ret == 65536) //no { return; } } } } void QmitkMITKIGTTrackingToolboxView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkMITKIGTTrackingToolboxView::UpdateTrackingTimer() { m_ToolVisualizationFilter->Update(); MITK_DEBUG << "Number of outputs ToolVisualizationFilter: " << m_ToolVisualizationFilter->GetNumberOfIndexedOutputs(); MITK_DEBUG << "Number of inputs ToolVisualizationFilter: " << m_ToolVisualizationFilter->GetNumberOfIndexedInputs(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (m_logging) { this->m_loggingFilter->Update(); m_loggedFrames = this->m_loggingFilter->GetRecordCounter(); 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();} } m_Controls->m_TrackingToolsStatusWidget->Refresh(); } void QmitkMITKIGTTrackingToolboxView::OnChooseFileClicked() { QString filename = QFileDialog::getSaveFileName(NULL,tr("Choose Logging File"), "/", "*.*"); if (filename == "") return; this->m_Controls->m_LoggingFileName->setText(filename); } void QmitkMITKIGTTrackingToolboxView::StartLogging() { if (!m_logging) { //initialize logging filter m_loggingFilter = mitk::NavigationDataRecorder::New(); m_loggingFilter->SetRecordingMode(mitk::NavigationDataRecorder::NormalFile); if (m_Controls->m_xmlFormat->isChecked()) m_loggingFilter->SetOutputFormat(mitk::NavigationDataRecorder::xml); else if (m_Controls->m_csvFormat->isChecked()) m_loggingFilter->SetOutputFormat(mitk::NavigationDataRecorder::csv); std::string filename = m_Controls->m_LoggingFileName->text().toStdString().c_str(); // this part has been changed in order to prevent crash of the program if(!filename.empty()) m_loggingFilter->SetFileName(filename); else if(filename.empty()){ std::string errormessage = "File name has not been set, please set the file name"; mitkThrowException(mitk::IGTIOException)<SetFileName(filename); } if (m_Controls->m_LoggingLimit->isChecked()){m_loggingFilter->SetRecordCountLimit(m_Controls->m_LoggedFramesLimit->value());} //connect filter for(int i=0; iGetNumberOfOutputs(); i++){m_loggingFilter->AddNavigationData(m_ToolVisualizationFilter->GetOutput(i));} //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(NULL, "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) { //update label this->m_Controls->m_LoggingLabel->setText("Logging OFF"); m_loggingFilter->StopRecording(); m_logging = false; EnableLoggingButtons(); } } void QmitkMITKIGTTrackingToolboxView::OnAddSingleTool() { QString Identifier = "Tool#"; if (m_toolStorage.IsNotNull()) Identifier += QString::number(m_toolStorage->GetToolCount()); else Identifier += "0"; m_Controls->m_NavigationToolCreationWidget->Initialize(GetDataStorage(),Identifier.toStdString()); m_Controls->m_NavigationToolCreationWidget->SetTrackingDeviceType(m_Controls->m_configurationWidget->GetTrackingDevice()->GetType(),false); m_Controls->m_TrackingToolsWidget->setCurrentIndex(1); } void QmitkMITKIGTTrackingToolboxView::OnAddSingleToolFinished() { m_Controls->m_TrackingToolsWidget->setCurrentIndex(0); if (this->m_toolStorage.IsNull()) m_toolStorage = mitk::NavigationToolStorage::New(GetDataStorage()); m_toolStorage->AddTool(m_Controls->m_NavigationToolCreationWidget->GetCreatedTool()); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); QString toolLabel = QString("Loaded Tools: "); } void QmitkMITKIGTTrackingToolboxView::OnAddSingleToolCanceled() { m_Controls->m_TrackingToolsWidget->setCurrentIndex(0); } 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::TimeSlicedGeometry::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_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_StopLogging->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::DisableOptionsButtons() { m_Controls->m_ShowTrackingVolume->setEnabled(false); m_Controls->m_UpdateRate->setEnabled(false); m_Controls->m_ShowToolQuaternions->setEnabled(false); m_Controls->m_OptionsUpdateRateLabel->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::EnableOptionsButtons() { m_Controls->m_ShowTrackingVolume->setEnabled(true); m_Controls->m_UpdateRate->setEnabled(true); m_Controls->m_ShowToolQuaternions->setEnabled(true); m_Controls->m_OptionsUpdateRateLabel->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::EnableTrackingConfigurationButtons() { m_Controls->m_AutoDetectTools->setEnabled(true); if (m_Controls->m_configurationWidget->GetTrackingDevice()->GetType() != mitk::NDIAurora) 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::NDIAurora) m_Controls->m_AddSingleTool->setEnabled(false); m_Controls->m_LoadTools->setEnabled(false); m_Controls->m_ResetTools->setEnabled(false); } 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 49c5e2729a..9f98905b42 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui @@ -1,690 +1,704 @@ QmitkMITKIGTTrackingToolboxViewControls 0 0 438 1001 0 0 QmitkTemplate 0 Tracking 0 0 0 300 16777215 280 0 0 <!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:8.25pt; 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:14pt; font-weight:600;">Tracking Tools</span></p></body></html> 0 0 Loaded Tools: <none> Qt::Horizontal 40 20 Auto Detection 200 150 Qt::Horizontal 40 20 120 0 Add Single Tool Qt::Horizontal 40 20 <!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:8.25pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-style:italic;">(only load tool storage files created </span></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-style:italic;">with </span><span style=" font-size:8pt; font-style:italic;">the &quot;NavigationToolManager&quot;)</span></p></body></html> Qt::AlignJustify|Qt::AlignVCenter 120 0 Load Tool Storage Qt::Horizontal 40 20 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:8.25pt; 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:14pt; font-weight:600;">Tracking Control</span></p></body></html> Status: <not configured> Qt::Horizontal 40 20 120 0 Connect Qt::Horizontal 40 20 120 0 Start Tracking Qt::Horizontal 40 20 120 0 Stop Tracking Qt::Horizontal 40 20 120 0 Disconnect Qt::Vertical 20 40 Options true Show Tracking Volume true Select Model: Qt::Horizontal Update Rate (Times Per Second) Qt::Horizontal 40 20 999 10 Show Tool Quaternions + + + + Caution, only for backward compatibility: + + + + + + + Inverse mode (Quaternions are stored inverse) + + + Qt::Vertical 20 597 Logging Filename: C:/logfile.csv Choose File Limit Number Of Logged Frames: Qt::Horizontal 40 20 1 9999 300 CSV format true XML format Logging Status Logging OFF Logged Frames: 0 Qt::Horizontal 40 20 Start Logging Stop Logging Qt::Vertical 20 40 QmitkTrackingDeviceConfigurationWidget QWidget
QmitkTrackingDeviceConfigurationWidget.h
1
QmitkToolTrackingStatusWidget QWidget
QmitkToolTrackingStatusWidget.h
1
QmitkNavigationToolCreationWidget QWidget
QmitkNavigationToolCreationWidget.h
1