PointSetIO.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2016 Imperial College London
5  * Copyright 2013-2016 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_PointSetIO_H
21 #define MIRTK_PointSetIO_H
22 
23 #include "mirtk/IOConfig.h"
24 #include "mirtk/PointSet.h"
25 
26 #include "vtkSmartPointer.h"
27 #include "vtkDataSet.h"
28 #include "vtkPointSet.h"
29 #include "vtkPolyData.h"
30 #include "vtkPointData.h"
31 #include "vtkCellArray.h"
32 
33 #if MIRTK_IO_WITH_GIFTI
34  #include "vtkPoints.h"
35  #include "vtkDataArray.h"
36  #include "vtkInformationStringKey.h"
37  #include "vtkInformationIntegerKey.h"
38  #include "vtkInformationDoubleKey.h"
39 #endif
40 
41 
42 namespace mirtk {
43 
44 
45 // =============================================================================
46 // File name extension
47 // =============================================================================
48 
49 /// Default extension for given data set
50 const char *DefaultExtension(vtkDataSet *);
51 
52 // =============================================================================
53 // Generic I/O functions
54 // =============================================================================
55 
56 /// Auxiliary macro to parse common point set output file type options
57 #define HANDLE_POINTSETIO_OPTION(fopt) \
58  if (OPTION("-ascii") || OPTION("-nobinary")) fopt = FO_ASCII; \
59  else if (OPTION("-noascii") || OPTION("-binary")) fopt = FO_Binary; \
60  else if (OPTION("-compress")) fopt = FO_Binary; \
61  else if (OPTION("-nocompress")) fopt = FO_NoCompress
62 
63 /// Enumeration of file type options
65 {
66  FO_Default, ///< Default options
67  FO_ASCII, ///< Uncompressed ASCII
68  FO_Binary, ///< (Compressed) binary
69  FO_NoCompress ///< Unompressed binary
70 };
71 
72 /// Read point set from file
73 ///
74 /// @param[in] fname File name.
75 /// @param[in] exit_on_failure Call exit when point set could not be read.
76 ///
77 /// @return Point set. Dataset is empty if file could not be read and @p exit_on_failure is @c false.
78 vtkSmartPointer<vtkPointSet> ReadPointSet(const char *fname, bool exit_on_failure = true);
79 
80 /// Read point set from file
81 ///
82 /// @param[in] fname File name.
83 /// @param[out] fopt Input file type option to be passed to WritePointSet
84 /// in order to save point set again in an equivalent
85 /// file format when the same file format extension is used.
86 /// @param[in] exit_on_failure Call exit when point set could not be read.
87 ///
88 /// @return Point set. Dataset is empty if file could not be read and @p exit_on_failure is @c false.
89 vtkSmartPointer<vtkPointSet> ReadPointSet(const char *fname, FileOption &fopt, bool exit_on_failure = true);
90 
91 /// Read polygonal dataset from file
92 ///
93 /// @param[in] fname File name.
94 /// @param[in] exit_on_failure Call exit when point set could not be read.
95 ///
96 /// @return Polygonal dataset. Dataset is empty if file could not be read and @p exit_on_failure is @c false.
97 vtkSmartPointer<vtkPolyData> ReadPolyData(const char *fname, bool exit_on_failure = true);
98 
99 /// Read polygonal dataset from file
100 ///
101 /// @param[in] fname File name.
102 /// @param[out] fopt Input file type option to be passed to WritePointSet
103 /// in order to save point set again in an equivalent
104 /// file format when the same file format extension is used.
105 /// @param[in] exit_on_failure Call exit when point set could not be read.
106 ///
107 /// @return Polygonal dataset. Dataset is empty if file could not be read and @p exit_on_failure is @c false.
108 vtkSmartPointer<vtkPolyData> ReadPolyData(const char *fname, FileOption &fopt, bool exit_on_failure = true);
109 
110 /// Write point set to file
111 ///
112 /// @param fname File name. The extension determines the output format.
113 /// @param pointset Point set to write.
114 /// @param fopt Whether to use ASCII, binary, or compressed binary file format.
115 ///
116 /// @return Whether point set was written successfully to the specified file.
117 bool WritePointSet(const char *fname, vtkPointSet *pointset, FileOption fopt = FO_Default);
118 
119 /// Write polygonal dataset to file
120 ///
121 /// @param fname File name. The extension determines the output format.
122 /// @param polydata Polydata to write.
123 /// @param fopt Whether to use ASCII, binary, or compressed binary file format.
124 ///
125 /// @return Whether point set was written successfully to the specified file.
126 bool WritePolyData(const char *fname, vtkPolyData *polydata, FileOption fopt = FO_Default);
127 
128 // =============================================================================
129 // CSV I/O functions
130 // =============================================================================
131 
132 /// Read point set (attributes) from CSV file
133 ///
134 /// This function reads point data arrays from the columns of a CSV file.
135 /// The first line must contain the column names, i.e., a CSV header is expected.
136 /// The number of rows must match the number of points in the reference point set
137 /// when the CSV file does not contain three columns whose name matches the
138 /// regular expression "((Point|Coord)\.)?(X|Y|Z)". Columns with a common name
139 /// prefix including a trailing dot are combined into a single multi-component
140 /// data array with component names following the '.' separator in the column
141 /// name. For example, columns "Gradient.X", "Gradient.Y", and "Gradient.Z"
142 /// are combined into one output point data array named "Gradient" with components
143 /// "X", "Y", and "Z". The data is initially read into data arrays of type
144 /// VTK_FLOAT. When all components can be converted lossless to an integral type,
145 /// the output data array is converted to either VTK_SHORT or VTK_INT.
146 ///
147 /// @param[in] fname File name.
148 /// @param[in] sep Separator.
149 /// @param[in] pointset Reference point set. When the table does not contain
150 /// 'X', 'Y', and 'Z' columns with point set coordinates,
151 /// the points of this reference point set are used.
152 /// Moreover, topological information is not read from a
153 /// table file and is thus inherited from the reference
154 /// \p pointset. The output point set will have the same
155 /// type as the reference \p pointset of which a shallow
156 /// copy is made.
157 ///
158 /// @return Polygonal dataset. Dataset is empty if file could not be read.
159 vtkSmartPointer<vtkPointSet> ReadPointSetTable(const char *fname, char sep = ',',
160  vtkPointSet *pointset = nullptr);
161 
162 /// Write point set (attributes) to CSV file
163 ///
164 /// @param[in] fname File name.
165 /// @param[in] pointset Point set.
166 /// @param[in] ids Whether to save point IDs in first column.
167 /// @param[in] coords Whether to save x, y, z point coordinate columns.
168 /// @param[in] sep Separator.
169 bool WritePointSetTable(const char *fname, vtkPointSet *pointset,
170  char sep = ',', bool ids = true, bool coords = true);
171 
172 // =============================================================================
173 // TetGen I/O functions
174 // =============================================================================
175 
176 /// Write point set to TetGen .node file
177 ///
178 /// @param fname File name.
179 /// @param pointset Point set.
180 ///
181 /// @return Whether dataset was written successfully to the specified file.
182 bool WriteTetGenNode(const char *fname, vtkPointSet *pointset);
183 
184 /// Write polygonal dataset to TetGen .poly file
185 ///
186 /// @param fname File name.
187 /// @param polydata Polygonal dataset.
188 /// @param holes Hole list.
189 ///
190 /// @return Whether dataset was written successfully to the specified file.
191 bool WriteTetGenPoly(const char *fname, vtkPolyData *polydata, const PointSet *holes = nullptr);
192 
193 /// Write polygonal dataset to TetGen .smesh file
194 ///
195 /// @param fname File name.
196 /// @param polydata Polygonal dataset.
197 /// @param holes Hole list.
198 ///
199 /// @return Whether dataset was written successfully to the specified file.
200 bool WriteTetGenSMesh(const char *fname, vtkPolyData *polydata, const PointSet *holes = nullptr);
201 
202 // =============================================================================
203 // BrainSuite I/O functions
204 // =============================================================================
205 
206 /// Read BrainSuite surface from .dfs file
207 ///
208 /// @param[in] fname File name.
209 ///
210 /// @return Polygonal dataset. Dataset is empty if file could not be read.
211 vtkSmartPointer<vtkPolyData> ReadDFS(const char *fname);
212 
213 /// Write surface in BrainSuite .dfs format
214 ///
215 /// @param[in] fname File name.
216 /// @param[in] polydata Polygonal dataset.
217 ///
218 /// @return Whether surface was written successfully to the specified file.
219 bool WriteDFS(const char *fname, vtkPolyData *polydata);
220 
221 // =============================================================================
222 // Object File Format I/O functions
223 // =============================================================================
224 
225 /// Read polygonal dataset from Object File Format (.off) file
226 ///
227 /// @param[in] fname File name.
228 ///
229 /// @return Polygonal dataset. Dataset is empty if file could not be read.
230 vtkSmartPointer<vtkPolyData> ReadOFF(const char *fname);
231 
232 /// Write polygonal dataset to Object File Format (.off) file
233 ///
234 /// @param[in] fname File name.
235 /// @param[in] polydata Polygonal dataset.
236 ///
237 /// @return Whether dataset was written successfully to the specified file.
238 bool WriteOFF(const char *fname, vtkPolyData *polydata);
239 
240 // =============================================================================
241 // GIFTI I/O functions -- https://www.nitrc.org/projects/gifti/
242 // =============================================================================
243 #if MIRTK_IO_WITH_GIFTI
244 
245 /// GIFTI meta data keys
246 ///
247 /// @sa Section 3.0 Standard MetaData of GIFTI file format specification at
248 /// https://www.nitrc.org/frs/download.php/2871/GIFTI_Surface_Format.pdf
249 class GiftiMetaData
250 {
251  // ---------------------------------------------------------------------------
252  // vtkInformation key instances for standard GIFTI meta data entries
253 public:
254 
255  /// Date and possibly time when the GIFTI file was written
256  static vtkInformationStringKey *DATE();
257 
258  /// Name of user that wrote the GIFTI file
259  static vtkInformationStringKey *USER_NAME();
260 
261  /// ID of subject whose anatomical structure the point set models
262  static vtkInformationStringKey *SUBJECT_ID();
263 
264  /// A unique string that identifies a surface
265  static vtkInformationStringKey *SURFACE_ID();
266 
267  /// A unique string that identifies a data array (UUID)
268  static vtkInformationStringKey *UNIQUE_ID();
269 
270  /// Name of GIFTI data array
271  static vtkInformationStringKey *NAME();
272 
273  /// Description of GIFTI file or data array
274  static vtkInformationStringKey *DESCRIPTION();
275 
276  /// Included in a GIFTI time series file, specifies repetition time (TR)
277  /// and is equivalent to the slice_duration of a NIfTI volume
278  static vtkInformationDoubleKey *TIME_STEP();
279 
280  /// Data space of point set before any coordinate system transformation
281  static vtkInformationStringKey *DATA_SPACE();
282 
283  /// Anatomical structure that the point set models
284  static vtkInformationStringKey *ANATOMICAL_STRUCTURE_PRIMARY();
285 
286  /// Further describe anatomical structure that the point set models
287  static vtkInformationStringKey *ANATOMICAL_STRUCTURE_SECONDARY();
288 
289  /// Describes geometry of the point set
290  static vtkInformationStringKey *GEOMETRIC_TYPE();
291 
292  /// Topology of surface model
293  static vtkInformationStringKey *TOPOLOGICAL_TYPE();
294 
295  /// Intent code of functional data array
296  static vtkInformationIntegerKey *INTENT_CODE();
297 
298  /// First parameter of statistical test
299  static vtkInformationDoubleKey *INTENT_P1();
300 
301  /// Second parameter of statistical test
302  static vtkInformationDoubleKey *INTENT_P2();
303 
304  /// Third parameter of statistical test
305  static vtkInformationDoubleKey *INTENT_P3();
306 
307  // ---------------------------------------------------------------------------
308  // vtkInformation key instances for HCP GIFTI meta data entries
309 
310  /// Information about software that produced the data file
311  ///
312  /// For example, HCP Workbench stores its version and the version of the used
313  /// runtime library, Git commit SHA, OS name, and compiler information here.
314  static vtkInformationStringKey *PROGRAM_PROVENANCE();
315 
316  /// Command and arguments that produced the (.func.gii) data file
317  static vtkInformationStringKey *PROVENANCE();
318 
319  /// Command and arguments of parent command that executed the command specified
320  /// by the "Provenance" meta data entry to produce the data file
321  ///
322  /// @sa PROVENANCE
323  static vtkInformationStringKey *PARENT_PROVENANCE();
324 
325  /// Working directory of the command that produced the data file
326  ///
327  /// @sa PROVENANCE
328  static vtkInformationStringKey *WORKING_DIRECTORY();
329 
330  // ---------------------------------------------------------------------------
331  // Sets of meta data keys
332 
333  /// Standard meta data keys of a GIFTI file
334  static Array<vtkInformationKey *> KeysForFile();
335 
336  /// Standard meta data keys of a GIFTI data array with specified intent
337  static Array<vtkInformationKey *> KeysForDataArray(int = -1);
338 
339  /// Get meta data value for given vtkInformationKey as string
340  static string Get(vtkInformation *, vtkInformationKey *);
341 };
342 
343 /// Read point set coordinates from GIFTI ([.coord].gii) file
344 ///
345 /// @param[in] fname File name.
346 /// @param[in,out] info vtkInformation to which to add geometric meta data.
347 /// If nullptr, the meta data is discarded.
348 /// @param[in] errmsg Whether to print error messages if any.
349 ///
350 /// @return Point set coordinates or empty set if file could not be read
351 /// or has no valid GIFTI data array with intent @c NIFTI_INTENT_POINTSET.
352 vtkSmartPointer<vtkPoints> ReadGIFTICoordinates(const char *fname,
353  vtkInformation *info = nullptr,
354  bool errmsg = false);
355 
356 /// Read surface topology from GIFTI ([.surf|.topo].gii) file
357 ///
358 /// @param[in] fname File name.
359 /// @param[in,out] info vtkInformation to which to add topological meta data.
360 /// If nullptr, the meta data is discarded.
361 /// @param[in] errmsg Whether to print error messages if any.
362 ///
363 /// @return Triangle list or nullptr if file could not be read or has no valid
364 /// GIFTI data array with intent @c NIFTI_INTENT_TRIANGLE.
365 vtkSmartPointer<vtkCellArray> ReadGIFTITopology(const char *fname,
366  vtkInformation *info = nullptr,
367  bool errmsg = false);
368 
369 /// Read point data arrays from GIFTI (.gii) file
370 ///
371 /// @param[in] fname File name.
372 /// @param[in] errmsg Whether to print error messages if any.
373 ///
374 /// @return Point data arrays or nullptr if file could not be read.
375 vtkSmartPointer<vtkPointData> ReadGIFTIPointData(const char *fname,
376  bool errmsg = false);
377 
378 /// Read polygonal dataset from GIFTI (.gii) file
379 ///
380 /// Standard GIFTI meta data is stored in the vtkInformation of the returned
381 /// vtkPolyData instance and the respective information of the corresponding
382 /// vtkDataArray instances of its point data.
383 ///
384 /// @param[in] fname File name.
385 /// @param[in,out] surface Polygonal dataset to which to add GIFTI data arrays.
386 /// If nullptr, a new polygonal dataset is allocated
387 /// and a GIFTI data array with @c NIFTI_INTENT_POINTSET
388 /// must be present in the GIFTI file. If input surface
389 /// has a previously read point set, the GIFTI file from
390 /// which to read additional point data can use sparse
391 /// storage using a data array with @c NIFTI_INTENT_NODE_INDEX
392 /// that specifies the points to which the read data array
393 /// values are added. Missing data values default to zero.
394 /// @param[in] errmsg Whether to print error messages if any.
395 ///
396 /// @return Polygonal dataset. Dataset is empty if file could not be read.
397 ///
398 /// Example:
399 /// @code
400 /// // Read geometry and topology of cortical surface model
401 /// vtkSmartPointer<vtkPolyData> surface = ReadGIFTI("cortex.surf.gii");
402 /// // Add shape measurements and functional statistics as surface point data
403 /// surface = ReadGIFTI("cortex.shape.gii", surface);
404 /// surface = ReadGIFTI("cortex.func.gii", surface);
405 /// @endcode
406 ///
407 /// @sa https://www.nitrc.org/projects/gifti/
408 vtkSmartPointer<vtkPolyData> ReadGIFTI(const char *fname,
409  vtkPolyData *surface = nullptr,
410  bool errmsg = false);
411 
412 /// Write polygonal dataset to GIFTI (.gii) file
413 ///
414 /// @param[in] fname File name. Based on the extension either all or only
415 /// certain data arrays of the polygonal dataset are saved.
416 /// - .surf.gii: Point coordinates and topology.
417 /// - .coords.gii: Point coordinates.
418 /// - .topo.gii: Topology.
419 /// - otherwise: Point coordinates, topology, and point data.
420 /// @param[in] polydata Polygonal dataset.
421 /// @param[in] fopt GIFTI file encoding.
422 ///
423 /// @return Whether dataset was written successfully to the specified file.
424 ///
425 /// @sa https://www.nitrc.org/projects/gifti/
426 bool WriteGIFTI(const char *fname, vtkPolyData *polydata, FileOption fopt = FO_Default);
427 
428 #endif // MIRTK_IO_WITH_GIFTI
429 
430 } // namespace mirtk
431 
432 #endif // MIRTK_PointSetIO_H
vtkSmartPointer< vtkPolyData > ReadPolyData(const char *fname, bool exit_on_failure=true)
const char * DefaultExtension(vtkDataSet *)
Default extension for given data set.
Default options.
Definition: PointSetIO.h:66
bool WriteDFS(const char *fname, vtkPolyData *polydata)
Unompressed binary.
Definition: PointSetIO.h:69
string Get(const ParameterList &params, string name)
Get parameter value from parameters list.
Definition: Object.h:202
vtkSmartPointer< vtkPointSet > ReadPointSetTable(const char *fname, char sep=',', vtkPointSet *pointset=nullptr)
bool WriteOFF(const char *fname, vtkPolyData *polydata)
Uncompressed ASCII.
Definition: PointSetIO.h:67
Definition: IOConfig.h:41
bool WriteTetGenPoly(const char *fname, vtkPolyData *polydata, const PointSet *holes=nullptr)
bool WritePointSet(const char *fname, vtkPointSet *pointset, FileOption fopt=FO_Default)
bool WriteTetGenNode(const char *fname, vtkPointSet *pointset)
bool WritePolyData(const char *fname, vtkPolyData *polydata, FileOption fopt=FO_Default)
vtkSmartPointer< vtkPolyData > ReadDFS(const char *fname)
FileOption
Enumeration of file type options.
Definition: PointSetIO.h:64
vtkSmartPointer< vtkPointSet > ReadPointSet(const char *fname, bool exit_on_failure=true)
(Compressed) binary
Definition: PointSetIO.h:68
bool WriteTetGenSMesh(const char *fname, vtkPolyData *polydata, const PointSet *holes=nullptr)
vtkSmartPointer< vtkPolyData > ReadOFF(const char *fname)
bool WritePointSetTable(const char *fname, vtkPointSet *pointset, char sep=',', bool ids=true, bool coords=true)