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