1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkXMLUnstructuredDataWriter.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkXMLUnstructuredDataWriter.h"
16 
17 #include "vtkCellArray.h"
18 #include "vtkCellData.h"
19 #include "vtkCellIterator.h"
20 #include "vtkDataArray.h"
21 #include "vtkDataCompressor.h"
22 #include "vtkDataSetAttributes.h"
23 #include "vtkErrorCode.h"
24 #include "vtkGenericCell.h"
25 #include "vtkIdTypeArray.h"
26 #include "vtkInformation.h"
27 #include "vtkInformationVector.h"
28 #include "vtkObjectFactory.h"
29 #include "vtkPointData.h"
30 #include "vtkPointSet.h"
31 #include "vtkPoints.h"
32 #include "vtkPolyhedron.h"
33 #include "vtkStreamingDemandDrivenPipeline.h"
34 #include "vtkUnsignedCharArray.h"
35 #define vtkXMLOffsetsManager_DoNotInclude
36 #include "vtkXMLOffsetsManager.h"
37 #undef  vtkXMLOffsetsManager_DoNotInclude
38 
39 #include <cassert>
40 
41 //----------------------------------------------------------------------------
vtkXMLUnstructuredDataWriter()42 vtkXMLUnstructuredDataWriter::vtkXMLUnstructuredDataWriter()
43 {
44   this->NumberOfPieces = 1;
45   this->WritePiece = -1;
46   this->GhostLevel = 0;
47   this->CellPoints = vtkIdTypeArray::New();
48   this->CellOffsets = vtkIdTypeArray::New();
49   this->CellPoints->SetName("connectivity");
50   this->CellOffsets->SetName("offsets");
51 
52   this->CurrentPiece = 0;
53   this->FieldDataOM->Allocate(0);
54   this->PointsOM    = new OffsetsManagerGroup;
55   this->PointDataOM = new OffsetsManagerArray;
56   this->CellDataOM  = new OffsetsManagerArray;
57 
58   this->Faces = vtkIdTypeArray::New();
59   this->FaceOffsets = vtkIdTypeArray::New();
60   this->Faces->SetName("faces");
61   this->FaceOffsets->SetName("faceoffsets");
62 }
63 
64 //----------------------------------------------------------------------------
~vtkXMLUnstructuredDataWriter()65 vtkXMLUnstructuredDataWriter::~vtkXMLUnstructuredDataWriter()
66 {
67   this->CellPoints->Delete();
68   this->CellOffsets->Delete();
69   this->Faces->Delete();
70   this->FaceOffsets->Delete();
71 
72   delete this->PointsOM;
73   delete this->PointDataOM;
74   delete this->CellDataOM;
75 }
76 
77 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)78 void vtkXMLUnstructuredDataWriter::PrintSelf(ostream& os, vtkIndent indent)
79 {
80   this->Superclass::PrintSelf(os,indent);
81   os << indent << "NumberOfPieces: " << this->NumberOfPieces << "\n";
82   os << indent << "WritePiece: " << this->WritePiece << "\n";
83   os << indent << "GhostLevel: " << this->GhostLevel << "\n";
84 }
85 
86 //----------------------------------------------------------------------------
GetInputAsPointSet()87 vtkPointSet* vtkXMLUnstructuredDataWriter::GetInputAsPointSet()
88 {
89   return static_cast<vtkPointSet*>(this->Superclass::GetInput());
90 }
91 
92 //----------------------------------------------------------------------------
ProcessRequest(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)93 int vtkXMLUnstructuredDataWriter::ProcessRequest(vtkInformation* request,
94                                                  vtkInformationVector** inputVector,
95                                                  vtkInformationVector* outputVector)
96 {
97 
98   if(request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT()))
99   {
100     if((this->WritePiece < 0) || (this->WritePiece >= this->NumberOfPieces))
101     {
102       this->SetInputUpdateExtent(
103         this->CurrentPiece, this->NumberOfPieces, this->GhostLevel);
104     }
105     else
106     {
107       this->SetInputUpdateExtent(
108         this->WritePiece, this->NumberOfPieces, this->GhostLevel);
109     }
110     return 1;
111   }
112 
113   // generate the data
114   else if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
115   {
116     this->SetErrorCode(vtkErrorCode::NoError);
117 
118     if(!this->Stream && !this->FileName && !this->WriteToOutputString)
119     {
120       this->SetErrorCode(vtkErrorCode::NoFileNameError);
121       vtkErrorMacro("The FileName or Stream must be set first or "
122         "the output must be written to a string.");
123       return 0;
124     }
125 
126     int numPieces = this->NumberOfPieces;
127 
128     if (this->WritePiece >= 0)
129     {
130       this->CurrentPiece = this->WritePiece;
131     }
132     else
133     {
134       float wholeProgressRange[2] = {0,1};
135       this->SetProgressRange(wholeProgressRange, this->CurrentPiece, this->NumberOfPieces);
136     }
137 
138     int result = 1;
139     if ((this->CurrentPiece == 0 && this->CurrentTimeIndex == 0) || this->WritePiece >= 0)
140     {
141       // We are just starting to write.  Do not call
142       // UpdateProgressDiscrete because we want a 0 progress callback the
143       // first time.
144       this->UpdateProgress(0);
145 
146       // Initialize progress range to entire 0..1 range.
147       if (this->WritePiece >= 0)
148       {
149         float wholeProgressRange[2] = {0,1};
150         this->SetProgressRange(wholeProgressRange, 0, 1);
151       }
152 
153       if (!this->OpenStream())
154       {
155         this->NumberOfPieces = numPieces;
156         return 0;
157       }
158 
159       if (this->GetInputAsDataSet() != nullptr &&
160           (this->GetInputAsDataSet()->GetPointGhostArray() != nullptr &&
161            this->GetInputAsDataSet()->GetCellGhostArray() != nullptr))
162       {
163         // use the current version for the file.
164         this->UsePreviousVersion = false;
165       }
166 
167       // Write the file.
168       if (!this->StartFile())
169       {
170         this->NumberOfPieces = numPieces;
171         return 0;
172       }
173 
174       if (!this->WriteHeader())
175       {
176         this->NumberOfPieces = numPieces;
177         return 0;
178       }
179 
180       this->CurrentTimeIndex = 0;
181       if( this->DataMode == vtkXMLWriter::Appended && this->FieldDataOM->GetNumberOfElements())
182       {
183         vtkNew<vtkFieldData> fieldDataCopy;
184         this->UpdateFieldData(fieldDataCopy);
185 
186         // Write the field data arrays.
187         this->WriteFieldDataAppendedData(fieldDataCopy,
188           this->CurrentTimeIndex, this->FieldDataOM);
189         if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
190         {
191           this->DeletePositionArrays();
192           return 0;
193         }
194       }
195     }
196 
197     if( !(this->UserContinueExecuting == 0)) //if user ask to stop do not try to write a piece
198     {
199       result = this->WriteAPiece();
200     }
201 
202     if((this->WritePiece < 0) || (this->WritePiece >= this->NumberOfPieces))
203     {
204       // Tell the pipeline to start looping.
205       if (this->CurrentPiece == 0)
206       {
207         request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1);
208       }
209       this->CurrentPiece++;
210     }
211 
212     if (this->CurrentPiece == this->NumberOfPieces || this->WritePiece >= 0)
213     {
214       request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING());
215       this->CurrentPiece = 0;
216       // We are done writing all the pieces, lets loop over time now:
217       this->CurrentTimeIndex++;
218 
219       if( this->UserContinueExecuting != 1 )
220       {
221         if (!this->WriteFooter())
222         {
223           this->NumberOfPieces = numPieces;
224           return 0;
225         }
226 
227         if (!this->EndFile())
228         {
229           this->NumberOfPieces = numPieces;
230           return 0;
231         }
232 
233         this->CloseStream();
234         this->CurrentTimeIndex = 0; // Reset
235       }
236     }
237     this->NumberOfPieces = numPieces;
238 
239     // We have finished writing (at least this piece)
240     this->SetProgressPartial(1);
241     return result;
242   }
243   return this->Superclass::ProcessRequest(request, inputVector, outputVector);
244 }
245 
246 //----------------------------------------------------------------------------
AllocatePositionArrays()247 void vtkXMLUnstructuredDataWriter::AllocatePositionArrays()
248 {
249   this->NumberOfPointsPositions = new vtkTypeInt64[this->NumberOfPieces];
250 
251   this->PointsOM->Allocate(this->NumberOfPieces, this->NumberOfTimeSteps);
252   this->PointDataOM->Allocate(this->NumberOfPieces);
253   this->CellDataOM->Allocate(this->NumberOfPieces);
254 }
255 
256 //----------------------------------------------------------------------------
DeletePositionArrays()257 void vtkXMLUnstructuredDataWriter::DeletePositionArrays()
258 {
259   delete [] this->NumberOfPointsPositions;
260   this->NumberOfPointsPositions = nullptr;
261 }
262 
263 //----------------------------------------------------------------------------
WriteHeader()264 int vtkXMLUnstructuredDataWriter::WriteHeader()
265 {
266   vtkIndent indent = vtkIndent().GetNextIndent();
267 
268   ostream& os = *(this->Stream);
269 
270   if(!this->WritePrimaryElement(os, indent))
271   {
272     return 0;
273   }
274 
275   this->WriteFieldData(indent.GetNextIndent());
276 
277   if(this->DataMode == vtkXMLWriter::Appended)
278   {
279     vtkIndent nextIndent = indent.GetNextIndent();
280 
281     this->AllocatePositionArrays();
282 
283     if((this->WritePiece < 0) || (this->WritePiece >= this->NumberOfPieces))
284     {
285       // Loop over each piece and write its structure.
286       int i;
287       for(i=0; i < this->NumberOfPieces; ++i)
288       {
289         // Open the piece's element.
290         os << nextIndent << "<Piece";
291         this->WriteAppendedPieceAttributes(i);
292         if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
293         {
294           this->DeletePositionArrays();
295           return 0;
296         }
297         os << ">\n";
298 
299         this->WriteAppendedPiece(i, nextIndent.GetNextIndent());
300         if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
301         {
302           this->DeletePositionArrays();
303           return 0;
304         }
305 
306         // Close the piece's element.
307         os << nextIndent << "</Piece>\n";
308       }
309     }
310     else
311     {
312       // Write just the requested piece.
313       // Open the piece's element.
314       os << nextIndent << "<Piece";
315       this->WriteAppendedPieceAttributes(this->WritePiece);
316       if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
317       {
318         this->DeletePositionArrays();
319         return 0;
320       }
321       os << ">\n";
322 
323       this->WriteAppendedPiece(this->WritePiece, nextIndent.GetNextIndent());
324       if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
325       {
326         this->DeletePositionArrays();
327         return 0;
328       }
329 
330       // Close the piece's element.
331       os << nextIndent << "</Piece>\n";
332     }
333 
334     // Close the primary element.
335     os << indent << "</" << this->GetDataSetName() << ">\n";
336     os.flush();
337     if (os.fail())
338     {
339       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
340       this->DeletePositionArrays();
341       return 0;
342     }
343 
344     this->StartAppendedData();
345     if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
346     {
347       this->DeletePositionArrays();
348       return 0;
349     }
350 
351   }
352 
353   return 1;
354 }
355 
CreateFaceStream(vtkCellIterator * cellIter,vtkIdTypeArray * faceStream,vtkIdTypeArray * faceOffsets)356 void CreateFaceStream(vtkCellIterator* cellIter, vtkIdTypeArray* faceStream, vtkIdTypeArray* faceOffsets)
357 {
358   vtkNew<vtkGenericCell> cell;
359 
360   faceStream->Reset();
361   faceOffsets->Reset();
362 
363   vtkIdType offset(0);
364   for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal();
365        cellIter->GoToNextCell())
366   {
367     vtkIdType ct = cellIter->GetCellType();
368     if (ct != VTK_POLYHEDRON)
369     {
370       faceOffsets->InsertNextValue(-1);
371       continue;
372     }
373     cellIter->GetCell(cell.GetPointer());
374     vtkCell* theCell = cell->GetRepresentativeCell();
375     vtkPolyhedron* poly = vtkPolyhedron::SafeDownCast(theCell);
376     if (!poly || !poly->GetNumberOfFaces())
377     {
378       continue;
379     }
380 
381     vtkIdType n(0);
382     vtkIdType* faces = poly->GetFaces();
383     vtkIdType nFaces = faces[n++];
384 
385     // create offset in vtkUnstructuredGrid fashion, this will later be converted using ConvertFaces
386     faceOffsets->InsertNextValue(offset);
387 
388     faceStream->InsertNextValue(nFaces);
389     for(vtkIdType i = 0; i < nFaces; ++i)
390     {
391       vtkIdType nFaceVerts = faces[n++];
392       faceStream->InsertNextValue(nFaceVerts);
393       for (vtkIdType j = 0; j < nFaceVerts; ++j)
394       {
395         vtkIdType vi = faces[n++];
396         faceStream->InsertNextValue(vi);
397       }
398     }
399     offset += n;
400   }
401 }
402 
403 
404 //----------------------------------------------------------------------------
WriteAPiece()405 int vtkXMLUnstructuredDataWriter::WriteAPiece()
406 {
407   vtkIndent indent = vtkIndent().GetNextIndent();
408 
409   int result=1;
410 
411   if(this->DataMode == vtkXMLWriter::Appended)
412   {
413     this->WriteAppendedPieceData(this->CurrentPiece);
414   }
415   else
416   {
417     result = this->WriteInlineMode(indent);
418   }
419 
420   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
421   {
422     this->DeletePositionArrays();
423     result = 0;
424   }
425   return result;
426 }
427 
428 //----------------------------------------------------------------------------
WriteFooter()429 int vtkXMLUnstructuredDataWriter::WriteFooter()
430 {
431   vtkIndent indent = vtkIndent().GetNextIndent();
432 
433   ostream& os = *(this->Stream);
434 
435   if(this->DataMode == vtkXMLWriter::Appended)
436   {
437     this->DeletePositionArrays();
438     this->EndAppendedData();
439   }
440   else
441   {
442     // Close the primary element.
443     os << indent << "</" << this->GetDataSetName() << ">\n";
444     os.flush();
445     if (os.fail())
446     {
447       return 0;
448     }
449   }
450 
451   return 1;
452 }
453 
454 //----------------------------------------------------------------------------
WriteInlineMode(vtkIndent indent)455 int vtkXMLUnstructuredDataWriter::WriteInlineMode(vtkIndent indent)
456 {
457   ostream& os = *(this->Stream);
458   vtkIndent nextIndent = indent.GetNextIndent();
459 
460   // Open the piece's element.
461   os << nextIndent << "<Piece";
462   this->WriteInlinePieceAttributes();
463   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
464   {
465     return 0;
466   }
467   os << ">\n";
468 
469   this->WriteInlinePiece(nextIndent.GetNextIndent());
470   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
471   {
472     return 0;
473   }
474 
475   // Close the piece's element.
476   os << nextIndent << "</Piece>\n";
477 
478   return 1;
479 }
480 
481 //----------------------------------------------------------------------------
WriteInlinePieceAttributes()482 void vtkXMLUnstructuredDataWriter::WriteInlinePieceAttributes()
483 {
484   vtkPointSet* input = this->GetInputAsPointSet();
485   this->WriteScalarAttribute("NumberOfPoints",
486                              input->GetNumberOfPoints());
487 }
488 
489 //----------------------------------------------------------------------------
WriteInlinePiece(vtkIndent indent)490 void vtkXMLUnstructuredDataWriter::WriteInlinePiece(vtkIndent indent)
491 {
492   vtkPointSet* input = this->GetInputAsPointSet();
493 
494   // Split progress among point data, cell data, and point arrays.
495   float progressRange[2] = {0,0};
496   this->GetProgressRange(progressRange);
497   float fractions[4];
498   this->CalculateDataFractions(fractions);
499 
500   // Set the range of progress for the point data arrays.
501   this->SetProgressRange(progressRange, 0, fractions);
502 
503   // Write the point data arrays.
504   this->WritePointDataInline(input->GetPointData(), indent);
505   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
506   {
507     return;
508   }
509 
510   // Set the range of progress for the cell data arrays.
511   this->SetProgressRange(progressRange, 1, fractions);
512 
513   // Write the cell data arrays.
514   this->WriteCellDataInline(input->GetCellData(), indent);
515   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
516   {
517     return;
518   }
519 
520   // Set the range of progress for the point specification array.
521   this->SetProgressRange(progressRange, 2, fractions);
522 
523   // Write the point specification array.
524   this->WritePointsInline(input->GetPoints(), indent);
525 }
526 
527 //----------------------------------------------------------------------------
WriteAppendedPieceAttributes(int index)528 void vtkXMLUnstructuredDataWriter::WriteAppendedPieceAttributes(int index)
529 {
530   this->NumberOfPointsPositions[index] =
531     this->ReserveAttributeSpace("NumberOfPoints");
532 }
533 
534 //----------------------------------------------------------------------------
WriteAppendedPiece(int index,vtkIndent indent)535 void vtkXMLUnstructuredDataWriter::WriteAppendedPiece(int index,
536                                                       vtkIndent indent)
537 {
538   vtkPointSet* input = this->GetInputAsPointSet();
539 
540   this->WritePointDataAppended(input->GetPointData(), indent,
541     &this->PointDataOM->GetPiece(index));
542   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
543   {
544     return;
545   }
546 
547   this->WriteCellDataAppended(input->GetCellData(), indent,
548     &this->CellDataOM->GetPiece(index));
549   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
550   {
551     return;
552   }
553 
554   this->WritePointsAppended(input->GetPoints(), indent,
555     &this->PointsOM->GetPiece(index));
556 }
557 
558 //----------------------------------------------------------------------------
WriteAppendedPieceData(int index)559 void vtkXMLUnstructuredDataWriter::WriteAppendedPieceData(int index)
560 {
561   ostream& os = *(this->Stream);
562   vtkPointSet* input = this->GetInputAsPointSet();
563 
564   std::streampos returnPosition = os.tellp();
565   os.seekp(std::streampos(this->NumberOfPointsPositions[index]));
566   vtkPoints* points = input->GetPoints();
567   this->WriteScalarAttribute("NumberOfPoints",
568                              (points?points->GetNumberOfPoints():0));
569   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
570   {
571     return;
572   }
573   os.seekp(returnPosition);
574 
575   // Split progress among point data, cell data, and point arrays.
576   float progressRange[2] = {0,0};
577   this->GetProgressRange(progressRange);
578   float fractions[4];
579   this->CalculateDataFractions(fractions);
580 
581   // Set the range of progress for the point data arrays.
582   this->SetProgressRange(progressRange, 0, fractions);
583 
584   // Write the point data arrays.
585   this->WritePointDataAppendedData(input->GetPointData(), this->CurrentTimeIndex,
586                                   &this->PointDataOM->GetPiece(index));
587   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
588   {
589     return;
590   }
591 
592   // Set the range of progress for the cell data arrays.
593   this->SetProgressRange(progressRange, 1, fractions);
594 
595   // Write the cell data arrays.
596   this->WriteCellDataAppendedData(input->GetCellData(), this->CurrentTimeIndex,
597                                   &this->CellDataOM->GetPiece(index));
598   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
599   {
600     return;
601   }
602 
603   // Set the range of progress for the point specification array.
604   this->SetProgressRange(progressRange, 2, fractions);
605 
606   // Write the point specification array.
607   // Since we are writing the point let save the Modified Time of vtkPoints:
608   this->WritePointsAppendedData(input->GetPoints(), this->CurrentTimeIndex,
609                                 &this->PointsOM->GetPiece(index));
610 }
611 
612 //----------------------------------------------------------------------------
WriteCellsInline(const char * name,vtkCellIterator * cellIter,vtkIdType numCells,vtkIdType cellSizeEstimate,vtkIndent indent)613 void vtkXMLUnstructuredDataWriter::WriteCellsInline(
614     const char *name, vtkCellIterator *cellIter, vtkIdType numCells,
615     vtkIdType cellSizeEstimate, vtkIndent indent)
616 {
617   this->ConvertCells(cellIter, numCells, cellSizeEstimate);
618 
619   vtkNew<vtkUnsignedCharArray> types;
620   types->Allocate(numCells);
621   vtkIdType nPolyhedra(0);
622   for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal();
623        cellIter->GoToNextCell())
624   {
625     vtkIdType ct = cellIter->GetCellType();
626     if (ct == VTK_POLYHEDRON)
627     {
628       ++nPolyhedra;
629     }
630     types->InsertNextValue(static_cast<unsigned char>(ct));
631   }
632 
633   if (nPolyhedra > 0)
634   {
635     vtkNew<vtkIdTypeArray> faces, offsets;
636     CreateFaceStream(cellIter, faces.GetPointer(), offsets.GetPointer());
637     this->ConvertFaces(faces.GetPointer(), offsets.GetPointer());
638   }
639   else
640   {
641     this->Faces->SetNumberOfTuples(0);
642     this->FaceOffsets->SetNumberOfTuples(0);
643   }
644 
645   this->WriteCellsInlineWorker(name, types.GetPointer(), indent);
646 }
647 
648 //----------------------------------------------------------------------------
WriteCellsInline(const char * name,vtkCellArray * cells,vtkDataArray * types,vtkIndent indent)649 void vtkXMLUnstructuredDataWriter::WriteCellsInline(const char* name,
650                                                     vtkCellArray* cells,
651                                                     vtkDataArray* types,
652                                                     vtkIndent indent)
653 {
654   this->WriteCellsInline(name, cells, types, nullptr, nullptr, indent);
655 }
656 
657 
658 //----------------------------------------------------------------------------
WriteCellsInline(const char * name,vtkCellArray * cells,vtkDataArray * types,vtkIdTypeArray * faces,vtkIdTypeArray * faceOffsets,vtkIndent indent)659 void vtkXMLUnstructuredDataWriter::WriteCellsInline(const char* name,
660                         vtkCellArray* cells,  vtkDataArray* types,
661                         vtkIdTypeArray* faces, vtkIdTypeArray* faceOffsets,
662                         vtkIndent indent)
663 {
664   if(cells)
665   {
666     this->ConvertCells(cells);
667   }
668   this->ConvertFaces(faces, faceOffsets);
669 
670   this->WriteCellsInlineWorker(name, types, indent);
671 }
672 
673 //----------------------------------------------------------------------------
WriteCellsInlineWorker(const char * name,vtkDataArray * types,vtkIndent indent)674 void vtkXMLUnstructuredDataWriter::WriteCellsInlineWorker(
675     const char *name, vtkDataArray *types, vtkIndent indent)
676 {
677   ostream& os = *(this->Stream);
678   os << indent << "<" << name << ">\n";
679 
680   // Split progress by cell connectivity, offset, and type arrays.
681   float progressRange[2] = {0,0};
682   this->GetProgressRange(progressRange);
683   float fractions[6];
684   this->CalculateCellFractions(fractions, types?types->GetNumberOfTuples():0);
685 
686   // Set the range of progress for the connectivity array.
687   this->SetProgressRange(progressRange, 0, fractions);
688 
689   // Write the connectivity array.
690   this->WriteArrayInline(this->CellPoints, indent.GetNextIndent());
691   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
692   {
693     return;
694   }
695 
696   // Set the range of progress for the offsets array.
697   this->SetProgressRange(progressRange, 1, fractions);
698 
699   // Write the offsets array.
700   this->WriteArrayInline(this->CellOffsets, indent.GetNextIndent());
701   if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
702   {
703     return;
704   }
705 
706   if(types)
707   {
708     // Set the range of progress for the types array.
709     this->SetProgressRange(progressRange, 2, fractions);
710 
711     // Write the types array.
712     this->WriteArrayInline(types, indent.GetNextIndent(), "types");
713     if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
714     {
715       return;
716     }
717   }
718 
719   if (this->Faces->GetNumberOfTuples())
720   {
721     // Set the range of progress for the faces array.
722     this->SetProgressRange(progressRange, 3, fractions);
723 
724     // Write the connectivity array.
725     this->WriteArrayInline(this->Faces, indent.GetNextIndent(), "faces");
726     if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
727     {
728       return;
729     }
730   }
731 
732   if (this->FaceOffsets->GetNumberOfTuples())
733   {
734     // Set the range of progress for the face offset array.
735     this->SetProgressRange(progressRange, 4, fractions);
736 
737     // Write the face offsets array.
738     this->WriteArrayInline(this->FaceOffsets, indent.GetNextIndent(), "faceoffsets");
739     if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
740     {
741       return;
742     }
743   }
744 
745   os << indent << "</" << name << ">\n";
746   os.flush();
747   if (os.fail())
748   {
749     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
750   }
751 }
752 
753 //----------------------------------------------------------------------------
WriteCellsAppended(const char * name,vtkDataArray * types,vtkIndent indent,OffsetsManagerGroup * cellsManager)754 void vtkXMLUnstructuredDataWriter::WriteCellsAppended(const char* name,
755                                                       vtkDataArray* types,
756                                                       vtkIndent indent,
757                                                       OffsetsManagerGroup *cellsManager)
758 {
759   this->WriteCellsAppended(name, types, nullptr, nullptr, indent, cellsManager);
760 }
761 
762 //----------------------------------------------------------------------------
WriteCellsAppended(const char * name,vtkDataArray * types,vtkIdTypeArray * faces,vtkIdTypeArray * faceOffsets,vtkIndent indent,OffsetsManagerGroup * cellsManager)763 void vtkXMLUnstructuredDataWriter::WriteCellsAppended(const char* name,
764                                                       vtkDataArray* types,
765                                                       vtkIdTypeArray* faces,
766                                                       vtkIdTypeArray* faceOffsets,
767                                                       vtkIndent indent,
768                                                       OffsetsManagerGroup *cellsManager)
769 {
770   this->ConvertFaces(faces,faceOffsets);
771   ostream& os = *(this->Stream);
772   os << indent << "<" << name << ">\n";
773 
774   // Helper for the 'for' loop
775   vtkDataArray *allcells[5];
776   allcells[0] = this->CellPoints;
777   allcells[1] = this->CellOffsets;
778   allcells[2] = types;
779   allcells[3] = this->Faces->GetNumberOfTuples() ? this->Faces : nullptr;
780   allcells[4] = this->FaceOffsets->GetNumberOfTuples() ? this->FaceOffsets : nullptr;
781   const char *names[] = {nullptr, nullptr, "types", nullptr, nullptr};
782 
783   for(int t=0; t<this->NumberOfTimeSteps; t++)
784   {
785     for(int i=0; i<5; i++)
786     {
787       if(allcells[i])
788       {
789         this->WriteArrayAppended(allcells[i], indent.GetNextIndent(),
790           cellsManager->GetElement(i), names[i], 0, t);
791         if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
792         {
793           return;
794         }
795       }
796     }
797   }
798   os << indent << "</" << name << ">\n";
799   os.flush();
800   if (os.fail())
801   {
802     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
803     return;
804   }
805 
806 }
807 
808 //----------------------------------------------------------------------------
WriteCellsAppended(const char * name,vtkCellIterator * cellIter,vtkIdType numCells,vtkIndent indent,OffsetsManagerGroup * cellsManager)809 void vtkXMLUnstructuredDataWriter::WriteCellsAppended(
810     const char *name, vtkCellIterator *cellIter, vtkIdType numCells,
811     vtkIndent indent, OffsetsManagerGroup *cellsManager)
812 {
813   vtkNew<vtkUnsignedCharArray> types;
814   types->Allocate(numCells);
815   vtkIdType nPolyhedra(0);
816   for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal();
817        cellIter->GoToNextCell())
818   {
819     vtkIdType ct = cellIter->GetCellType();
820     if (ct == VTK_POLYHEDRON)
821     {
822       ++nPolyhedra;
823     }
824     types->InsertNextValue(static_cast<unsigned char>(ct));
825   }
826   if (nPolyhedra > 0)
827   {
828     vtkNew<vtkIdTypeArray> faces, offsets;
829     CreateFaceStream(cellIter, faces.GetPointer(), offsets.GetPointer());
830     this->WriteCellsAppended(name, types.GetPointer(), faces.GetPointer(), offsets.GetPointer(), indent, cellsManager);
831   }
832   else
833   {
834     this->WriteCellsAppended(name, types.GetPointer(), nullptr, nullptr, indent, cellsManager);
835   }
836 }
837 
838 //----------------------------------------------------------------------------
839 void
WriteCellsAppendedData(vtkCellArray * cells,vtkDataArray * types,int timestep,OffsetsManagerGroup * cellsManager)840 vtkXMLUnstructuredDataWriter::WriteCellsAppendedData(vtkCellArray* cells,
841                                                      vtkDataArray* types,
842                                                      int timestep,
843                                                      OffsetsManagerGroup *cellsManager)
844 {
845   this->WriteCellsAppendedData(cells, types, nullptr, nullptr, timestep, cellsManager);
846 }
847 
848 //----------------------------------------------------------------------------
WriteCellsAppendedData(vtkCellIterator * cellIter,vtkIdType numCells,vtkIdType cellSizeEstimate,int timestep,OffsetsManagerGroup * cellsManager)849 void vtkXMLUnstructuredDataWriter::WriteCellsAppendedData(
850     vtkCellIterator *cellIter, vtkIdType numCells, vtkIdType cellSizeEstimate,
851     int timestep, OffsetsManagerGroup *cellsManager)
852 {
853   this->ConvertCells(cellIter, numCells, cellSizeEstimate);
854 
855   vtkNew<vtkUnsignedCharArray> types;
856   types->Allocate(this->CellOffsets->GetNumberOfTuples() + 1);
857   int nPolyhedra(0);
858   for(cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal();
859       cellIter->GoToNextCell())
860   {
861     vtkIdType ct = cellIter->GetCellType();
862     if (ct == VTK_POLYHEDRON)
863     {
864       ++nPolyhedra;
865     }
866     types->InsertNextValue(static_cast<unsigned char>(ct));
867   }
868 
869   if (nPolyhedra > 0)
870   {
871     // even though it looks like we do this for the second time
872     // the test points out that it is needed here.
873     vtkNew<vtkIdTypeArray> faces, offsets;
874     CreateFaceStream(cellIter, faces.GetPointer(), offsets.GetPointer());
875     this->ConvertFaces(faces.GetPointer(), offsets.GetPointer());
876   }
877   else
878   {
879     this->Faces->SetNumberOfTuples(0);
880     this->FaceOffsets->SetNumberOfTuples(0);
881   }
882 
883   this->WriteCellsAppendedDataWorker(types.GetPointer(), timestep,
884                                      cellsManager);
885 }
886 
887 //----------------------------------------------------------------------------
888 void
WriteCellsAppendedData(vtkCellArray * cells,vtkDataArray * types,vtkIdTypeArray * faces,vtkIdTypeArray * faceOffsets,int timestep,OffsetsManagerGroup * cellsManager)889 vtkXMLUnstructuredDataWriter::WriteCellsAppendedData(vtkCellArray* cells,
890                                                      vtkDataArray* types,
891                                                      vtkIdTypeArray* faces,
892                                                      vtkIdTypeArray* faceOffsets,
893                                                      int timestep,
894                                                      OffsetsManagerGroup *cellsManager)
895 {
896   if (cells)
897   {
898     this->ConvertCells(cells);
899   }
900 
901   this->ConvertFaces(faces, faceOffsets);
902   this->WriteCellsAppendedDataWorker(types, timestep, cellsManager);
903 }
904 
905 //----------------------------------------------------------------------------
WriteCellsAppendedDataWorker(vtkDataArray * types,int timestep,OffsetsManagerGroup * cellsManager)906 void vtkXMLUnstructuredDataWriter::WriteCellsAppendedDataWorker(
907     vtkDataArray *types, int timestep, OffsetsManagerGroup *cellsManager)
908 {
909   // Split progress by cell connectivity, offset, and type arrays.
910   float progressRange[5] = {0,0,0,0,0};
911   this->GetProgressRange(progressRange);
912   float fractions[6];
913   this->CalculateCellFractions(fractions, types?types->GetNumberOfTuples():0);
914 
915   // Helper for the 'for' loop
916   vtkDataArray *allcells[5];
917   allcells[0] = this->CellPoints;
918   allcells[1] = this->CellOffsets;
919   allcells[2] = types;
920   allcells[3] = this->Faces->GetNumberOfTuples() ? this->Faces : nullptr;
921   allcells[4] = this->FaceOffsets->GetNumberOfTuples() ? this->FaceOffsets : nullptr;
922 
923   for(int i=0; i<5; i++)
924   {
925     if(allcells[i])
926     {
927       // Set the range of progress for the connectivity array.
928       this->SetProgressRange(progressRange, i, fractions);
929 
930       vtkMTimeType mtime = allcells[i]->GetMTime();
931       vtkMTimeType &cellsMTime = cellsManager->GetElement(i).GetLastMTime();
932       // Only write cells if MTime has changed
933       if( cellsMTime != mtime )
934       {
935         cellsMTime = mtime;
936         // Write the connectivity array.
937         this->WriteArrayAppendedData(allcells[i],
938           cellsManager->GetElement(i).GetPosition(timestep),
939           cellsManager->GetElement(i).GetOffsetValue(timestep));
940         if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
941         {
942           return;
943         }
944       }
945       else
946       {
947         // One timestep must have already been written or the
948         // mtime would have changed and we would not be here.
949         assert( timestep > 0 );
950         cellsManager->GetElement(i).GetOffsetValue(timestep) =
951           cellsManager->GetElement(i).GetOffsetValue(timestep-1);
952         this->ForwardAppendedDataOffset(cellsManager->GetElement(i).GetPosition(timestep),
953                                         cellsManager->GetElement(i).GetOffsetValue(timestep),
954                                         "offset" );
955       }
956     }
957   }
958 }
959 
960 //----------------------------------------------------------------------------
ConvertCells(vtkCellIterator * cellIter,vtkIdType numCells,vtkIdType cellSizeEstimate)961 void vtkXMLUnstructuredDataWriter::ConvertCells(
962     vtkCellIterator *cellIter, vtkIdType numCells, vtkIdType cellSizeEstimate)
963 {
964   this->CellPoints->Allocate(numCells * cellSizeEstimate);
965   this->CellOffsets->Allocate(numCells);
966 
967   for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal();
968        cellIter->GoToNextCell())
969   {
970     vtkIdType *begin = cellIter->GetPointIds()->GetPointer(0);
971     vtkIdType *end = begin + cellIter->GetNumberOfPoints();
972     while (begin != end)
973     {
974       this->CellPoints->InsertNextValue(*begin++);
975     }
976 
977     this->CellOffsets->InsertNextValue(this->CellPoints->GetNumberOfTuples());
978   }
979 
980   this->CellPoints->Squeeze();
981   this->CellOffsets->Squeeze();
982 }
983 
984 //----------------------------------------------------------------------------
ConvertCells(vtkCellArray * cells)985 void vtkXMLUnstructuredDataWriter::ConvertCells(vtkCellArray* cells)
986 {
987   vtkIdTypeArray* connectivity = cells->GetData();
988   vtkIdType numberOfCells = cells->GetNumberOfCells();
989   vtkIdType numberOfTuples = connectivity->GetNumberOfTuples();
990 
991   this->CellPoints->SetNumberOfTuples(numberOfTuples - numberOfCells);
992   this->CellOffsets->SetNumberOfTuples(numberOfCells);
993 
994   vtkIdType* inCell = connectivity->GetPointer(0);
995   vtkIdType* outCellPointsBase = this->CellPoints->GetPointer(0);
996   vtkIdType* outCellPoints = outCellPointsBase;
997   vtkIdType* outCellOffset = this->CellOffsets->GetPointer(0);
998 
999   vtkIdType i;
1000   for(i=0;i < numberOfCells; ++i)
1001   {
1002     vtkIdType numberOfPoints = *inCell++;
1003     memcpy(outCellPoints, inCell, sizeof(vtkIdType)*numberOfPoints);
1004     outCellPoints += numberOfPoints;
1005     inCell += numberOfPoints;
1006     *outCellOffset++ = outCellPoints - outCellPointsBase;
1007   }
1008 }
1009 
1010 //----------------------------------------------------------------------------
ConvertFaces(vtkIdTypeArray * faces,vtkIdTypeArray * faceOffsets)1011 void vtkXMLUnstructuredDataWriter::ConvertFaces(vtkIdTypeArray* faces,
1012                                                 vtkIdTypeArray* faceOffsets)
1013 {
1014   if (!faces || !faces->GetNumberOfTuples() ||
1015       !faceOffsets || !faceOffsets->GetNumberOfTuples())
1016   {
1017     this->Faces->SetNumberOfTuples(0);
1018     this->FaceOffsets->SetNumberOfTuples(0);
1019     return;
1020   }
1021 
1022   // copy faces stream.
1023   this->Faces->SetNumberOfTuples(faces->GetNumberOfTuples());
1024   vtkIdType * fromPtr = faces->GetPointer(0);
1025   vtkIdType * toPtr = this->Faces->GetPointer(0);
1026   for (vtkIdType i = 0; i < faces->GetNumberOfTuples(); i++)
1027   {
1028     *toPtr++ = *fromPtr++;
1029   }
1030 
1031   // this->FaceOffsets point to the face arrays of cells. Specifically
1032   // FaceOffsets[i] points to the end of the i-th cell's faces + 1. While
1033   // input faceOffsets[i] points to the beginning of the i-th cell. Note
1034   // that for both arrays, a non-polyhedron cell has an offset of -1.
1035   vtkIdType numberOfCells = faceOffsets->GetNumberOfTuples();
1036   this->FaceOffsets->SetNumberOfTuples(numberOfCells);
1037   vtkIdType* newOffsetPtr = this->FaceOffsets->GetPointer(0);
1038   vtkIdType* oldOffsetPtr = faceOffsets->GetPointer(0);
1039   vtkIdType* facesPtr = this->Faces->GetPointer(0);
1040   bool foundPolyhedronCell = false;
1041   for (vtkIdType i = 0; i < numberOfCells; i++)
1042   {
1043     if (oldOffsetPtr[i] < 0) //non-polyhedron cell
1044     {
1045       newOffsetPtr[i] = -1;
1046     }
1047     else // polyhedron cell
1048     {
1049       foundPolyhedronCell = true;
1050       // read numberOfFaces in a cell
1051       vtkIdType currLoc = oldOffsetPtr[i];
1052       vtkIdType numberOfCellFaces = facesPtr[currLoc];
1053       currLoc += 1;
1054       for (vtkIdType j = 0; j < numberOfCellFaces; j++)
1055       {
1056         // read numberOfPoints in a face
1057         vtkIdType numberOfFacePoints = facesPtr[currLoc];
1058         currLoc += numberOfFacePoints + 1;
1059       }
1060       newOffsetPtr[i] = currLoc;
1061     }
1062   }
1063 
1064   if (!foundPolyhedronCell)
1065   {
1066     this->Faces->SetNumberOfTuples(0);
1067     this->FaceOffsets->SetNumberOfTuples(0);
1068   }
1069 }
1070 
1071 //----------------------------------------------------------------------------
GetNumberOfInputPoints()1072 vtkIdType vtkXMLUnstructuredDataWriter::GetNumberOfInputPoints()
1073 {
1074   vtkPointSet* input = this->GetInputAsPointSet();
1075   vtkPoints* points = input->GetPoints();
1076   return points?points->GetNumberOfPoints():0;
1077 }
1078 
1079 //----------------------------------------------------------------------------
CalculateDataFractions(float * fractions)1080 void vtkXMLUnstructuredDataWriter::CalculateDataFractions(float* fractions)
1081 {
1082   // Calculate the fraction of point/cell data and point
1083   // specifications contributed by each component.
1084   vtkPointSet* input = this->GetInputAsPointSet();
1085   int pdArrays = input->GetPointData()->GetNumberOfArrays();
1086   int cdArrays = input->GetCellData()->GetNumberOfArrays();
1087   vtkIdType pdSize = pdArrays*this->GetNumberOfInputPoints();
1088   vtkIdType cdSize = cdArrays*this->GetNumberOfInputCells();
1089   int total = (pdSize+cdSize+this->GetNumberOfInputPoints());
1090   if(total == 0)
1091   {
1092     total = 1;
1093   }
1094   fractions[0] = 0;
1095   fractions[1] = float(pdSize)/total;
1096   fractions[2] = float(pdSize+cdSize)/total;
1097   fractions[3] = 1;
1098 }
1099 
1100 //----------------------------------------------------------------------------
CalculateCellFractions(float * fractions,vtkIdType typesSize)1101 void vtkXMLUnstructuredDataWriter::CalculateCellFractions(float* fractions,
1102                                                           vtkIdType typesSize)
1103 {
1104   // Calculate the fraction of cell specification data contributed by
1105   // each of the connectivity, offset, and type arrays.
1106   vtkIdType connectSize = this->CellPoints->GetNumberOfTuples();
1107   vtkIdType offsetSize = this->CellOffsets->GetNumberOfTuples();
1108   vtkIdType faceSize = this->Faces ? this->Faces->GetNumberOfTuples() : 0;
1109   vtkIdType faceoffsetSize = this->FaceOffsets ?
1110                                this->FaceOffsets->GetNumberOfTuples() : 0;
1111   vtkIdType total = connectSize+offsetSize+faceSize+faceoffsetSize+typesSize;
1112   if(total == 0)
1113   {
1114     total = 1;
1115   }
1116   fractions[0] = 0;
1117   fractions[1] = float(connectSize)/total;
1118   fractions[2] = float(connectSize+offsetSize)/total;
1119   fractions[3] = float(connectSize+offsetSize+faceSize)/total;
1120   fractions[4] = float(connectSize+offsetSize+faceSize+faceoffsetSize)/total;
1121   fractions[5] = 1;
1122 }
1123 
1124 //----------------------------------------------------------------------------
SetInputUpdateExtent(int piece,int numPieces,int ghostLevel)1125 void vtkXMLUnstructuredDataWriter::SetInputUpdateExtent(
1126   int piece, int numPieces, int ghostLevel)
1127 {
1128   vtkInformation* inInfo =
1129     this->GetExecutive()->GetInputInformation(0, 0);
1130   inInfo->Set(
1131     vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), numPieces);
1132   inInfo->Set(
1133     vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), piece);
1134   inInfo->Set(
1135     vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(), ghostLevel);
1136 }
1137 
1138