diff --git a/Modules/IGT/TrackingDevices/mitkPolhemusInterface.cpp b/Modules/IGT/TrackingDevices/mitkPolhemusInterface.cpp index 678ca57596..ec30718bf9 100644 --- a/Modules/IGT/TrackingDevices/mitkPolhemusInterface.cpp +++ b/Modules/IGT/TrackingDevices/mitkPolhemusInterface.cpp @@ -1,349 +1,377 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #define _USE_MATH_DEFINES #include #include BYTE MotionBuf[0x1FA400]; mitk::PolhemusInterface::PolhemusInterface() : m_continousTracking(false) { m_pdiDev = new CPDIdev(); m_numberOfTools = 0; } mitk::PolhemusInterface::~PolhemusInterface() { delete m_pdiDev; } bool mitk::PolhemusInterface::InitializeDevice() { m_pdiDev->ResetTracker(); m_pdiDev->ResetSAlignment(-1); m_pdiDev->Trace(TRUE, 7); m_continousTracking = false; return true; } bool mitk::PolhemusInterface::SetupDevice() { m_pdiDev->SetPnoBuffer(MotionBuf, 0x1FA400); m_pdiDev->SetMetric(true); //use cm instead of inches m_pdiDev->StartPipeExport(); CPDImdat pdiMDat; pdiMDat.Empty(); pdiMDat.Append(PDI_MODATA_FRAMECOUNT); pdiMDat.Append(PDI_MODATA_POS); pdiMDat.Append(PDI_MODATA_ORI); m_pdiDev->SetSDataList(-1, pdiMDat); CPDIbiterr cBE; m_pdiDev->GetBITErrs(cBE); if (!(cBE.IsClear())) { m_pdiDev->ClearBITErrs(); } return true; } bool mitk::PolhemusInterface::StartTracking() { m_continousTracking = true; return m_pdiDev->StartContPno(0); } bool mitk::PolhemusInterface::StopTracking() { m_continousTracking = false; m_pdiDev->StopContPno(); return true; } bool mitk::PolhemusInterface::Connect() { bool returnValue; //Initialize, and if it is not successful, return false. if (!InitializeDevice()) { returnValue = false; } //Connect else if (m_pdiDev->CnxReady()) { returnValue = true; } //If it is not successful, search for connections. else { CPDIser pdiSer; m_pdiDev->SetSerialIF(&pdiSer); ePiCommType eType = m_pdiDev->DiscoverCnx(); switch (eType) { case PI_CNX_USB: MITK_INFO << "USB Connection: " << m_pdiDev->GetLastResultStr(); break; case PI_CNX_SERIAL: MITK_INFO << "Serial Connection: " << m_pdiDev->GetLastResultStr(); break; default: MITK_INFO << "DiscoverCnx result: " << m_pdiDev->GetLastResultStr(); break; } //Setup device if (!SetupDevice()) { returnValue = false; } else { returnValue = m_pdiDev->CnxReady(); } } if (returnValue) { m_numberOfTools = this->GetNumberOfTools(); } - return returnValue; + //TODO: Hier muss die ToolListe irgendwie erstellt werden. Das muss das device wissen. arg. + m_ToolName.push_back(1); + m_ToolName.push_back(3); + //HACK ENDE + return returnValue; } bool mitk::PolhemusInterface::Disconnect() { bool returnValue = true; //If Tracking is running, stop tracking first if (m_continousTracking) { this->StopTracking(); } returnValue = m_pdiDev->Disconnect(); MITK_INFO << "Disconnect: " << m_pdiDev->GetLastResultStr(); return returnValue; } std::vector mitk::PolhemusInterface::GetLastFrame() { PBYTE pBuf; DWORD dwSize; //read one frame if (!m_pdiDev->LastPnoPtr(pBuf, dwSize)) { MITK_WARN << m_pdiDev->GetLastResultStr(); } std::vector returnValue = ParsePolhemusRawData(pBuf, dwSize); if (returnValue.empty()) { MITK_WARN << "Cannot parse data / no tools present"; } return returnValue; } unsigned int mitk::PolhemusInterface::GetNumberOfTools() { if (m_continousTracking) return GetLastFrame().size(); else return GetSingleFrame().size(); } std::vector mitk::PolhemusInterface::GetSingleFrame() { if (m_continousTracking) { MITK_WARN << "Cannot get a single frame when continuous tracking is on!"; return std::vector(); } PBYTE pBuf; DWORD dwSize; //read one frame if (!m_pdiDev->ReadSinglePnoBuf(pBuf, dwSize)) { MITK_WARN << m_pdiDev->GetLastResultStr(); return std::vector(); } return ParsePolhemusRawData(pBuf, dwSize); } std::vector mitk::PolhemusInterface::ParsePolhemusRawData(PBYTE pBuf, DWORD dwSize) { std::vector returnValue; DWORD i = 0; while (i < dwSize) { BYTE ucSensor = pBuf[i + 2]; SHORT shSize = pBuf[i + 6]; // skip rest of header i += 8; PDWORD pFC = (PDWORD)(&pBuf[i]); PFLOAT pPno = (PFLOAT)(&pBuf[i + 4]); mitk::PolhemusInterface::trackingData currentTrackingData; currentTrackingData.id = ucSensor; currentTrackingData.pos[0] = pPno[0] * 10; //from cm to mm currentTrackingData.pos[1] = pPno[1] * 10; currentTrackingData.pos[2] = pPno[2] * 10; double azimuthAngle = pPno[3] / 180 * M_PI; //from degree to rad double elevationAngle = pPno[4] / 180 * M_PI; double rollAngle = pPno[5] / 180 * M_PI; vnl_quaternion eulerQuat(rollAngle, elevationAngle, azimuthAngle); currentTrackingData.rot = eulerQuat; returnValue.push_back(currentTrackingData); i += shSize; } return returnValue; } void mitk::PolhemusInterface::SetHemisphereTrackingEnabled(bool _HeisphereTrackingEnabeled) { + //only if connection is ready! + if (!this->m_pdiDev->CnxReady()) + return; + //HemisphereTracking is switched on by SetSHemiTrack(-1). "-1" means for all sensors. //To switch heisphere tracking of, you need to set a hemisphere vector by calling SetSHemisphere(-1, { (float)1,0,0 }) if (_HeisphereTrackingEnabeled) { //Remember the Hemisphere and Position when switching on to avoid wrong positions ("jumps") when swithing HemiTracking off. - for (int i = 0; i < m_numberOfTools; ++i) + if (m_Hemispheres.empty()) { - m_Hemispheres.push_back(GetHemisphere(i + 1)); + //only if it is empty. Otherwise, it might already be on and we overwrite it with (0|0|0). + for (int i = 0; i < m_numberOfTools; ++i) + { + m_Hemispheres.push_back(GetHemisphere(m_ToolName[i])); + } } - m_pdiDev->SetSHemiTrack(-1); } - else if (!m_Hemispheres.empty()) + + //switch HemiTracking OFF + else { //Get Tool Position. ToDo, this should not be the tool tip but the sensor position. Any chance, to get that from Polhemus interface?! std::vector _position; if (m_continousTracking) { _position = GetLastFrame(); } else { _position = GetSingleFrame(); } + + if (m_Hemispheres.empty()) + { + //Default Hemisphere for all tools, maybe the first setup... + //But we still check the position, 'cause maybe the tool is in negative space... + mitk::Vector3D temp; + mitk::FillVector3D(temp, 1, 0, 0); + m_Hemispheres.assign(m_numberOfTools, temp); + } + for (int i = 0; i < m_numberOfTools; ++i) { + if (m_Hemispheres.at(i).GetNorm() == 0) + { + //hemisphere vector can be 0 if Polhemus was in "HemiTracking" status when MITK connected or when user manually set it... + mitk::FillVector3D(m_Hemispheres.at(i), 1, 0, 0); + } + //Scalar product between mitk::point and mitk::vector double _scalarProduct = _position.at(i).pos.GetVectorFromOrigin() * m_Hemispheres.at(i); //if scalar product is negative, then the tool is in the opposite sphere then when we started to track. //Hence, we have to set the inverted hemisphere. //For default (1|0|0) this means, if x is negative, we have to set (-1|0|0). But we want to keep it generic if user sets different hemisphere... if (_scalarProduct < 0) { m_Hemispheres.at(i) = -1. * m_Hemispheres.at(i); } - //Tool count for Polhemus starts at 1... - SetHemisphere(i + 1, m_Hemispheres.at(i)); - } - } - else - { - //Default Hemisphere, first setup... - mitk::Vector3D temp; - mitk::FillVector3D(temp, 1, 0, 0); - this->SetHemisphere(-1, temp); - //MITK_INFO << m_pdiDev->GetLastResultStr(); + SetHemisphere(m_ToolName[i], m_Hemispheres.at(i)); + } + //clean up hemispheres! + m_Hemispheres.clear(); } } void mitk::PolhemusInterface::ToggleHemisphere(int _tool) { + //only if connection is ready! + if (!this->m_pdiDev->CnxReady()) + return; + + //we have a single tool number, which is identical with Polhemus index, i.e. first tool is "1", not "0"... + //is hemiTracking on? BOOL _hemiTrack; - //-1 == all tools + m_pdiDev->GetSHemiTrack(_tool, _hemiTrack); + + //if hemiTracing is on, switch it off. + if (_hemiTrack) + SetHemisphereTrackingEnabled(false); + + //toggel. if (_tool == -1) { + //GetHemisphere(-1) returns the first tool. Hence, we have to loop over all tools manually... for (int i = 0; i < m_numberOfTools; ++i) { - //is hemiTrack on? - m_pdiDev->GetSHemiTrack(i,_hemiTrack); - - m_Hemispheres.at(i)[0] = -m_Hemispheres.at(i)[0]; - m_Hemispheres.at(i)[1] = -m_Hemispheres.at(i)[1]; - m_Hemispheres.at(i)[2] = -m_Hemispheres.at(i)[2]; - SetHemisphere(i, m_Hemispheres.at(i)); - if (_hemiTrack) m_pdiDev->SetSHemiTrack(i); + this->SetHemisphere(m_ToolName[i], -1.*this->GetHemisphere(m_ToolName[i])); } } else { - //is hemiTrack on? - m_pdiDev->GetSHemiTrack(_tool, _hemiTrack); - - m_Hemispheres.at(_tool)[0] = -m_Hemispheres.at(_tool)[0]; - m_Hemispheres.at(_tool)[1] = -m_Hemispheres.at(_tool)[1]; - m_Hemispheres.at(_tool)[2] = -m_Hemispheres.at(_tool)[2]; - SetHemisphere(_tool, m_Hemispheres.at(_tool)); - if (_hemiTrack) m_pdiDev->SetSHemiTrack(_tool); + this->SetHemisphere(_tool, -1.*this->GetHemisphere(_tool)); } - - + //if hemiTracing was on, switch it on again. + if (_hemiTrack) + SetHemisphereTrackingEnabled(true); } void mitk::PolhemusInterface::SetHemisphere(int _tool, mitk::Vector3D _hemisphere) { + //only if connection is ready! + if (!this->m_pdiDev->CnxReady()) + return; m_pdiDev->SetSHemisphere(_tool, { (float)_hemisphere[0], (float)_hemisphere[1], (float)_hemisphere[2] }); } mitk::Vector3D mitk::PolhemusInterface::GetHemisphere(int _tool) { + //only if connection is ready! + if (!this->m_pdiDev->CnxReady()) + return nullptr; PDI3vec _hemisphere; mitk::Vector3D _returnVector; //Doesn't work in continuous mode. Don't know why, but so it is... Hence: stop and restart... if (m_continousTracking) { m_continousTracking = false; m_pdiDev->StopContPno(); m_pdiDev->GetSHemisphere(_tool, _hemisphere); MITK_DEBUG << "Get Hemisphere: " << m_pdiDev->GetLastResultStr(); mitk::FillVector3D(_returnVector, _hemisphere[0], _hemisphere[1], _hemisphere[2]); m_pdiDev->StartContPno(0); m_continousTracking = true; } else { m_pdiDev->GetSHemisphere(_tool, _hemisphere); MITK_DEBUG << "Get Hemisphere: " << m_pdiDev->GetLastResultStr(); mitk::FillVector3D(_returnVector, _hemisphere[0], _hemisphere[1], _hemisphere[2]); } return _returnVector; } void mitk::PolhemusInterface::PrintStatus() { MITK_INFO << "Polhemus status: " << this->m_pdiDev->CnxReady(); } \ No newline at end of file diff --git a/Modules/IGT/TrackingDevices/mitkPolhemusInterface.h b/Modules/IGT/TrackingDevices/mitkPolhemusInterface.h index 21e794104d..175ad273d6 100644 --- a/Modules/IGT/TrackingDevices/mitkPolhemusInterface.h +++ b/Modules/IGT/TrackingDevices/mitkPolhemusInterface.h @@ -1,130 +1,143 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKPolhemusINTERFACE_H_HEADER_INCLUDED_ #define MITKPolhemusINTERFACE_H_HEADER_INCLUDED_ #include #include #include #include "mitkCommon.h" #include #include #include #include #include #include class CPDIdev; namespace mitk { /** Documentation: * \brief An object of this class represents the interface to Polhemus trackers. + * All variables with the name "tool" start with index 1, which is the station number of Polhemus. + * Make sure to call functions in this class with parameter "1" if you want to loop over all tools. + * If you need to access an array (e.g. m_Hemisphere), you need to use "_tool -1" and adapt your index for loops... * \ingroup IGT */ class MITKIGT_EXPORT PolhemusInterface : public itk::Object { public: mitkClassMacroItkParent(PolhemusInterface,itk::Object); itkFactorylessNewMacro(Self); itkCloneMacro(Self); struct trackingData { mitk::Point3D pos; mitk::Quaternion rot; BYTE id; }; /** * \brief Opens the connection to the device and makes it ready to track tools. * \return Returns true if there is a connection to the device and the device is ready to track tools, false if not. */ bool StartTracking(); /** * \brief Clears all resources. After this method have been called the system isn't ready to track any longer. * \return Returns true if the operation was succesful, false if not. */ bool StopTracking(); bool Connect(); bool Disconnect(); /** @return Returns a single frame. Only works if the tracking device is not in continous tracking mode. Returns an empty vector in case of an error.*/ std::vector GetSingleFrame(); /** @return Returns the last frame when the tracking device is in continous tracking mode. Returns an empty vector in case of an error.*/ std::vector GetLastFrame(); /** @return Returns the number of tools. Returns 0 if no information is avialable.*/ unsigned int GetNumberOfTools(); - /** Enables/disables hemisphere tracking for all sensors. */ + /** Enables/disables hemisphere tracking for all stations/tools. */ void SetHemisphereTrackingEnabled(bool _HeisphereTrackingEnabeled); - /** Toggles the current hemisphere. Parameter _tool describes, for which tool the hemisphere should change. Default -1 toggles all tools.*/ + /** Toggles the current hemisphere. Parameter _tool describes, for which tool the hemisphere should change. Default -1 toggles all tools. + Index starts at "1" for the first tool (i.e. station number of Polhemus). Not 0! + */ void ToggleHemisphere(int _tool = -1); /** Convenient method to print the status of the tracking device (true/false) if connection is established. For debugging...*/ void PrintStatus(); - /** Sets the Hemisphere of tool _tool to the vector _hemisphere */ + /** Sets the Hemisphere of tool _tool to the vector _hemisphere. "-1" sets all tools. + Index starts at "1" for the first tool (i.e. station number of Polhemus). Not 0! + */ void SetHemisphere(int _tool, mitk::Vector3D _hemisphere); - /** Get the Hemisphere for _tool as mitk vector */ + /** Get the Hemisphere for _tool as mitk vector. -1 ("all tools") returns hemisphere of first tool. + Index starts at "1" for the first tool (i.e. station number of Polhemus). Not 0! + */ mitk::Vector3D GetHemisphere(int _tool); protected: /** * \brief standard constructor */ PolhemusInterface(); /** * \brief standard destructor */ ~PolhemusInterface(); /** Polhemus liberty/patriot tracker object*/ CPDIdev* m_pdiDev; /** Parses polhemus raw data to a collection of tracking data of single tools. */ std::vector ParsePolhemusRawData(PBYTE pBuf, DWORD dwSize); unsigned int m_numberOfTools; bool m_continousTracking; bool InitializeDevice(); bool SetupDevice(); private: std::vector m_Hemispheres; + //This vector stores the order of tools, which are available. + //E.g. only Sensor 1 and 3 are attached, then this vector maps the first tool (0) to Polhemus identifier 1 and the second tool (1) to Polhemus 3. + std::vector m_ToolName; + }; }//mitk #endif