CustusX  16.5
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxIGTLinkConversionPolyData.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 /*==========================================================================
34 
35  Portions (c) Copyright 2008-2014 Brigham and Women's Hospital (BWH) All Rights Reserved.
36 
37  See Doc/copyright/copyright.txt
38  or http://www.slicer.org/copyright/copyright.txt for details.
39 
40  Program: 3D Slicer
41  Module: vtkIGTLToMRMLPolyData.cxx
42 
43 ==========================================================================*/
45 
46 // OpenIGTLink includes
47 #include <igtl_util.h>
48 #include <igtlPolyDataMessage.h>
49 
50 // VTK includes
51 #include <vtkPolyData.h>
52 #include <vtkIntArray.h>
53 #include <vtkMatrix4x4.h>
54 #include <vtkObjectFactory.h>
55 #include <vtkSmartPointer.h>
56 #include <vtkVertex.h>
57 #include <vtkCellArray.h>
58 #include <vtkPolyLine.h>
59 #include <vtkPolygon.h>
60 #include <vtkTriangleStrip.h>
61 #include <vtkFloatArray.h>
62 #include <vtkDataSetAttributes.h>
63 #include <vtkPointData.h>
64 #include <vtkCellData.h>
65 
66 // CX includes
67 #include "cxMesh.h"
69 #include "cxTypeConversions.h"
70 #include "cxLogger.h"
71 
72 namespace cx
73 {
74 
75 igtl::PolyDataMessage::Pointer IGTLinkConversionPolyData::encode(MeshPtr in, PATIENT_COORDINATE_SYSTEM externalSpace)
76 {
77  igtl::PolyDataMessage::Pointer retval = igtl::PolyDataMessage::New();
78  IGTLinkConversionBase baseConverter;
79 
80  retval->SetDeviceName(cstring_cast(in->getName()));
81  baseConverter.encode_timestamp(in->getAcquisitionTime(), retval);
82  vtkPolyDataPtr polyData = in->getVtkPolyData();
83  polyData = this->encodeCoordinateSystem(in, externalSpace);
84  this->encode_vtkPolyData(polyData, retval);
85 
86  return retval;
87 }
88 
89 MeshPtr IGTLinkConversionPolyData::decode(igtl::PolyDataMessage *in, PATIENT_COORDINATE_SYSTEM externalSpace)
90 {
91  vtkPolyDataPtr polyData = this->decode_vtkPolyData(in);
92  polyData = this->decodeCoordinateSystem(polyData, externalSpace);
93  QDateTime timestamp = IGTLinkConversionBase().decode_timestamp(in);
94  QString deviceName = in->GetDeviceName();
95 
96  MeshPtr retval(new Mesh(deviceName));
97  retval->setVtkPolyData(polyData);
98  retval->setAcquisitionTime(timestamp);
99  return retval;
100 }
101 
102 vtkPolyDataPtr IGTLinkConversionPolyData::decodeCoordinateSystem(vtkPolyDataPtr polyData, PATIENT_COORDINATE_SYSTEM externalSpace)
103 {
105  Transform3D rMs = sMr.inv();
106 
107  MeshPtr mesh(new Mesh("temp", "temp", polyData));
108  vtkPolyDataPtr poly = mesh->getTransformedPolyData(rMs);
109  return poly;
110 }
111 
112 vtkPolyDataPtr IGTLinkConversionPolyData::encodeCoordinateSystem(MeshPtr mesh, PATIENT_COORDINATE_SYSTEM externalSpace)
113 {
114  Transform3D rMd = mesh->get_rMd();
116  Transform3D sMd = sMr * rMd;
117 
118  vtkPolyDataPtr poly = mesh->getTransformedPolyData(sMd);
119  return poly;
120 }
121 
122 vtkPolyDataPtr IGTLinkConversionPolyData::decode_vtkPolyData(igtl::PolyDataMessage* msg)
123 {
124  // NOTE: This method is mostly a copy-paste from Slicer.
125  // Avoid refactoring the internals, as it is important to keep the code similar to the origin.
126 
127  igtl::PolyDataMessage* polyDataMsg = msg;
128 
129  vtkSmartPointer<vtkPolyData> poly = vtkSmartPointer<vtkPolyData>::New();
130 
131  // Points
132  igtl::PolyDataPointArray::Pointer pointsArray = polyDataMsg->GetPoints();
133  int npoints = pointsArray->GetNumberOfPoints();
134  if (npoints > 0)
135  {
136  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
137  for (int i = 0; i < npoints; i ++)
138  {
139  igtlFloat32 point[3];
140  pointsArray->GetPoint(i, point);
141  points->InsertNextPoint(point); // TODO: use the id returned by this call?
142  }
143  poly->SetPoints(points);
144  }
145  else
146  {
147  // ERROR: No points defined
148  }
149 
150  // Vertices
151  igtl::PolyDataCellArray::Pointer verticesArray = polyDataMsg->GetVertices();
152  int nvertices = verticesArray.IsNotNull() ? verticesArray->GetNumberOfCells() : 0;
153  if (nvertices > 0)
154  {
155  vtkSmartPointer<vtkCellArray> vertCells = vtkSmartPointer<vtkCellArray>::New();
156  for (int i = 0; i < nvertices; i ++)
157  {
158  vtkSmartPointer<vtkVertex> vertex = vtkSmartPointer<vtkVertex>::New();
159 
160  std::list<igtlUint32> cell;
161  verticesArray->GetCell(i, cell);
162  //for (unsigned int j = 0; j < cell.size(); j ++) // TODO: is cell.size() always 1?
163  //{
164  std::list<igtlUint32>::iterator iter;
165  iter = cell.begin();
166  vertex->GetPointIds()->SetId(i, *iter);
167  //}
168  vertCells->InsertNextCell(vertex);
169  }
170  poly->SetVerts(vertCells);
171  }
172 
173  // Lines
174  igtl::PolyDataCellArray::Pointer linesArray = polyDataMsg->GetLines();
175  int nlines = linesArray.IsNotNull() ? linesArray->GetNumberOfCells() : 0;
176  if (nlines > 0)
177  {
178  vtkSmartPointer<vtkCellArray> lineCells = vtkSmartPointer<vtkCellArray>::New();
179  for(int i = 0; i < nlines; i++)
180  {
181  vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New();
182 
183  std::list<igtlUint32> cell;
184  linesArray->GetCell(i, cell);
185  polyLine->GetPointIds()->SetNumberOfIds(cell.size());
186  std::list<igtlUint32>::iterator iter;
187  int j = 0;
188  for (iter = cell.begin(); iter != cell.end(); iter ++)
189  {
190  polyLine->GetPointIds()->SetId(j, *iter);
191  j++;
192  }
193  lineCells->InsertNextCell(polyLine);
194  }
195  poly->SetLines(lineCells);
196  }
197 
198  // Polygons
199  igtl::PolyDataCellArray::Pointer polygonsArray = polyDataMsg->GetPolygons();
200  int npolygons =polygonsArray.IsNotNull() ? polygonsArray->GetNumberOfCells() : 0;
201  if (npolygons > 0)
202  {
203  vtkSmartPointer<vtkCellArray> polygonCells = vtkSmartPointer<vtkCellArray>::New();
204  for(int i = 0; i < npolygons; i++)
205  {
206  vtkSmartPointer<vtkPolygon> polygon = vtkSmartPointer<vtkPolygon>::New();
207 
208  std::list<igtlUint32> cell;
209  polygonsArray->GetCell(i, cell);
210  polygon->GetPointIds()->SetNumberOfIds(cell.size());
211  std::list<igtlUint32>::iterator iter;
212  int j = 0;
213  for (iter = cell.begin(); iter != cell.end(); iter ++)
214  {
215  polygon->GetPointIds()->SetId(j, *iter);
216  j++;
217  }
218  polygonCells->InsertNextCell(polygon);
219  }
220  poly->SetPolys(polygonCells);
221  }
222 
223  // Triangle Strips
224  igtl::PolyDataCellArray::Pointer triangleStripsArray = polyDataMsg->GetTriangleStrips();
225  int ntstrips = triangleStripsArray.IsNotNull() ? triangleStripsArray->GetNumberOfCells() : 0;
226  if (ntstrips > 0)
227  {
228  vtkSmartPointer<vtkCellArray> tstripCells = vtkSmartPointer<vtkCellArray>::New();
229  for(int i = 0; i < ntstrips; i++)
230  {
231  vtkSmartPointer<vtkTriangleStrip> tstrip = vtkSmartPointer<vtkTriangleStrip>::New();
232 
233  std::list<igtlUint32> cell;
234  triangleStripsArray->GetCell(i, cell);
235  tstrip->GetPointIds()->SetNumberOfIds(cell.size());
236  std::list<igtlUint32>::iterator iter;
237  int j = 0;
238  for (iter = cell.begin(); iter != cell.end(); iter ++)
239  {
240  tstrip->GetPointIds()->SetId(j, *iter);
241  j++;
242  }
243  tstripCells->InsertNextCell(tstrip);
244  }
245  poly->SetStrips(tstripCells);
246  }
247 
248  // Attribute
249  int nAttributes = polyDataMsg->GetNumberOfAttributes();
250  for (int i = 0; i < nAttributes; i ++)
251  {
252  igtl::PolyDataAttribute::Pointer attribute;
253  attribute = polyDataMsg->GetAttribute(i);
254 
255  vtkSmartPointer<vtkFloatArray> data =
256  vtkSmartPointer<vtkFloatArray>::New();
257 
258  data->SetName(attribute->GetName()); //set the name of the value
259  int n = attribute->GetSize();
260 
261  // NOTE: Data types for POINT (igtl::PolyDataMessage::POINT_*) and CELL
262  // (igtl::PolyDataMessage::CELL_*) have the same lower 4 bit.
263  // By masking the values with 0x0F, attribute types (either SCALAR, VECTOR, NORMAL,
264  // TENSOR, or RGBA) can be obtained. On the other hand, by masking the value
265  // with 0xF0, data types (POINT or CELL) can be obtained.
266  // See, igtlPolyDataMessage.h in the OpenIGTLink library.
267  switch (attribute->GetType() & 0x0F)
268  {
269  case igtl::PolyDataAttribute::POINT_SCALAR:
270  {
271  data->SetNumberOfComponents(1);
272  break;
273  }
274  case igtl::PolyDataAttribute::POINT_VECTOR:
275  case igtl::PolyDataAttribute::POINT_NORMAL:
276  {
277  data->SetNumberOfComponents(3);
278  break;
279  }
280  case igtl::PolyDataAttribute::POINT_TENSOR:
281  {
282  data->SetNumberOfComponents(9); // TODO: Is it valid in Slicer?
283  break;
284  }
285  case igtl::PolyDataAttribute::POINT_RGBA:
286  {
287  data->SetNumberOfComponents(4); // TODO: Is it valid in Slicer?
288  break;
289  }
290  default:
291  {
292  // ERROR
293  break;
294  }
295  }
296  data->SetNumberOfTuples(n);
297  attribute->GetData(static_cast<igtl_float32*>(data->GetPointer(0)));
298 
299  if ((attribute->GetType() & 0xF0) == 0) // POINT
300  {
301  poly->GetPointData()->AddArray(data);
302  }
303  else // CELL
304  {
305  poly->GetCellData()->AddArray(data);
306  }
307  }
308 
309  poly->Modified();
310  return poly;
311 }
312 
313 //---------------------------------------------------------------------------
314 void IGTLinkConversionPolyData::encode_vtkPolyData(vtkPolyDataPtr in, igtl::PolyDataMessage* outMsg)
315 {
316  // NOTE: This method is mostly a copy-paste from Slicer.
317  // Avoid refactoring the internals, as it is important to keep the code similar to the origin.
318 
319  vtkSmartPointer<vtkPolyData> poly = in;
320 
321  // Points
322  vtkSmartPointer<vtkPoints> points = poly->GetPoints();
323  if (points.GetPointer() != NULL)
324  {
325  int npoints = points->GetNumberOfPoints();
326  if (npoints > 0)
327  {
328  igtl::PolyDataPointArray::Pointer pointArray = igtl::PolyDataPointArray::New();
329  for (int i = 0; i < npoints; i ++)
330  {
331  double *p = points->GetPoint(i);
332  pointArray->AddPoint(static_cast<igtlFloat32>(p[0]),
333  static_cast<igtlFloat32>(p[1]),
334  static_cast<igtlFloat32>(p[2]));
335  }
336  outMsg->SetPoints(pointArray);
337  }
338  }
339 
340  // Vertices
341  vtkSmartPointer<vtkCellArray> vertCells = poly->GetVerts();
342  if (vertCells.GetPointer() != NULL)
343  {
344  igtl::PolyDataCellArray::Pointer verticesArray = igtl::PolyDataCellArray::New();
345  if (this->VTKToIGTLCellArray(vertCells, verticesArray) > 0)
346  {
347  outMsg->SetVertices(verticesArray);
348  }
349  }
350 
351  // Lines
352  vtkSmartPointer<vtkCellArray> lineCells = poly->GetLines();
353  if (lineCells.GetPointer() != NULL)
354  {
355  igtl::PolyDataCellArray::Pointer linesArray = igtl::PolyDataCellArray::New();
356  if (this->VTKToIGTLCellArray(lineCells, linesArray) > 0)
357  {
358  outMsg->SetLines(linesArray);
359  }
360  }
361 
362  // Polygons
363  vtkSmartPointer<vtkCellArray> polygonCells = poly->GetPolys();
364  if (polygonCells.GetPointer() != NULL)
365  {
366  igtl::PolyDataCellArray::Pointer polygonsArray = igtl::PolyDataCellArray::New();
367  if (this->VTKToIGTLCellArray(polygonCells, polygonsArray) > 0)
368  {
369  outMsg->SetPolygons(polygonsArray);
370  }
371  }
372 
373  // Triangl strips
374  vtkSmartPointer<vtkCellArray> triangleStripCells = poly->GetStrips();
375  if (triangleStripCells.GetPointer() != NULL)
376  {
377  igtl::PolyDataCellArray::Pointer triangleStripsArray = igtl::PolyDataCellArray::New();
378  if (this->VTKToIGTLCellArray(triangleStripCells, triangleStripsArray) > 0)
379  {
380  outMsg->SetTriangleStrips(triangleStripsArray);
381  }
382  }
383 
384  // Attributes for points
385  vtkSmartPointer<vtkPointData> pdata = poly->GetPointData();
386  int nPointAttributes = pdata->GetNumberOfArrays();
387  if (nPointAttributes > 0)
388  {
389  for (int i = 0; i < nPointAttributes; i ++)
390  {
391  igtl::PolyDataAttribute::Pointer attribute = igtl::PolyDataAttribute::New();
392  if (this->VTKToIGTLAttribute(pdata, i, attribute) > 0)
393  {
394  outMsg->AddAttribute(attribute);
395  }
396  }
397  }
398 
399 
400  // Attributes for cells
401  vtkSmartPointer<vtkCellData> cdata = poly->GetCellData();
402  int nCellAttributes = cdata->GetNumberOfArrays();
403  if (nCellAttributes > 0)
404  {
405  for (int i = 0; i < nCellAttributes; i ++)
406  {
407  igtl::PolyDataAttribute::Pointer attribute = igtl::PolyDataAttribute::New();
408  if (this->VTKToIGTLAttribute(cdata, i, attribute) > 0)
409  {
410  outMsg->AddAttribute(attribute);
411  }
412  }
413  }
414 }
415 
416 //---------------------------------------------------------------------------
417 int IGTLinkConversionPolyData::VTKToIGTLCellArray(vtkCellArray* src, igtl::PolyDataCellArray* dest)
418 {
419  if (src && dest)
420  {
421  int ncells = src->GetNumberOfCells();
422  if (ncells > 0)
423  {
424  vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New();
425  src->InitTraversal();
426  while (src->GetNextCell(idList))
427  {
428  std::list<igtlUint32> cell;
429  int nIds = idList->GetNumberOfIds();
430  for (int i = 0; i < nIds; i ++)
431  {
432  cell.push_back(idList->GetId(i));
433  }
434  dest->AddCell(cell);
435  }
436  }
437  return ncells;
438  }
439  else
440  {
441  return 0;
442  }
443 
444 }
445 
446 
447 //---------------------------------------------------------------------------
448 int IGTLinkConversionPolyData::VTKToIGTLAttribute(vtkDataSetAttributes* src, int i, igtl::PolyDataAttribute* dest)
449 {
450 
451  //vtkSmartPointer<vtkPointData> src = poly->GetPointData();
452  if ((!src) || (!dest))
453  {
454  return 0;
455  }
456 
457  // Check the range of index i
458  if (i < 0 || i >= src->GetNumberOfArrays())
459  {
460  return 0;
461  }
462 
463  // NOTE: Data types for POINT (igtl::PolyDataMessage::POINT_*) and CELL
464  // (igtl::PolyDataMessage::CELL_*) have the same bits exept the 3rd bit (0x10).
465  // attrType will contain the 3rd bit based on the type of vtkDataSetAttributes
466  // (either vtkCellData or vtkPointData). See, igtlPolyDataMessage.h in the OpenIGTLink library.
467  int attrTypeBit;
468  if (src->IsTypeOf("vtkCellData"))
469  {
470  attrTypeBit = 0x10;
471  }
472  else // vtkPointData
473  {
474  attrTypeBit = 0x00;
475  }
476 
477  vtkSmartPointer<vtkDataArray> array = src->GetArray(i);
478  int ncomps = array->GetNumberOfComponents();
479  if (ncomps == 1)
480  {
481  dest->SetType(igtl::PolyDataAttribute::POINT_SCALAR | attrTypeBit);
482  }
483  else if (ncomps == 3)
484  {
485  // TODO: how to differenciate normal and vector?
486  dest->SetType(igtl::PolyDataAttribute::POINT_NORMAL | attrTypeBit);
487  }
488  else if (ncomps == 9)
489  {
490  dest->SetType(igtl::PolyDataAttribute::POINT_TENSOR | attrTypeBit);
491  }
492  else if (ncomps == 4)
493  {
494  dest->SetType(igtl::PolyDataAttribute::POINT_RGBA | attrTypeBit);
495  }
496  dest->SetName((array->GetName() ? array->GetName() : ""));
497  int ntuples = array->GetNumberOfTuples();
498  dest->SetSize(ntuples);
499 
500  for (int j = 0; j < ntuples; j ++)
501  {
502  double * tuple = array->GetTuple(j);
503  igtlFloat32 data[9];
504  for (int k = 0; k < ncomps; k ++)
505  {
506  data[k] = static_cast<igtlFloat32>(tuple[k]);
507  }
508  dest->SetNthData(j, data);
509  }
510 
511  return 1;
512 
513 }
514 
515 
516 } //namespace cx
A mesh data set.
Definition: cxMesh.h:61
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
cxResource_EXPORT Transform3D createTransformFromReferenceToExternal(PATIENT_COORDINATE_SYSTEM external)
cstring_cast_Placeholder cstring_cast(const T &val)
vtkSmartPointer< class vtkPolyData > vtkPolyDataPtr
boost::shared_ptr< class Mesh > MeshPtr