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