iMSTK
Interactive Medical Simulation Toolkit
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Pages
imstkVTKMeshIO.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkVTKMeshIO.h"
8 #include "imstkGeometryUtilities.h"
9 #include "imstkHexahedralMesh.h"
10 #include "imstkImageData.h"
11 #include "imstkLineMesh.h"
12 #include "imstkLogger.h"
13 #include "imstkSurfaceMesh.h"
14 #include "imstkTetrahedralMesh.h"
15 
16 #include <vtkBMPReader.h>
17 #include <vtkBMPWriter.h>
18 #include <vtkDICOMImageReader.h>
19 #include <vtkGenericDataObjectReader.h>
20 #include <vtkGenericDataObjectWriter.h>
21 #include <vtkImageData.h>
22 #include <vtkJPEGReader.h>
23 #include <vtkJPEGWriter.h>
24 #include <vtkMetaImageReader.h>
25 #include <vtkMetaImageWriter.h>
26 #include <vtkNIFTIImageReader.h>
27 #include <vtkNIFTIImageWriter.h>
28 #include <vtkNrrdReader.h>
29 #include <vtkOBJReader.h>
30 #include <vtkOBJWriter.h>
31 #include <vtkPLYReader.h>
32 #include <vtkPLYWriter.h>
33 #include <vtkPNGReader.h>
34 #include <vtkPNGWriter.h>
35 #include <vtkPolyDataWriter.h>
36 #include <vtkSTLReader.h>
37 #include <vtkSTLWriter.h>
38 #include <vtkTriangleFilter.h>
39 #include <vtkUnstructuredGrid.h>
40 #include <vtkXMLPolyDataReader.h>
41 #include <vtkXMLPolyDataWriter.h>
42 #include <vtkXMLUnstructuredGridReader.h>
43 #include <vtkXMLUnstructuredGridWriter.h>
44 
45 namespace imstk
46 {
47 std::shared_ptr<PointSet>
48 VTKMeshIO::read(const std::string& filePath, MeshFileType meshType)
49 {
50  switch (meshType)
51  {
52  case MeshFileType::VTK:
53  {
54  return VTKMeshIO::readVtkGenericFormatData<vtkGenericDataObjectReader>(filePath);
55  }
56  case MeshFileType::VTU:
57  {
58  return VTKMeshIO::readVtkUnstructuredGrid<vtkXMLUnstructuredGridReader>(filePath);
59  }
60  case MeshFileType::VTP:
61  {
62  return VTKMeshIO::readVtkPolyData<vtkXMLPolyDataReader>(filePath);
63  }
64  case MeshFileType::STL:
65  {
66  return VTKMeshIO::readVtkPolyData<vtkSTLReader>(filePath);
67  }
68  case MeshFileType::PLY:
69  {
70  return VTKMeshIO::readVtkPolyData<vtkPLYReader>(filePath);
71  }
72  case MeshFileType::OBJ:
73  {
74  return VTKMeshIO::readVtkPolyData<vtkOBJReader>(filePath);
75  }
76  case MeshFileType::DCM:
77  {
78  return VTKMeshIO::readVtkImageDataDICOM(filePath);
79  }
80  case MeshFileType::NRRD:
81  {
82  return VTKMeshIO::readVtkImageData<vtkNrrdReader>(filePath);
83  }
84  case MeshFileType::NII:
85  {
86  return VTKMeshIO::readVtkImageDataNIFTI(filePath);
87  }
88  case MeshFileType::MHD:
89  {
90  return VTKMeshIO::readVtkImageData<vtkMetaImageReader>(filePath);
91  }
92  case MeshFileType::PNG:
93  {
94  return VTKMeshIO::readVtkImageData<vtkPNGReader>(filePath);
95  }
96  case MeshFileType::JPG:
97  {
98  return VTKMeshIO::readVtkImageData<vtkJPEGReader>(filePath);
99  }
100  case MeshFileType::BMP:
101  {
102  return VTKMeshIO::readVtkImageData<vtkBMPReader>(filePath);
103  }
104  default:
105  {
106  LOG(FATAL) << "Error: file type not supported for input " << filePath;
107  return nullptr;
108  }
109  }
110 }
111 
112 bool
113 VTKMeshIO::write(const std::shared_ptr<PointSet> imstkMesh, const std::string& filePath, const MeshFileType meshType)
114 {
115  if (auto imgMesh = std::dynamic_pointer_cast<ImageData>(imstkMesh))
116  {
117  switch (meshType)
118  {
119  case MeshFileType::NII:
120  return VTKMeshIO::writeVtkImageDataNIFTI(imgMesh, filePath);
121  case MeshFileType::MHD:
122  return VTKMeshIO::writeMetaImageData(imgMesh, filePath);
123  case MeshFileType::PNG:
124  return VTKMeshIO::writeVtkImageData<vtkPNGWriter>(imgMesh, filePath);
125  case MeshFileType::JPG:
126  return VTKMeshIO::writeVtkImageData<vtkJPEGWriter>(imgMesh, filePath);
127  case MeshFileType::BMP:
128  return VTKMeshIO::writeVtkImageData<vtkBMPWriter>(imgMesh, filePath);
129  default:
130  LOG(WARNING) << "Error: file type not supported for ImageData. Target path supplied:" << filePath;
131  return false;
132  }
133  }
134  else if (auto tetMesh = std::dynamic_pointer_cast<TetrahedralMesh>(imstkMesh))
135  {
136  switch (meshType)
137  {
138  case MeshFileType::VTU:
139  return VTKMeshIO::writeVtkUnstructuredGrid<vtkXMLUnstructuredGridWriter>(tetMesh, filePath);
140  case MeshFileType::VTK:
141  return VTKMeshIO::writeVtkUnstructuredGrid<vtkGenericDataObjectWriter>(tetMesh, filePath);
142  default:
143  LOG(WARNING) << "Error: file type not supported for TetrahedralMesh. Target path supplied:" << filePath;
144  return false;
145  }
146  }
147  else if (auto hexMesh = std::dynamic_pointer_cast<HexahedralMesh>(imstkMesh))
148  {
149  switch (meshType)
150  {
151  case MeshFileType::VTU:
152  return VTKMeshIO::writeVtkUnstructuredGrid<vtkXMLUnstructuredGridWriter>(hexMesh, filePath);
153  case MeshFileType::VTK:
154  return VTKMeshIO::writeVtkUnstructuredGrid<vtkGenericDataObjectWriter>(hexMesh, filePath);
155  default:
156  LOG(WARNING) << "Error: file type not supported for HexahedralMesh. Target path supplied:" << filePath;
157  return false;
158  }
159  }
160  else if (auto sMesh = std::dynamic_pointer_cast<SurfaceMesh>(imstkMesh))
161  {
162  switch (meshType)
163  {
164  case MeshFileType::VTP:
165  return VTKMeshIO::writeVtkPolyData<vtkXMLPolyDataWriter>(sMesh, filePath);
166  case MeshFileType::STL:
167  return VTKMeshIO::writeVtkPolyData<vtkSTLWriter>(sMesh, filePath);
168  case MeshFileType::PLY:
169  return VTKMeshIO::writeVtkPolyData<vtkPLYWriter>(sMesh, filePath);
170  case MeshFileType::VTK:
171  return VTKMeshIO::writeVtkPolyData<vtkPolyDataWriter>(sMesh, filePath);
172  case MeshFileType::OBJ:
173  return VTKMeshIO::writeVtkPolyData<vtkOBJWriter>(sMesh, filePath);
174  default:
175  LOG(WARNING) << "Error: file type not supported for SurfaceMesh. Target path supplied:" << filePath;
176  return false;
177  }
178  }
179  else if (auto lMesh = std::dynamic_pointer_cast<LineMesh>(imstkMesh))
180  {
181  switch (meshType)
182  {
183  case MeshFileType::VTK:
184  return VTKMeshIO::writeVtkPolyData<vtkPolyDataWriter>(lMesh, filePath);
185  case MeshFileType::VTP:
186  return VTKMeshIO::writeVtkPolyData<vtkXMLPolyDataWriter>(lMesh, filePath);
187  default:
188  LOG(WARNING) << "Error: file type not supported for LineMesh. Target path supplied:" << filePath;
189  return false;
190  }
191  }
192  else if (auto ptMesh = std::dynamic_pointer_cast<PointSet>(imstkMesh))
193  {
194  switch (meshType)
195  {
196  case MeshFileType::VTK:
197  return VTKMeshIO::writeVtkPointSet<vtkGenericDataObjectWriter>(ptMesh, filePath);
198  default:
199  LOG(WARNING) << "Error: file type not supported for PointSet. Target path supplied:" << filePath;
200  return false;
201  }
202  }
203  else
204  {
205  LOG(WARNING) << "Error: the provided mesh is not a surface or volumetric mesh. Target path supplied:" << filePath;
206  return false;
207  }
208 }
209 
210 template<typename ReaderType>
211 std::shared_ptr<PointSet>
212 VTKMeshIO::readVtkGenericFormatData(const std::string& filePath)
213 {
214  auto reader = vtkSmartPointer<ReaderType>::New();
215  reader->SetFileName(filePath.c_str());
216  reader->Update();
217 
218  if (vtkSmartPointer<vtkPolyData> vtkMesh = reader->GetPolyDataOutput())
219  {
220  // Try to convert to surface mesh, if no elements exist try reading as a line mesh
221  std::shared_ptr<SurfaceMesh> surfMesh = GeometryUtils::copyToSurfaceMesh(vtkMesh);
222  if (surfMesh->getNumCells() > 0)
223  {
224  return surfMesh;
225  }
226  std::shared_ptr<LineMesh> lineMesh = GeometryUtils::copyToLineMesh(vtkMesh);
227  if (lineMesh->getNumCells() > 0)
228  {
229  return lineMesh;
230  }
231  return GeometryUtils::copyToPointSet(vtkMesh);
232  }
233 
234  if (vtkUnstructuredGrid* vtkMesh = reader->GetUnstructuredGridOutput())
235  {
236  return GeometryUtils::copyToCellMesh(vtkMesh);
237  }
238 
239  LOG(FATAL) << "Error: could not read with VTK reader for input " << filePath;
240  return nullptr;
241 }
242 
243 template<typename ReaderType>
244 std::shared_ptr<SurfaceMesh>
245 VTKMeshIO::readVtkPolyData(const std::string& filePath)
246 {
247  auto reader = vtkSmartPointer<ReaderType>::New();
248  reader->SetFileName(filePath.c_str());
249  reader->Update();
250 
251  auto triFilter = vtkSmartPointer<vtkTriangleFilter>::New();
252  triFilter->SetInputData(reader->GetOutput());
253  triFilter->Update();
254 
255  vtkSmartPointer<vtkPolyData> vtkMesh = triFilter->GetOutput();
256  return GeometryUtils::copyToSurfaceMesh(vtkMesh);
257 }
258 
259 template<typename WriterType>
260 bool
261 VTKMeshIO::writeVtkImageData(const std::shared_ptr<ImageData> imstkMesh, const std::string& filePath)
262 {
263  vtkSmartPointer<vtkImageData> vtkMesh = GeometryUtils::copyToVtkImageData(imstkMesh);
264  if (!vtkMesh)
265  {
266  return false;
267  }
268 
269  auto writer = vtkSmartPointer<WriterType>::New();
270  if (vtkMesh->GetDimensions()[2] == 1)
271  {
272  writer->SetFileDimensionality(2);
273  }
274  else
275  {
276  writer->SetFileDimensionality(3);
277  }
278  writer->SetInputData(vtkMesh);
279  writer->SetFileName(filePath.c_str());
280  writer->Write();
281 
282  return true;
283 }
284 
285 template<typename WriterType>
286 bool
287 VTKMeshIO::writeVtkPolyData(std::shared_ptr<SurfaceMesh> imstkMesh, const std::string& filePath)
288 {
289  vtkSmartPointer<vtkPolyData> vtkMesh = GeometryUtils::copyToVtkPolyData(imstkMesh);
290  if (!vtkMesh)
291  {
292  return false;
293  }
294 
295  auto writer = vtkSmartPointer<WriterType>::New();
296  writer->SetInputData(vtkMesh);
297  writer->SetFileName(filePath.c_str());
298  writer->Update();
299 
300  return true;
301 }
302 
303 template<typename WriterType>
304 bool
305 VTKMeshIO::writeVtkPolyData(std::shared_ptr<LineMesh> imstkMesh, const std::string& filePath)
306 {
307  vtkSmartPointer<vtkPolyData> vtkMesh = GeometryUtils::copyToVtkPolyData(imstkMesh);
308  if (!vtkMesh)
309  {
310  return false;
311  }
312 
313  auto writer = vtkSmartPointer<WriterType>::New();
314  writer->SetInputData(vtkMesh);
315  writer->SetFileName(filePath.c_str());
316  writer->Update();
317 
318  return true;
319 }
320 
321 template<typename WriterType>
322 bool
323 VTKMeshIO::writeVtkPointSet(const std::shared_ptr<PointSet> imstkMesh, const std::string& filePath)
324 {
325  vtkSmartPointer<vtkPointSet> vtkMesh = GeometryUtils::copyToVtkPointSet(imstkMesh);
326  if (!vtkMesh)
327  {
328  return false;
329  }
330 
331  auto writer = vtkSmartPointer<WriterType>::New();
332  writer->SetInputData(vtkMesh);
333  writer->SetFileName(filePath.c_str());
334  writer->Update();
335 
336  return true;
337 }
338 
339 template<typename ReaderType>
340 std::shared_ptr<AbstractCellMesh>
341 VTKMeshIO::readVtkUnstructuredGrid(const std::string& filePath)
342 {
343  auto reader = vtkSmartPointer<ReaderType>::New();
344  reader->SetFileName(filePath.c_str());
345  reader->Update();
346 
347  vtkSmartPointer<vtkUnstructuredGrid> vtkMesh = reader->GetOutput();
348  return GeometryUtils::copyToCellMesh(vtkMesh);
349 }
350 
351 std::shared_ptr<ImageData>
352 VTKMeshIO::readVtkImageDataDICOM(const std::string& filePath)
353 {
354  bool isDirectory;
355 
356  CHECK(MeshIO::fileExists(filePath, isDirectory)) << "Error: file " << filePath << " not found!";
357 
358  if (!isDirectory)
359  {
360  return VTKMeshIO::readVtkImageData<vtkDICOMImageReader>(filePath);
361  }
362 
363  auto reader = vtkSmartPointer<vtkDICOMImageReader>::New();
364  reader->SetDirectoryName(filePath.c_str());
365  reader->Update();
366 
367  std::shared_ptr<ImageData> imageData(
368  std::move(GeometryUtils::copyToImageData(reader->GetOutput())));
369  return imageData;
370 }
371 
372 template<typename WriterType>
373 bool
374 VTKMeshIO::writeVtkUnstructuredGrid(std::shared_ptr<TetrahedralMesh> tetMesh, const std::string& filePath)
375 {
376  auto vtkMesh = GeometryUtils::copyToVtkUnstructuredGrid(tetMesh);
377 
378  if (!vtkMesh)
379  {
380  LOG(WARNING) << "Error: conversion unsuccessful. Target path supplied:" << filePath;
381  return false;
382  }
383 
384  auto writer = vtkSmartPointer<WriterType>::New();
385  writer->SetInputData(vtkMesh);
386  writer->SetFileName(filePath.c_str());
387  writer->Update();
388 
389  return true;
390 }
391 
392 template<typename WriterType>
393 bool
394 VTKMeshIO::writeVtkUnstructuredGrid(std::shared_ptr<HexahedralMesh> hMesh, const std::string& filePath)
395 {
396  auto vtkMesh = GeometryUtils::copyToVtkUnstructuredGrid(hMesh);
397 
398  if (!vtkMesh)
399  {
400  LOG(WARNING) << "Error: conversion unsuccessful. Target path supplied:" << filePath;
401  return false;
402  }
403 
404  auto writer = vtkSmartPointer<WriterType>::New();
405  writer->SetInputData(vtkMesh);
406  writer->SetFileName(filePath.c_str());
407  writer->Update();
408 
409  return true;
410 }
411 
412 template<typename ReaderType>
413 std::shared_ptr<ImageData>
414 VTKMeshIO::readVtkImageData(const std::string& filePath)
415 {
416  auto reader = vtkSmartPointer<ReaderType>::New();
417  reader->SetFileName(filePath.c_str());
418  reader->Update();
419 
420  std::shared_ptr<ImageData> imageData(std::move(GeometryUtils::copyToImageData(reader->GetOutput())));
421  return imageData;
422 }
423 
424 std::shared_ptr<ImageData>
425 VTKMeshIO::readVtkImageDataNIFTI(const std::string& filePath)
426 {
427  auto reader = vtkSmartPointer<vtkNIFTIImageReader>::New();
428  reader->SetFileName(filePath.c_str());
429  reader->SetFileDimensionality(3);
430  reader->Update();
431 
432  std::shared_ptr<ImageData> imageData(std::move(GeometryUtils::copyToImageData(reader->GetOutput())));
433  return imageData;
434 }
435 
436 bool
437 VTKMeshIO::writeVtkImageDataNIFTI(std::shared_ptr<ImageData> imageData, const std::string& filePath)
438 {
439  // Copy instead of couple for thread safety
440  auto vtkMesh = GeometryUtils::copyToVtkImageData(imageData);
441  if (!vtkMesh)
442  {
443  LOG(WARNING) << "Error: conversion unsuccessful. Target path supplied:" << filePath;
444  return false;
445  }
446 
447  auto writer = vtkSmartPointer<vtkNIFTIImageWriter>::New();
448  writer->SetFileName(filePath.c_str());
449  if (vtkMesh->GetDimensions()[2] == 1)
450  {
451  writer->SetFileDimensionality(2);
452  }
453  else
454  {
455  writer->SetFileDimensionality(3);
456  }
457  writer->SetInputData(vtkMesh);
458  writer->Update();
459  return true;
460 }
461 
462 bool
463 VTKMeshIO::writeMetaImageData(std::shared_ptr<ImageData> imageData, const std::string& filePath)
464 {
465  vtkSmartPointer<vtkImageData> vtkImage = GeometryUtils::copyToVtkImageData(imageData);
466  if (!vtkImage)
467  {
468  LOG(WARNING) << "Error: conversion unsuccessful. Target path supplied:" << filePath;
469  return false;
470  }
471 
472  auto writer = vtkSmartPointer<vtkMetaImageWriter>::New();
473  if (vtkImage->GetDimensions()[2] == 1)
474  {
475  writer->SetFileDimensionality(2);
476  }
477  else
478  {
479  writer->SetFileDimensionality(3);
480  }
481  writer->SetInputData(vtkImage);
482  writer->SetFileName(filePath.c_str());
483  writer->SetRAWFileName((filePath + ".raw").c_str());
484  writer->Write();
485  return true;
486 }
487 } // namespace imstk
vtkSmartPointer< vtkUnstructuredGrid > copyToVtkUnstructuredGrid(std::shared_ptr< TetrahedralMesh > imstkMesh)
Converts imstk tetrahedral mesh into a vtk unstructured grid.
static std::shared_ptr< AbstractCellMesh > readVtkUnstructuredGrid(const std::string &filePath)
Reads vtk unstructured grid. Drops cells that aren&#39;t of the last cell type.
static std::shared_ptr< ImageData > readVtkImageDataNIFTI(const std::string &filePath)
Reads nifti/nii format image data.
MeshFileType
Enumeration the mesh file type.
Definition: imstkMeshIO.h:19
std::shared_ptr< LineMesh > copyToLineMesh(vtkSmartPointer< vtkPolyData > vtkMesh)
Converts vtk polydata into a imstk surface mesh.
static bool writeVtkPolyData(const std::shared_ptr< SurfaceMesh > imstkMesh, const std::string &filePath)
Writes the given surface mesh to given file path using the provided writer type.
vtkSmartPointer< vtkPolyData > copyToVtkPolyData(std::shared_ptr< LineMesh > imstkMesh)
Converts imstk line mesh into a vtk polydata.
Compound Geometry.
static bool writeVtkImageData(const std::shared_ptr< ImageData > imstkMesh, const std::string &filePath)
Writes the given image data to given file path using the provided writer type.
static bool writeVtkImageDataNIFTI(std::shared_ptr< ImageData > imageData, const std::string &filePath)
Write nifti/nii format image data.
std::shared_ptr< AbstractCellMesh > copyToCellMesh(vtkSmartPointer< vtkUnstructuredGrid > vtkMesh)
Get imstk cell mesh given vtkUnstructuredGrid as input iMSTK only supports homogenous cells...
static bool write(const std::shared_ptr< PointSet > imstkMesh, const std::string &filePath, const MeshFileType meshType)
Writes the given mesh to the specified file path.
static std::shared_ptr< ImageData > readVtkImageDataDICOM(const std::string &filePath)
TODO.
vtkSmartPointer< vtkPointSet > copyToVtkPointSet(std::shared_ptr< PointSet > imstkMesh)
Converts imstk point set into a vtk polydata.
static bool writeVtkUnstructuredGrid(const std::shared_ptr< TetrahedralMesh > tetMesh, const std::string &filePath)
Writes the given volumetric mesh to given file path.
std::shared_ptr< SurfaceMesh > copyToSurfaceMesh(vtkSmartPointer< vtkPolyData > vtkMesh)
Converts vtk polydata into a imstk surface mesh.
static bool writeMetaImageData(std::shared_ptr< ImageData > imageData, const std::string &filePath)
Write meta/mhd format image data.
static bool writeVtkPointSet(const std::shared_ptr< PointSet > imstkMesh, const std::string &filePath)
Writes the given point set to given file path using the provided writer type.
std::shared_ptr< PointSet > copyToPointSet(vtkSmartPointer< vtkPointSet > vtkMesh)
Converts vtk polydata into a imstk point set.
static bool fileExists(const std::string &file, bool &isDirectory)
Returns true if the file exists, else false. Also sets isDirectory to true if the path is a directory...
Definition: imstkMeshIO.cpp:91
static std::shared_ptr< ImageData > readVtkImageData(const std::string &filePath)
Reads vtk image data.