Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkIGTLMessageToNavigationDataFilter.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
18 #include "igtlTrackingDataMessage.h"
19 #include "igtlQuaternionTrackingDataMessage.h"
20 #include "igtlTransformMessage.h"
21 #include "mitkQuaternion.h"
22 #include <vnl/vnl_det.h>
23 
26 {
28  this->SetNumberOfRequiredOutputs(1);
29  this->SetNthOutput(0, output.GetPointer());
30 }
31 
33 {
34 }
35 
37 {
38  this->SetInput(0, msg);
39 }
40 
42 {
43  if (msg == NULL) // if an input is set to NULL, remove it
44  {
45  this->RemoveInput(idx);
46  }
47  else
48  {
49  // ProcessObject is not const-correct so a const_cast is required here
50  this->ProcessObject::SetNthInput(idx, const_cast<IGTLMessage*>(msg));
51  }
52  this->CreateOutputsForAllInputs();
53 }
54 
55 const mitk::IGTLMessage*
57 {
58  if (this->GetNumberOfInputs() < 1)
59  return NULL;
60 
61  return static_cast<const IGTLMessage*>(this->ProcessObject::GetInput(0));
62 }
63 
64 const mitk::IGTLMessage*
66 {
67  if (this->GetNumberOfInputs() < 1)
68  return NULL;
69 
70  return static_cast<const IGTLMessage*>(this->ProcessObject::GetInput(idx));
71 }
72 
73 const mitk::IGTLMessage*
75 {
76  const DataObjectPointerArray& inputs = const_cast<Self*>(this)->GetInputs();
77  for (DataObjectPointerArray::const_iterator it = inputs.begin();
78  it != inputs.end(); ++it)
79  {
80  if (std::string(messageName) ==
81  (static_cast<IGTLMessage*>(it->GetPointer()))->GetName())
82  {
83  return static_cast<IGTLMessage*>(it->GetPointer());
84  }
85  }
86  return NULL;
87 }
88 
89 itk::ProcessObject::DataObjectPointerArraySizeType
91 {
92  DataObjectPointerArray outputs = this->GetInputs();
93  for (DataObjectPointerArray::size_type i = 0; i < outputs.size(); ++i)
94  {
95  if (messageName ==
96  (static_cast<IGTLMessage*>(outputs.at(i).GetPointer()))->GetName())
97  {
98  return i;
99  }
100  }
101  throw std::invalid_argument("output name does not exist");
102 }
103 
105  mitk::IGTLMessageSource* UpstreamFilter)
106 {
107  for (DataObjectPointerArraySizeType i = 0;
108  i < UpstreamFilter->GetNumberOfOutputs(); i++)
109  {
110  this->SetInput(i, UpstreamFilter->GetOutput(i));
111  }
112 }
113 
115  unsigned int numOutputs)
116 {
117  this->SetNumberOfIndexedOutputs(numOutputs);
118  this->CreateOutputsForAllInputs();
119 }
120 
122 {
123  // create outputs for all inputs
124  // this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs());
125  bool isModified = false;
126  for (unsigned int idx = 0; idx < this->GetNumberOfIndexedOutputs(); ++idx)
127  {
128  if (this->GetOutput(idx) == NULL)
129  {
131  this->SetNthOutput(idx, newOutput);
132  isModified = true;
133  }
134  }
135 
136  if (isModified)
137  this->Modified();
138 }
139 
141 {
142  const mitk::IGTLMessage* input = this->GetInput(0);
143  assert(input);
144 
145  //cast the input message into the proper type
146  igtl::TransformMessage* tMsg =
147  (igtl::TransformMessage*)(input->GetMessage().GetPointer());
148 
149  //check if cast was successful
150  if (!tMsg)
151  {
152  mitkThrow() << "Cast from igtl::MessageBase to igtl::TransformMessage "
153  << "failed! Please check the message.";
154  }
155 
156  /* update outputs with tracking data from tools */
157  for (unsigned int i = 0; i < this->GetNumberOfOutputs(); ++i)
158  {
159  mitk::NavigationData* output = this->GetOutput(i);
160  assert(output);
161 
162  if (input->IsDataValid() == false)
163  {
164  output->SetDataValid(false);
165  continue;
166  }
167 
168  //get the transformation matrix and convert it into an affinetransformation
169  igtl::Matrix4x4 transformation_;
170  tMsg->GetMatrix(transformation_);
171  mitk::AffineTransform3D::Pointer affineTransformation =
173  mitk::Matrix3D transformation;
175  for (unsigned int r = 0; r < 3; r++)
176  {
177  for (unsigned int c = 0; c < 3; c++)
178  {
179  transformation.GetVnlMatrix().set(r, c, transformation_[r][c]);
180  }
181  offset.SetElement(r, transformation_[r][3]);
182  }
183  //convert the igtl matrix here and set it in the affine transformation
184  affineTransformation->SetMatrix(transformation);
185  affineTransformation->SetOffset(offset);
186 
187  //create a new navigation data here, there is a neat constructor for
188  //affine transformations that sets the orientation, position according to
189  //the affine transformation. The other values are initialized with standard
190  //values
192  mitk::NavigationData::New(affineTransformation, true);
193  //set the time stamp
194  nd->SetIGTTimeStamp(input->GetTimeStamp());
195  //set the name
196  nd->SetName(input->GetName());
197 
198  output->Graft(nd);
199  }
200 }
201 
203 {
204  const mitk::IGTLMessage* input = this->GetInput(0);
205  assert(input);
206 
207  //cast the input message into the proper type
208  igtl::TrackingDataMessage* tdMsg =
209  (igtl::TrackingDataMessage*)(input->GetMessage().GetPointer());
210 
211  //check if cast was successful
212  if (!tdMsg)
213  {
214  mitkThrow() << "Cast from igtl::MessageBase to igtl::TrackingDataMessage "
215  << "failed! Please check the message.";
216  }
217 
218  //get the number of tracking data elements
219  unsigned int numTrackingDataElements =
220  tdMsg->GetNumberOfTrackingDataElements();
221 
222  if (!numTrackingDataElements)
223  {
224  MITK_ERROR("IGTLMsgToNavDataFilter") << "There are no tracking data "
225  "elements in this message";
226  }
227 
228  /* update outputs with tracking data from tools */
229  for (unsigned int i = 0; i < this->GetNumberOfOutputs(); ++i)
230  {
231  mitk::NavigationData* output = this->GetOutput(i);
232  assert(output);
233 
234  //invalidate the output
235  output->SetDataValid(false);
236 
237  //check if the current index, all outputs that have no corresponding input
238  //tracking element stay invalidated, the others are validated according to
239  //the tracking element
240  if (input->IsDataValid() == false || i >= numTrackingDataElements)
241  {
242  continue;
243  }
244  output->SetDataValid(true);
245 
246  //get the tracking data element which holds all the data
248  tdMsg->GetTrackingDataElement(i, td);
249 
250  //get the transformation matrix and convert it into an affinetransformation
251  igtl::Matrix4x4 transformation_;
252  td->GetMatrix(transformation_);
253  mitk::AffineTransform3D::Pointer affineTransformation =
255  mitk::Matrix3D transformation;
257  for (unsigned int r = 0; r < 3; r++)
258  {
259  for (unsigned int c = 0; c < 3; c++)
260  {
261  transformation.GetVnlMatrix().set(r, c, transformation_[r][c]);
262  }
263  offset.SetElement(r, transformation_[r][3]);
264  }
265  //convert the igtl matrix here and set it in the affine transformation
266  affineTransformation->SetMatrix(transformation);
267  affineTransformation->SetOffset(offset);
268 
270 
271  //check the rotation matrix
272  vnl_matrix_fixed<ScalarType, 3, 3> rotationMatrix =
273  affineTransformation->GetMatrix().GetVnlMatrix();
274  vnl_matrix_fixed<ScalarType, 3, 3> rotationMatrixTransposed =
275  rotationMatrix.transpose();
276  // a quadratic matrix is a rotation matrix exactly when determinant is 1
277  // and transposed is inverse
278  if (!Equal(1.0, vnl_det(rotationMatrix), 0.1)
279  || !((rotationMatrix*rotationMatrixTransposed).is_identity(0.1)))
280  {
281  MITK_ERROR("IGTLMsgToNavDataFilter") << "tried to initialize NavData "
282  << "with non-rotation matrix :" << rotationMatrix << " (Does your "
283  "AffineTransform3D object include spacing? This is not "
284  "supported by NavigationData objects!)";
286  }
287  else
288  {
289  //create a new navigation data here, there is a neat constructor for
290  //affine transformations that sets the orientation, position according to
291  //the affine transformation. The other values are initialized with standard
292  //values
293  nd = mitk::NavigationData::New(affineTransformation, true);
294  }
295  //set the time stamp
296  nd->SetIGTTimeStamp(input->GetIGTTimeStamp());
297  //set the name
298  nd->SetName(td->GetName());
299  output->Graft(nd);
300  }
301 }
302 
303 void
305 {
306  const mitk::IGTLMessage* input = this->GetInput(0);
307  assert(input);
308 
309  //cast the input message into the proper type
310  igtl::QuaternionTrackingDataMessage* tdMsg =
311  (igtl::QuaternionTrackingDataMessage*)(input->GetMessage().GetPointer());
312 
313  //check if cast was successful
314  if (!tdMsg)
315  {
316  mitkThrow() << "Cast from igtl::MessageBase to igtl::TrackingDataMessage "
317  << "failed! Please check the message.";
318  }
319 
320  //get the number of tracking data elements
321  unsigned int numTrackingDataElements =
322  tdMsg->GetNumberOfQuaternionTrackingDataElements();
323 
324  if (!numTrackingDataElements)
325  {
326  MITK_ERROR("IGTLMsgToNavDataFilter") << "There are no tracking data "
327  "elements in this message";
328  }
329 
330  /* update outputs with tracking data from tools */
331  for (unsigned int i = 0; i < this->GetNumberOfOutputs(); ++i)
332  {
333  mitk::NavigationData* output = this->GetOutput(i);
334  assert(output);
335 
336  //invalidate the output
337  output->SetDataValid(false);
338 
339  //check if the current index, all outputs that have no corresponding input
340  //tracking element stay invalidated, the others are validated according to
341  //the tracking element
342  if (input->IsDataValid() == false || i >= numTrackingDataElements)
343  {
344  continue;
345  }
346  output->SetDataValid(true);
347 
348  //get the tracking data element which holds all the data
350  tdMsg->GetQuaternionTrackingDataElement(i, td);
351 
352  //get the quaternion and set it
353  float quaternion_[4]; //igtl quat type
354  td->GetQuaternion(quaternion_);
355  mitk::Quaternion quaternion;
356  quaternion.put(0, quaternion_[0]);
357  quaternion.put(1, quaternion_[1]);
358  quaternion.put(2, quaternion_[2]);
359  quaternion.put(3, quaternion_[3]);
360  output->SetOrientation(quaternion);
361  output->SetHasOrientation(true);
362 
363  //get the position and set it
364  float position_[3]; //igtl position type
365  td->GetPosition(position_);
366  mitk::NavigationData::PositionType position; //mitk position type
367  position.SetElement(0, position_[0]);
368  position.SetElement(1, position_[1]);
369  position.SetElement(2, position_[2]);
370  output->SetPosition(position);
371  output->SetHasPosition(true);
372  //set the time stamp
373  output->SetIGTTimeStamp(input->GetTimeStamp());
374  //set the name
375  output->SetName(td->GetName());
376 
377  //there is no explicit covarience matrix
379  }
380 }
381 
383 {
384  //get the IGTLMessage from the previous filter
385  const mitk::IGTLMessage* input = this->GetInput(0);
386  assert(input);
387 
388  //check if the message is valid, if it is not valid we do not generate new
389  //outputs
390  if (!input->IsDataValid())
391  {
392  MITK_DEBUG("IGTLMessageToNavigationDataFilter") << "Input data is invalid.";
393  return;
394  }
395 
396  //get the message type
397  const char* msgType = input->GetIGTLMessageType();
398 
399  //check if the IGTL message has the proper type
400  if (strcmp(msgType, "TRANSFORM") == 0)
401  {
402  this->GenerateTransformData();
403  }
404  else if (strcmp(msgType, "TDATA") == 0)
405  {
406  this->GenerateTrackingDataData();
407  }
408  else if (strcmp(msgType, "QTDATA") == 0)
409  {
410  this->GenerateQuaternionTrackingDataData();
411  }
412  else
413  {
414  //the message has another type
415  //ignore
416  MITK_INFO("IGTLMessageToNavigationDataFilter") << "The input has a unknown "
417  << "message type: "
418  << msgType;
419  }
420 }
421 
423 {
424  // Superclass::GenerateOutputInformation();
425 
426  // mitk::NavigationData* output = this->GetOutput(0);
427  // assert(output);
428  // const mitk::IGTLMessage* input = this->GetInput(0);
429  // assert(input);
430 
431  itkDebugMacro(<< "GenerateOutputInformation()");
432 
433  // output->Initialize(input->GetPixelType(), input->GetDimension(), input->GetDimensions());
434 
435  // // initialize geometry
436  // output->SetPropertyList(input->GetPropertyList()->Clone());
437  // mitk::TimeGeometry::Pointer clonGeometry = input->GetTimeGeometry()->Clone();
438  // output->SetTimeGeometry(clonGeometry.GetPointer());
439 }
virtual bool IsDataValid() const
returns true if the object contains valid data
virtual igtl::MessageBase::Pointer GetMessage() const
returns the OpenIGTLink message
DataObjectPointerArraySizeType GetInputIndex(std::string messageName)
return the index of the input with name messageName, throw std::invalid_argument exception if that na...
static Pointer New()
virtual void ConnectTo(mitk::IGTLMessageSource *UpstreamFilter)
Connects the input of this filter to the outputs of the given IGTLMessageSource.
itk::SmartPointer< Self > Pointer
#define MITK_INFO
Definition: mitkLogMacros.h:22
itk::Matrix< mitk::ScalarType, 6, 6 > CovarianceMatrixType
type that holds the error characterization of the position and orientation measurements ...
virtual void SetCovErrorMatrix(CovarianceMatrixType _arg)
sets the 6x6 Error Covariance Matrix of the NavigationData object
#define MITK_ERROR
Definition: mitkLogMacros.h:24
Navigation Data.
virtual void SetName(const char *_arg)
set the name of the NavigationData object
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
DataCollection - Class to facilitate loading/accessing structured data.
virtual void SetInput(const IGTLMessage *msg)
Set the input of this filter.
virtual void SetDataValid(bool _arg)
sets the dataValid flag of the NavigationData object indicating if the object contains valid data ...
const char * GetIGTLMessageType() const
virtual void SetIGTTimeStamp(TimeStampType _arg)
sets the IGT timestamp of the NavigationData object
virtual void GenerateOutputInformation() override
Defines how the input will be copied into the output.
virtual void SetHasPosition(bool _arg)
sets the HasPosition flag of the NavigationData object
void CreateOutputsForAllInputs()
Create an output for each input.
const IGTLMessage * GetInput(void) const
Get the input of this filter.
static Vector3D offset
IGTLMessage * GetOutput(void)
return the output (output with id 0) of the filter
virtual void SetHasOrientation(bool _arg)
sets the HasOrientation flag of the NavigationData object
A wrapper for the OpenIGTLink message type.
virtual void SetOrientation(OrientationType _arg)
sets the orientation of the NavigationData object
void SetNumberOfExpectedOutputs(unsigned int numOutputs)
Sets the number of expected outputs.
#define mitkThrow()
virtual const char * GetName() const
returns the name of the IGTLMessage object
OpenIGTLink message source.
vnl_quaternion< ScalarType > Quaternion
virtual void SetPosition(PositionType _arg)
sets the position of the NavigationData object
virtual void Graft(const DataObject *data) override
Graft the data and information from one NavigationData to another.
MITKNEWMODULE_EXPORT bool Equal(mitk::ExampleDataStructure *leftHandSide, mitk::ExampleDataStructure *rightHandSide, mitk::ScalarType eps, bool verbose)
Returns true if the example data structures are considered equal.
virtual TimeStampType GetIGTTimeStamp() const
gets the IGT timestamp of the IGTLMessage object
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.