diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.cpp index 1f66ed8b5b..c8defa2c4a 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.cpp @@ -1,346 +1,346 @@ /*=================================================================== 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. ===================================================================*/ #define _USE_MATH_DEFINES #include "mitkNavigationDataCSVSequentialPlayer.h" #include #include #include #include #include mitk::NavigationDataCSVSequentialPlayer::NavigationDataCSVSequentialPlayer() : mitk::NavigationDataPlayerBase() { m_NavigationDatas = std::vector(); m_CurrentPos = 0; m_Filetype = mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV; } mitk::NavigationDataCSVSequentialPlayer::~NavigationDataCSVSequentialPlayer() { } bool mitk::NavigationDataCSVSequentialPlayer::IsAtEnd() { if (m_CurrentPos >= m_NavigationDatas.size()) return true; else return false; } void mitk::NavigationDataCSVSequentialPlayer:: SetFileName(const std::string& fileName) { this->SetNumberOfOutputs(1); FillOutputEmpty(0); MITK_INFO << "Reading file: " << fileName; m_NavigationDatas = GetNavigationDatasFromFile(fileName); this->Modified(); } void mitk::NavigationDataCSVSequentialPlayer::FillOutputEmpty(int number) { this->SetNthOutput(number, GetEmptyNavigationData()); } mitk::NavigationData::Pointer mitk::NavigationDataCSVSequentialPlayer::GetEmptyNavigationData() { mitk::NavigationData::Pointer emptyNd = mitk::NavigationData::New(); mitk::NavigationData::PositionType position; mitk::NavigationData::OrientationType orientation(0.0, 0.0, 0.0, 0.0); position.Fill(0.0); emptyNd->SetPosition(position); emptyNd->SetOrientation(orientation); emptyNd->SetDataValid(false); return emptyNd; } int mitk::NavigationDataCSVSequentialPlayer::GetNumberOfSnapshots() { return m_NavigationDatas.size(); } void mitk::NavigationDataCSVSequentialPlayer::GenerateData() { for (unsigned int index = 0; index < this->GetNumberOfOutputs(); index++) { mitk::NavigationData* output = this->GetOutput(index); if (m_CurrentPos > m_NavigationDatas.size()) { FillOutputEmpty(index); return; } output->Graft(this->m_NavigationDatas.at(m_CurrentPos)); m_CurrentPos++; } } void mitk::NavigationDataCSVSequentialPlayer::UpdateOutputInformation() { this->Modified(); // make sure that we need to be updated Superclass::UpdateOutputInformation(); } std::vector mitk::NavigationDataCSVSequentialPlayer::GetNavigationDatasFromFile(std::string filename) { std::vector returnValue = std::vector(); std::vector fileContentLineByLine = GetFileContentLineByLine(filename); for (int i = 1; (i < fileContentLineByLine.size()); i++) //skip header so start at 1 { returnValue.push_back(GetNavigationDataOutOfOneLine(fileContentLineByLine.at(i))); } return returnValue; } std::vector mitk::NavigationDataCSVSequentialPlayer::GetFileContentLineByLine(std::string filename) { std::vector readData = std::vector(); //save old locale char * oldLocale; oldLocale = setlocale(LC_ALL, 0); //define own locale std::locale C("C"); setlocale(LC_ALL, "C"); //read file std::ifstream file; file.open(filename.c_str(), std::ios::in); if (file.good()) { //read out file file.seekg(0L, std::ios::beg); // move to begin of file int count = 0; //int count2 = 0; while (!file.eof()) { std::string buffer; std::getline(file, buffer); // read out file line by line //for Polhemus tracker: just take every 24th sample if (count == 0) if (buffer.size() > 0) { //MITK_INFO << "read(" << count2 << "): " << buffer.substr(0,30); //count2++; readData.push_back(buffer); } count++; if (count == 24) count = 0; } } file.close(); //switch back to old locale setlocale(LC_ALL, oldLocale); return readData; } mitk::NavigationData::Pointer mitk::NavigationDataCSVSequentialPlayer::GetNavigationDataOutOfOneLine(std::string line) { mitk::NavigationData::Pointer returnValue = mitk::NavigationData::New(); QString myLine = QString(line.c_str()); QStringList myLineList = myLine.split(','); mitk::Point3D position; mitk::Quaternion orientation; bool valid = false; double time; //this is for custom csv files. You have adapt the column numbers to correctly //interpret your csv file. if (m_Filetype = mitk::NavigationDataCSVSequentialPlayer::ManualLoggingCSV) { if (myLineList.size() < 10) { MITK_ERROR << "Error: cannot read line: only found " << myLineList.size() << " fields. Last field: " << myLineList.at(myLineList.size() - 1).toStdString(); returnValue = GetEmptyNavigationData(); return returnValue; } valid = true; //if no valid flag is given: simply set to true //############# Variant for the Aurora measurements ############### //############# (CUSTOM .csv files from MITK) ############### /* position[0] = myLineList.at(3).toDouble(); position[1] = myLineList.at(4).toDouble(); position[2] = myLineList.at(5).toDouble(); orientation[0] = myLineList.at(6).toDouble(); //qx orientation[1] = myLineList.at(7).toDouble(); //qy orientation[2] = myLineList.at(8).toDouble(); //qz orientation[3] = myLineList.at(9).toDouble(); //qr */ //Variant for the polhemus measurements in August 2016 //(.csv files from the polhemus software) //Important: due to the documentation, Polhemus uses //a left handed coordinate system while MITK uses a //right handed. A conversion is not included in this //read in method yet, because this is not required //for this special rotation evaliation (no matter //if it turns 11.25 degree to left or right). For //other usage this might be important to adapt! position[0] = myLineList.at(4).toDouble(); position[1] = myLineList.at(5).toDouble(); position[2] = myLineList.at(6).toDouble(); //Doesn't work... don't know how to interpret the //Polhemus quaternions. They are seem to different //different to other quaternions (NDI, Claron, etc.) //http://www.mathepedia.de/Quaternionen.aspx /* double qr = myLineList.at(7).toDouble(); double qx = myLineList.at(8).toDouble(); double qy = myLineList.at(9).toDouble(); double qz = myLineList.at(10).toDouble(); vnl_quaternion newQuat(qx, qy, qz, qr); orientation = newQuat; orientation.normalize();*/ /* orientation[3] = qr; //qr orientation[0] = qx; //qx orientation[1] = qy; //qy orientation[2] = qz; //qz orientation.normalize(); */ //Using Euler angles instead does work //azimuth: rotation about Z axis of reference frame double azimuthAngle = (myLineList.at(11).toDouble() / 180 * M_PI); //elevation: rotation about Y' axis (transformed Y axis of sonsor frame) double elevationAngle = (myLineList.at(12).toDouble() / 180 * M_PI); //roll: rotation about X axis of sensor frame double rollAngle = (myLineList.at(13).toDouble() / 180 * M_PI); vnl_quaternion eulerQuat(rollAngle, elevationAngle, azimuthAngle); orientation = eulerQuat; /* //code block for conversion from axis-angular representation double rotationAngle = myLineList.at(7).toDouble(); double rotationAxis[3]; rotationAxis[0] = myLineList.at(8).toDouble(); rotationAxis[1] = myLineList.at(9).toDouble(); rotationAxis[2] = myLineList.at(10).toDouble(); double betragRotationAxis = sqrt(pow(rotationAxis[0], 2) + pow(rotationAxis[1], 2) + pow(rotationAxis[2], 2)); rotationAngle /= betragRotationAxis; rotationAxis[0] /= betragRotationAxis; rotationAxis[1] /= betragRotationAxis; rotationAxis[2] /= betragRotationAxis; double qr = cos(rotationAngle/2); double qx = rotationAxis[0] * sin(rotationAngle/2); double qy = rotationAxis[1] * sin(rotationAngle/2); double qz = rotationAxis[1] * sin(rotationAngle/2); */ /* //code block for conversion from left-handed to right-handed mitk::Quaternion linksZuRechtsdrehend; double rotationAngle = -M_PI; double rotationAxis[3]; rotationAxis[0] = 0; rotationAxis[1] = 0; rotationAxis[2] = 1; linksZuRechtsdrehend[3] = cos(rotationAngle / 2); linksZuRechtsdrehend[0] = rotationAxis[0] * sin(rotationAngle / 2); linksZuRechtsdrehend[1] = rotationAxis[1] * sin(rotationAngle / 2); linksZuRechtsdrehend[2] = rotationAxis[2] * sin(rotationAngle / 2); orientation = orientation * linksZuRechtsdrehend; */ } //this is for MITK csv files that have been recorded with the MITK //navigation data recorder. You can also use the navigation data player //class from the MITK-IGT module instead. else if (m_Filetype = mitk::NavigationDataCSVSequentialPlayer::NavigationDataCSV) { if (myLineList.size() < 8) { MITK_ERROR << "Error: cannot read line: only found " << myLineList.size() << " fields. Last field: " << myLineList.at(myLineList.size() - 1).toStdString(); returnValue = GetEmptyNavigationData(); return returnValue; } time = myLineList.at(2).toDouble(); if (myLineList.at(3).toStdString() == "1") valid = true; position[0] = myLineList.at(2).toDouble(); position[1] = myLineList.at(3).toDouble(); position[2] = myLineList.at(4).toDouble(); orientation[0] = myLineList.at(5).toDouble(); //qx orientation[1] = myLineList.at(6).toDouble(); //qy orientation[2] = myLineList.at(7).toDouble(); //qz orientation[3] = myLineList.at(8).toDouble(); //qr } //returnValue->SetTimeStamp(time); //DOES NOT WORK ANY MORE... CANNOT SET TIME TO itk::timestamp CLASS returnValue->SetDataValid(valid); returnValue->SetPosition(position); returnValue->SetOrientation(orientation); return returnValue; } void mitk::NavigationDataCSVSequentialPlayer::SetOptions(bool rightHanded, std::string separatorSign, int sampleCount, bool headerRow, int xPos, int yPos, - int zPos, bool useQuats, int qx, int qy, int qz, int qr, int azimuth, int elevatino, int roll, bool eulerInRadiants) + int zPos, bool useQuats, int qx, int qy, int qz, int qr, int azimuth, int elevation, int roll, bool eulerInRadiants) { m_RightHanded = rightHanded; m_SeparatorSign = separatorSign; m_SampleCount = sampleCount; m_HeaderRow = headerRow; m_XPos = xPos; m_YPos = yPos; m_ZPos = zPos; m_UseQuats = useQuats; m_Qx = qx; m_Qy = qy; m_Qz = qz; m_Qr = qr; m_Azimuth = azimuth; m_Elevation = elevation; m_Roll = roll; m_EulersInRadiants = eulerInRadiants; } diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.h b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.h index 7e69b3d74a..da8c9330e2 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.h +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkNavigationDataCSVSequentialPlayer.h @@ -1,153 +1,152 @@ /*=================================================================== 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 MITKNavigationDataCSVSequentialPlayer_H_HEADER_INCLUDED_ #define MITKNavigationDataCSVSequentialPlayer_H_HEADER_INCLUDED_ #include #include "tinyxml.h" namespace mitk { /**Documentation * \brief This class is a NavigationDataPlayer which can play CSV formatted * files in sequential order, which means it doesn't care about timestamps and just * outputs the navigationdatas in their sequential order. * * It is thought to interpret custom csv files. To do so please adapt the column * numbers of position and orientation in the internal method GetNavigationDataOutOfOneLine(). * * So far only one (the first) tool is read in as required for the hummel protocol measurements. * * This class can also interpret MITK style csv files (set filetype to NavigationDataCSV), but * you can also use the MITK navigation data player class inside the MITK-IGT module which * is newer and better maintained. * * \ingroup IGT */ class NavigationDataCSVSequentialPlayer : public NavigationDataPlayerBase { public: mitkClassMacro(NavigationDataCSVSequentialPlayer, NavigationDataPlayerBase); itkNewMacro(Self); - NavigationDataCSVSequentialPlayer(); /** * \brief sets the file name and path (if XMLString is set, this is neglected) */ void SetFileName(const std::string& _FileName); /** - * @brief SetOptions sets the options for reading out the data out of the correct postions of the file + * @brief SetOptions sets the options for reading out the data out of the correct postions of the file. They need to be set before using the player * @param rightHanded true if the used coordinate System is right handed, false if it is left handed * @param seperatorSign symbol that is used to separate the values in the .csv file * @param sampleCount every n-th sample in the file that should be used * @param headerRow true if the .csv file has a header row otherwise false * @param xPos number of the colum in the .csv file for the x-coordinates of the position * @param yPos number of the colum in the .csv file for the y-coordinates of the position * @param zPos number of the colum in the .csv file for the z-coordinates of the position * @param useQuats true if Quaternions are used to construct the orientation, false if Euler Angles are used * @param qx number of the column in the .csv file for the x component of the quaternion * @param qy number of the column in the .csv file for the y component of the quaternion * @param qz number of the column in the .csv file for the z component of the quaternion * @param qr number of the column in the .csv file for the r component of the quaternion * @param azimuth number of the colum in the .csv file for Azimuth (Euler Angles) * @param elevatino number of the colum in the .csv file for Elevation (Euler Angles) * @param roll number of the colum in the .csv file for Roll (Euler Angles) * @param eulerInRadiants true if the Euler Angles in the .csv file are in radiants, false if they are in degrees */ void SetOptions(bool rightHanded, std::string seperatorSign, int sampleCount, bool headerRow, int xPos, int yPos, int zPos, bool useQuats, int qx, int qy, int qz, int qr, int azimuth, int elevatino, int roll, bool eulerInRadiants); /** * \brief returns the file name and path */ itkGetStringMacro(FileName); enum Filetype { NavigationDataCSV, //for csv files from the MITK navigation data player ManualLoggingCSV //for custum csv files }; /** * \brief Sets the file type. ManualLoggingCSV is default and is thought for your * custom csv files. You can also set it to NavigationDataCSV, then this * player interprets MITK style csv files. */ itkSetMacro(Filetype, Filetype); /** * \return Returns true if the player reached the end of the file. */ bool IsAtEnd(); /** * \brief Used for pipeline update just to tell the pipeline * that we always have to update */ virtual void UpdateOutputInformation(); int GetNumberOfSnapshots(); protected: NavigationDataCSVSequentialPlayer(); virtual ~NavigationDataCSVSequentialPlayer(); /// /// do the work here /// virtual void GenerateData(); std::string m_FileName; int m_CurrentPos; Filetype m_Filetype; //member for the navigation datas which were read (only one output is supported at the moment) std::vector m_NavigationDatas; std::vector GetNavigationDatasFromFile(std::string filename); std::vector GetFileContentLineByLine(std::string filename); mitk::NavigationData::Pointer GetNavigationDataOutOfOneLine(std::string line); void FillOutputEmpty(int number); mitk::NavigationData::Pointer GetEmptyNavigationData(); bool m_RightHanded; //true if the used coordinate System is right handed, false if it is left handed std::string m_SeparatorSign; //symbol that is used to separate the values in the .csv file int m_SampleCount; //every n-th sample in the file that should be used bool m_HeaderRow; //true if the .csv file has a header row otherwise false int m_XPos; //number of the colum in the .csv file for the x-coordinates of the position int m_YPos; //number of the colum in the .csv file for the y-coordinates of the position int m_ZPos; //number of the colum in the .csv file for the z-coordinates of the position bool m_UseQuats; //true if Quaternions are used to construct the orientation, false if Euler Angles are used int m_Qx; //number of the column in the .csv file for the x component of the quaternion int m_Qy; //number of the column in the .csv file for the y component of the quaternion int m_Qz; //number of the column in the .csv file for the z component of the quaternion int m_Qr; //number of the column in the .csv file for the r component of the quaternion int m_Azimuth; //number of the colum in the .csv file for Azimuth (Euler Angles) int m_Elevation; //number of the colum in the .csv file for Elevation (Euler Angles) int m_Roll; //number of the colum in the .csv file for Roll (Euler Angles) bool m_EulersInRadiants; // true if the Euler Angles in the .csv file are in radiants, false if they are in degrees }; } // namespace mitk #endif /* MITKNavigationDataCSVSequentialPlayer_H_HEADER_INCLUDED_ */