1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkMeshIOBase_h
19 #define itkMeshIOBase_h
20 #include "ITKIOMeshBaseExport.h"
21 
22 #include "itkByteSwapper.h"
23 #include "itkCellInterface.h"
24 #include "itkCovariantVector.h"
25 #include "itkDiffusionTensor3D.h"
26 #include "itkIntTypes.h"
27 #include "itkLightProcessObject.h"
28 #include "itkMatrix.h"
29 #include "itkRGBPixel.h"
30 #include "itkRGBAPixel.h"
31 #include "itkSymmetricSecondRankTensor.h"
32 #include "itkVariableLengthVector.h"
33 #include "itkVariableSizeMatrix.h"
34 #include "itkVector.h"
35 #include "itkNumberToString.h"
36 
37 #include <string>
38 #include <complex>
39 #include <fstream>
40 
41 namespace itk
42 {
43 /** \class MeshIOBase
44  * \brief Abstract superclass defines mesh IO interface.
45  *
46  * MeshIOBase is a class that reads and/or writes Mesh / QuadEdgeMesh data
47  * of a particular format (such as PNG or raw binary). The
48  * MeshIOBase encapsulates both the reading and writing of data. The
49  * MeshIOBase is used by the MeshFileReader class (to read data)
50  * and the MeshFileWriter (to write data) into a single file.
51  * Normally the user does not directly
52  * manipulate this class other than to instantiate it, set the FileName,
53  * and assign it to a MeshFileReader or MeshFileWriter.
54  *
55  * A Pluggable factory pattern is used this allows different kinds of readers
56  * to be registered (even at run time) without having to modify the
57  * code in this class.
58  *
59  * \author Wanlin Zhu. Uviversity of New South Wales, Australia.
60  *
61  * \sa MeshFileWriter
62  * \sa MeshFileReader
63  *
64  * \ingroup IOFilters
65  * \ingroup ITKIOMeshBase
66  *
67  */
68 
69 class ITKIOMeshBase_EXPORT MeshIOBase:public LightProcessObject
70 {
71 public:
72   ITK_DISALLOW_COPY_AND_ASSIGN(MeshIOBase);
73 
74   /** Standard class type aliases. */
75   using Self = MeshIOBase;
76   using Superclass = LightProcessObject;
77   using ConstPointer = SmartPointer< const Self >;
78   using Pointer = SmartPointer< Self >;
79 
80   /** Type for the list of strings to be used for extensions.  */
81   using ArrayOfExtensionsType = std::vector< std::string >;
82 
83   /** Type for representing size of bytes, and or positions along a file */
84   using StreamOffsetType = std::streamoff;
85 
86   using SizeValueType = IdentifierType;
87 
88   /**
89     * \class UnknownType
90     * Used to return information when types are unknown.
91     * \ingroup ITKIOMeshBase
92     */
93   class UnknownType {};
94 
95   /** Run-time type information (and related methods). */
96   itkTypeMacro(MeshIOBase, LightProcessObject);
97 
98   /** Set/Get the name of the file to be read. */
99   itkSetStringMacro(FileName);
100   itkGetStringMacro(FileName);
101 
102   /** Enums used to manipulate the point/cell pixel type. The pixel type provides
103      * context for automatic data conversions (for instance, RGB to
104      * SCALAR, VECTOR to SCALAR). */
105   typedef  enum {UNKNOWNPIXELTYPE, SCALAR, RGB, RGBA, OFFSET, VECTOR,
106                  POINT, COVARIANTVECTOR, SYMMETRICSECONDRANKTENSOR,
107                  DIFFUSIONTENSOR3D, COMPLEX, FIXEDARRAY, ARRAY, MATRIX,
108                  VARIABLELENGTHVECTOR, VARIABLESIZEMATRIX}  IOPixelType;
109 
110   /** Enums used to manipulate the component type. The component type
111    * refers to the actual storage class associated with either a
112    * SCALAR pixel type or elements of a compound pixel. */
113   typedef  enum {UNKNOWNCOMPONENTTYPE, UCHAR, CHAR, USHORT, SHORT, UINT, INT,
114                  ULONG, LONG, LONGLONG, ULONGLONG, FLOAT, DOUBLE, LDOUBLE} IOComponentType;
115 
116   /** Enums used to specify write style: whether binary or ASCII. Some
117     * subclasses use this, some ignore it. */
118   typedef  enum {ASCII, BINARY, TYPENOTAPPLICABLE} FileType;
119 
120   /** Enums used to specify byte order; whether Big Endian or Little Endian.
121   * Some subclasses use this, some ignore it. */
122   typedef  enum {BigEndian, LittleEndian, OrderNotApplicable} ByteOrder;
123 
124   /** Enums used to specify cell type */
125   typedef  enum {VERTEX_CELL = 0, LINE_CELL, TRIANGLE_CELL,
126                  QUADRILATERAL_CELL, POLYGON_CELL, TETRAHEDRON_CELL, HEXAHEDRON_CELL,
127                  QUADRATIC_EDGE_CELL, QUADRATIC_TRIANGLE_CELL,
128                  LAST_ITK_CELL, MAX_ITK_CELLS = 255}  CellGeometryType;
129 
130   /** Set/Get the type of the point/cell pixel. The PixelTypes provides context
131     * to the IO mechanisms for data conversions.  PixelTypes can be
132     * SCALAR, RGB, RGBA, VECTOR, COVARIANTVECTOR, POINT, INDEX. If
133     * the PIXELTYPE is SCALAR, then the NumberOfComponents should be 1.
134     * Any other of PIXELTYPE will have more than one component. */
135   itkSetEnumMacro(PointPixelType, IOPixelType);
136   itkGetEnumMacro(PointPixelType, IOPixelType);
137   itkSetEnumMacro(CellPixelType, IOPixelType);
138   itkGetEnumMacro(CellPixelType, IOPixelType);
139 
140   /** Set/Get the component type of the point, cell, point data and cell data.
141     This is always a native type. */
142   itkSetEnumMacro(PointComponentType, IOComponentType);
143   itkGetEnumMacro(PointComponentType, IOComponentType);
144   itkSetEnumMacro(CellComponentType, IOComponentType);
145   itkGetEnumMacro(CellComponentType, IOComponentType);
146   itkSetEnumMacro(PointPixelComponentType, IOComponentType);
147   itkGetEnumMacro(PointPixelComponentType, IOComponentType);
148   itkSetEnumMacro(CellPixelComponentType, IOComponentType);
149   itkGetEnumMacro(CellPixelComponentType, IOComponentType);
150 
151   template< typename T >
152   struct MapComponentType {
153     static constexpr IOComponentType CType = UNKNOWNCOMPONENTTYPE;
154   };
155 
156   template< typename T >
157   void SetPixelType(const T & itkNotUsed(dummy), bool UsePointPixel = true)
158   {
159     if ( UsePointPixel )
160       {
161       SetNumberOfPointPixelComponents(1);
162       SetPointPixelComponentType(MapComponentType< T >::CType);
163       SetPointPixelType(SCALAR);
164       }
165     else
166       {
167       SetNumberOfCellPixelComponents(1);
168       SetCellPixelComponentType(MapComponentType< T >::CType);
169       SetCellPixelType(SCALAR);
170       }
171   }
172 
173   template< typename T >
174   void SetPixelType(const RGBPixel< T > & itkNotUsed(dummy), bool UsePointPixel = true)
175   {
176     if ( UsePointPixel )
177       {
178       SetNumberOfPointPixelComponents(3);
179       SetPointPixelComponentType(MapComponentType< T >::CType);
180       SetPointPixelType(RGB);
181       }
182     else
183       {
184       SetNumberOfCellPixelComponents(3);
185       SetCellPixelComponentType(MapComponentType< T >::CType);
186       SetCellPixelType(RGB);
187       }
188   }
189 
190   template< typename T >
191   void SetPixelType(const RGBAPixel< T > & itkNotUsed(dummy), bool UsePointPixel = true)
192   {
193     if ( UsePointPixel )
194       {
195       SetNumberOfPointPixelComponents(4);
196       SetPointPixelComponentType(MapComponentType< T >::CType);
197       SetPointPixelType(RGBA);
198       }
199     else
200       {
201       SetNumberOfCellPixelComponents(4);
202       SetCellPixelComponentType(MapComponentType< T >::CType);
203       SetCellPixelType(RGBA);
204       }
205   }
206 
207   template< typename T, unsigned int VLength >
208   void SetPixelType(const Vector< T, VLength > & itkNotUsed(dummy), bool UsePointPixel = true)
209   {
210     if ( UsePointPixel )
211       {
212       SetNumberOfPointPixelComponents(VLength);
213       SetPointPixelComponentType(MapComponentType< T >::CType);
214       SetPointPixelType(VECTOR);
215       }
216     else
217       {
218       SetNumberOfCellPixelComponents(VLength);
219       SetCellPixelComponentType(MapComponentType< T >::CType);
220       SetCellPixelType(VECTOR);
221       }
222   }
223 
224   template< typename T, unsigned int VLength >
225   void SetPixelType(const CovariantVector< T, VLength > & itkNotUsed(dummy), bool UsePointPixel = true)
226   {
227     if ( UsePointPixel )
228       {
229       SetNumberOfPointPixelComponents(VLength);
230       SetPointPixelComponentType(MapComponentType< T >::CType);
231       SetPointPixelType(COVARIANTVECTOR);
232       }
233     else
234       {
235       SetNumberOfCellPixelComponents(VLength);
236       SetCellPixelComponentType(MapComponentType< T >::CType);
237       SetCellPixelType(COVARIANTVECTOR);
238       }
239   }
240 
241   template< typename T, unsigned int VLength >
242   void SetPixelType(const FixedArray< T, VLength > & itkNotUsed(dummy), bool UsePointPixel = true)
243   {
244     if ( UsePointPixel )
245       {
246       SetNumberOfPointPixelComponents(VLength);
247       SetPointPixelComponentType(MapComponentType< T >::CType);
248       SetPointPixelType(FIXEDARRAY);
249       }
250     else
251       {
252       SetNumberOfCellPixelComponents(VLength);
253       SetCellPixelComponentType(MapComponentType< T >::CType);
254       SetCellPixelType(FIXEDARRAY);
255       }
256   }
257 
258   template< typename T, unsigned int VLength >
259   void SetPixelType(const SymmetricSecondRankTensor< T, VLength > itkNotUsed(dummy), bool UsePointPixel = true)
260   {
261     if ( UsePointPixel )
262       {
263       SetNumberOfPointPixelComponents(VLength * ( VLength + 1 ) / 2);
264       SetPointPixelComponentType(MapComponentType< T >::CType);
265       SetPointPixelType(SYMMETRICSECONDRANKTENSOR);
266       }
267     else
268       {
269       SetNumberOfCellPixelComponents(VLength * ( VLength + 1 ) / 2);
270       SetCellPixelComponentType(MapComponentType< T >::CType);
271       SetCellPixelType(SYMMETRICSECONDRANKTENSOR);
272       }
273   }
274 
275   template< typename T >
276   void SetPixelType(const DiffusionTensor3D< T > & itkNotUsed(dummy), bool UsePointPixel = true)
277   {
278     if ( UsePointPixel )
279       {
280       SetNumberOfPointPixelComponents(6);
281       SetPointPixelComponentType(MapComponentType< T >::CType);
282       SetPointPixelType(DIFFUSIONTENSOR3D);
283       }
284     else
285       {
286       SetNumberOfCellPixelComponents(6);
287       SetCellPixelComponentType(MapComponentType< T >::CType);
288       SetCellPixelType(DIFFUSIONTENSOR3D);
289       }
290   }
291 
292   template< typename T, unsigned int NR, unsigned int NC >
293   void SetPixelType(const Matrix< T, NR, NC > & itkNotUsed(dummy), bool UsePointPixel = true)
294   {
295     if ( UsePointPixel )
296       {
297       SetNumberOfPointPixelComponents(NR * NC);
298       SetPointPixelComponentType(MapComponentType< T >::CType);
299       SetPointPixelType(MATRIX);
300       }
301     else
302       {
303       SetNumberOfCellPixelComponents(NR * NC);
304       SetCellPixelComponentType(MapComponentType< T >::CType);
305       SetCellPixelType(MATRIX);
306       }
307   }
308 
309   template< typename T >
310   void SetPixelType(const std::complex< T > & itkNotUsed(dummy), bool UsePointPixel = true)
311   {
312     if ( UsePointPixel )
313       {
314       SetNumberOfPointPixelComponents(2);
315       SetPointPixelComponentType(MapComponentType< T >::CType);
316       SetPointPixelType(COMPLEX);
317       }
318     else
319       {
320       SetNumberOfCellPixelComponents(2);
321       SetCellPixelComponentType(MapComponentType< T >::CType);
322       SetCellPixelType(COMPLEX);
323       }
324   }
325 
326   template< typename T >
327   void SetPixelType(const Array< T > & array, bool UsePointPixel = true)
328   {
329     if ( UsePointPixel )
330       {
331       SetNumberOfPointPixelComponents( array.Size() );
332       SetPointPixelComponentType(MapComponentType< T >::CType);
333       SetPointPixelType(ARRAY);
334       }
335     else
336       {
337       SetNumberOfCellPixelComponents( array.Size() );
338       SetCellPixelComponentType(MapComponentType< T >::CType);
339       SetCellPixelType(ARRAY);
340       }
341   }
342 
343   template< typename T >
344   void SetPixelType(const VariableLengthVector< T > & vector, bool UsePointPixel = true)
345   {
346     if ( UsePointPixel )
347       {
348       SetNumberOfPointPixelComponents( vector.Size() );
349       SetPointPixelComponentType(MapComponentType< T >::CType);
350       SetPointPixelType(VARIABLELENGTHVECTOR);
351       }
352     else
353       {
354       SetNumberOfCellPixelComponents( vector.Size() );
355       SetCellPixelComponentType(MapComponentType< T >::CType);
356       SetCellPixelType(VARIABLELENGTHVECTOR);
357       }
358   }
359 
360   template< typename T >
361   void SetPixelType(const VariableSizeMatrix< T > & matrix, bool UsePointPixel = true)
362   {
363     if ( UsePointPixel )
364       {
365       SetNumberOfPointPixelComponents( matrix.Rows() * matrix.Cols() );
366       SetPointPixelComponentType(MapComponentType< T >::CType);
367       SetPointPixelType(VARIABLESIZEMATRIX);
368       }
369     else
370       {
371       SetNumberOfCellPixelComponents( matrix.Rows() * matrix.Cols() );
372       SetCellPixelComponentType(MapComponentType< T >::CType);
373       SetCellPixelType(VARIABLESIZEMATRIX);
374       }
375   }
376 
377   /** Set/Get the number of components per pixel in the mesh. This may
378      * be set by the reading process. For SCALAR pixel types,
379      * NumberOfComponents will be 1.  For other pixel types,
380      * NumberOfComponents will be greater than or equal to one. */
381   itkSetMacro(NumberOfPointPixelComponents, unsigned int);
382   itkGetConstMacro(NumberOfPointPixelComponents, unsigned int);
383   itkSetMacro(NumberOfCellPixelComponents, unsigned int);
384   itkGetConstMacro(NumberOfCellPixelComponents, unsigned int);
385   itkSetMacro(PointDimension, unsigned int);
386   itkGetConstMacro(PointDimension, unsigned int);
387   itkSetMacro(NumberOfPoints, SizeValueType);
388   itkGetConstMacro(NumberOfPoints, SizeValueType);
389   itkSetMacro(NumberOfCells, SizeValueType);
390   itkGetConstMacro(NumberOfCells, SizeValueType);
391   itkSetMacro(NumberOfPointPixels, SizeValueType);
392   itkGetConstMacro(NumberOfPointPixels, SizeValueType);
393   itkSetMacro(NumberOfCellPixels, SizeValueType);
394   itkGetConstMacro(NumberOfCellPixels, SizeValueType);
395   itkSetMacro(CellBufferSize, SizeValueType);
396   itkGetConstMacro(CellBufferSize, SizeValueType);
397   itkSetMacro(UpdatePoints, bool);
398   itkGetConstMacro(UpdatePoints, bool);
399   itkSetMacro(UpdateCells, bool);
400   itkGetConstMacro(UpdateCells, bool);
401   itkSetMacro(UpdatePointData, bool);
402   itkGetConstMacro(UpdatePointData, bool);
403   itkSetMacro(UpdateCellData, bool);
404   itkGetConstMacro(UpdateCellData, bool);
405 
406   unsigned int GetComponentSize(IOComponentType componentType) const;
407 
408   /** Convenience method returns the IOComponentType as a string. This can be
409      * used for writing output files. */
410   std::string GetComponentTypeAsString(IOComponentType) const;
411 
412   /** Convenience method returns the IOPixelType as a string. This can be
413    * used for writing output files. */
414   std::string GetPixelTypeAsString(IOPixelType) const;
415 
416   /** These methods control whether the file is written binary or ASCII.
417   * Many file formats (i.e., subclasses) ignore this flag. */
418   itkSetEnumMacro(FileType, FileType);
419   itkGetEnumMacro(FileType, FileType);
420 
SetFileTypeToASCII()421   void SetFileTypeToASCII()
422   {
423     this->SetFileType(ASCII);
424   }
425 
SetFileTypeToBinary()426   void SetFileTypeToBinary()
427   {
428     this->SetFileType(BINARY);
429   }
430 
431   /** These methods indicate the byte ordering of the file you are
432      * trying to read in. These methods will then either swap or not
433      * swap the bytes depending on the byte ordering of the machine it
434      * is being run on. For example, reading in a BigEndian file on a
435      * BigEndian machine will result in no swapping. Trying to read the
436      * same file on a LittleEndian machine will result in swapping.
437      * Note: most UNIX machines are BigEndian while PC's and VAX's are
438      * LittleEndian. So if the file you are reading in was generated on
439      * a VAX or PC, SetByteOrderToLittleEndian() otherwise
440      * SetByteOrderToBigEndian().  Some MeshIOBase subclasses
441      * ignore these methods. */
442   itkSetEnumMacro(ByteOrder, ByteOrder);
443   itkGetEnumMacro(ByteOrder, ByteOrder);
444 
SetByteOrderToBigEndian()445   void SetByteOrderToBigEndian()
446   {
447     this->SetByteOrder(BigEndian);
448   }
449 
SetByteOrderToLittleEndian()450   void SetByteOrderToLittleEndian()
451   {
452     this->SetByteOrder(LittleEndian);
453   }
454 
455   /** Set/Get a boolean to use the compression or not. */
456   itkSetMacro(UseCompression, bool);
457   itkGetConstMacro(UseCompression, bool);
458   itkBooleanMacro(UseCompression);
459 
460   /** Convenience method returns the FileType as a string. This can be
461      * used for writing output files. */
462   std::string GetFileTypeAsString(FileType) const;
463 
464   /** Convenience method returns the ByteOrder as a string. This can be
465    * used for writing output files. */
466   std::string GetByteOrderAsString(ByteOrder) const;
467 
468   /*-------- This part of the interfaces deals with reading data ----- */
469   /** Determine the file type. Returns true if this MeshIO can read the
470      * file specified. */
471   virtual bool CanReadFile(const char *) = 0;
472 
473   /** Determin the required information and whether need to ReadPoints,
474     ReadCells, ReadPointData and ReadCellData */
475   virtual void ReadMeshInformation() = 0;
476 
477   /** Reads the data from disk into the memory buffer provided. */
478   virtual void ReadPoints(void *buffer) = 0;
479 
480   virtual void ReadCells(void *buffer) = 0;
481 
482   virtual void ReadPointData(void *buffer) = 0;
483 
484   virtual void ReadCellData(void *buffer) = 0;
485 
486   /*-------- This part of the interfaces deals with writing data ----- */
487 
488   /** Writes the data to disk from the memory buffer provided. Make sure
489      * that the IORegions has been set properly. */
490   virtual bool CanWriteFile(const char *)  = 0;
491 
492   virtual void WriteMeshInformation() = 0;
493 
494   virtual void WritePoints(void *buffer) = 0;
495 
496   virtual void WriteCells(void *buffer) = 0;
497 
498   virtual void WritePointData(void *buffer) = 0;
499 
500   virtual void WriteCellData(void *buffer) = 0;
501 
502   virtual void Write() = 0;
503 
504   /** This method returns an array with the list of filename extensions
505    * supported for reading by this MeshIO class. This is intended to
506    * facilitate GUI and application level integration.
507    */
508   const ArrayOfExtensionsType & GetSupportedReadExtensions() const;
509 
510   /** This method returns an array with the list of filename extensions
511    * supported for writing by this MeshIO class. This is intended to
512    * facilitate GUI and application level integration.
513    */
514   const ArrayOfExtensionsType & GetSupportedWriteExtensions() const;
515 
516 protected:
517   MeshIOBase();
518   ~MeshIOBase() override = default;
519 
520   void PrintSelf(std::ostream & os, Indent indent) const override;
521 
522   /** Insert an extension to the list of supported extensions for reading. */
523   void AddSupportedReadExtension(const char *extension);
524 
525   /** Insert an extension to the list of supported extensions for writing. */
526   void AddSupportedWriteExtension(const char *extension);
527 
528   /** Read data from input file stream to buffer with ascii style */
529   template< typename T >
ReadBufferAsAscii(T * buffer,std::ifstream & inputFile,SizeValueType numberOfComponents)530   void ReadBufferAsAscii(T *buffer, std::ifstream & inputFile, SizeValueType numberOfComponents)
531   {
532     for ( SizeValueType i = 0; i < numberOfComponents; i++ )
533       {
534       inputFile >> buffer[i];
535       }
536   }
537 
538   /** Read data from input file to buffer with binary style */
539   template< typename T >
ReadBufferAsBinary(T * buffer,std::ifstream & inputFile,SizeValueType numberOfComponents)540   void ReadBufferAsBinary(T *buffer, std::ifstream & inputFile, SizeValueType numberOfComponents)
541   {
542     inputFile.read( reinterpret_cast< char * >( buffer ), numberOfComponents * sizeof( T ) );
543 
544     if ( m_ByteOrder == BigEndian )
545       {
546       if ( itk::ByteSwapper< T >::SystemIsLittleEndian() )
547         {
548         itk::ByteSwapper< T >::SwapRangeFromSystemToBigEndian(buffer, numberOfComponents);
549         }
550       }
551     else if ( m_ByteOrder == LittleEndian )
552       {
553       if ( itk::ByteSwapper< T >::SystemIsBigEndian() )
554         {
555         itk::ByteSwapper< T >::SwapRangeFromSystemToLittleEndian(buffer, numberOfComponents);
556         }
557       }
558   }
559 
560   /** Write buffer to output file stream with ascii style */
561   template< typename T >
WriteBufferAsAscii(T * buffer,std::ofstream & outputFile,SizeValueType numberOfLines,SizeValueType numberOfComponents)562   void WriteBufferAsAscii(T *buffer, std::ofstream & outputFile, SizeValueType numberOfLines, SizeValueType numberOfComponents)
563   {
564     NumberToString<T> convert;
565     for ( SizeValueType ii = 0; ii < numberOfLines; ii++ )
566       {
567       for ( SizeValueType jj = 0; jj < numberOfComponents; jj++ )
568         {
569         outputFile << convert(buffer[ii * numberOfComponents + jj]) << "  ";
570         }
571       outputFile << '\n';
572       }
573   }
574 
575   /** Write buffer to output file stream with binary style */
576   template< typename TOutput, typename TInput >
WriteBufferAsBinary(TInput * buffer,std::ofstream & outputFile,SizeValueType numberOfComponents)577   void WriteBufferAsBinary(TInput *buffer, std::ofstream & outputFile, SizeValueType numberOfComponents)
578   {
579     if ( typeid( TInput ) == typeid( TOutput ) )
580       {
581       if ( m_ByteOrder == BigEndian && itk::ByteSwapper< TInput >::SystemIsLittleEndian() )
582         {
583         itk::ByteSwapper< TInput >::SwapRangeFromSystemToBigEndian(buffer, numberOfComponents);
584         }
585       else if ( m_ByteOrder == LittleEndian && itk::ByteSwapper< TInput >::SystemIsBigEndian() )
586         {
587         itk::ByteSwapper< TInput >::SwapRangeFromSystemToLittleEndian(buffer, numberOfComponents);
588         }
589 
590       outputFile.write(reinterpret_cast< char * >( buffer ), numberOfComponents);
591       }
592     else
593       {
594       auto * data = new TOutput[numberOfComponents];
595       for ( SizeValueType ii = 0; ii < numberOfComponents; ii++ )
596         {
597         data[ii] = static_cast< TOutput >( buffer[ii] );
598         }
599 
600       if ( m_ByteOrder == BigEndian && itk::ByteSwapper< TOutput >::SystemIsLittleEndian() )
601         {
602         itk::ByteSwapper< TOutput >::SwapRangeFromSystemToBigEndian(data, numberOfComponents);
603         }
604       else if ( m_ByteOrder == LittleEndian && itk::ByteSwapper< TOutput >::SystemIsBigEndian() )
605         {
606         itk::ByteSwapper< TOutput >::SwapRangeFromSystemToLittleEndian(data, numberOfComponents);
607         }
608 
609       outputFile.write(reinterpret_cast< char * >( data ), numberOfComponents);
610       delete[] data;
611       }
612   }
613 
614   /** Read cells from a data buffer, used when writting cells. This function
615     write all kind of cells as it is stored in cells container. It is used when
616     cells container have only one kind of cells */
617   template< typename TInput, typename TOutput >
ReadCellsBuffer(TInput * input,TOutput * output)618   void ReadCellsBuffer(TInput *input, TOutput *output)
619   {
620     if ( input && output )
621       {
622       SizeValueType inputIndex = NumericTraits< SizeValueType >::ZeroValue();
623       SizeValueType outputIndex = NumericTraits< SizeValueType >::ZeroValue();
624       for ( SizeValueType ii = 0; ii < m_NumberOfCells; ii++ )
625         {
626         inputIndex++; // ignore the cell type
627         auto numberOfPoints = static_cast< unsigned int >( input[inputIndex++] );
628         for ( unsigned int jj = 0; jj < numberOfPoints; jj++ )
629           {
630           output[outputIndex++] = static_cast< TOutput >( input[inputIndex++] );
631           }
632         }
633       }
634   }
635 
636   /** Read cells from input buffer, used when Writting cells. This function only
637     write specified type of cells(used when input cells container composes
638     multiple type of cells and only want to write a specified cell type */
639   template< typename TInput, typename TOutput >
ReadCellsBuffer(TInput * input,TOutput * output,MeshIOBase::CellGeometryType type)640   void ReadCellsBuffer(TInput *input, TOutput *output, MeshIOBase::CellGeometryType type)
641   {
642     if ( input && output )
643       {
644       SizeValueType inputIndex = itk::NumericTraits< SizeValueType >::ZeroValue();
645       SizeValueType outputIndex = itk::NumericTraits< SizeValueType >::ZeroValue();
646 
647       for ( SizeValueType ii = 0; ii < m_NumberOfCells; ii++ )
648         {
649         auto cellType = static_cast< MeshIOBase::CellGeometryType >( input[inputIndex++] );
650         auto nn = static_cast< unsigned int >( input[inputIndex++] );
651         if ( cellType == type )
652           {
653           output[outputIndex++] = nn;
654           for ( unsigned int jj = 0; jj < nn; jj++ )
655             {
656             output[outputIndex++] = static_cast< TOutput >( input[inputIndex++] );
657             }
658           }
659         else
660           {
661           inputIndex += nn;
662           }
663         }
664       }
665   }
666 
667   /** Write cells to a data buffer, used when readding mesh, used for cellType
668     with constant number of points */
669   template< typename TInput, typename TOutput >
WriteCellsBuffer(TInput * input,TOutput * output,CellGeometryType cellType,unsigned int numberOfPoints,SizeValueType numberOfCells)670   void WriteCellsBuffer(TInput *input, TOutput *output, CellGeometryType cellType, unsigned int numberOfPoints, SizeValueType numberOfCells)
671   {
672     if ( input && output )
673       {
674       SizeValueType inputIndex = NumericTraits< SizeValueType >::ZeroValue();
675       SizeValueType outputIndex = NumericTraits< SizeValueType >::ZeroValue();
676       for ( SizeValueType ii = 0; ii < numberOfCells; ii++ )
677         {
678         output[outputIndex++] = static_cast< TOutput >( cellType );
679         output[outputIndex++] = static_cast< TOutput >( numberOfPoints );
680         for ( unsigned int jj = 0; jj < numberOfPoints; jj++ )
681           {
682           output[outputIndex++] = static_cast< TOutput >( input[inputIndex++] );
683           }
684         }
685       }
686   }
687 
688   /** Write cells to a data buffer, used when readding mesh, used for cellType
689     with non-constant number of points */
690   template< typename TInput, typename TOutput >
WriteCellsBuffer(TInput * input,TOutput * output,CellGeometryType cellType,SizeValueType numberOfCells)691   void WriteCellsBuffer(TInput *input, TOutput *output, CellGeometryType cellType, SizeValueType numberOfCells)
692   {
693     if ( input && output )
694       {
695       SizeValueType inputIndex = NumericTraits< SizeValueType >::ZeroValue();
696       SizeValueType outputIndex = NumericTraits< SizeValueType >::ZeroValue();
697       for ( SizeValueType ii = 0; ii < numberOfCells; ii++ )
698         {
699         auto numberOfPoints = static_cast< unsigned int >( input[inputIndex++] );
700         output[outputIndex++] = static_cast< TOutput >( cellType );
701         output[outputIndex++] = static_cast< TOutput >( numberOfPoints );
702         for ( unsigned int jj = 0; jj < numberOfPoints; jj++ )
703           {
704           output[outputIndex++] = static_cast< TOutput >( input[inputIndex++] );
705           }
706         }
707       }
708   }
709 
710 protected:
711   /** Big or Little Endian, and the type of the file. (May be ignored.) */
712   ByteOrder m_ByteOrder{OrderNotApplicable};
713   FileType  m_FileType{ASCII};
714 
715   /** Filename to read */
716   std::string m_FileName;
717 
718   /** Should we compress the data? */
719   bool m_UseCompression{false};
720 
721   /** Used internally to keep track of the type of the component. */
722   IOComponentType m_PointComponentType{UNKNOWNCOMPONENTTYPE};
723   IOComponentType m_CellComponentType{UNKNOWNCOMPONENTTYPE};
724   IOComponentType m_PointPixelComponentType{UNKNOWNCOMPONENTTYPE};
725   IOComponentType m_CellPixelComponentType{UNKNOWNCOMPONENTTYPE};
726 
727   /** Used internally to keep track of the type of the pixel. */
728   IOPixelType m_PointPixelType{SCALAR};
729   IOPixelType m_CellPixelType{SCALAR};
730 
731   /** Stores the number of components per pixel. This will be 1 for
732     * grayscale images, 3 for RGBPixel images, and 4 for RGBPixelA images. */
733   unsigned int m_NumberOfPointPixelComponents{0};
734   unsigned int m_NumberOfCellPixelComponents{0};
735 
736   /** The number of independent dimensions in the point. */
737   SizeValueType m_PointDimension{3};
738 
739   /** The number of points and cells */
740   SizeValueType m_NumberOfPoints;
741   SizeValueType m_NumberOfCells;
742   SizeValueType m_NumberOfPointPixels;
743   SizeValueType m_NumberOfCellPixels;
744 
745   /** The buffer size of cells */
746   SizeValueType m_CellBufferSize;
747 
748   /** Flags indicate whether read or write points, cells, point data and cell
749     data */
750   bool m_UpdatePoints{false};
751   bool m_UpdateCells{false};
752   bool m_UpdatePointData{false};
753   bool m_UpdateCellData{false};
754 
755 private:
756   ArrayOfExtensionsType m_SupportedReadExtensions;
757   ArrayOfExtensionsType m_SupportedWriteExtensions;
758 };
759 #define MESHIOBASE_TYPEMAP(type, ctype)            \
760   template< >                                      \
761   struct MeshIOBase:: MapComponentType< type >     \
762   {                                                \
763     static constexpr IOComponentType CType = ctype;    \
764   }
765 
766 MESHIOBASE_TYPEMAP(unsigned char, UCHAR);
767 MESHIOBASE_TYPEMAP(char, CHAR);
768 MESHIOBASE_TYPEMAP(unsigned short, USHORT);
769 MESHIOBASE_TYPEMAP(short, SHORT);
770 MESHIOBASE_TYPEMAP(unsigned int, UINT);
771 MESHIOBASE_TYPEMAP(int, INT);
772 MESHIOBASE_TYPEMAP(unsigned long, ULONG);
773 MESHIOBASE_TYPEMAP(long, LONG);
774 MESHIOBASE_TYPEMAP(unsigned long long, ULONGLONG);
775 MESHIOBASE_TYPEMAP(long long, LONGLONG);
776 MESHIOBASE_TYPEMAP(float, FLOAT);
777 MESHIOBASE_TYPEMAP(double, DOUBLE);
778 MESHIOBASE_TYPEMAP(long double, LDOUBLE);
779 #undef MESHIOBASE_TYPEMAP
780 } // end namespace itk
781 
782 #endif
783