diff --git a/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.cpp b/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.cpp index d4e3ccba1b..6b8f8edb0e 100644 --- a/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.cpp +++ b/Modules/IGT/TrackingDevices/mitkOpenIGTLinkTrackingDevice.cpp @@ -1,575 +1,575 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkOpenIGTLinkTrackingDevice.h" #include "mitkOpenIGTLinkTrackingTool.h" #include "mitkIGTConfig.h" #include "mitkIGTTimeStamp.h" #include "mitkIGTHardwareException.h" #include "mitkTrackingTypes.h" #include #include #include #include #include #include //sleep headers #include #include typedef itk::MutexLockHolder MutexLockHolder; mitk::OpenIGTLinkTrackingDevice::OpenIGTLinkTrackingDevice() : mitk::TrackingDevice(), m_UpdateRate(60) { //set the type of this tracking device this->m_Data = mitk::OpenIGTLinkTypeInformation::GetDeviceDataOpenIGTLinkTrackingDeviceConnection(); m_OpenIGTLinkClient = mitk::IGTLClient::New(true); m_OpenIGTLinkClient->SetName("OpenIGTLink Tracking Device"); m_OpenIGTLinkClient->EnableInfiniteBufferingMode(false); m_IGTLDeviceSource = mitk::IGTLTransformDeviceSource::New(); m_IGTLDeviceSource->SetIGTLDevice(m_OpenIGTLinkClient); } mitk::OpenIGTLinkTrackingDevice::~OpenIGTLinkTrackingDevice() { } int mitk::OpenIGTLinkTrackingDevice::GetPortNumber() { return m_OpenIGTLinkClient->GetPortNumber(); } bool mitk::OpenIGTLinkTrackingDevice::AutoDetectToolsAvailable() { return true; } mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::AutoDetectTools() { mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New(); if (m_OpenIGTLinkClient->GetPortNumber() == -1) { MITK_WARN << "Connection not initialized, aborting (invalid port number)."; return mitk::NavigationToolStorage::New(); } //open connection try { m_IGTLDeviceSource->Connect(); m_IGTLDeviceSource->StartCommunication(); } catch (std::runtime_error &e) { MITK_WARN << "AutoDetection: Open IGT Link device retruned an error while trying to connect: " << e.what(); return mitk::NavigationToolStorage::New(); } //get a message to find out type mitk::IGTLMessage::Pointer receivedMessage = ReceiveMessage(100); const char* msgType = receivedMessage->GetIGTLMessageType(); mitk::OpenIGTLinkTrackingDevice::TrackingMessageType type = GetMessageTypeFromString(msgType); switch (type) { case TDATA: returnValue = DiscoverToolsFromTData(dynamic_cast(receivedMessage->GetMessage().GetPointer())); break; case QTDATA: returnValue = DiscoverToolsFromQTData(dynamic_cast(receivedMessage->GetMessage().GetPointer())); break; case TRANSFORM: returnValue = DiscoverToolsFromTransform(); break; default: MITK_INFO << "Server does not send tracking data. Received data is not of a compatible type. Received type: " << msgType; } //close connection try { m_IGTLDeviceSource->StopCommunication(); m_IGTLDeviceSource->Disconnect(); } catch (std::runtime_error &e) { MITK_WARN << "AutoDetection: Open IGT Link device retruned an error while trying to disconnect: " << e.what(); return mitk::NavigationToolStorage::New(); } return returnValue; } std::string mitk::OpenIGTLinkTrackingDevice::GetHostname() { return m_OpenIGTLinkClient->GetHostname(); } void mitk::OpenIGTLinkTrackingDevice::SetPortNumber(int portNumber) { m_OpenIGTLinkClient->SetPortNumber(portNumber); } void mitk::OpenIGTLinkTrackingDevice::SetHostname(std::string hostname) { m_OpenIGTLinkClient->SetHostname(hostname); } bool mitk::OpenIGTLinkTrackingDevice::IsDeviceInstalled() { return true; } mitk::TrackingTool* mitk::OpenIGTLinkTrackingDevice::AddTool(const char* toolName, const char* fileName) { mitk::OpenIGTLinkTrackingTool::Pointer t;// = mitk::OpenIGTLinkTrackingTool::New(); //TODO: Implement if (this->InternalAddTool(t) == false) return NULL; return t.GetPointer(); } bool mitk::OpenIGTLinkTrackingDevice::InternalAddTool(OpenIGTLinkTrackingTool::Pointer tool) { m_AllTools.push_back(tool); return true; } bool mitk::OpenIGTLinkTrackingDevice::DiscoverTools(int waitingTime) { if (m_OpenIGTLinkClient->GetPortNumber() == -1) { MITK_WARN << "Connection not initialized, aborting (invalid port number)."; return false; } try { m_IGTLDeviceSource->Connect(); m_IGTLDeviceSource->StartCommunication(); } catch (std::runtime_error &e) { MITK_WARN << "Open IGT Link device retruned an error while trying to connect: " << e.what(); return false; } mitk::IGTLMessage::Pointer receivedMessage = ReceiveMessage(waitingTime); //check the tracking stream for the number and type of tools //igtl::MessageBase::Pointer receivedMessage = m_OpenIGTLinkClient->GetNextMessage(); if (receivedMessage.IsNull()) { MITK_WARN << "No message was received. Is there really a server?"; return false; } else if (!receivedMessage->IsDataValid()) { MITK_WARN << "Received invalid message."; return false; } const char* msgType = receivedMessage->GetIGTLMessageType(); mitk::OpenIGTLinkTrackingDevice::TrackingMessageType type = GetMessageTypeFromString(msgType); mitk::NavigationToolStorage::Pointer foundTools; switch (type) { case TDATA: foundTools = DiscoverToolsFromTData(dynamic_cast(receivedMessage->GetMessage().GetPointer())); break; case QTDATA: foundTools = DiscoverToolsFromQTData(dynamic_cast(receivedMessage->GetMessage().GetPointer())); break; case TRANSFORM: foundTools = DiscoverToolsFromTransform(); break; default: MITK_INFO << "Server does not send tracking data. Received data is not of a compatible type. Received type: " << msgType; return false; } if (foundTools.IsNull() || (foundTools->GetToolCount() == 0)) { return false; } for (int i = 0; i < foundTools->GetToolCount(); i++) { AddNewToolForName(foundTools->GetTool(i)->GetToolName(), i); } MITK_INFO << "Found tools: " << foundTools->GetToolCount(); return true; } mitk::IGTLMessage::Pointer mitk::OpenIGTLinkTrackingDevice::ReceiveMessage(int waitingTime) { mitk::IGTLMessage::Pointer receivedMessage; //send a message to the server: start tracking stream mitk::IGTLMessageFactory::Pointer msgFactory = m_OpenIGTLinkClient->GetMessageFactory(); std::string message = "STT_TDATA"; igtl::MessageBase::Pointer sttMsg = msgFactory->CreateInstance(message); //TODO: Fix this to dynamically get this from GUI ((igtl::StartTrackingDataMessage*)sttMsg.GetPointer())->SetResolution(m_UpdateRate); - m_OpenIGTLinkClient->SendMessage(mitk::IGTLMessage::New(sttMsg, message)); + m_OpenIGTLinkClient->SendMessage(mitk::IGTLMessage::New(sttMsg)); std::chrono::high_resolution_clock::time_point time = std::chrono::high_resolution_clock::now(); std::chrono::milliseconds d = std::chrono::milliseconds(waitingTime); while (!(receivedMessage.IsNotNull() && receivedMessage->IsDataValid())) { m_IGTLDeviceSource->Update(); receivedMessage = m_IGTLDeviceSource->GetOutput(); if ((time + d) < std::chrono::high_resolution_clock::now()) break; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } return receivedMessage; } mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromTData(igtl::TrackingDataMessage::Pointer tdMsg) { mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New(); MITK_INFO << "Start discovering tools by TDATA messages"; if (tdMsg == nullptr) { MITK_WARN << "Message was not a TrackingDataMessage, aborting!"; return returnValue; } int numberOfTools = tdMsg->GetNumberOfTrackingDataElements(); MITK_INFO << "Found " << numberOfTools << " tools"; for (int i = 0; i < numberOfTools; i++) { igtl::TrackingDataElement::Pointer currentTrackingData; tdMsg->GetTrackingDataElement(i, currentTrackingData); std::string name = currentTrackingData->GetName(); std::stringstream identifier; identifier << "AutoDetectedTool-" << i; i++; mitk::NavigationTool::Pointer newTool = ConstructDefaultOpenIGTLinkTool(name, identifier.str()); returnValue->AddTool(newTool); } m_IGTLDeviceSource->StopCommunication(); SetState(Ready); return returnValue; } mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromQTData(igtl::QuaternionTrackingDataMessage::Pointer msg) { mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New(); MITK_INFO << "Start discovering tools by QTDATA messages"; if (msg == nullptr) { MITK_WARN << "Message was not a QuaternionTrackingDataMessage, aborting!"; return returnValue; } int numberOfTools = msg->GetNumberOfQuaternionTrackingDataElements(); MITK_INFO << "Found " << numberOfTools << " tools"; for (int i = 0; i < numberOfTools; i++) { igtl::QuaternionTrackingDataElement::Pointer currentTrackingData; msg->GetQuaternionTrackingDataElement(i, currentTrackingData); std::string name = currentTrackingData->GetName(); std::stringstream identifier; identifier << "AutoDetectedTool-" << i; i++; mitk::NavigationTool::Pointer newTool = ConstructDefaultOpenIGTLinkTool(name, identifier.str()); returnValue->AddTool(newTool); } m_IGTLDeviceSource->StopCommunication(); SetState(Ready); return returnValue; } void mitk::OpenIGTLinkTrackingDevice::AddNewToolForName(std::string name, int i) { mitk::OpenIGTLinkTrackingTool::Pointer newTool = mitk::OpenIGTLinkTrackingTool::New(); if (name == "") //if no name was given create a default name { std::stringstream defaultName; defaultName << "OpenIGTLinkTool#" << i; name = defaultName.str(); } MITK_INFO << "Added tool " << name << " to tracking device."; newTool->SetToolName(name); InternalAddTool(newTool); } mitk::NavigationToolStorage::Pointer mitk::OpenIGTLinkTrackingDevice::DiscoverToolsFromTransform(int NumberOfMessagesToWait) { MITK_INFO << "Start discovering tools by TRANSFORM messages"; mitk::NavigationToolStorage::Pointer returnValue = mitk::NavigationToolStorage::New(); std::map toolNameMap; for (int j=0; jUpdate(); igtl::TransformMessage::Pointer msg = dynamic_cast(m_IGTLDeviceSource->GetOutput()->GetMessage().GetPointer()); if (msg == nullptr || msg.IsNull()) { MITK_INFO << "Received message could not be casted to TransformMessage. Skipping.."; continue; } int count = toolNameMap[msg->GetDeviceName()]; if (count == 0) { //MITK_WARN << "ADDED NEW TOOL TO TOOLCHAIN: " << msg->GetDeviceName() << " - 1"; toolNameMap[msg->GetDeviceName()] = 1; } else { toolNameMap[msg->GetDeviceName()]++; //MITK_WARN << "INCREMENTED TOOL COUNT IN TOOLCHAIN: " << msg->GetDeviceName() << " - " << toolNameMap[msg->GetDeviceName()]; } } int i = 0; for (std::map::iterator it = toolNameMap.begin(); it != toolNameMap.end(); ++it) { MITK_INFO << "Found tool: " << it->first; std::stringstream name; name << it->first; std::stringstream identifier; identifier << "AutoDetectedTool-" << i; i++; mitk::NavigationTool::Pointer newTool = ConstructDefaultOpenIGTLinkTool(name.str(), identifier.str()); returnValue->AddTool(newTool); } return returnValue; } mitk::NavigationTool::Pointer mitk::OpenIGTLinkTrackingDevice::ConstructDefaultOpenIGTLinkTool(std::string name, std::string identifier) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(name); mitk::Surface::Pointer myCone = mitk::Surface::New(); vtkConeSource *vtkData = vtkConeSource::New(); vtkData->SetAngle(5.0); vtkData->SetResolution(50); vtkData->SetHeight(6.0f); vtkData->SetRadius(2.0f); vtkData->SetCenter(0.0, 0.0, 0.0); vtkData->Update(); myCone->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); newNode->SetData(myCone); mitk::NavigationTool::Pointer newTool = mitk::NavigationTool::New(); newTool->SetDataNode(newNode); newTool->SetIdentifier(identifier); newTool->SetTrackingDeviceType(mitk::OpenIGTLinkTypeInformation::GetDeviceDataOpenIGTLinkTrackingDeviceConnection().Line); return newTool; } void mitk::OpenIGTLinkTrackingDevice::UpdateTools() { if (this->GetState() != Tracking) { MITK_ERROR << "Method was called in the wrong state, something went wrong!"; return; } m_IGTLMsgToNavDataFilter->Update(); mitk::NavigationData::Pointer currentNavData = m_IGTLMsgToNavDataFilter->GetOutput(); const char* name = currentNavData->GetName(); //MITK_WARN << name; for (int i = 0; i < m_AllTools.size(); i++) { if (strcmp(m_AllTools.at(i)->GetToolName(), name) == 0) { m_AllTools.at(i)->SetDataValid(currentNavData->IsDataValid()); m_AllTools.at(i)->SetPosition(currentNavData->GetPosition()); m_AllTools.at(i)->SetOrientation(currentNavData->GetOrientation()); m_AllTools.at(i)->SetIGTTimeStamp(currentNavData->GetIGTTimeStamp()); } } } bool mitk::OpenIGTLinkTrackingDevice::StartTracking() { //check tracking state if (this->GetState() != Ready) { MITK_WARN << "Cannot start tracking, device is not ready!"; return false; } try { m_IGTLDeviceSource->StartCommunication(); //send a message to the server: start tracking stream mitk::IGTLMessageFactory::Pointer msgFactory = m_OpenIGTLinkClient->GetMessageFactory(); std::string message = "STT_TDATA"; //m_OpenIGTLinkClient->SendMessage(msgFactory->CreateInstance(message)); } catch (std::runtime_error &e) { MITK_WARN << "Open IGT Link device retruned an error while starting communication: " << e.what(); return false; } //create internal igtl pipeline m_IGTLMsgToNavDataFilter = mitk::IGTLMessageToNavigationDataFilter::New(); m_IGTLMsgToNavDataFilter->SetNumberOfExpectedOutputs(this->GetToolCount()); m_IGTLMsgToNavDataFilter->ConnectTo(m_IGTLDeviceSource); //connect itk events typedef itk::SimpleMemberCommand< mitk::OpenIGTLinkTrackingDevice > CurCommandType; CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); messageReceivedCommand->SetCallbackFunction(this, &mitk::OpenIGTLinkTrackingDevice::UpdateTools); m_MessageReceivedObserverTag = m_OpenIGTLinkClient->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); this->SetState(Tracking); return true; } bool mitk::OpenIGTLinkTrackingDevice::StopTracking() { //check tracking state if (this->GetState() != Tracking) { MITK_WARN << "Cannot open connection, device is already connected!"; return false; } m_OpenIGTLinkClient->RemoveObserver(m_MessageReceivedObserverTag); //disconnect itk events try { m_IGTLDeviceSource->StopCommunication(); } catch (std::runtime_error &e) { MITK_WARN << "Open IGT Link device retruned an error while stopping communication: " << e.what(); return false; } this->SetState(Ready); return true; } unsigned int mitk::OpenIGTLinkTrackingDevice::GetToolCount() const { return (unsigned int)this->m_AllTools.size(); } mitk::TrackingTool* mitk::OpenIGTLinkTrackingDevice::GetTool(unsigned int toolNumber) const { if (toolNumber >= this->GetToolCount()) return NULL; else return this->m_AllTools[toolNumber]; } bool mitk::OpenIGTLinkTrackingDevice::OpenConnection() { //check tracking state if (this->GetState() != Setup) { MITK_WARN << "Cannot open connection, device is already connected!"; return false; } try { m_IGTLDeviceSource->Connect(); } catch (std::runtime_error &e) { MITK_WARN << "Open IGT Link device retruned an error while trying to connect: " << e.what(); return false; } this->SetState(Ready); return true; } bool mitk::OpenIGTLinkTrackingDevice::CloseConnection() { //check tracking state if (this->GetState() != Ready) { MITK_WARN << "Cannot close connection, device is in the wrong state!"; return false; } try { m_IGTLDeviceSource->Disconnect(); } catch (std::runtime_error &e) { MITK_WARN << "Open IGT Link device retruned an error while trying to disconnect: " << e.what(); return false; } this->SetState(Setup); return true; } std::vector mitk::OpenIGTLinkTrackingDevice::GetAllTools() { return this->m_AllTools; } mitk::OpenIGTLinkTrackingDevice::TrackingMessageType mitk::OpenIGTLinkTrackingDevice::GetMessageTypeFromString(const char* messageTypeString) { if (strcmp(messageTypeString, "TDATA") == 0) { return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::TDATA; } else if (strcmp(messageTypeString, "QTDATA") == 0) { return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::QTDATA; } else if (strcmp(messageTypeString, "TRANSFORM") == 0) { return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::TRANSFORM; } else { return mitk::OpenIGTLinkTrackingDevice::TrackingMessageType::UNKNOWN; } } diff --git a/Modules/OpenIGTLink/Testing/mitkOpenIGTLinkClientServerTest.cpp b/Modules/OpenIGTLink/Testing/mitkOpenIGTLinkClientServerTest.cpp index 49d5f89f47..d2238e53fb 100644 --- a/Modules/OpenIGTLink/Testing/mitkOpenIGTLinkClientServerTest.cpp +++ b/Modules/OpenIGTLink/Testing/mitkOpenIGTLinkClientServerTest.cpp @@ -1,260 +1,260 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //TEST #include #include //STD #include #include //MITK #include "mitkIGTLServer.h" #include "mitkIGTLClient.h" #include "mitkIGTLMessageFactory.h" //IGTL #include "igtlStatusMessage.h" #include "igtlClientSocket.h" #include "igtlServerSocket.h" static int PORT = 35352; static const std::string HOSTNAME = "localhost"; static const std::string SERVER_DEVICE_NAME = "Test Server"; static const std::string CLIENT_ONE_DEVICE_NAME = "Test Client 1"; static const std::string CLIENT_TWO_DEVICE_NAME = "Test Client 2"; class mitkOpenIGTLinkClientServerTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkOpenIGTLinkClientServerTestSuite); //MITK_TEST(Test_JustIGTLImpl_OpenAndCloseAndThenReopenAndCloseServer_Successful); //MITK_TEST(Test_ConnectingOneClientAndOneServer_Successful); //MITK_TEST(Test_ConnectingMultipleClientsToOneServer_Successful); #ifdef _WIN32 //does only work under windows, see bug 19633 MITK_TEST(Test_DisconnectionServerFirst_Successful); #endif //MITK_TEST(Test_SendingMessageFromServerToOneClient_Successful); //MITK_TEST(Test_SendingMessageFromServerToMultipleClients_Successful); CPPUNIT_TEST_SUITE_END(); private: std::string m_Message; mitk::IGTLServer::Pointer m_Server; mitk::IGTLClient::Pointer m_Client_One; mitk::IGTLClient::Pointer m_Client_Two; mitk::IGTLMessageFactory::Pointer m_MessageFactory; public: void setUp() override { std::this_thread::sleep_for(std::chrono::milliseconds(20)); m_Message = "This is a test status message"; m_MessageFactory = mitk::IGTLMessageFactory::New(); m_Server = mitk::IGTLServer::New(true); m_Client_One = mitk::IGTLClient::New(true); m_Client_Two = mitk::IGTLClient::New(true); m_Server->SetObjectName(SERVER_DEVICE_NAME); m_Server->SetHostname(HOSTNAME); m_Server->SetName(SERVER_DEVICE_NAME); m_Server->SetPortNumber(PORT); m_Client_One->SetObjectName(CLIENT_ONE_DEVICE_NAME); m_Client_One->SetHostname(HOSTNAME); m_Client_One->SetName(CLIENT_ONE_DEVICE_NAME); m_Client_One->SetPortNumber(PORT); m_Client_Two->SetObjectName(CLIENT_TWO_DEVICE_NAME); m_Client_Two->SetHostname(HOSTNAME); m_Client_Two->SetName(CLIENT_TWO_DEVICE_NAME); m_Client_Two->SetPortNumber(PORT); } void tearDown() override { std::this_thread::sleep_for(std::chrono::milliseconds(20)); m_Message.clear(); m_Server = nullptr; m_Client_One = nullptr; m_Client_Two = nullptr; m_MessageFactory = nullptr; } void testMessagesEqual(igtl::MessageBase::Pointer sentMessage, igtl::MessageBase::Pointer receivedMessage) { std::string lhs(sentMessage->GetDeviceName()); std::string rhs(receivedMessage->GetDeviceName()); CPPUNIT_ASSERT_MESSAGE("The device names were not the same", lhs == rhs); igtl::StatusMessage::Pointer receivedStatusMessage = dynamic_cast(receivedMessage.GetPointer()); igtl::StatusMessage::Pointer sentStatusMessage = dynamic_cast(sentMessage.GetPointer()); CPPUNIT_ASSERT_MESSAGE("The received message was not of the appropriate type.", receivedStatusMessage != nullptr); CPPUNIT_ASSERT_MESSAGE("The sent message was not of the appropriate type.", sentStatusMessage != nullptr); lhs = receivedStatusMessage->GetStatusString(); rhs = sentStatusMessage->GetStatusString(); CPPUNIT_ASSERT_MESSAGE("The sent and received message did not contain the same status message.", lhs == rhs); CPPUNIT_ASSERT_MESSAGE("The sent message did not contain the correct status message.", lhs == m_Message); CPPUNIT_ASSERT_MESSAGE("The received message did not contain the correct status message.", m_Message == rhs); }; void Test_JustIGTLImpl_OpenAndCloseAndThenReopenAndCloseServer_Successful() { igtl::ServerSocket::Pointer server = igtl::ServerSocket::New(); igtl::ClientSocket::Pointer client = igtl::ClientSocket::New(); CPPUNIT_ASSERT(server->CreateServer(PORT) == 0); CPPUNIT_ASSERT(client->ConnectToServer("localhost", PORT) == 0); client->CloseSocket(); server->CloseSocket(); CPPUNIT_ASSERT(server->CreateServer(PORT) == 0); CPPUNIT_ASSERT(client->ConnectToServer("localhost", PORT) == 0); client->CloseSocket(); server->CloseSocket(); server = nullptr; client = nullptr; } void Test_ConnectingOneClientAndOneServer_Successful() { CPPUNIT_ASSERT_MESSAGE("Could not open Connection with Server", m_Server->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Could not connect to Server with first client", m_Client_One->OpenConnection()); CPPUNIT_ASSERT(m_Client_One->CloseConnection()); CPPUNIT_ASSERT(m_Server->CloseConnection()); } void Test_ConnectingMultipleClientsToOneServer_Successful() { CPPUNIT_ASSERT_MESSAGE("Could not open Connection with Server", m_Server->OpenConnection()); m_Server->StartCommunication(); CPPUNIT_ASSERT_MESSAGE("Could not connect to Server with first client", m_Client_One->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Could not start communication with first client", m_Client_One->StartCommunication()); CPPUNIT_ASSERT_MESSAGE("Could not connect to Server with second client", m_Client_Two->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Could not start communication with second client", m_Client_Two->StartCommunication()); CPPUNIT_ASSERT(m_Client_One->CloseConnection()); CPPUNIT_ASSERT(m_Client_Two->CloseConnection()); CPPUNIT_ASSERT(m_Server->CloseConnection()); } void Test_DisconnectionServerFirst_Successful() { CPPUNIT_ASSERT_MESSAGE("Could not open Connection with Server", m_Server->OpenConnection()); m_Server->StartCommunication(); CPPUNIT_ASSERT_MESSAGE("Could not connect to Server with first client", m_Client_One->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Could not start communication with first client", m_Client_One->StartCommunication()); CPPUNIT_ASSERT_MESSAGE("Could not connect to Server with second client", m_Client_Two->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Could not start communication with second client", m_Client_Two->StartCommunication()); std::this_thread::sleep_for(std::chrono::milliseconds(200)); CPPUNIT_ASSERT(m_Server->CloseConnection()); CPPUNIT_ASSERT(m_Client_One->CloseConnection()); CPPUNIT_ASSERT(m_Client_Two->CloseConnection()); } void Test_SendingMessageFromServerToOneClient_Successful() { CPPUNIT_ASSERT_MESSAGE("Server not connected to Client.", m_Server->OpenConnection()); CPPUNIT_ASSERT_MESSAGE("Client 1 not connected to Server.", m_Client_One->OpenConnection()); m_Server->StartCommunication(); m_Client_One->StartCommunication(); igtl::MessageBase::Pointer sentMessage = m_MessageFactory->CreateInstance("STATUS"); dynamic_cast(sentMessage.GetPointer())->SetStatusString(m_Message.c_str()); - m_Server->SendMessage(mitk::IGTLMessage::New(sentMessage, m_Message)); + m_Server->SendMessage(mitk::IGTLMessage::New(sentMessage)); igtl::MessageBase::Pointer receivedMessage; int steps = 0; while ((receivedMessage = m_Client_One->GetMessageQueue()->PullMiscMessage()) == nullptr) { std::this_thread::sleep_for(std::chrono::milliseconds(5)); if (++steps > 20) break; } CPPUNIT_ASSERT(receivedMessage != nullptr); CPPUNIT_ASSERT(m_Client_One->StopCommunication()); CPPUNIT_ASSERT(m_Server->StopCommunication()); CPPUNIT_ASSERT(m_Client_One->CloseConnection()); CPPUNIT_ASSERT(m_Server->CloseConnection()); testMessagesEqual(sentMessage, receivedMessage); } void Test_SendingMessageFromServerToMultipleClients_Successful() { CPPUNIT_ASSERT_MESSAGE("Server not connected to Client.", m_Server->OpenConnection()); m_Server->StartCommunication(); CPPUNIT_ASSERT_MESSAGE("Client 1 not connected to Server.", m_Client_One->OpenConnection()); m_Client_One->StartCommunication(); CPPUNIT_ASSERT_MESSAGE("Client 2 not connected to Server.", m_Client_Two->OpenConnection()); m_Client_Two->StartCommunication(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); igtl::MessageBase::Pointer sentMessage = m_MessageFactory->CreateInstance("STATUS"); dynamic_cast(sentMessage.GetPointer())->SetStatusString(m_Message.c_str()); - m_Server->SendMessage(mitk::IGTLMessage::New(sentMessage, m_Message)); + m_Server->SendMessage(mitk::IGTLMessage::New(sentMessage)); MITK_INFO << "SENT MESSAGE"; igtl::MessageBase::Pointer receivedMessage1; igtl::MessageBase::Pointer receivedMessage2; int steps = 0; while (receivedMessage1 == nullptr || receivedMessage2 == nullptr) { std::this_thread::sleep_for(std::chrono::milliseconds(20)); igtl::MessageBase::Pointer tmpMessage1 = m_Client_One->GetMessageQueue()->PullMiscMessage(); if (tmpMessage1.IsNotNull()) receivedMessage1 = tmpMessage1; igtl::MessageBase::Pointer tmpMessage2 = m_Client_Two->GetMessageQueue()->PullMiscMessage(); if (tmpMessage2.IsNotNull()) receivedMessage2 = tmpMessage2; if (++steps > 50) break; } CPPUNIT_ASSERT(m_Client_Two->StopCommunication()); CPPUNIT_ASSERT(m_Client_One->StopCommunication()); CPPUNIT_ASSERT(m_Server->StopCommunication()); CPPUNIT_ASSERT(m_Client_Two->CloseConnection()); CPPUNIT_ASSERT(m_Client_One->CloseConnection()); CPPUNIT_ASSERT(m_Server->CloseConnection()); CPPUNIT_ASSERT_MESSAGE("Message from first client was null..", receivedMessage1 != nullptr); CPPUNIT_ASSERT_MESSAGE("Message from first client was null..", receivedMessage1.IsNotNull()); CPPUNIT_ASSERT_MESSAGE("Message from second client was null..", receivedMessage2 != nullptr); CPPUNIT_ASSERT_MESSAGE("Message from second client was null..", receivedMessage2.IsNotNull()); testMessagesEqual(sentMessage, receivedMessage1); testMessagesEqual(sentMessage, receivedMessage2); testMessagesEqual(receivedMessage2, receivedMessage1); } }; MITK_TEST_SUITE_REGISTRATION(mitkOpenIGTLinkClientServer) diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.cpp b/Modules/OpenIGTLink/mitkIGTLDevice.cpp index 0a3c9ac77a..506300dea5 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.cpp +++ b/Modules/OpenIGTLink/mitkIGTLDevice.cpp @@ -1,567 +1,567 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkIGTLDevice.h" //#include "mitkIGTException.h" //#include "mitkIGTTimeStamp.h" #include #include #include #include #include #include //remove later #include //TODO: Which timeout is acceptable and also needed to transmit image data? Is there a maximum data limit? static const int SOCKET_SEND_RECEIVE_TIMEOUT_MSEC = 100; typedef itk::MutexLockHolder MutexLockHolder; mitk::IGTLDevice::IGTLDevice(bool ReadFully) : // m_Data(mitk::DeviceDataUnspecified), m_State(mitk::IGTLDevice::Setup), m_Name("Unspecified Device"), m_StopCommunication(false), m_Hostname("127.0.0.1"), m_PortNumber(-1), m_MultiThreader(nullptr), m_SendThreadID(0), m_ReceiveThreadID(0), m_ConnectThreadID(0) { m_ReadFully = ReadFully; m_StopCommunicationMutex = itk::FastMutexLock::New(); m_StateMutex = itk::FastMutexLock::New(); // m_LatestMessageMutex = itk::FastMutexLock::New(); m_SendingFinishedMutex = itk::FastMutexLock::New(); m_ReceivingFinishedMutex = itk::FastMutexLock::New(); m_ConnectingFinishedMutex = itk::FastMutexLock::New(); // execution rights are owned by the application thread at the beginning m_SendingFinishedMutex->Lock(); m_ReceivingFinishedMutex->Lock(); m_ConnectingFinishedMutex->Lock(); m_MultiThreader = itk::MultiThreader::New(); // m_Data = mitk::DeviceDataUnspecified; // m_LatestMessage = igtl::MessageBase::New(); m_MessageFactory = mitk::IGTLMessageFactory::New(); m_MessageQueue = mitk::IGTLMessageQueue::New(); } mitk::IGTLDevice::~IGTLDevice() { /* stop communication and disconnect from igtl device */ if (GetState() == Running) { this->StopCommunication(); this->CloseConnection(); } else if (GetState() == Ready) { this->CloseConnection(); } /* cleanup tracking thread */ if (m_MultiThreader.IsNotNull()) { if ((m_SendThreadID != 0)) { m_MultiThreader->TerminateThread(m_SendThreadID); } if ((m_ReceiveThreadID != 0)) { m_MultiThreader->TerminateThread(m_ReceiveThreadID); } if ((m_ConnectThreadID != 0)) { m_MultiThreader->TerminateThread(m_ConnectThreadID); } } m_MultiThreader = nullptr; } mitk::IGTLDevice::IGTLDeviceState mitk::IGTLDevice::GetState() const { MutexLockHolder lock(*m_StateMutex); return m_State; } void mitk::IGTLDevice::SetState(IGTLDeviceState state) { itkDebugMacro("setting m_State to " << state); m_StateMutex->Lock(); // MutexLockHolder lock(*m_StateMutex); // lock and unlock the mutex if (m_State == state) { m_StateMutex->Unlock(); return; } m_State = state; m_StateMutex->Unlock(); this->Modified(); } bool mitk::IGTLDevice::TestConnection() { return true; } unsigned int mitk::IGTLDevice::ReceivePrivate(igtl::Socket* socket) { // Create a message buffer to receive header igtl::MessageHeader::Pointer headerMsg; headerMsg = igtl::MessageHeader::New(); // Initialize receive buffer headerMsg->InitPack(); // Receive generic header from the socket int r = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), 0); //MITK_INFO << "Server received r = " << r; //MITK_INFO << "Received r = " << r; if (r == 0) //connection error { // an error was received, therefore the communication with this socket // must be stoppedy return IGTL_STATUS_NOT_PRESENT; } else if (r == -1) //timeout { // a timeout was received, this is no error state, thus, do nothing return IGTL_STATUS_TIME_OUT; } else if (r == headerMsg->GetPackSize()) { // Deserialize the header and check the CRC // ERROR HERE: This probably means the header data is corrupted... int crcCheck = headerMsg->Unpack(1); if (crcCheck & igtl::MessageHeader::UNPACK_HEADER) { // Allocate a time stamp igtl::TimeStamp::Pointer ts; ts = igtl::TimeStamp::New(); // Get time stamp igtlUint32 sec; igtlUint32 nanosec; headerMsg->GetTimeStamp(ts); ts->GetTimeStamp(&sec, &nanosec); // std::cerr << "Time stamp: " // << sec << "." // << nanosec << std::endl; // std::cerr << "Dev type and name: " << headerMsg->GetDeviceType() << " " // << headerMsg->GetDeviceName() << std::endl; // headerMsg->Print(std::cout); //check the type of the received message //if it is a GET_, STP_ or RTS_ command push it into the command queue //otherwise continue reading the whole message from the socket const char* curDevType = headerMsg->GetDeviceType(); if (std::strstr(curDevType, "GET_") != nullptr || std::strstr(curDevType, "STP_") != nullptr || std::strstr(curDevType, "RTS_") != nullptr) { this->m_MessageQueue->PushCommandMessage(headerMsg); this->InvokeEvent(CommandReceivedEvent()); return IGTL_STATUS_OK; } //Create a message according to the header message igtl::MessageBase::Pointer curMessage; curMessage = m_MessageFactory->CreateInstance(headerMsg); //check if the curMessage is created properly, if not the message type is //not supported and the message has to be skipped if (curMessage.IsNull()) { socket->Skip(headerMsg->GetBodySizeToRead(), 0); // MITK_ERROR("IGTLDevice") << "The received type is not supported. Please " // "add it to the message factory."; return IGTL_STATUS_NOT_FOUND; } //insert the header to the message and allocate the pack curMessage->SetMessageHeader(headerMsg); curMessage->AllocatePack(); // Receive transform data from the socket int receiveCheck = 0; receiveCheck = socket->Receive(curMessage->GetPackBodyPointer(), curMessage->GetPackBodySize(), m_ReadFully); if (receiveCheck > 0) { int c = curMessage->Unpack(1); if (!(c & igtl::MessageHeader::UNPACK_BODY)) { return IGTL_STATUS_CHECKSUM_ERROR; } //check the type of the received message //if it is a command push it into the command queue //otherwise into the normal receive queue //STP_ commands are handled here because they implemented additional //member variables that are not stored in the header message if (std::strstr(curDevType, "STT_") != nullptr) { this->m_MessageQueue->PushCommandMessage(curMessage); this->InvokeEvent(CommandReceivedEvent()); } else { if(m_LogMessages) - MITK_INFO << "Received Message: " << mitk::IGTLMessage::New(curMessage, "")->ToString(); + MITK_INFO << "Received Message: " << mitk::IGTLMessage::New(curMessage)->ToString(); this->m_MessageQueue->PushMessage(curMessage); this->InvokeEvent(MessageReceivedEvent()); } return IGTL_STATUS_OK; } else { MITK_ERROR("IGTLDevice") << "Received a valid header but could not " << "read the whole message."; return IGTL_STATUS_UNKNOWN_ERROR; } } else { //CRC check failed MITK_ERROR << "CRC Check failed"; return IGTL_STATUS_CHECKSUM_ERROR; } } else { //Message size information and actual data size don't match. //this state is not suppossed to be reached, return unknown error MITK_ERROR << "IGTL status unknown"; return IGTL_STATUS_UNKNOWN_ERROR; } } void mitk::IGTLDevice::SendMessage(mitk::IGTLMessage::Pointer msg) { m_MessageQueue->PushSendMessage(msg); } unsigned int mitk::IGTLDevice::SendMessagePrivate(mitk::IGTLMessage::Pointer msg, igtl::Socket::Pointer socket) { //check the input message if (msg.IsNull()) { MITK_ERROR("IGTLDevice") << "Could not send message because message is not " "valid. Please check."; return false; } igtl::MessageBase* sendMessage = msg->GetMessage(); // add the name of this device to the message sendMessage->SetDeviceName(this->GetName().c_str()); // Pack (serialize) and send sendMessage->Pack(); int sendSuccess = socket->Send(sendMessage->GetPackPointer(), sendMessage->GetPackSize()); if (sendSuccess) { if(m_LogMessages) MITK_INFO << "Send IGTL message: " << msg->ToString(); this->InvokeEvent(MessageSentEvent()); return IGTL_STATUS_OK; } else { return IGTL_STATUS_UNKNOWN_ERROR; } } void mitk::IGTLDevice::RunCommunication(void (IGTLDevice::*ComFunction)(void), itk::FastMutexLock* mutex) { if (this->GetState() != Running) return; try { // keep lock until end of scope MutexLockHolder communicationFinishedLockHolder(*mutex); // Because m_StopCommunication is used by two threads, access has to be guarded // by a mutex. To minimize thread locking, a local copy is used here bool localStopCommunication; // update the local copy of m_StopCommunication this->m_StopCommunicationMutex->Lock(); localStopCommunication = this->m_StopCommunication; this->m_StopCommunicationMutex->Unlock(); while ((this->GetState() == Running) && (localStopCommunication == false)) { (this->*ComFunction)(); /* Update the local copy of m_StopCommunication */ this->m_StopCommunicationMutex->Lock(); localStopCommunication = m_StopCommunication; this->m_StopCommunicationMutex->Unlock(); // time to relax, this sets the maximum ever possible framerate to 1000 Hz itksys::SystemTools::Delay(1); } } catch (...) { mutex->Unlock(); this->StopCommunication(); MITK_ERROR("IGTLDevice::RunCommunication") << "Error while communicating. Thread stopped."; //mitkThrowException(mitk::IGTException) << "Error while communicating. Thread stopped."; } // StopCommunication was called, thus the mode should be changed back to Ready now // that the tracking loop has ended. //this->SetState(Ready); //this is done elsewhere MITK_DEBUG("IGTLDevice::RunCommunication") << "Reached end of communication."; // returning from this function (and ThreadStartCommunication()) // this will end the thread return; } bool mitk::IGTLDevice::StartCommunication() { if (this->GetState() != Ready) return false; // go to mode Running this->SetState(Running); // set a timeout for the sending and receiving this->m_Socket->SetTimeout(SOCKET_SEND_RECEIVE_TIMEOUT_MSEC); // update the local copy of m_StopCommunication this->m_StopCommunicationMutex->Lock(); this->m_StopCommunication = false; this->m_StopCommunicationMutex->Unlock(); // transfer the execution rights to tracking thread m_SendingFinishedMutex->Unlock(); m_ReceivingFinishedMutex->Unlock(); m_ConnectingFinishedMutex->Unlock(); // start new threads that execute the communication m_SendThreadID = m_MultiThreader->SpawnThread(this->ThreadStartSending, this); m_ReceiveThreadID = m_MultiThreader->SpawnThread(this->ThreadStartReceiving, this); m_ConnectThreadID = m_MultiThreader->SpawnThread(this->ThreadStartConnecting, this); // mitk::IGTTimeStamp::GetInstance()->Start(this); return true; } bool mitk::IGTLDevice::StopCommunication() { if (this->GetState() == Running) // Only if the object is in the correct state { // m_StopCommunication is used by two threads, so we have to ensure correct // thread handling m_StopCommunicationMutex->Lock(); m_StopCommunication = true; m_StopCommunicationMutex->Unlock(); // we have to wait here that the other thread recognizes the STOP-command // and executes it m_SendingFinishedMutex->Lock(); m_ReceivingFinishedMutex->Lock(); m_ConnectingFinishedMutex->Lock(); // mitk::IGTTimeStamp::GetInstance()->Stop(this); // notify realtime clock // StopCommunication was called, thus the mode should be changed back // to Ready now that the tracking loop has ended. this->SetState(Ready); } return true; } bool mitk::IGTLDevice::CloseConnection() { if (this->GetState() == Setup) { return true; } else if (this->GetState() == Running) { this->StopCommunication(); } m_Socket->CloseSocket(); /* return to setup mode */ this->SetState(Setup); // this->InvokeEvent(mitk::LostConnectionEvent()); return true; } bool mitk::IGTLDevice::SendRTSMessage(const char* type) { //construct the device type for the return message, it starts with RTS_ and //continues with the requested type std::string returnType("RTS_"); returnType.append(type); //create a return message igtl::MessageBase::Pointer rtsMsg = this->m_MessageFactory->CreateInstance(returnType); //if retMsg is NULL there is no return message defined and thus it is not //necessary to send one back if (rtsMsg.IsNotNull()) { - this->SendMessage(mitk::IGTLMessage::New(rtsMsg, returnType)); + this->SendMessage(mitk::IGTLMessage::New(rtsMsg)); return true; } else { return false; } } void mitk::IGTLDevice::Connect() { MITK_DEBUG << "mitk::IGTLDevice::Connect();"; } igtl::ImageMessage::Pointer mitk::IGTLDevice::GetNextImage2dMessage() { return this->m_MessageQueue->PullImage2dMessage(); } igtl::ImageMessage::Pointer mitk::IGTLDevice::GetNextImage3dMessage() { return this->m_MessageQueue->PullImage3dMessage(); } igtl::TransformMessage::Pointer mitk::IGTLDevice::GetNextTransformMessage() { return this->m_MessageQueue->PullTransformMessage(); } igtl::TrackingDataMessage::Pointer mitk::IGTLDevice::GetNextTrackingDataMessage() { igtl::TrackingDataMessage::Pointer msg = this->m_MessageQueue->PullTrackingMessage(); return msg; } igtl::StringMessage::Pointer mitk::IGTLDevice::GetNextStringMessage() { return this->m_MessageQueue->PullStringMessage(); } igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextMiscMessage() { return this->m_MessageQueue->PullMiscMessage(); } igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextCommand() { return m_MessageQueue->PullCommandMessage(); } void mitk::IGTLDevice::EnableInfiniteBufferingMode(bool enable) { m_MessageQueue->EnableInfiniteBuffering(enable); } void mitk::IGTLDevice::EnableInfiniteBufferingMode( mitk::IGTLMessageQueue::Pointer queue, bool enable) { queue->EnableInfiniteBuffering(enable); } ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartSending(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == nullptr) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == nullptr) { return ITK_THREAD_RETURN_VALUE; } IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; if (igtlDevice != nullptr) { igtlDevice->RunCommunication(&mitk::IGTLDevice::Send, igtlDevice->m_SendingFinishedMutex); } igtlDevice->m_SendThreadID = 0; // erase thread id because thread will end. return ITK_THREAD_RETURN_VALUE; } ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartReceiving(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == nullptr) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == nullptr) { return ITK_THREAD_RETURN_VALUE; } IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; if (igtlDevice != nullptr) { igtlDevice->RunCommunication(&mitk::IGTLDevice::Receive, igtlDevice->m_ReceivingFinishedMutex); } igtlDevice->m_ReceiveThreadID = 0; // erase thread id because thread will end. return ITK_THREAD_RETURN_VALUE; } ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartConnecting(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == nullptr) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == nullptr) { return ITK_THREAD_RETURN_VALUE; } IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; if (igtlDevice != nullptr) { igtlDevice->RunCommunication(&mitk::IGTLDevice::Connect, igtlDevice->m_ConnectingFinishedMutex); } igtlDevice->m_ConnectThreadID = 0; // erase thread id because thread will end. return ITK_THREAD_RETURN_VALUE; } diff --git a/Modules/OpenIGTLink/mitkIGTLMessage.cpp b/Modules/OpenIGTLink/mitkIGTLMessage.cpp index a5e844c7b9..6da685c03f 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessage.cpp +++ b/Modules/OpenIGTLink/mitkIGTLMessage.cpp @@ -1,181 +1,180 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkIGTLMessage.h" #include "mitkException.h" #include "mitkIGTLMessageCommon.h" mitk::IGTLMessage::IGTLMessage() : itk::DataObject(), m_DataValid(false), m_IGTTimeStamp(0), m_Name() { m_Message = igtl::MessageBase::New(); } mitk::IGTLMessage::IGTLMessage(const mitk::IGTLMessage& toCopy) : itk::DataObject() { // TODO SW: Graft does the same, remove code duplications, set Graft to // deprecated, remove duplication in tescode this->Graft(&toCopy); } mitk::IGTLMessage::~IGTLMessage() { } -mitk::IGTLMessage::IGTLMessage(igtl::MessageBase::Pointer message, - std::string name) +mitk::IGTLMessage::IGTLMessage(igtl::MessageBase::Pointer message) { this->SetMessage(message); - this->SetName(name); + this->SetName(message->GetDeviceName()); } void mitk::IGTLMessage::Graft( const DataObject *data ) { // Attempt to cast data to an IGTLMessage const Self* msg; try { msg = dynamic_cast(data); } catch( ... ) { itkExceptionMacro( << "mitk::IGTLMessage::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ); return; } if (!msg) { // pointer could not be cast back down itkExceptionMacro( << "mitk::IGTLMessage::Graft cannot cast " << typeid(data).name() << " to " << typeid(const Self *).name() ); return; } // Now copy anything that is needed this->SetMessage(msg->GetMessage()); this->SetDataValid(msg->IsDataValid()); this->SetIGTTimeStamp(msg->GetIGTTimeStamp()); this->SetName(msg->GetName()); } void mitk::IGTLMessage::SetMessage(igtl::MessageBase::Pointer msg) { m_Message = msg; unsigned int ts = 0; unsigned int frac = 0; m_Message->GetTimeStamp(&ts, &frac); //ts = seconds / frac = nanoseconds double timestamp = ts * 1000.0 + frac; this->SetIGTTimeStamp(timestamp); this->SetDataValid(true); } bool mitk::IGTLMessage::IsDataValid() const { return m_DataValid; } void mitk::IGTLMessage::PrintSelf(std::ostream& os, itk::Indent indent) const { this->Superclass::PrintSelf(os, indent); os << indent << "name: " << this->GetName() << std::endl; os << indent << "data valid: " << this->IsDataValid() << std::endl; os << indent << "TimeStamp: " << this->GetIGTTimeStamp() << std::endl; os << indent << "OpenIGTLinkMessage: " << std::endl; m_Message->Print(os); } std::string mitk::IGTLMessage::ToString() const { std::stringstream output; output << "name: " << this->GetName() << std::endl << "MessageType: " << this->GetIGTLMessageType() << std::endl << "TimeStamp: " << this->GetIGTTimeStamp() << std::endl << "OpenIGTLinkMessage: " << std::endl; return output.str(); } void mitk::IGTLMessage::CopyInformation( const DataObject* data ) { this->Superclass::CopyInformation( data ); const Self * nd = nullptr; try { nd = dynamic_cast(data); } catch( ... ) { // data could not be cast back down itkExceptionMacro(<< "mitk::IGTLMessage::CopyInformation() cannot cast " << typeid(data).name() << " to " << typeid(Self*).name() ); } if ( !nd ) { // pointer could not be cast back down itkExceptionMacro(<< "mitk::IGTLMessage::CopyInformation() cannot cast " << typeid(data).name() << " to " << typeid(Self*).name() ); } /* copy all meta data */ } bool mitk::Equal(const mitk::IGTLMessage& leftHandSide, const mitk::IGTLMessage& rightHandSide, ScalarType /*eps*/, bool verbose) { bool returnValue = true; if( std::string(rightHandSide.GetName()) != std::string(leftHandSide.GetName()) ) { if(verbose) { MITK_INFO << "[( IGTLMessage )] Name differs."; MITK_INFO << "leftHandSide is " << leftHandSide.GetName() << "rightHandSide is " << rightHandSide.GetName(); } returnValue = false; } if( rightHandSide.GetIGTTimeStamp() != leftHandSide.GetIGTTimeStamp() ) { if(verbose) { MITK_INFO << "[( IGTLMessage )] IGTTimeStamp differs."; MITK_INFO << "leftHandSide is " << leftHandSide.GetIGTTimeStamp() << "rightHandSide is " << rightHandSide.GetIGTTimeStamp(); } returnValue = false; } return returnValue; } const char* mitk::IGTLMessage::GetIGTLMessageType() const { return this->m_Message->GetDeviceType(); } template < typename IGTLMessageType > IGTLMessageType* mitk::IGTLMessage::GetMessage() const { return dynamic_cast(this->m_Message); } diff --git a/Modules/OpenIGTLink/mitkIGTLMessage.h b/Modules/OpenIGTLink/mitkIGTLMessage.h index 5e0596605e..4ad923f8a7 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessage.h +++ b/Modules/OpenIGTLink/mitkIGTLMessage.h @@ -1,199 +1,199 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIGTLMESSAGEH_HEADER_INCLUDED_ #define MITKIGTLMESSAGEH_HEADER_INCLUDED_ #include #include "MitkOpenIGTLinkExports.h" #include #include #include "igtlMessageBase.h" namespace mitk { /**Documentation * \brief A wrapper for the OpenIGTLink message type * * This class represents the data object that is passed through the * MITK-OpenIGTLink filter pipeline. It wraps the OpenIGTLink message type. * Additionally, it contains a data structure that contains error/plausibility * information. * */ class MITKOPENIGTLINK_EXPORT IGTLMessage : public itk::DataObject { public: mitkClassMacroItkParent(IGTLMessage, itk::DataObject); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - mitkNewMacro2Param(Self, igtl::MessageBase::Pointer,std::string); + mitkNewMacro1Param(Self, igtl::MessageBase::Pointer); /** * \brief type that holds the time at which the data was recorded in milliseconds */ typedef double TimeStampType; /** * \brief Sets the OpenIGTLink message */ void SetMessage(igtl::MessageBase::Pointer msg); /** * \brief returns the OpenIGTLink message */ itkGetConstMacro(Message, igtl::MessageBase::Pointer); /** * \brief returns true if the object contains valid data */ virtual bool IsDataValid() const; /** * \brief sets the dataValid flag of the IGTLMessage object indicating if * the object contains valid data */ itkSetMacro(DataValid, bool); /** * \brief gets the IGT timestamp of the IGTLMessage object */ itkGetConstMacro(IGTTimeStamp, TimeStampType); /** * \brief set the name of the IGTLMessage object */ itkSetStringMacro(Name); /** * \brief returns the name of the IGTLMessage object */ itkGetStringMacro(Name); /** * \brief Graft the data and information from one IGTLMessage to another. * * Copies the content of data into this object. * This is a convenience method to setup a second IGTLMessage object with * all the meta information of another IGTLMessage object. * Note that this method is different than just using two * SmartPointers to the same IGTLMessage object since separate DataObjects * are still maintained. */ virtual void Graft(const DataObject *data) override; /** * \brief copy meta data of a IGTLMessage object * * copies all meta data from IGTLMessage data to this object */ virtual void CopyInformation(const DataObject* data) override; /** * \brief Prints the object information to the given stream os. * \param os The stream which is used to print the output. * \param indent Defines the indentation of the output. */ void PrintSelf(std::ostream& os, itk::Indent indent) const override; std::string ToString() const; /** Compose with another IGTLMessage * * This method composes self with another IGTLMessage of the * same dimension, modifying self to be the composition of self * and other. If the argument pre is true, then other is * precomposed with self; that is, the resulting transformation * consists of first applying other to the source, followed by * self. If pre is false or omitted, then other is post-composed * with self; that is the resulting transformation consists of * first applying self to the source, followed by other. */ void Compose(const mitk::IGTLMessage::Pointer n, const bool pre = false); /** Returns the OpenIGTL Message type **/ const char* GetIGTLMessageType() const; template < typename IGTLMessageType > IGTLMessageType* GetMessage() const; protected: mitkCloneMacro(Self); IGTLMessage(); /** * Copy constructor internally used. */ IGTLMessage(const mitk::IGTLMessage& toCopy); /** * Creates a IGTLMessage object from an igtl::MessageBase and a given name. */ - IGTLMessage(igtl::MessageBase::Pointer message, std::string name = ""); + IGTLMessage(igtl::MessageBase::Pointer message); virtual ~IGTLMessage(); /** * \brief holds the actual OpenIGTLink message */ igtl::MessageBase::Pointer m_Message; /** * \brief defines if the object contains valid values */ bool m_DataValid; /** * \brief contains the time at which the tracking data was recorded */ TimeStampType m_IGTTimeStamp; /** * \brief name of the navigation data */ std::string m_Name; private: // pre = false static mitk::IGTLMessage::Pointer getComposition( const mitk::IGTLMessage::Pointer nd1, const mitk::IGTLMessage::Pointer nd2); /** * \brief sets the IGT timestamp of the IGTLMessage object */ itkSetMacro(IGTTimeStamp, TimeStampType); }; /** * @brief Equal A function comparing two OpenIGTLink message objects for * being equal in meta- and imagedata * * @ingroup MITKTestingAPI * * Following aspects are tested for equality: * - TBD * * @param rightHandSide An IGTLMessage to be compared * @param leftHandSide An IGTLMessage to be compared * @param eps Tolarence for comparison. You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output * or not. * @return true, if all subsequent comparisons are true, false otherwise */ MITKOPENIGTLINK_EXPORT bool Equal( const mitk::IGTLMessage& leftHandSide, const mitk::IGTLMessage& rightHandSide, ScalarType eps = mitk::eps, bool verbose = false ); } // namespace mitk #endif /* MITKIGTLMESSAGEH_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp index 075e100236..e652c36133 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceCommandWidget.cpp @@ -1,293 +1,293 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkIGTLDeviceCommandWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include const std::string QmitkIGTLDeviceCommandWidget::VIEW_ID = "org.mitk.views.igtldevicesourcemanagementwidget"; QmitkIGTLDeviceCommandWidget::QmitkIGTLDeviceCommandWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false), m_MessageReceivedObserverTag(0), m_CommandReceivedObserverTag(0), m_LostConnectionObserverTag(0), m_NewConnectionObserverTag(0), m_StateModifiedObserverTag(0) { m_Controls = NULL; this->m_IGTLDevice = NULL; CreateQtPartControl(this); } QmitkIGTLDeviceCommandWidget::~QmitkIGTLDeviceCommandWidget() { if (m_MessageReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); if (m_CommandReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); if (m_LostConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); if (m_NewConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); if (m_StateModifiedObserverTag) this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } void QmitkIGTLDeviceCommandWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLDeviceCommandWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } //connect slots with signals CreateConnections(); } void QmitkIGTLDeviceCommandWidget::CreateConnections() { if (m_Controls) { // connect the widget items with the methods connect( m_Controls->butSendCommand, SIGNAL(clicked()), this, SLOT(OnSendCommand())); connect( m_Controls->commandsComboBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(OnCommandChanged(const QString &))); } //this is used for thread seperation, otherwise the worker thread would change the ui elements //which would cause an exception connect(this, SIGNAL(AdaptGUIToStateSignal()), this, SLOT(AdaptGUIToState())); } void QmitkIGTLDeviceCommandWidget::OnDeviceStateChanged() { //this->AdaptGUIToState(); emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceCommandWidget::AdaptGUIToState() { if (this->m_IGTLDevice.IsNotNull()) { //check the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDevice->GetState(); switch (state) { case mitk::IGTLDevice::Setup: this->m_Controls->commandsComboBox->setEnabled(false); this->m_Controls->butSendCommand->setEnabled(false); this->m_Controls->fpsSpinBox->setEnabled(false); break; case mitk::IGTLDevice::Ready: this->m_Controls->commandsComboBox->setEnabled(true); this->m_Controls->butSendCommand->setEnabled(true); this->m_Controls->fpsSpinBox->setEnabled(false); break; case mitk::IGTLDevice::Running: if ( this->m_IGTLDevice->GetNumberOfConnections() == 0 ) { //just a server can run and have 0 connections this->m_Controls->butSendCommand->setEnabled(false); this->m_Controls->fpsSpinBox->setEnabled(false); this->m_Controls->commandsComboBox->setEnabled(false); } else { this->m_Controls->commandsComboBox->setEnabled(true); this->m_Controls->butSendCommand->setEnabled(true); // this->m_Controls->fpsSpinBox->setEnabled(true); } break; default: mitkThrow() << "Invalid Device State"; break; } } else { this->DisableSourceControls(); } } void QmitkIGTLDeviceCommandWidget::Initialize(mitk::IGTLDevice::Pointer device) { //reset the GUI DisableSourceControls(); //reset the observers if ( this->m_IGTLDevice.IsNotNull() ) { this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } if(device.IsNotNull()) { //get the device this->m_IGTLDevice = device; //check if the device is a server or a client if ( dynamic_cast( this->m_IGTLDevice.GetPointer()) == NULL ) { m_IsClient = false; } else { m_IsClient = true; } typedef itk::SimpleMemberCommand< QmitkIGTLDeviceCommandWidget > CurCommandType; // CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); // messageReceivedCommand->SetCallbackFunction( // this, &QmitkIGTLDeviceCommandWidget::OnMessageReceived ); // this->m_MessageReceivedObserverTag = // this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); // CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); // commandReceivedCommand->SetCallbackFunction( // this, &QmitkIGTLDeviceCommandWidget::OnCommandReceived ); // this->m_CommandReceivedObserverTag = // this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); connectionLostCommand->SetCallbackFunction( this, &QmitkIGTLDeviceCommandWidget::OnLostConnection ); this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::LostConnectionEvent(), connectionLostCommand); CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkIGTLDeviceCommandWidget::OnNewConnection ); this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); stateModifiedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceCommandWidget::OnDeviceStateChanged ); this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( itk::ModifiedEvent(), stateModifiedCommand); //Fill the commands combo box with all available commands FillCommandsComboBox(); } else { m_IGTLDevice = NULL; } this->AdaptGUIToState(); } void QmitkIGTLDeviceCommandWidget::DisableSourceControls() { this->m_Controls->commandsComboBox->setEnabled(false); this->m_Controls->butSendCommand->setEnabled(false); this->m_Controls->fpsSpinBox->setEnabled(false); } void QmitkIGTLDeviceCommandWidget::OnSendCommand() { //Set the frames per second of the current command in case of a STT_ command if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_BIND" ) == 0 ) { ((igtl::StartBindMessage*)this->m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } else if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_QTDATA" ) == 0 ) { ((igtl::StartQuaternionTrackingDataMessage*)m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } else if ( std::strcmp( m_CurrentCommand->GetDeviceType(), "STT_TDATA" ) == 0 ) { ((igtl::StartTrackingDataMessage*)this->m_CurrentCommand.GetPointer())-> SetResolution(this->m_Controls->fpsSpinBox->value()); } - m_IGTLDevice->SendMessage(mitk::IGTLMessage::New(m_CurrentCommand, "")); + m_IGTLDevice->SendMessage(mitk::IGTLMessage::New(m_CurrentCommand)); } void QmitkIGTLDeviceCommandWidget::OnCommandChanged( const QString & curCommand) { if ( curCommand.isEmpty() ) return; mitk::IGTLMessageFactory::Pointer msgFactory = this->m_IGTLDevice->GetMessageFactory(); //create a new message that fits to the selected get message type command this->m_CurrentCommand = msgFactory->CreateInstance( curCommand.toStdString()); //enable/disable the FPS spinbox this->m_Controls->fpsSpinBox->setEnabled(curCommand.contains("STT_")); } void QmitkIGTLDeviceCommandWidget::OnLostConnection() { //get the IGTL device that invoked this event // mitk::IGTLDevice* dev = (mitk::IGTLDevice*)caller; //this->AdaptGUIToState(); emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceCommandWidget::OnNewConnection() { //this->AdaptGUIToState(); emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceCommandWidget::FillCommandsComboBox() { //load the msg factory from the client (maybe this will be moved later on) mitk::IGTLMessageFactory::Pointer msgFactory = this->m_IGTLDevice->GetMessageFactory(); //get the available commands as std::list std::list commandsList_ = msgFactory->GetAvailableMessageRequestTypes(); //create a string list to convert the std::list this->m_Controls->commandsComboBox->clear(); while ( commandsList_.size() ) { //fill the combo box with life this->m_Controls->commandsComboBox->addItem( QString::fromStdString(commandsList_.front())); commandsList_.pop_front(); } } diff --git a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp index 5b9e328186..47278dac77 100644 --- a/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp +++ b/Modules/OpenIGTLinkUI/Qmitk/QmitkIGTLDeviceSourceManagementWidget.cpp @@ -1,246 +1,246 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkIGTLDeviceSourceManagementWidget.h" //mitk headers #include #include #include #include //qt headers #include #include #include #include //igtl #include #include #include #include //poco headers #include const std::string QmitkIGTLDeviceSourceManagementWidget::VIEW_ID = "org.mitk.views.igtldevicesourcemanagementwidget"; QmitkIGTLDeviceSourceManagementWidget::QmitkIGTLDeviceSourceManagementWidget( QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_IsClient(false), m_MessageReceivedObserverTag(0), m_CommandReceivedObserverTag(0), m_LostConnectionObserverTag(0), m_NewConnectionObserverTag(0), m_StateModifiedObserverTag(0) { m_Controls = NULL; this->m_IGTLDevice = NULL; CreateQtPartControl(this); } QmitkIGTLDeviceSourceManagementWidget::~QmitkIGTLDeviceSourceManagementWidget() { if (m_MessageReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); if (m_CommandReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); if (m_LostConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); if (m_NewConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); if (m_StateModifiedObserverTag) this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } void QmitkIGTLDeviceSourceManagementWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkIGTLDeviceSourceManagementWidgetControls; // setup GUI widgets m_Controls->setupUi(parent); } //connect slots with signals CreateConnections(); } void QmitkIGTLDeviceSourceManagementWidget::CreateConnections() { if (m_Controls) { connect( m_Controls->butSend, SIGNAL(clicked()), this, SLOT(OnSendMessage())); } //this is used for thread seperation, otherwise the worker thread would change the ui elements //which would cause an exception connect(this, SIGNAL(AdaptGUIToStateSignal()), this, SLOT(AdaptGUIToState())); } void QmitkIGTLDeviceSourceManagementWidget::OnDeviceStateChanged() { emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSourceManagementWidget::AdaptGUIToState() { if (this->m_IGTLDeviceSource.IsNotNull()) { //check the state of the device mitk::IGTLDevice::IGTLDeviceState state = this->m_IGTLDeviceSource->GetIGTLDevice()->GetState(); switch (state) { case mitk::IGTLDevice::Setup: this->m_Controls->editSend->setEnabled(false); this->m_Controls->butSend->setEnabled(false); break; case mitk::IGTLDevice::Ready: this->m_Controls->editSend->setEnabled(false); this->m_Controls->butSend->setEnabled(false); break; case mitk::IGTLDevice::Running: if ( this->m_IGTLDevice->GetNumberOfConnections() == 0 ) { //just a server can run and have 0 connections this->m_Controls->editSend->setEnabled(false); this->m_Controls->butSend->setEnabled(false); } else { this->m_Controls->editSend->setEnabled(true); this->m_Controls->butSend->setEnabled(true); } break; default: mitkThrow() << "Invalid Device State"; break; } m_Controls->selectedSourceLabel->setText( m_IGTLDeviceSource->GetName().c_str()); } else { this->DisableSourceControls(); } } void QmitkIGTLDeviceSourceManagementWidget::LoadSource( mitk::IGTLDeviceSource::Pointer sourceToLoad) { //reset the GUI DisableSourceControls(); //reset the observers if ( this->m_IGTLDevice.IsNotNull() ) { if (m_MessageReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_MessageReceivedObserverTag); if (m_CommandReceivedObserverTag) this->m_IGTLDevice->RemoveObserver(m_CommandReceivedObserverTag); if (m_LostConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_LostConnectionObserverTag); if (m_NewConnectionObserverTag) this->m_IGTLDevice->RemoveObserver(m_NewConnectionObserverTag); if (m_StateModifiedObserverTag) this->m_IGTLDevice->RemoveObserver(m_StateModifiedObserverTag); } if(sourceToLoad.IsNotNull()) { this->m_IGTLDeviceSource = sourceToLoad; //get the device this->m_IGTLDevice = this->m_IGTLDeviceSource->GetIGTLDevice(); //initialize the other GUI elements this->m_Controls->connectionSetupWidget->Initialize(this->m_IGTLDevice); this->m_Controls->commandWidget->Initialize(this->m_IGTLDevice); //check if the device is a server or a client if ( dynamic_cast( this->m_IGTLDeviceSource->GetIGTLDevice()) == NULL ) { m_IsClient = false; } else { m_IsClient = true; } typedef itk::SimpleMemberCommand< QmitkIGTLDeviceSourceManagementWidget > CurCommandType; CurCommandType::Pointer messageReceivedCommand = CurCommandType::New(); messageReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived ); this->m_MessageReceivedObserverTag = this->m_IGTLDevice->AddObserver(mitk::MessageReceivedEvent(), messageReceivedCommand); CurCommandType::Pointer commandReceivedCommand = CurCommandType::New(); commandReceivedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnCommandReceived ); this->m_CommandReceivedObserverTag = this->m_IGTLDevice->AddObserver(mitk::CommandReceivedEvent(), commandReceivedCommand); CurCommandType::Pointer connectionLostCommand = CurCommandType::New(); connectionLostCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnLostConnection ); this->m_LostConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::LostConnectionEvent(), connectionLostCommand); CurCommandType::Pointer newConnectionCommand = CurCommandType::New(); newConnectionCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnNewConnection ); this->m_NewConnectionObserverTag = this->m_IGTLDevice->AddObserver( mitk::NewClientConnectionEvent(), newConnectionCommand); CurCommandType::Pointer stateModifiedCommand = CurCommandType::New(); stateModifiedCommand->SetCallbackFunction( this, &QmitkIGTLDeviceSourceManagementWidget::OnDeviceStateChanged ); this->m_StateModifiedObserverTag = this->m_IGTLDevice->AddObserver( itk::ModifiedEvent(), stateModifiedCommand); } else { m_IGTLDeviceSource = NULL; } this->AdaptGUIToState(); } void QmitkIGTLDeviceSourceManagementWidget::DisableSourceControls() { m_Controls->selectedSourceLabel->setText(""); m_Controls->editSend->setEnabled(false); m_Controls->butSend->setEnabled(false); } void QmitkIGTLDeviceSourceManagementWidget::OnSendMessage() { std::string toBeSend = m_Controls->editSend->text().toStdString(); igtl::StringMessage::Pointer msg = igtl::StringMessage::New(); msg->SetString(toBeSend); - this->m_IGTLDevice->SendMessage(mitk::IGTLMessage::New((igtl::MessageBase::Pointer)msg, toBeSend)); + this->m_IGTLDevice->SendMessage(mitk::IGTLMessage::New((igtl::MessageBase::Pointer)msg)); } void QmitkIGTLDeviceSourceManagementWidget::OnMessageReceived() { } void QmitkIGTLDeviceSourceManagementWidget::OnCommandReceived() { } void QmitkIGTLDeviceSourceManagementWidget::OnLostConnection() { emit AdaptGUIToStateSignal(); } void QmitkIGTLDeviceSourceManagementWidget::OnNewConnection() { emit AdaptGUIToStateSignal(); } diff --git a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/OpenIGTLinkExample.cpp b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/OpenIGTLinkExample.cpp index 8e7adf35a2..0c35dfb245 100644 --- a/Plugins/org.mitk.gui.qt.igtexamples/src/internal/OpenIGTLinkExample.cpp +++ b/Plugins/org.mitk.gui.qt.igtexamples/src/internal/OpenIGTLinkExample.cpp @@ -1,242 +1,242 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkRenderWindow.h" // Qt #include // mitk #include #include #include #include #include // vtk #include // #include "OpenIGTLinkExample.h" //igtl #include "igtlStringMessage.h" #include "igtlTrackingDataMessage.h" const std::string OpenIGTLinkExample::VIEW_ID = "org.mitk.views.OpenIGTLinkExample"; void OpenIGTLinkExample::SetFocus() { } OpenIGTLinkExample::~OpenIGTLinkExample() { this->DestroyPipeline(); if (m_IGTLDeviceSource.IsNotNull()) { m_IGTLDeviceSource->UnRegisterMicroservice(); } } void OpenIGTLinkExample::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); // connect the widget items with the methods connect( m_Controls.butStart, SIGNAL(clicked()), this, SLOT(Start()) ); connect( &m_Timer, SIGNAL(timeout()), this, SLOT(UpdatePipeline())); //create a new OpenIGTLinkExample Client m_IGTLClient = mitk::IGTLClient::New(false); m_IGTLClient->SetName("OIGTL Example Client Device"); //create a new OpenIGTLinkExample Device source m_IGTLDeviceSource = mitk::IGTLDeviceSource::New(); //set the client as the source for the device source m_IGTLDeviceSource->SetIGTLDevice(m_IGTLClient); m_IGTLDeviceSource->RegisterAsMicroservice(); } void OpenIGTLinkExample::CreatePipeline() { //create a filter that converts OpenIGTLinkExample messages into navigation data m_IGTLMsgToNavDataFilter = mitk::IGTLMessageToNavigationDataFilter::New(); //create a visualization filter m_VisFilter = mitk::NavigationDataObjectVisualizationFilter::New(); //we expect a tracking data message with three tools. Since we cannot change //the outputs at runtime we have to set it manually. m_IGTLMsgToNavDataFilter->SetNumberOfExpectedOutputs(m_Controls.channelSpinBox->value()); //connect the filters with each other //the OpenIGTLinkExample messages will be passed to the first filter that converts //it to navigation data, then it is passed to the visualization filter that //will visualize the transformation m_IGTLMsgToNavDataFilter->ConnectTo(m_IGTLDeviceSource); m_VisFilter->ConnectTo(m_IGTLMsgToNavDataFilter); //create an object that will be moved respectively to the navigation data for (size_t i = 0; i < m_IGTLMsgToNavDataFilter->GetNumberOfIndexedOutputs(); i++) { mitk::DataNode::Pointer newNode = mitk::DataNode::New(); QString name("DemoNode IGTLProviderExmpl T"); name.append(QString::number(i)); newNode->SetName(name.toStdString()); //create small sphere and use it as surface mitk::Surface::Pointer mySphere = mitk::Surface::New(); vtkSphereSource *vtkData = vtkSphereSource::New(); vtkData->SetRadius(2.0f); vtkData->SetCenter(0.0, 0.0, 0.0); vtkData->Update(); mySphere->SetVtkPolyData(vtkData->GetOutput()); vtkData->Delete(); newNode->SetData(mySphere); m_VisFilter->SetRepresentationObject(i, mySphere); m_DemoNodes.append(newNode); } this->ResizeBoundingBox(); } void OpenIGTLinkExample::DestroyPipeline() { m_VisFilter = nullptr; foreach(mitk::DataNode::Pointer node, m_DemoNodes) { this->GetDataStorage()->Remove(node); } this->m_DemoNodes.clear(); } void OpenIGTLinkExample::Start() { if (this->m_Controls.butStart->text().contains("Start Pipeline")) { static bool isFirstTime = true; if (isFirstTime) { //Setup the pipeline this->CreatePipeline(); isFirstTime = false; } m_Timer.setInterval(this->m_Controls.visualizationUpdateRateSpinBox->value()); m_Timer.start(); //this->m_Controls.visualizationUpdateRateSpinBox->setEnabled(true); this->m_Controls.butStart->setText("Stop Pipeline"); } else { m_Timer.stop(); igtl::StopTrackingDataMessage::Pointer stopStreaming = igtl::StopTrackingDataMessage::New(); - this->m_IGTLClient->SendMessage(mitk::IGTLMessage::New((igtl::MessageBase::Pointer) stopStreaming, "")); + this->m_IGTLClient->SendMessage(mitk::IGTLMessage::New((igtl::MessageBase::Pointer) stopStreaming)); this->m_Controls.butStart->setText("Start Pipeline"); //this->m_Controls.visualizationUpdateRateSpinBox->setEnabled(false); } } void OpenIGTLinkExample::UpdatePipeline() { if (this->m_Controls.visualizeCheckBox->isChecked()) { //update the pipeline m_VisFilter->Update(); ////update the boundings //mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); //Update rendering mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { //no visualization so we just update this filter m_IGTLMsgToNavDataFilter->Update(); //record a timestamp if the output is new //static double previousTimestamp; //double curTimestamp = m_IGTLMsgToNavDataFilter->GetOutput()->GetIGTTimeStamp(); //if (previousTimestamp != curTimestamp) static mitk::NavigationData::Pointer previousND = mitk::NavigationData::New(); mitk::NavigationData* curND = m_IGTLMsgToNavDataFilter->GetOutput(); //std::cout << "9: igt timestamp: " << curND->GetIGTTimeStamp() << std::endl; //std::cout << "9: timestamp: " << curND->GetTimeStamp() << std::endl; if ( !mitk::Equal( *(previousND.GetPointer()), *curND ) ) { //previousTimestamp = curTimestamp; previousND->Graft(curND); } } //check if the timer interval changed static int previousValue = 0; int currentValue = this->m_Controls.visualizationUpdateRateSpinBox->value(); if (previousValue != currentValue) { m_Timer.setInterval(currentValue); previousValue = currentValue; } } /** * \brief To initialize the scene to the bounding box of all visible objects */ void OpenIGTLinkExample::ResizeBoundingBox() { // get all nodes mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetAll(); mitk::TimeGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs); if (bounds.IsNull()) { return; } //expand the bounding box in case the instruments are all at one position mitk::Point3D center = bounds->GetCenterInWorld(); mitk::Geometry3D::BoundsArrayType extended_bounds = bounds->GetGeometryForTimeStep(0)->GetBounds(); for (unsigned int i = 0; i < 3; ++i) { if (bounds->GetExtentInWorld(i) < 500) { // extend the bounding box extended_bounds[i * 2] = center[i] - 500 / 2.0; extended_bounds[i * 2 + 1] = center[i] + 500 / 2.0; } } //set the extended bounds bounds->GetGeometryForTimeStep(0)->SetBounds(extended_bounds); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeViews(bounds); }