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