1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkXMLPDataReader.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 "vtkXMLPDataReader.h"
16 
17 #include "vtkCallbackCommand.h"
18 #include "vtkCellData.h"
19 #include "vtkDataArray.h"
20 #include "vtkDataArraySelection.h"
21 #include "vtkDataSet.h"
22 #include "vtkPointData.h"
23 #include "vtkXMLDataElement.h"
24 #include "vtkXMLDataReader.h"
25 #include "vtkInformationVector.h"
26 #include "vtkInformation.h"
27 #include "vtkStreamingDemandDrivenPipeline.h"
28 
29 #include <vtksys/ios/sstream>
30 
31 
32 //----------------------------------------------------------------------------
vtkXMLPDataReader()33 vtkXMLPDataReader::vtkXMLPDataReader()
34 {
35   this->GhostLevel = 0;
36 
37   this->NumberOfPieces = 0;
38 
39   this->PieceElements = 0;
40   this->PieceReaders = 0;
41   this->CanReadPieceFlag = 0;
42 
43   this->PathName = 0;
44 
45   // Setup a callback for the internal serial readers to report
46   // progress.
47   this->PieceProgressObserver = vtkCallbackCommand::New();
48   this->PieceProgressObserver->SetCallback(&vtkXMLPDataReader::PieceProgressCallbackFunction);
49   this->PieceProgressObserver->SetClientData(this);
50 }
51 
52 //----------------------------------------------------------------------------
~vtkXMLPDataReader()53 vtkXMLPDataReader::~vtkXMLPDataReader()
54 {
55   if(this->NumberOfPieces)
56     {
57     this->DestroyPieces();
58     }
59   if(this->PathName)
60     {
61     delete [] this->PathName;
62     }
63   this->PieceProgressObserver->Delete();
64 }
65 
66 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)67 void vtkXMLPDataReader::PrintSelf(ostream& os, vtkIndent indent)
68 {
69   this->Superclass::PrintSelf(os, indent);
70   os << indent << "NumberOfPieces: " << this->NumberOfPieces << "\n";
71 }
72 
73 //----------------------------------------------------------------------------
GetPieceInputAsDataSet(int piece)74 vtkDataSet* vtkXMLPDataReader::GetPieceInputAsDataSet(int piece)
75 {
76   vtkXMLDataReader* reader = this->PieceReaders[piece];
77   if(!reader)
78     {
79     return 0;
80     }
81   if(reader->GetNumberOfOutputPorts() < 1)
82     {
83     return 0;
84     }
85   return static_cast<vtkDataSet*>(reader->GetOutputDataObject(0));
86 }
87 
88 
89 //----------------------------------------------------------------------------
SetupOutputData()90 void vtkXMLPDataReader::SetupOutputData()
91 {
92   this->Superclass::SetupOutputData();
93 
94   // Setup the output arrays.
95   vtkXMLDataElement* ePointData = this->PPointDataElement;
96   vtkXMLDataElement* eCellData = this->PCellDataElement;
97   vtkDataSet* output = vtkDataSet::SafeDownCast(this->GetCurrentOutput());
98   vtkPointData* pointData = output->GetPointData();
99   vtkCellData* cellData = output->GetCellData();
100 
101   // Get the size of the output arrays.
102   unsigned long pointTuples = this->GetNumberOfPoints();
103   unsigned long cellTuples = this->GetNumberOfCells();
104 
105   // Allocate data in the arrays.
106   int i;
107   if(ePointData)
108     {
109     for(i=0;i < ePointData->GetNumberOfNestedElements();++i)
110       {
111       vtkXMLDataElement* eNested = ePointData->GetNestedElement(i);
112       if(this->PointDataArrayIsEnabled(eNested))
113         {
114         vtkAbstractArray* array = this->CreateArray(eNested);
115         if(array)
116           {
117           array->SetNumberOfTuples(pointTuples);
118           pointData->AddArray(array);
119           array->Delete();
120           }
121         else
122           {
123           this->DataError = 1;
124           }
125         }
126       }
127     }
128 
129   if(eCellData)
130     {
131     for(i = 0; i < eCellData->GetNumberOfNestedElements(); i++)
132       {
133       vtkXMLDataElement* eNested = eCellData->GetNestedElement(i);
134       if(this->CellDataArrayIsEnabled(eNested))
135         {
136         vtkAbstractArray* array = this->CreateArray(eNested);
137         if(array)
138           {
139           array->SetNumberOfTuples(cellTuples);
140           cellData->AddArray(array);
141           array->Delete();
142           }
143         else
144           {
145           this->DataError = 1;
146           }
147         }
148       }
149     }
150 
151   // Setup attribute indices for the point data and cell data.
152   this->ReadAttributeIndices(ePointData, pointData);
153   this->ReadAttributeIndices(eCellData, cellData);
154 
155 }
156 
157 //----------------------------------------------------------------------------
ReadXMLInformation()158 int vtkXMLPDataReader::ReadXMLInformation()
159 {
160   // First setup the filename components.
161   this->SplitFileName();
162 
163   // Now proceed with reading the information.
164   return this->Superclass::ReadXMLInformation();
165 }
166 
167 
168 //----------------------------------------------------------------------------
169 // Note that any changes (add or removing information) made to this method
170 // should be replicated in CopyOutputInformation
SetupOutputInformation(vtkInformation * outInfo)171 void vtkXMLPDataReader::SetupOutputInformation(vtkInformation *outInfo)
172 {
173   if (this->InformationError)
174     {
175     vtkErrorMacro("Should not still be processing output information if have set InformationError");
176     return;
177     }
178 
179   // Initialize DataArraySelections to anable all that are present
180   this->SetDataArraySelections(this->PPointDataElement, this->PointDataArraySelection);
181   this->SetDataArraySelections(this->PCellDataElement, this->CellDataArraySelection);
182 
183   // Setup the Field Information for PointData.  We only need the
184   // information from one piece because all pieces have the same set of arrays.
185   vtkInformationVector *infoVector = NULL;
186   if (!this->SetFieldDataInfo(this->PPointDataElement,
187     vtkDataObject::FIELD_ASSOCIATION_POINTS, this->GetNumberOfPoints(), infoVector))
188     {
189     return;
190     }
191   if (infoVector)
192     {
193     outInfo->Set(vtkDataObject::POINT_DATA_VECTOR(), infoVector);
194     infoVector->Delete();
195     }
196 
197   // now the Cell data
198   infoVector = NULL;
199   if (!this->SetFieldDataInfo(this->PCellDataElement,
200     vtkDataObject::FIELD_ASSOCIATION_CELLS, this->GetNumberOfCells(), infoVector))
201     {
202     return;
203     }
204   if (infoVector)
205     {
206     outInfo->Set(vtkDataObject::CELL_DATA_VECTOR(), infoVector);
207     infoVector->Delete();
208     }
209 
210 }
211 
212 
213 //----------------------------------------------------------------------------
CopyOutputInformation(vtkInformation * outInfo,int port)214 void vtkXMLPDataReader::CopyOutputInformation(vtkInformation *outInfo,
215                                               int port)
216 {
217   vtkInformation *localInfo =
218     this->GetExecutive()->GetOutputInformation( port );
219   if ( localInfo->Has(vtkDataObject::POINT_DATA_VECTOR()) )
220     {
221     outInfo->CopyEntry( localInfo, vtkDataObject::POINT_DATA_VECTOR() );
222     }
223   if ( localInfo->Has(vtkDataObject::CELL_DATA_VECTOR()) )
224     {
225     outInfo->CopyEntry( localInfo, vtkDataObject::CELL_DATA_VECTOR() );
226     }
227 }
228 
229 
230 //----------------------------------------------------------------------------
ReadPrimaryElement(vtkXMLDataElement * ePrimary)231 int vtkXMLPDataReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary)
232 {
233   if(!this->Superclass::ReadPrimaryElement(ePrimary))
234     {
235     return 0;
236     }
237   // Read information about the data.
238   if(!ePrimary->GetScalarAttribute("GhostLevel", this->GhostLevel))
239     {
240     this->GhostLevel = 0;
241     }
242 
243   // Read information about the pieces.
244   this->PPointDataElement = 0;
245   this->PCellDataElement = 0;
246   int i;
247   int numNested = ePrimary->GetNumberOfNestedElements();
248   int numPieces = 0;
249   for(i=0;i < numNested; ++i)
250     {
251     vtkXMLDataElement* eNested = ePrimary->GetNestedElement(i);
252     if(strcmp(eNested->GetName(), "Piece") == 0)
253       {
254       ++numPieces;
255       }
256     else if(strcmp(eNested->GetName(), "PPointData") == 0)
257       {
258       this->PPointDataElement = eNested;
259       }
260     else if(strcmp(eNested->GetName(), "PCellData") == 0)
261       {
262       this->PCellDataElement = eNested;
263       }
264     }
265   this->SetupPieces(numPieces);
266   int piece = 0;
267   for(i=0;i < numNested; ++i)
268     {
269     vtkXMLDataElement* eNested = ePrimary->GetNestedElement(i);
270     if(strcmp(eNested->GetName(), "Piece") == 0)
271       {
272       if(!this->ReadPiece(eNested, piece++))
273         {
274         return 0;
275         }
276       }
277     }
278 
279   return 1;
280 }
281 
282 //----------------------------------------------------------------------------
SetupPieces(int numPieces)283 void vtkXMLPDataReader::SetupPieces(int numPieces)
284 {
285   if(this->NumberOfPieces)
286     {
287     this->DestroyPieces();
288     }
289   this->NumberOfPieces = numPieces;
290   this->PieceElements = new vtkXMLDataElement*[this->NumberOfPieces];
291   this->PieceReaders = new vtkXMLDataReader*[this->NumberOfPieces];
292   this->CanReadPieceFlag = new int[this->NumberOfPieces];
293   int i;
294   for(i=0;i < this->NumberOfPieces;++i)
295     {
296     this->PieceElements[i] = 0;
297     this->PieceReaders[i] = 0;
298     this->CanReadPieceFlag[i] = 0;
299     }
300 }
301 
302 //----------------------------------------------------------------------------
DestroyPieces()303 void vtkXMLPDataReader::DestroyPieces()
304 {
305   int i;
306   for(i=0;i < this->NumberOfPieces;++i)
307     {
308     if(this->PieceReaders[i])
309       {
310       this->PieceReaders[i]->RemoveObserver(this->PieceProgressObserver);
311       this->PieceReaders[i]->Delete();
312       }
313     }
314   delete [] this->PieceElements;
315   delete [] this->CanReadPieceFlag;
316   delete [] this->PieceReaders;
317   this->PieceElements = 0;
318   this->PieceReaders = 0;
319   this->NumberOfPieces = 0;
320 }
321 
322 //----------------------------------------------------------------------------
ReadPiece(vtkXMLDataElement * ePiece,int index)323 int vtkXMLPDataReader::ReadPiece(vtkXMLDataElement* ePiece, int index)
324 {
325   this->Piece = index;
326   return this->ReadPiece(ePiece);
327 }
328 
329 //----------------------------------------------------------------------------
ReadPiece(vtkXMLDataElement * ePiece)330 int vtkXMLPDataReader::ReadPiece(vtkXMLDataElement* ePiece)
331 {
332   this->PieceElements[this->Piece] = ePiece;
333 
334   const char* fileName = ePiece->GetAttribute("Source");
335   if(!fileName)
336     {
337     vtkErrorMacro("Piece " << this->Piece << " has no Source attribute.");
338     return 0;
339     }
340 
341   // The file name is relative to the summary file.  Convert it to
342   // something we can use.
343   char *pieceFileName = this->CreatePieceFileName(fileName);
344 
345   vtkXMLDataReader* reader = this->CreatePieceReader();
346   this->PieceReaders[this->Piece] = reader;
347   this->PieceReaders[this->Piece]->AddObserver(vtkCommand::ProgressEvent,
348                                                this->PieceProgressObserver);
349   reader->SetFileName(pieceFileName);
350 
351   delete [] pieceFileName;
352 
353   return 1;
354 }
355 
356 //----------------------------------------------------------------------------
ReadPieceData(int index)357 int vtkXMLPDataReader::ReadPieceData(int index)
358 {
359   this->Piece = index;
360 
361   // We need data, make sure the piece can be read.
362   if(!this->CanReadPiece(this->Piece))
363     {
364     vtkErrorMacro("File for piece " << this->Piece << " cannot be read.");
365     return 0;
366     }
367 
368   // Actually read the data.
369   this->PieceReaders[this->Piece]->SetAbortExecute(0);
370   vtkDataArraySelection* pds =
371     this->PieceReaders[this->Piece]->GetPointDataArraySelection();
372   vtkDataArraySelection* cds =
373     this->PieceReaders[this->Piece]->GetCellDataArraySelection();
374   pds->CopySelections(this->PointDataArraySelection);
375   cds->CopySelections(this->CellDataArraySelection);
376   return this->ReadPieceData();
377 }
378 
379 //----------------------------------------------------------------------------
ReadPieceData()380 int vtkXMLPDataReader::ReadPieceData()
381 {
382   vtkDataSet* input = this->GetPieceInputAsDataSet(this->Piece);
383   vtkDataSet* output = vtkDataSet::SafeDownCast(this->GetCurrentOutput());
384 
385   // copy any field data
386   if (input->GetFieldData())
387     {
388     int i;
389     for (i = 0; i < input->GetFieldData()->GetNumberOfArrays(); i++)
390       {
391       output->GetFieldData()->AddArray( input->GetFieldData()->GetArray(i) );
392       }
393     }
394 
395   // Copy point data and cell data for this piece.
396   int i;
397   for(i=0;i < output->GetPointData()->GetNumberOfArrays();++i)
398     {
399     this->CopyArrayForPoints(input->GetPointData()->GetArray(i),
400                              output->GetPointData()->GetArray(i));
401     }
402   for(i=0;i < output->GetCellData()->GetNumberOfArrays();++i)
403     {
404     this->CopyArrayForCells(input->GetCellData()->GetArray(i),
405                             output->GetCellData()->GetArray(i));
406     }
407 
408   return 1;
409 }
410 
411 //----------------------------------------------------------------------------
CanReadPiece(int index)412 int vtkXMLPDataReader::CanReadPiece(int index)
413 {
414   // If necessary, test whether the piece can be read.
415   vtkXMLDataReader* reader = this->PieceReaders[index];
416   if(reader && !this->CanReadPieceFlag[index])
417     {
418     if(reader->CanReadFile(reader->GetFileName()))
419       {
420       // We can read the piece.  Save result to avoid later repeat of
421       // test.
422       this->CanReadPieceFlag[index] = 1;
423       }
424     else
425       {
426       // We cannot read the piece.  Destroy the reader to avoid later
427       // repeat of test.
428       this->PieceReaders[index] = 0;
429       reader->Delete();
430       }
431     }
432 
433   return (this->PieceReaders[index]? 1:0);
434 }
435 
436 //----------------------------------------------------------------------------
CreatePieceFileName(const char * fileName)437 char* vtkXMLPDataReader::CreatePieceFileName(const char* fileName)
438 {
439   vtksys_ios::ostringstream fn_with_warning_C4701;
440 
441   // only prepend the path if the given file name is not
442   // absolute (i.e. doesn't start with '/')
443   if(this->PathName && fileName && fileName[0] != '/')
444     {
445     fn_with_warning_C4701 << this->PathName;
446     }
447   fn_with_warning_C4701 << fileName;
448 
449   size_t len = fn_with_warning_C4701.str().length();
450   char *buffer = new char[len + 1];
451   strncpy(buffer, fn_with_warning_C4701.str().c_str(), len);
452   buffer[len] = '\0';
453 
454   return buffer;
455 }
456 
457 //----------------------------------------------------------------------------
SplitFileName()458 void vtkXMLPDataReader::SplitFileName()
459 {
460   if(!this->FileName)
461     {
462     vtkErrorMacro( << "Need to specify a filename" );
463     return;
464     }
465 
466   // Pull the PathName component out of the FileName.
467   size_t length = strlen(this->FileName);
468   char* fileName = new char[length+1];
469   strcpy(fileName, this->FileName);
470   char* begin = fileName;
471   char* end = fileName + length;
472   char* s;
473 
474 #if defined(_WIN32)
475   // Convert to UNIX-style slashes.
476   for(s=begin;s != end;++s) { if(*s == '\\') { *s = '/'; } }
477 #endif
478 
479   // Extract the path name up to the last '/'.
480   if(this->PathName)
481     {
482     delete [] this->PathName;
483     this->PathName = 0;
484     }
485   char* rbegin = end-1;
486   char* rend = begin-1;
487   for(s=rbegin;s != rend;--s)
488     {
489     if(*s == '/')
490       {
491       break;
492       }
493     }
494   if(s >= begin)
495     {
496     length = (s-begin)+1;
497     this->PathName = new char[length+1];
498     strncpy(this->PathName, this->FileName, length);
499     this->PathName[length] = '\0';
500     }
501 
502   // Cleanup temporary name.
503   delete [] fileName;
504 }
505 
506 //----------------------------------------------------------------------------
PieceProgressCallbackFunction(vtkObject *,unsigned long,void * clientdata,void *)507 void vtkXMLPDataReader::PieceProgressCallbackFunction(vtkObject*, unsigned long,
508                                                       void* clientdata, void*)
509 {
510   reinterpret_cast<vtkXMLPDataReader*>(clientdata)->PieceProgressCallback();
511 }
512 
513 //----------------------------------------------------------------------------
PieceProgressCallback()514 void vtkXMLPDataReader::PieceProgressCallback()
515 {
516   float width = this->ProgressRange[1]-this->ProgressRange[0];
517   float pieceProgress = this->PieceReaders[this->Piece]->GetProgress();
518   float progress = this->ProgressRange[0] + pieceProgress*width;
519   this->UpdateProgressDiscrete(progress);
520   if(this->AbortExecute)
521     {
522     this->PieceReaders[this->Piece]->SetAbortExecute(1);
523     }
524 }
525