diff --git a/Modules/OpenIGTLink/files.cmake b/Modules/OpenIGTLink/files.cmake index 568f62a470..2028300562 100644 --- a/Modules/OpenIGTLink/files.cmake +++ b/Modules/OpenIGTLink/files.cmake @@ -1,4 +1,7 @@ set(CPP_FILES mitkIGTLClient.cpp mitkIGTLDevice.cpp + mitkIGTLMessageSource.cpp + mitkIGTLDeviceSource.cpp + mitkIGTLMessage.cpp ) diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.cpp b/Modules/OpenIGTLink/mitkIGTLDevice.cpp index 8a1b278356..e3b537073c 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.cpp +++ b/Modules/OpenIGTLink/mitkIGTLDevice.cpp @@ -1,424 +1,429 @@ /*=================================================================== 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 "mitkIGTTimeStamp.h" #include #include #include #include typedef itk::MutexLockHolder MutexLockHolder; mitk::IGTLDevice::IGTLDevice() : // m_Data(mitk::DeviceDataUnspecified), m_State(mitk::IGTLDevice::Setup), m_StopCommunication(false), m_PortNumber(-1), m_MultiThreader(NULL), m_ThreadID(0) { m_StopCommunicationMutex = itk::FastMutexLock::New(); m_StateMutex = itk::FastMutexLock::New(); m_SocketMutex = itk::FastMutexLock::New(); m_CommunicationFinishedMutex = itk::FastMutexLock::New(); // execution rights are owned by the application thread at the beginning m_CommunicationFinishedMutex->Lock(); m_MultiThreader = itk::MultiThreader::New(); // m_Data = mitk::DeviceDataUnspecified; } mitk::IGTLDevice::~IGTLDevice() { /* stop communication and disconnect from igtl device */ if (GetState() == Running) { this->StopCommunication(); } if (GetState() == Ready) { this->CloseConnection(); } /* cleanup tracking thread */ if ((m_ThreadID != 0) && (m_MultiThreader.IsNotNull())) { m_MultiThreader->TerminateThread(m_ThreadID); } m_MultiThreader = NULL; } 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); MutexLockHolder lock(*m_StateMutex); // lock and unlock the mutex if (m_State == state) { return; } m_State = state; this->Modified(); } //mitk::IGTLDeviceData mitk::IGTLDevice::GetData() const{ // return m_Data; //} //void mitk::IGTLDevice::SetData(mitk::IGTLDeviceData data){ // m_Data = data; //} bool mitk::IGTLDevice::SendMessage(igtl::MessageBase::Pointer msg) { // if (input == NULL) // return SERIALSENDERROR; // std::string message; // if (addCRC == true) // message = *input + CalcCRC(input) + std::string(1, CR); // else // message = *input + std::string(1, CR); // //unsigned int messageLength = message.length() + 1; // +1 for CR // // Clear send buffer // this->ClearSendBuffer(); // // Send the date to the device // MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex // long returnvalue = m_SerialCommunication->Send(message); // if (returnvalue == 0) // return SERIALSENDERROR; // else // return NDIOKAY; return true; } //mitk::NDIErrorCode mitk::IGTLDevice::Receive(std::string* answer, unsigned int numberOfBytes) //{ // if (answer == NULL) // return SERIALRECEIVEERROR; // MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex // long returnvalue = m_SerialCommunication->Receive(*answer, numberOfBytes); // never read more bytes than the device has send, the function will block until enough bytes are send... // if (returnvalue == 0) // return SERIALRECEIVEERROR; // else // return NDIOKAY; //} bool mitk::IGTLDevice::TestConnection() { // if (this->GetState() != Setup) // { // return mitk::TrackingSystemNotSpecified; // } // m_SerialCommunication = mitk::SerialCommunication::New(); // //m_DeviceProtocol = mitk::NDIProtocol::New(); // //m_DeviceProtocol->SetTrackingDevice(this); // //m_DeviceProtocol->UseCRCOn(); // /* init local com port to standard com settings for a NDI tracking device: // 9600 baud, 8 data bits, no parity, 1 stop bit, no hardware handshake // */ // if (m_DeviceName.empty()) // m_SerialCommunication->SetPortNumber(m_PortNumber); // else // m_SerialCommunication->SetDeviceName(m_DeviceName); // m_SerialCommunication->SetBaudRate(mitk::SerialCommunication::BaudRate9600); // m_SerialCommunication->SetDataBits(mitk::SerialCommunication::DataBits8); // m_SerialCommunication->SetParity(mitk::SerialCommunication::None); // m_SerialCommunication->SetStopBits(mitk::SerialCommunication::StopBits1); // m_SerialCommunication->SetSendTimeout(5000); // m_SerialCommunication->SetReceiveTimeout(5000); // if (m_SerialCommunication->OpenConnection() == 0) // error // { // m_SerialCommunication = NULL; // return mitk::TrackingSystemNotSpecified; // } // /* Reset Tracking device by sending a serial break for 500ms */ // m_SerialCommunication->SendBreak(400); // /* Read answer from tracking device (RESETBE6F) */ // static const std::string reset("RESETBE6F\r"); // std::string answer = ""; // this->Receive(&answer, reset.length()); // read answer (should be RESETBE6F) // this->ClearReceiveBuffer(); // flush the receive buffer of all remaining data (carriage return, strings other than reset // if (reset.compare(answer) != 0) // check for RESETBE6F // { // m_SerialCommunication->CloseConnection(); // m_SerialCommunication = NULL; // mitkThrowException(mitk::IGTHardwareException) << "Hardware Reset of tracking device did not work"; // } // /* Now the tracking device is reset, start initialization */ // NDIErrorCode returnvalue; // /* initialize the tracking device */ // //returnvalue = m_DeviceProtocol->INIT(); // //if (returnvalue != NDIOKAY) // //{ // // this->SetErrorMessage("Could not initialize the tracking device"); // // return mitk::TrackingSystemNotSpecified; // //} // mitk::TrackingDeviceType deviceType; // returnvalue = m_DeviceProtocol->VER(deviceType); // if ((returnvalue != NDIOKAY) || (deviceType == mitk::TrackingSystemNotSpecified)) // { // m_SerialCommunication = NULL; // return mitk::TrackingSystemNotSpecified; // } // m_SerialCommunication = NULL; // return deviceType; return true; } ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartCommunication(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData; if (igtlDevice != NULL) { igtlDevice->RunCommunication(); } igtlDevice->m_ThreadID = 0; // erase thread id because thread will end. return ITK_THREAD_RETURN_VALUE; } void mitk::IGTLDevice::RunCommunication() { if (this->GetState() != Running) return; // keep lock until end of scope MutexLockHolder communicationFinishedLockHolder(*m_CommunicationFinishedMutex); // 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)) { //POLLLING // 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 this->m_SocketMutex->Lock(); int r = m_Socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(),1); this->m_SocketMutex->Unlock(); if(r == 0) { //this->StopCommunication(); // an error was received, therefor the communication must be stopped m_StopCommunicationMutex->Lock(); m_StopCommunication = true; m_StopCommunicationMutex->Unlock(); } else if (r == headerMsg->GetPackSize()) { // Deserialize the header and check the CRC 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); //check for invalid timestamps // if(sec != 0) { std::cerr << "Time stamp: " << sec << "." << nanosec << std::endl; std::cerr << "Dev type and name: " << headerMsg->GetDeviceType() << " " << headerMsg->GetDeviceName() << std::endl; headerMsg->Print(std::cout); if (strcmp(headerMsg->GetDeviceType(), "TRANSFORM") == 0) { //ReceiveImage(socket, headerMsg); // Create a message buffer to receive transform data igtl::TransformMessage::Pointer transMsg; transMsg = igtl::TransformMessage::New(); transMsg->SetMessageHeader(headerMsg); transMsg->AllocatePack(); // Receive transform data from the socket m_Socket->Receive(transMsg->GetPackBodyPointer(), transMsg->GetPackBodySize()); // Deserialize the transform data // If you want to skip CRC check, call Unpack() without argument. int c = transMsg->Unpack(1); if (c & igtl::MessageHeader::UNPACK_BODY) // if CRC check is OK { // Retrive the transform data igtl::Matrix4x4 matrix; transMsg->GetMatrix(matrix); igtl::PrintMatrix(matrix); std::cerr << std::endl; } } } } } else { //Message size information and actual data size don't match. } // m_MarkerPointsMutex->Lock(); // lock points data structure // returnvalue = this->m_DeviceProtocol->POS3D(&m_MarkerPoints); // update points data structure with new position data from tracking device // m_MarkerPointsMutex->Unlock(); // if (!((returnvalue == NDIOKAY) || (returnvalue == NDICRCERROR) || (returnvalue == NDICRCDOESNOTMATCH))) // right now, do not stop on crc errors // { // std::cout << "Error in POS3D: could not read data. Possibly no markers present." << std::endl; // } /* Update the local copy of m_StopCommunication */ this->m_StopCommunicationMutex->Lock(); localStopCommunication = m_StopCommunication; this->m_StopCommunicationMutex->Unlock(); itksys::SystemTools::Delay(1); } // StopCommunication was called, thus the mode should be changed back to Ready now // that the tracking loop has ended. this->SetState(Ready); 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; this->SetState(Running); // go to mode Running // 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_CommunicationFinishedMutex->Unlock(); // start a new thread that executes the communication m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartCommunication, 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_CommunicationFinishedMutex->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(); // //init before closing to force the field generator from aurora to switch itself off // m_DeviceProtocol->INIT(); // /* close the serial connection */ // m_SerialCommunication->CloseConnection(); // /* invalidate all tools */ // this->InvalidateAll(); /* return to setup mode */ this->SetState(Setup); // m_SerialCommunication = NULL; return true; } + +igtl::MessageBase* mitk::IGTLDevice::GetLatestMessage() +{ + return igtl::MessageBase::New(); +} diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.h b/Modules/OpenIGTLink/mitkIGTLDevice.h index f47871a249..799b68811a 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.h +++ b/Modules/OpenIGTLink/mitkIGTLDevice.h @@ -1,177 +1,182 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKIGTLDEVICE_H #define MITKIGTLDEVICE_H #include #include "itkObject.h" #include "mitkCommon.h" #include "itkFastMutexLock.h" #include //#include #include "igtlSocket.h" #include "igtlMessageBase.h" namespace mitk { /**Documentation * \brief Interface for all Open IGT Link Devices * * Defines the methods that are common for all devices using Open IGT Link. * */ class MITK_OPENIGTLINK_EXPORT IGTLDevice : public itk::Object { public: mitkClassMacro(IGTLDevice, itk::Object) /** * Type for state variable. The IGTLDevice is always in one of these states */ enum IGTLDeviceState {Setup, Ready, Running}; /** * \brief Opens a connection to the device * * This may only be called if there is currently no connection to the * device. If OpenConnection() is successful, the object will change from * Setup state to Ready state */ virtual bool OpenConnection() = 0; /** * \brief Closes the connection to the device * * This may only be called if there is currently a connection to the * device, but device is not running (e.g. object is in Ready state) */ virtual bool CloseConnection(); /** * \brief Stops the communication between the two devices * * This may only be called if there the device is in Running state */ virtual bool StopCommunication(); bool StartCommunication(); void RunCommunication(); /** * \brief Sends a message via the open IGT Link. * * This may only be called after the connection to the device has been * established with a call to OpenConnection() (E.g. object is in Ready * mode). This will change the object state from Ready to Running */ bool SendMessage(igtl::MessageBase::Pointer msg); /** * \brief return current object state (Setup, Ready or Running) */ IGTLDeviceState GetState() const; + /** + * \brief Returns the latest received message + */ + igtl::MessageBase* GetLatestMessage(); + /** * \brief return device data */ // igtl::MessageBase::Pointer GetData() const; /** * \brief set device data */ // void SetData(IGTLDeviceData data); /** * \brief Sets the port number of the device */ itkSetMacro(PortNumber,int); /** * \brief Returns the port number of the device */ itkGetMacro(PortNumber,int); /** * \brief Sets the ip/hostname of the device */ itkSetMacro(Hostname,std::string); /** * \brief Returns the ip/hostname of the device */ itkGetMacro(Hostname,std::string); /** * \brief static start method for the tracking thread. */ static ITK_THREAD_RETURN_TYPE ThreadStartCommunication(void* data); /** * \brief TestConnection() tries to connect to a IGTL server on the current * ip and port * * \todo check this description * * TestConnection() tries to connect to a IGTL server on the current * ip and port and returns which device it has found. * \return It returns the type of the device that answers. Throws an exception * if no device is available on that ip/port. * @throw mitk::IGTHardwareException Throws an exception if there are errors * while connecting to the device. */ virtual bool TestConnection(); protected: /** * \brief change object state */ void SetState(IGTLDeviceState state); IGTLDevice(); virtual ~IGTLDevice(); // IGTLDeviceData m_Data; ///< current device Data IGTLDeviceState m_State; ///< current object state (Setup, Ready or Running) bool m_StopCommunication; ///< signal stop to thread /** mutex to control access to m_StopThread */ itk::FastMutexLock::Pointer m_StopCommunicationMutex; /** mutex to manage control flow of StopTracking() */ itk::FastMutexLock::Pointer m_CommunicationFinishedMutex; /** mutex to control access to m_State */ itk::FastMutexLock::Pointer m_StateMutex; /** mutex to control access to m_Socket */ itk::FastMutexLock::Pointer m_SocketMutex; /** the hostname or ip of the device */ std::string m_Hostname; /** the port number of the device */ int m_PortNumber; /** the socket used to communicate with other IGTL devices */ igtl::Socket::Pointer m_Socket; private: /** creates worker thread that continuously polls interface for new messages */ itk::MultiThreader::Pointer m_MultiThreader; int m_ThreadID; ///< ID of polling thread }; } // namespace mitk #endif /* MITKIGTLDEVICE_H */ diff --git a/Modules/OpenIGTLink/mitkIGTLDeviceSource.cpp b/Modules/OpenIGTLink/mitkIGTLDeviceSource.cpp new file mode 100644 index 0000000000..7cb1ade9ad --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLDeviceSource.cpp @@ -0,0 +1,172 @@ +/*=================================================================== + +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 "mitkIGTLDeviceSource.h" + +#include "mitkIGTLDevice.h" +#include "mitkIGTLMessage.h" + +//#include "mitkIGTTimeStamp.h" +//#include "mitkIGTException.h" + +mitk::IGTLDeviceSource::IGTLDeviceSource() + : mitk::IGTLMessageSource(), m_IGTLDevice(NULL) +{ +} + +mitk::IGTLDeviceSource::~IGTLDeviceSource() +{ + if (m_IGTLDevice.IsNotNull()) + { + if (m_IGTLDevice->GetState() == mitk::IGTLDevice::Running) + { + this->StopCommunication(); + } + if (m_IGTLDevice->GetState() == mitk::IGTLDevice::Ready) + { + this->Disconnect(); + } + m_IGTLDevice = NULL; + } +} + +void mitk::IGTLDeviceSource::GenerateData() +{ + if (m_IGTLDevice.IsNull()) + return; + + /* update output with message from the device */ + IGTLMessage* msgOut = this->GetOutput(); + assert(msgOut); + igtl::MessageBase* msgIn = m_IGTLDevice->GetLatestMessage(); + assert(msgIn); + + msgOut->SetMessage(msgIn); + msgOut->SetName(msgIn->GetDeviceName()); +} + +void mitk::IGTLDeviceSource::SetIGTLDevice( mitk::IGTLDevice* igtlDevice ) +{ + MITK_DEBUG << "Setting IGTLDevice to " << igtlDevice; + if (this->m_IGTLDevice.GetPointer() != igtlDevice) + { + this->m_IGTLDevice = igtlDevice; + this->CreateOutputs(); + std::stringstream name; // create a human readable name for the source + name << "OpenIGTLink Message Source"; + this->SetName(name.str()); + } +} + +void mitk::IGTLDeviceSource::CreateOutputs() +{ + //if outputs are set then delete them + if (this->GetNumberOfOutputs() > 0) + { + for (int numOP = this->GetNumberOfOutputs() - 1; numOP >= 0; numOP--) + this->RemoveOutput(numOP); + this->Modified(); + } + + //fill the outputs if a valid OpenIGTLink device is set + if (m_IGTLDevice.IsNull()) + return; + + this->SetNumberOfIndexedOutputs(1); + if (this->GetOutput(0) == NULL) + { + DataObjectPointer newOutput = this->MakeOutput(0); + this->SetNthOutput(0, newOutput); + this->Modified(); + } +} + +void mitk::IGTLDeviceSource::Connect() +{ + if (m_IGTLDevice.IsNull()) + { + throw std::invalid_argument("mitk::IGTLDeviceSource: " + "No OpenIGTLink device set"); + } + if (this->IsConnected()) + { + return; + } + try + { + m_IGTLDevice->OpenConnection(); + } + catch (mitk::Exception &e) + { + throw std::runtime_error(std::string("mitk::IGTLDeviceSource: Could not open" + "connection to OpenIGTLink device. Error: ") + e.GetDescription()); + } +} + +void mitk::IGTLDeviceSource::StartCommunication() +{ + if (m_IGTLDevice.IsNull()) + throw std::invalid_argument("mitk::IGTLDeviceSource: " + "No OpenIGTLink device set"); + if (m_IGTLDevice->GetState() == mitk::IGTLDevice::Running) + return; + if (m_IGTLDevice->StartCommunication() == false) + throw std::runtime_error("mitk::IGTLDeviceSource: " + "Could not start communication"); +} + +void mitk::IGTLDeviceSource::Disconnect() +{ + if (m_IGTLDevice.IsNull()) + throw std::invalid_argument("mitk::IGTLDeviceSource: " + "No OpenIGTLink device set"); + if (m_IGTLDevice->CloseConnection() == false) + throw std::runtime_error("mitk::IGTLDeviceSource: Could not close connection" + " to OpenIGTLink device"); +} + +void mitk::IGTLDeviceSource::StopCommunication() +{ + if (m_IGTLDevice.IsNull()) + throw std::invalid_argument("mitk::IGTLDeviceSource: " + "No OpenIGTLink device set"); + if (m_IGTLDevice->StopCommunication() == false) + throw std::runtime_error("mitk::IGTLDeviceSource: " + "Could not stop communicating"); +} + +void mitk::IGTLDeviceSource::UpdateOutputInformation() +{ + this->Modified(); // make sure that we need to be updated + Superclass::UpdateOutputInformation(); +} + +bool mitk::IGTLDeviceSource::IsConnected() +{ + if (m_IGTLDevice.IsNull()) + return false; + + return (m_IGTLDevice->GetState() == mitk::IGTLDevice::Ready) || + (m_IGTLDevice->GetState() == mitk::IGTLDevice::Running); +} + +bool mitk::IGTLDeviceSource::IsCommunicating() +{ + if (m_IGTLDevice.IsNull()) + return false; + + return m_IGTLDevice->GetState() == mitk::IGTLDevice::Running; +} diff --git a/Modules/OpenIGTLink/mitkIGTLDeviceSource.h b/Modules/OpenIGTLink/mitkIGTLDeviceSource.h new file mode 100644 index 0000000000..10a40eaa63 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLDeviceSource.h @@ -0,0 +1,129 @@ +/*=================================================================== + +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 IGTLDEVICESOURCE_H_HEADER_INCLUDED_ +#define IGTLDEVICESOURCE_H_HEADER_INCLUDED_ + +#include "mitkIGTLDevice.h" +#include "mitkIGTLMessageSource.h" + +namespace mitk { + /**Documentation + * \brief Connects a mitk::IGTLDevice to a + * MITK-OpenIGTLink Message-Filterpipeline + * + * This class is the source of most OpenIGTLink pipelines. It encapsulates a + * mitk::IGTLDevice and provides the information/messages of the connected + * OpenIGTLink devices as igtl::MessageBase objects. Note, that there is just + * one single output. + * + */ + class MITK_OPENIGTLINK_EXPORT IGTLDeviceSource : public IGTLMessageSource + { + public: + mitkClassMacro(IGTLDeviceSource, IGTLMessageSource); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** + * \brief sets the OpenIGTLink device that will be used as a data source + */ + virtual void SetIGTLDevice(mitk::IGTLDevice* td); + + /** + * \brief returns the OpenIGTLink device that is used by this filter + */ + itkGetConstObjectMacro(IGTLDevice, mitk::IGTLDevice); + + /** + * \brief Establishes a connection to the OpenIGTLink device. If there is + * already a connection the method does nothing. + * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink + * device was set with SetIGTLDevice(). Will throw a std::runtime_error if + * the OpenIGTLink device returns an error. + */ + void Connect(); + + /** + * \brief Closes the connection to the OpenIGTLink device + * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink + * device was set with SetIGTLDevice(). Will throw a std::runtime_error if + * the OpenIGTLink device returns an error. + */ + void Disconnect(); + + /** + * \brief starts the communication of the device. + * This needs to be called before Update() or GetOutput()->Update(). If the + * device is already communicating the method does nothing. + * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink + * device was set with SetIGTLDevice(). Will throw a std::runtime_error if + * the OpenIGTLink device returns an error. + */ + void StartCommunication(); + + /** + * \brief stops the communication of the device. + * \warning. Will throw a std::invalid_argument exception if no OpenIGTLink + * device was set with SetIGTLDevice(). Will throw a std::runtime_error if + * the OpenIGTLink device returns an error. + */ + void StopCommunication(); + + /** + * \brief returns true if a connection to the OpenIGTLink device is established + * + */ + virtual bool IsConnected(); + + /** + * \brief returns true if communication is in progress + * + */ + virtual bool IsCommunicating(); + + /** + * \brief Used for pipeline update + */ + virtual void UpdateOutputInformation(); + + protected: + IGTLDeviceSource(); + virtual ~IGTLDeviceSource(); + + /** + * \brief filter execute method + * + * queries the OpenIGTLink device for new messages and updates its output + * igtl::MessageBase objects with it. + * \warning Will raise a std::out_of_range exception, if tools were added to + * the OpenIGTLink device after it was set as input for this filter + */ + virtual void GenerateData(); + + /** + * \brief Create the necessary outputs for the m_IGTLDevice + * + * This Method is called internally whenever outputs need to be reset. Old + * Outputs are deleted when called. + **/ + void CreateOutputs(); + + /** the OpenIGTLink device that is used as a source for this filter object*/ + mitk::IGTLDevice::Pointer m_IGTLDevice; + }; +} // namespace mitk +#endif /* MITKIGTLDeviceSource_H_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessage.cpp b/Modules/OpenIGTLink/mitkIGTLMessage.cpp new file mode 100644 index 0000000000..3104b2871f --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessage.cpp @@ -0,0 +1,158 @@ +/*=================================================================== + +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" + +mitk::IGTLMessage::IGTLMessage() : itk::DataObject(), +m_DataValid(false), m_IGTTimeStamp(0.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) +{ + this->SetMessage(message); + this->SetName(name); +} + +void mitk::IGTLMessage::Graft( const DataObject *data ) +{ + // Attempt to cast data to an IGTLMessage + const Self* nd; + try + { + nd = dynamic_cast( data ); + } + catch( ... ) + { + itkExceptionMacro( << "mitk::IGTLMessage::Graft cannot cast " + << typeid(data).name() << " to " + << typeid(const Self *).name() ); + return; + } + if (!nd) + { + // 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(nd->GetMessage()); + this->SetDataValid(nd->IsDataValid()); + this->SetIGTTimeStamp(nd->GetIGTTimeStamp()); + this->SetName(nd->GetName()); +} + +void mitk::IGTLMessage::SetMessage(igtl::MessageBase* msg) +{ + m_Message->Copy(msg); + unsigned int ts = 0; + unsigned int frac = 0; + m_Message->GetTimeStamp(&ts, &frac); + this->SetIGTTimeStamp((double)ts); + 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); +} + + +void mitk::IGTLMessage::CopyInformation( const DataObject* data ) +{ + this->Superclass::CopyInformation( data ); + + const Self * nd = NULL; + 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; +} diff --git a/Modules/OpenIGTLink/mitkIGTLMessage.h b/Modules/OpenIGTLink/mitkIGTLMessage.h new file mode 100644 index 0000000000..23d1d24e28 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessage.h @@ -0,0 +1,191 @@ +/*=================================================================== + +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 MITK_OPENIGTLINK_EXPORT IGTLMessage : public itk::DataObject + { + public: + mitkClassMacro(IGTLMessage, itk::DataObject); + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + mitkNewMacro2Param(Self, igtl::MessageBase::Pointer,std::string); + + /** + * \brief type that holds the time at which the data was recorded + */ + typedef double TimeStampType; + + /** + * \brief Sets the OpenIGTLink message + */ + void SetMessage(igtl::MessageBase* 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); + + /** + * \brief copy meta data of a IGTLMessage object + * + * copies all meta data from IGTLMessage data to this object + */ + virtual void CopyInformation(const DataObject* data); + + /** + * \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; + + /** 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); + + 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 = ""); + + 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 + */ + MITK_OPENIGTLINK_EXPORT bool Equal( const mitk::IGTLMessage& leftHandSide, + const mitk::IGTLMessage& rightHandSide, + ScalarType eps = mitk::eps, + bool verbose = false ); + +} // namespace mitk +#endif /* MITKIGTLMESSAGEH_HEADER_INCLUDED_ */ diff --git a/Modules/OpenIGTLink/mitkIGTLMessageSource.cpp b/Modules/OpenIGTLink/mitkIGTLMessageSource.cpp new file mode 100644 index 0000000000..5292644cc5 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageSource.cpp @@ -0,0 +1,173 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkIGTLMessageSource.h" +#include "mitkUIDGenerator.h" + +//Microservices +#include +#include +#include +#include + +const std::string mitk::IGTLMessageSource::US_INTERFACE_NAME = + "org.mitk.services.IGTLMessageSource"; +const std::string mitk::IGTLMessageSource::US_PROPKEY_DEVICENAME = + US_INTERFACE_NAME + ".devicename"; +const std::string mitk::IGTLMessageSource::US_PROPKEY_ID = + US_INTERFACE_NAME + ".id"; +const std::string mitk::IGTLMessageSource::US_PROPKEY_ISACTIVE = + US_INTERFACE_NAME + ".isActive"; + +mitk::IGTLMessageSource::IGTLMessageSource() + : itk::ProcessObject(), m_Name("IGTLMessageSource (no defined type)") +{ +} + +mitk::IGTLMessageSource::~IGTLMessageSource() +{ +} + +mitk::IGTLMessage* mitk::IGTLMessageSource::GetOutput() +{ + if (this->GetNumberOfIndexedOutputs() < 1) + return NULL; + + return static_cast(this->ProcessObject::GetPrimaryOutput()); +} + +mitk::IGTLMessage* mitk::IGTLMessageSource::GetOutput( + DataObjectPointerArraySizeType idx) +{ + IGTLMessage* out = + dynamic_cast( this->ProcessObject::GetOutput(idx) ); + if ( out == NULL && this->ProcessObject::GetOutput(idx) != NULL ) + { + itkWarningMacro (<< "Unable to convert output number " << idx << " to type " + << typeid( IGTLMessage ).name () ); + } + return out; +} + +mitk::IGTLMessage* mitk::IGTLMessageSource::GetOutput( + const std::string& messageName) +{ + DataObjectPointerArray outputs = this->GetOutputs(); + for (DataObjectPointerArray::iterator it = outputs.begin(); + it != outputs.end(); + ++it) + { + if (messageName == + (static_cast(it->GetPointer()))->GetName()) + { + return static_cast(it->GetPointer()); + } + } + return NULL; +} + +itk::ProcessObject::DataObjectPointerArraySizeType +mitk::IGTLMessageSource::GetOutputIndex( std::string messageName ) +{ + DataObjectPointerArray outputs = this->GetOutputs(); + for (DataObjectPointerArray::size_type i = 0; i < outputs.size(); ++i) + { + if (messageName == + (static_cast(outputs.at(i).GetPointer()))->GetName()) + { + return i; + } + } + throw std::invalid_argument("output name does not exist"); +} + +void mitk::IGTLMessageSource::RegisterAsMicroservice() +{ + // Get Context + us::ModuleContext* context = us::GetModuleContext(); + + // Define ServiceProps + us::ServiceProperties props; + mitk::UIDGenerator uidGen = + mitk::UIDGenerator ("org.mitk.services.IGTLMessageSource.id_", 16); + props[ US_PROPKEY_ID ] = uidGen.GetUID(); + props[ US_PROPKEY_DEVICENAME ] = m_Name; + m_ServiceRegistration = context->RegisterService(this, props); +} + +void mitk::IGTLMessageSource::UnRegisterMicroservice() +{ + if (m_ServiceRegistration != NULL) m_ServiceRegistration.Unregister(); + m_ServiceRegistration = 0; +} + +std::string mitk::IGTLMessageSource::GetMicroserviceID() +{ + us::Any referenceProperty = + this->m_ServiceRegistration.GetReference().GetProperty(US_PROPKEY_ID); + return referenceProperty.ToString(); +} + +void mitk::IGTLMessageSource::GraftOutput(itk::DataObject *graft) +{ + this->GraftNthOutput(0, graft); +} + +void mitk::IGTLMessageSource::GraftNthOutput(unsigned int idx, + itk::DataObject *graft) +{ + if ( idx >= this->GetNumberOfIndexedOutputs() ) + { + itkExceptionMacro(<<"Requested to graft output " << idx << " but this filter" + "only has " << this->GetNumberOfIndexedOutputs() << " Outputs."); + } + + if ( !graft ) + { + itkExceptionMacro(<<"Requested to graft output with a NULL pointer object" ); + } + + itk::DataObject* output = this->GetOutput(idx); + if ( !output ) + { + itkExceptionMacro(<<"Requested to graft output that is a NULL pointer" ); + } + // Call Graft on IGTLMessage to copy member data + output->Graft( graft ); +} + +itk::DataObject::Pointer mitk::IGTLMessageSource::MakeOutput ( DataObjectPointerArraySizeType /*idx*/ ) +{ + return IGTLMessage::New().GetPointer(); +} + +itk::DataObject::Pointer mitk::IGTLMessageSource::MakeOutput( const DataObjectIdentifierType & name ) +{ + itkDebugMacro("MakeOutput(" << name << ")"); + if( this->IsIndexedOutputName(name) ) + { + return this->MakeOutput( this->MakeIndexFromOutputName(name) ); + } + return static_cast(IGTLMessage::New().GetPointer()); +} + +mitk::PropertyList::ConstPointer mitk::IGTLMessageSource::GetParameters() const +{ + mitk::PropertyList::Pointer p = mitk::PropertyList::New(); + // add properties to p like this: + //p->SetProperty("MyFilter_MyParameter", mitk::PropertyDataType::New(m_MyParameter)); + return mitk::PropertyList::ConstPointer(p); +} diff --git a/Modules/OpenIGTLink/mitkIGTLMessageSource.h b/Modules/OpenIGTLink/mitkIGTLMessageSource.h new file mode 100644 index 0000000000..95c71f7928 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLMessageSource.h @@ -0,0 +1,179 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef MITKIGTLMESSAGESOURCE_H_HEADER_INCLUDED_ +#define MITKIGTLMESSAGESOURCE_H_HEADER_INCLUDED_ + +#include +#include "mitkPropertyList.h" +#include "MitkOpenIGTLinkExports.h" +#include "mitkIGTLMessage.h" + +// Microservices +#include +#include + +namespace mitk { + + /**Documentation + * \brief OpenIGTLink message source + * + * Base class for all OpenIGTLink filters that produce OpenIGTLink message + * objects as output. This class defines the output-interface for + * OpenIGTLinkMessageFilters. + * \warning: if Update() is called on any output object, all IGTLMessage filters + * will generate new output data for all outputs, not just the one on which + * Update() was called. + * + */ + class MITK_OPENIGTLINK_EXPORT IGTLMessageSource : public itk::ProcessObject + { + public: + mitkClassMacro(IGTLMessageSource, itk::ProcessObject); + + /** @return Returns a human readable name of this source. There will be a + * default name, or you can set the name with the method SetName() if you + * want to change it. + */ + itkGetMacro(Name,std::string); + + /** @brief Sets the human readable name of this source. There is also a + * default name, but you can use this method if you need to define it on your + * own. + */ + itkSetMacro(Name,std::string); + + /** + *\brief return the output (output with id 0) of the filter + */ + IGTLMessage* GetOutput(void); + + /** + *\brief return the output with id idx of the filter + */ + IGTLMessage* GetOutput(DataObjectPointerArraySizeType idx); + + /** + *\brief return the output with name messageName of the filter + */ + IGTLMessage* GetOutput(const std::string& messageName); + + /** + *\brief return the index of the output with name messageName, -1 if no output + * with that name was found + * + * \warning if a subclass has outputs that have different data type than + * igtl::MessageBase, they have to overwrite this method + */ + DataObjectPointerArraySizeType GetOutputIndex(std::string messageName); + + /** + *\brief Registers this object as a Microservice, making it available to every + * module and/or plugin. To unregister, call UnregisterMicroservice(). + */ + virtual void RegisterAsMicroservice(); + + /** + *\brief Registers this object as a Microservice, making it available to every + * module and/or plugin. + */ + virtual void UnRegisterMicroservice(); + + /** + *\brief Returns the id that this device is registered with. The id will only + * be valid, if the IGTLMessageSource has been registered using + * RegisterAsMicroservice(). + */ + std::string GetMicroserviceID(); + + /** + *\brief These Constants are used in conjunction with Microservices + */ + static const std::string US_INTERFACE_NAME; + static const std::string US_PROPKEY_DEVICENAME; + static const std::string US_PROPKEY_ID; + static const std::string US_PROPKEY_ISACTIVE; //NOT IMPLEMENTED YET! + + /** + *\brief Graft the specified DataObject onto this ProcessObject's output. + * + * See itk::ImageSource::GraftNthOutput for details + */ + virtual void GraftNthOutput(unsigned int idx, itk::DataObject *graft); + + /** + * \brief Graft the specified DataObject onto this ProcessObject's output. + * + * See itk::ImageSource::Graft Output for details + */ + virtual void GraftOutput(itk::DataObject *graft); + + /** + * Allocates a new output object and returns it. Currently the + * index idx is not evaluated. + * @param idx the index of the output for which an object should be created + * @returns the new object + */ + virtual itk::DataObject::Pointer MakeOutput ( DataObjectPointerArraySizeType idx ); + + /** + * This is a default implementation to make sure we have something. + * Once all the subclasses of ProcessObject provide an appopriate + * MakeOutput(), then ProcessObject::MakeOutput() can be made pure + * virtual. + */ + virtual itk::DataObject::Pointer MakeOutput(const DataObjectIdentifierType &name); + + /** + * \brief Set all filter parameters as the PropertyList p + * + * This method allows to set all parameters of a filter with one + * method call. For the names of the parameters, take a look at + * the GetParameters method of the filter + * This method has to be overwritten by each MITK-IGT filter. + */ + virtual void SetParameters(const mitk::PropertyList*){}; + + /** + * \brief Get all filter parameters as a PropertyList + * + * This method allows to get all parameters of a filter with one + * method call. The returned PropertyList must be assigned to a + * SmartPointer immediately, or else it will get destroyed. + * Every filter must overwrite this method to create a filter-specific + * PropertyList. Note that property names must be unique over all + * MITK-IGT filters. Therefore each filter should use its name as a prefix + * for each property name. + * Secondly, each filter should list the property names and data types + * in the method documentation. + */ + virtual mitk::PropertyList::ConstPointer GetParameters() const; + + protected: + IGTLMessageSource(); + virtual ~IGTLMessageSource(); + + std::string m_Name; + + + private: + us::ServiceRegistration m_ServiceRegistration; + }; +} // namespace mitk +// This is the microservice declaration. Do not meddle! +MITK_DECLARE_SERVICE_INTERFACE(mitk::IGTLMessageSource, "org.mitk.services.IGTLMessageSource") +#endif /* MITKIGTLMESSAGESOURCE_H_HEADER_INCLUDED_ */