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 itkMeshFileWriter_hxx
19 #define itkMeshFileWriter_hxx
20 
21 #include "itkCommand.h"
22 #include "itkDataObject.h"
23 #include "itkMeshConvertPixelTraits.h"
24 #include "itkMeshIOFactory.h"
25 #include "itkMeshFileWriter.h"
26 #include "itkObjectFactoryBase.h"
27 
28 #include "vnl/vnl_vector.h"
29 
30 namespace itk
31 {
32 template< typename TInputMesh >
33 MeshFileWriter< TInputMesh >
MeshFileWriter()34 ::MeshFileWriter()
35 {
36   m_MeshIO = nullptr;
37   m_UseCompression = false;
38   m_FactorySpecifiedMeshIO = false;
39   m_UserSpecifiedMeshIO = false;
40   m_FileTypeIsBINARY = false;
41 }
42 
43 template< typename TInputMesh >
44 void
45 MeshFileWriter< TInputMesh >
SetInput(const InputMeshType * input)46 ::SetInput(const InputMeshType *input)
47 {
48   this->ProcessObject::SetNthInput( 0, const_cast< TInputMesh * >( input ) );
49 }
50 
51 template< typename TInputMesh >
52 const typename MeshFileWriter< TInputMesh >::InputMeshType *
53 MeshFileWriter< TInputMesh >
GetInput()54 ::GetInput()
55 {
56   if ( this->GetNumberOfInputs() < 1 )
57     {
58     return nullptr;
59     }
60 
61   return static_cast< TInputMesh * >( this->ProcessObject::GetInput(0) );
62 }
63 
64 template< typename TInputMesh >
65 const typename MeshFileWriter< TInputMesh >::InputMeshType *
66 MeshFileWriter< TInputMesh >
GetInput(unsigned int idx)67 ::GetInput(unsigned int idx)
68 {
69   return static_cast< TInputMesh * >( this->ProcessObject::GetInput(idx) );
70 }
71 
72 template< typename TInputMesh >
73 void
74 MeshFileWriter< TInputMesh >
Write()75 ::Write()
76 {
77   const InputMeshType *input = this->GetInput();
78 
79   itkDebugMacro(<< "Writing an mesh file");
80 
81   // Make sure input is available
82   if ( input == nullptr )
83     {
84     itkExceptionMacro(<< "No input to writer!");
85     }
86 
87   // Make sure that we can write the file given the name
88   if ( m_FileName.empty() )
89     {
90     throw MeshFileWriterException(__FILE__, __LINE__, "FileName must be specified", ITK_LOCATION);
91     }
92 
93   if ( !( m_UserSpecifiedMeshIO && !m_MeshIO.IsNull() ) )
94     {
95     // Try creating via factory
96     if ( m_MeshIO.IsNull() )
97       {
98       itkDebugMacro(<< "Attempting factory creation of MeshIO for file: " << m_FileName);
99       m_MeshIO = MeshIOFactory::CreateMeshIO(m_FileName.c_str(), MeshIOFactory::WriteMode);
100       m_FactorySpecifiedMeshIO = true;
101       }
102     else
103       {
104       if ( m_FactorySpecifiedMeshIO && !m_MeshIO->CanWriteFile( m_FileName.c_str() ) )
105         {
106         itkDebugMacro(<< "MeshIO exists but doesn't know how to write file:" << m_FileName);
107         itkDebugMacro(<< "Attempting creation of MeshIO with a factory for file:" << m_FileName);
108         m_MeshIO = MeshIOFactory::CreateMeshIO(m_FileName.c_str(), MeshIOFactory::WriteMode);
109         m_FactorySpecifiedMeshIO = true;
110         }
111       }
112     }
113 
114   if ( m_MeshIO.IsNull() )
115     {
116     MeshFileWriterException e(__FILE__, __LINE__);
117     std::ostringstream      msg;
118     msg << " Could not create IO object for file " << m_FileName.c_str() << std::endl;
119     msg << "  Tried to create one of the following:" << std::endl;
120       {
121       for (auto & allobject : ObjectFactoryBase::CreateAllInstance("itkMeshIOBase") )
122         {
123         auto * io = dynamic_cast< MeshIOBase * >( allobject.GetPointer() );
124         msg << "    " << io->GetNameOfClass() << std::endl;
125         }
126       }
127 
128     msg << "  You probably failed to set a file suffix, or" << std::endl;
129     msg << "    set the suffix to an unsupported type." << std::endl;
130     e.SetDescription( msg.str().c_str() );
131     e.SetLocation(ITK_LOCATION);
132     throw e;
133     }
134 
135   // NOTE: this const_cast<> is due to the lack of const-correctness
136   // of the ProcessObject.
137   auto * nonConstInput = const_cast< InputMeshType * >( input );
138 
139   // Update the input.
140   // Streaming is not supported at this time.
141   nonConstInput->SetRequestedRegionToLargestPossibleRegion();
142   nonConstInput->Update();
143 
144   if ( m_FileTypeIsBINARY )
145     {
146     m_MeshIO->SetFileType(MeshIOBase::BINARY);
147     }
148   else
149     {
150     m_MeshIO->SetFileType(MeshIOBase::ASCII);
151     }
152 
153   if ( m_UseCompression )
154     {
155     m_MeshIO->UseCompressionOn();
156     }
157   else
158     {
159     m_MeshIO->UseCompressionOff();
160     }
161 
162   // Setup the MeshIO
163   m_MeshIO->SetFileName( m_FileName.c_str() );
164 
165   // Whether write points
166   if ( input->GetPoints() && input->GetNumberOfPoints() )
167     {
168     m_MeshIO->SetUpdatePoints(true);
169     m_MeshIO->SetNumberOfPoints( input->GetNumberOfPoints() );
170     m_MeshIO->SetPointDimension(TInputMesh::PointDimension);
171     m_MeshIO->SetPointComponentType(MeshIOBase::MapComponentType< typename TInputMesh::PointType::ValueType >::CType);
172     }
173 
174   // Whether write cells
175   if ( input->GetCells() && input->GetNumberOfCells() )
176     {
177     SizeValueType cellsBufferSize = 2 * input->GetNumberOfCells();
178     for ( typename TInputMesh::CellsContainerConstIterator ct = input->GetCells()->Begin(); ct != input->GetCells()->End(); ++ct )
179       {
180       cellsBufferSize += ct->Value()->GetNumberOfPoints();
181       }
182     m_MeshIO->SetCellBufferSize(cellsBufferSize);
183     m_MeshIO->SetUpdateCells(true);
184     m_MeshIO->SetNumberOfCells( input->GetNumberOfCells() );
185     m_MeshIO->SetCellComponentType(MeshIOBase::MapComponentType< typename TInputMesh::PointIdentifier >::CType);
186     }
187 
188   // Whether write point data
189   if ( input->GetPointData() && input->GetPointData()->Size() )
190     {
191     m_MeshIO->SetUpdatePointData(true);
192     m_MeshIO->SetNumberOfPointPixels( input->GetPointData()->Size() );
193     // m_MeshIO->SetNumberOfPointPixelComponents(MeshConvertPixelTraits<typename
194     // TInputMesh::PixelType>::GetNumberOfComponents());
195     m_MeshIO->SetPixelType(input->GetPointData()->ElementAt(0), true);
196     }
197 
198   // Whether write cell data
199   if ( input->GetCellData() && input->GetCellData()->Size() )
200     {
201     m_MeshIO->SetUpdateCellData(true);
202     m_MeshIO->SetNumberOfCellPixels( input->GetCellData()->Size() );
203     // m_MeshIO->SetNumberOfCellPixelComponents(MeshConvertPixelTraits<typename
204     // TInputMesh::CellPixelType>::GetNumberOfComponents());
205     m_MeshIO->SetPixelType(input->GetCellData()->ElementAt(0), false);
206     }
207 
208   this->InvokeEvent( StartEvent() );
209 
210   // Write mesh information
211   m_MeshIO->WriteMeshInformation();
212 
213   // write points
214   if ( input->GetPoints() && input->GetNumberOfPoints() )
215     {
216     WritePoints();
217     }
218 
219   // Write cells
220   if ( input->GetCells() && input->GetNumberOfCells() )
221     {
222     WriteCells();
223     }
224 
225   // Write point data
226   if ( input->GetPointData() && input->GetPointData()->Size() )
227     {
228     WritePointData();
229     }
230 
231   // Write cell data
232   if ( input->GetCellData() && input->GetCellData()->Size() )
233     {
234     WriteCellData();
235     }
236 
237   // Write to disk
238   m_MeshIO->Write();
239 
240   // Notify end event observers
241   this->InvokeEvent( EndEvent() );
242 
243   // Release upstream data if requested
244   this->ReleaseInputs();
245 }
246 
247 template< typename TInputMesh >
248 void
249 MeshFileWriter< TInputMesh >
WritePoints()250 ::WritePoints()
251 {
252   const InputMeshType *input = this->GetInput();
253 
254   itkDebugMacro(<< "Writing points: " << m_FileName);
255   SizeValueType pointsBufferSize = input->GetNumberOfPoints() * TInputMesh::PointDimension;
256   auto * buffer = new typename TInputMesh::PointType::ValueType[pointsBufferSize];
257   CopyPointsToBuffer(buffer);
258   m_MeshIO->WritePoints(buffer);
259   delete[] buffer;
260 }
261 
262 template< typename TInputMesh >
263 void
264 MeshFileWriter< TInputMesh >
WriteCells()265 ::WriteCells()
266 {
267   itkDebugMacro(<< "Writing cells: " << m_FileName);
268 
269   SizeValueType cellsBufferSize = m_MeshIO->GetCellBufferSize();
270   auto * buffer = new typename TInputMesh::PointIdentifier[cellsBufferSize];
271   CopyCellsToBuffer(buffer);
272   m_MeshIO->WriteCells(buffer);
273   delete[] buffer;
274 }
275 
276 template< typename TInputMesh >
277 void
278 MeshFileWriter< TInputMesh >
WritePointData()279 ::WritePointData()
280 {
281   const InputMeshType *input = this->GetInput();
282 
283   itkDebugMacro(<< "Writing point data: " << m_FileName);
284 
285   if ( input->GetPointData()->Size() )
286     {
287     const SizeValueType numberOfComponents = input->GetPointData()->Size()
288                                        * MeshConvertPixelTraits< typename TInputMesh::PixelType >::GetNumberOfComponents(
289       input->GetPointData()->ElementAt(0) );
290 
291     using ValueType = typename itk::NumericTraits< typename TInputMesh::PixelType >::ValueType;
292     auto * buffer = new ValueType[numberOfComponents];
293     CopyPointDataToBuffer(buffer);
294     m_MeshIO->WritePointData(buffer);
295     delete[] buffer;
296     }
297 }
298 
299 template< typename TInputMesh >
300 void
301 MeshFileWriter< TInputMesh >
WriteCellData()302 ::WriteCellData()
303 {
304   const InputMeshType *input = this->GetInput();
305 
306   itkDebugMacro(<< "Writing cell data: " << m_FileName);
307 
308   if ( input->GetCellData()->Size() )
309     {
310     const SizeValueType numberOfComponents = input->GetCellData()->Size()
311                                        * MeshConvertPixelTraits< typename TInputMesh::CellPixelType >::GetNumberOfComponents(
312       input->GetCellData()->ElementAt(0) );
313 
314     using ValueType = typename itk::NumericTraits< typename TInputMesh::CellPixelType >::ValueType;
315     auto * buffer = new ValueType[numberOfComponents];
316     CopyCellDataToBuffer(buffer);
317     m_MeshIO->WriteCellData(buffer);
318     delete[] buffer;
319     }
320 }
321 
322 template< typename TInputMesh >
323 template< typename Output >
324 void
325 MeshFileWriter< TInputMesh >
CopyPointsToBuffer(Output * data)326 ::CopyPointsToBuffer(Output *data)
327 {
328   const typename InputMeshType::PointsContainer * points = this->GetInput()->GetPoints();
329 
330   SizeValueType index = NumericTraits< SizeValueType >::ZeroValue();
331   typename TInputMesh::PointsContainerConstIterator pter = points->Begin();
332 
333   while ( pter != points->End() )
334     {
335     for ( unsigned int jj = 0; jj < TInputMesh::PointDimension; jj++ )
336       {
337       data[index++] = static_cast< Output >( pter.Value()[jj] );
338       }
339 
340     ++pter;
341     }
342 }
343 
344 template< typename TInputMesh >
345 template< typename Output >
346 void
347 MeshFileWriter< TInputMesh >
CopyCellsToBuffer(Output * data)348 ::CopyCellsToBuffer(Output *data)
349 {
350   // Get input mesh pointer
351   const typename InputMeshType::CellsContainer * cells = this->GetInput()->GetCells();
352 
353   // Define required variables
354   typename TInputMesh::PointIdentifier const  *ptIds;
355   typename TInputMesh::CellType * cellPtr;
356 
357   // For each cell
358   SizeValueType index = NumericTraits< SizeValueType >::ZeroValue();
359   typename TInputMesh::CellsContainerConstIterator cter = cells->Begin();
360   while ( cter != cells->End() )
361     {
362     cellPtr = cter.Value();
363 
364     // Write the cell type
365     switch ( cellPtr->GetType() )
366       {
367       case InputMeshCellType::VERTEX_CELL:
368         data[index++] = static_cast< Output >( MeshIOBase::VERTEX_CELL );
369         break;
370       case InputMeshCellType::LINE_CELL:
371         data[index++] = static_cast< Output >( MeshIOBase::LINE_CELL );
372         break;
373       case InputMeshCellType::TRIANGLE_CELL:
374         data[index++] = static_cast< Output >( MeshIOBase::TRIANGLE_CELL );
375         break;
376       case InputMeshCellType::QUADRILATERAL_CELL:
377         data[index++] = static_cast< Output >( MeshIOBase::QUADRILATERAL_CELL );
378         break;
379       case InputMeshCellType::POLYGON_CELL:
380         data[index++] = static_cast< Output >( MeshIOBase::POLYGON_CELL );
381         break;
382       case InputMeshCellType::TETRAHEDRON_CELL:
383         data[index++] = static_cast< Output >( MeshIOBase::TETRAHEDRON_CELL );
384         break;
385       case InputMeshCellType::HEXAHEDRON_CELL:
386         data[index++] = static_cast< Output >( MeshIOBase::HEXAHEDRON_CELL );
387         break;
388       case InputMeshCellType::QUADRATIC_EDGE_CELL:
389         data[index++] = static_cast< Output >( MeshIOBase::QUADRATIC_EDGE_CELL );
390         break;
391       case InputMeshCellType::QUADRATIC_TRIANGLE_CELL:
392         data[index++] = static_cast< Output >( MeshIOBase::QUADRATIC_TRIANGLE_CELL );
393         break;
394       default:
395         itkExceptionMacro(<< "Unknown mesh cell");
396       }
397 
398     // The second element is number of points for each cell
399     data[index++] = cellPtr->GetNumberOfPoints();
400 
401     // Others are point identifiers in the cell
402     ptIds = cellPtr->GetPointIds();
403     unsigned int numberOfPoints = cellPtr->GetNumberOfPoints();
404     for ( unsigned int ii = 0; ii < numberOfPoints; ii++ )
405       {
406       data[index++] = static_cast< Output >( ptIds[ii] );
407       }
408 
409     ++cter;
410     }
411 }
412 
413 template< typename TInputMesh >
414 template< typename Output >
415 void
416 MeshFileWriter< TInputMesh >
CopyPointDataToBuffer(Output * data)417 ::CopyPointDataToBuffer(Output *data)
418 {
419   const typename InputMeshType::PointDataContainer * pointData = this->GetInput()->GetPointData();
420 
421   //  typename TInputMesh::PixelType value = NumericTraits< typename
422   // TInputMesh::PixelType >::ZeroValue();
423   // TODO? NumericTraitsVariableLengthVectorPixel should define ZeroValue()
424   // Should define NumericTraitsArrayPixel
425 
426   unsigned int numberOfComponents = MeshConvertPixelTraits< typename TInputMesh::PixelType >::GetNumberOfComponents(
427     pointData->ElementAt(0) );
428 
429   SizeValueType index = 0;
430   typename TInputMesh::PointDataContainer::ConstIterator pter = pointData->Begin();
431   while ( pter != pointData->End() )
432     {
433     for ( unsigned int jj = 0; jj < numberOfComponents; jj++ )
434       {
435       data[index++] = static_cast< Output >
436                     ( MeshConvertPixelTraits< typename TInputMesh::PixelType >::GetNthComponent( jj, pter.Value() ) );
437       }
438 
439     ++pter;
440     }
441 }
442 
443 template< typename TInputMesh >
444 template< typename Output >
445 void
446 MeshFileWriter< TInputMesh >
CopyCellDataToBuffer(Output * data)447 ::CopyCellDataToBuffer(Output *data)
448 {
449   const typename InputMeshType::CellDataContainer * cellData = this->GetInput()->GetCellData();
450 
451   //  typename TInputMesh::CellPixelType value = NumericTraits< typename
452   // TInputMesh::CellPixelType >::ZeroValue();
453   // TODO? NumericTraitsVariableLengthVectorPixel should define ZeroValue()
454   // Should define NumericTraitsArrayPixel
455 
456   unsigned int numberOfComponents = MeshConvertPixelTraits< typename TInputMesh::CellPixelType >::GetNumberOfComponents(
457     cellData->ElementAt(0) );
458   SizeValueType index = 0;
459   typename TInputMesh::CellDataContainer::ConstIterator cter = cellData->Begin();
460   while ( cter != cellData->End() )
461     {
462     for ( unsigned int jj = 0; jj < numberOfComponents; jj++ )
463       {
464       data[index++] = static_cast< Output >
465                     ( MeshConvertPixelTraits< typename TInputMesh::CellPixelType >::GetNthComponent( jj, cter.Value() ) );
466       }
467     ++cter;
468     }
469 }
470 
471 template< typename TInputMesh >
472 void
473 MeshFileWriter< TInputMesh >
PrintSelf(std::ostream & os,Indent indent) const474 ::PrintSelf(std::ostream & os, Indent indent) const
475 {
476   Superclass::PrintSelf(os, indent);
477 
478   os << indent << "File Name: "
479      << ( m_FileName.data() ? m_FileName.data() : "(none)" ) << std::endl;
480 
481   os << indent << "Mesh IO: ";
482   if ( m_MeshIO.IsNull() )
483     {
484     os << "(none)\n";
485     }
486   else
487     {
488     os << m_MeshIO << "\n";
489     }
490 
491   if ( m_UseCompression )
492     {
493     os << indent << "Compression: On\n";
494     }
495   else
496     {
497     os << indent << "Compression: Off\n";
498     }
499 
500   if ( m_FactorySpecifiedMeshIO )
501     {
502     os << indent << "FactorySpecifiedMeshIO: On\n";
503     }
504   else
505     {
506     os << indent << "FactorySpecifiedMeshIO: Off\n";
507     }
508 }
509 } // end namespace itk
510 
511 #endif
512