Commit 47f8853d authored by Mathieu Malaterre's avatar Mathieu Malaterre

ENH: First pass at adding timesupport in XML file. Getting toward solving issue #1739

parent 10c02c39
/*=========================================================================
Program: Visualization Toolkit
Module: vtkOffsetsManagerArray.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
// .NAME OffsetsManager - Helper class due to PIMPL excess
// .SECTION Description
// This class is deisgned to work within vtkXMLWriter. It store a position
// in a file (unsigned long) and associate a offset in the file. This is
// usefull when writting TimeStep XML file when you want to forward the
// same offset from the AppendData section on every entry in let say
// <Points> definition
// Example:
// <Points>
// <DataArray type="Float32" TimeStep="0" format="appended" offset="268" />
// <DataArray type="Float32" TimeStep="1" format="appended" offset="268" />
// ...
// </Points>
// Therefore data is only stored once in the XML file. At read time the
// offset value is stored to determine whenever we need to read data
// (ie when offset different from previously stored offset)
// .SECTION See Also
// vtkXMLWriter
// .SECTION Warning
// Do not include this file in a header file, it will break PIMPL convention
#ifndef __vtkOffsetsManagerArray_h
#define __vtkOffsetsManagerArray_h
#include "vtkSystemIncludes.h"
#include <vtkstd/vector>
#include <assert.h>
//----------------------------------------------------------------------------
class OffsetsManager
{
public:
// Construct with default (unsigned long)-1 MTime
OffsetsManager()
{
this->LastMTime = (unsigned long)-1; //almost invalid state
}
~OffsetsManager()
{
}
void Allocate(int numTimeStep)
{
assert( numTimeStep > 0);
this->Positions.resize(numTimeStep);
this->OffsetValues.resize(numTimeStep);
}
unsigned long &GetPosition(unsigned int t)
{
assert( t < this->Positions.size());
return this->Positions[t];
}
unsigned long &GetOffsetValue(unsigned int t)
{
assert( t < this->OffsetValues.size());
return this->OffsetValues[t];
}
unsigned long &GetLastMTime()
{
return this->LastMTime;
}
private:
unsigned long LastMTime; // Previously written dataarray mtime
vtkstd::vector<unsigned long> Positions; // Position in the stream to write the offset
vtkstd::vector<unsigned long> OffsetValues; // Value of offset
};
//----------------------------------------------------------------------------
class OffsetsManagerGroup
{
public:
// This is kind of a hack since we need to consider both the case of Points with
// only one array over time and PointData with possibly multiple array over time
// therefore we need to use a OffsetsManagerGroup for representing offset from
// Points but OffsetsManagerArray for PointData. In both case the toplevel structure
// is a container of Pieces...
OffsetsManager &GetPiece(unsigned int index)
{
assert( index < this->Internals.size());
OffsetsManager &e = this->Internals[index];
return e;
}
// GetElement should be used when manipulating a OffsetsManagerArray
OffsetsManager &GetElement(unsigned int index)
{
assert( index < this->Internals.size());
OffsetsManager &e = this->Internals[index];
return e;
}
unsigned int GetNumberOfElements()
{
return this->Internals.size();
}
void Allocate(int numElements)
{
assert(numElements >= 0); //allow 0 for empty FieldData
this->Internals.resize(numElements);
}
void Allocate(int numElements, int numTimeSteps)
{
assert(numElements > 0);
assert(numTimeSteps > 0);
this->Internals.resize(numElements);
for(int i=0; i<numElements; i++)
{
this->Internals[i].Allocate(numTimeSteps);
}
}
private:
vtkstd::vector<OffsetsManager> Internals;
};
//----------------------------------------------------------------------------
class OffsetsManagerArray
{
public:
OffsetsManagerGroup &GetPiece(unsigned int index)
{
assert( index < this->Internals.size());
return this->Internals[index];
}
void Allocate(int numPieces)
{
assert(numPieces > 0);
this->Internals.resize(numPieces);
}
void Allocate(int numPieces, int numElements, int numTimeSteps)
{
assert(numPieces > 0);
assert(numElements > 0);
assert(numTimeSteps > 0);
this->Internals.resize(numPieces);
for(int i=0; i<numPieces; i++)
{
this->Internals[i].Allocate(numElements, numTimeSteps);
}
}
private:
vtkstd::vector<OffsetsManagerGroup> Internals;
};
#endif
......@@ -20,7 +20,7 @@
#include <ctype.h>
vtkCxxRevisionMacro(vtkXMLDataElement, "1.22");
vtkCxxRevisionMacro(vtkXMLDataElement, "1.23");
vtkStandardNewMacro(vtkXMLDataElement);
//----------------------------------------------------------------------------
......@@ -482,91 +482,88 @@ vtkXMLDataElement* vtkXMLDataElement::LookupElementUpScope(const char* id)
//----------------------------------------------------------------------------
int vtkXMLDataElement::GetScalarAttribute(const char* name, int& value)
{
return this->GetVectorAttribute(name, 1, &value);
return this->GetVectorAttribute(name, &value);
}
//----------------------------------------------------------------------------
int vtkXMLDataElement::GetScalarAttribute(const char* name, float& value)
{
return this->GetVectorAttribute(name, 1, &value);
return this->GetVectorAttribute(name, &value);
}
//----------------------------------------------------------------------------
int vtkXMLDataElement::GetScalarAttribute(const char* name, double& value)
{
return this->GetVectorAttribute(name, 1, &value);
return this->GetVectorAttribute(name, &value);
}
//----------------------------------------------------------------------------
int vtkXMLDataElement::GetScalarAttribute(const char* name,
unsigned long& value)
{
return this->GetVectorAttribute(name, 1, &value);
return this->GetVectorAttribute(name, &value);
}
//----------------------------------------------------------------------------
#ifdef VTK_USE_64BIT_IDS
int vtkXMLDataElement::GetScalarAttribute(const char* name, vtkIdType& value)
{
return this->GetVectorAttribute(name, 1, &value);
return this->GetVectorAttribute(name, &value);
}
#endif
//----------------------------------------------------------------------------
template <class T>
int vtkXMLDataElementVectorAttributeParse(const char* str, int length, T* data)
int vtkXMLDataElementVectorAttributeParse(const char* str, T* data)
{
if(!str || !length || !data) { return 0; }
if(!str || !data)
{
return 0;
}
strstream vstr;
vstr << str << ends;
int i;
for(i=0;i < length;++i)
int i=0;
while(vstr >> data[i])
{
vstr >> data[i];
if(!vstr) { return i; }
++i;
}
return length;
return i;
}
//----------------------------------------------------------------------------
int vtkXMLDataElement::GetVectorAttribute(const char* name, int length,
int* data)
int vtkXMLDataElement::GetVectorAttribute(const char* name, int* data)
{
return vtkXMLDataElementVectorAttributeParse(this->GetAttribute(name),
length, data);
data);
}
//----------------------------------------------------------------------------
int vtkXMLDataElement::GetVectorAttribute(const char* name, int length,
float* data)
int vtkXMLDataElement::GetVectorAttribute(const char* name, float* data)
{
return vtkXMLDataElementVectorAttributeParse(this->GetAttribute(name),
length, data);
data);
}
//----------------------------------------------------------------------------
int vtkXMLDataElement::GetVectorAttribute(const char* name, int length,
double* data)
int vtkXMLDataElement::GetVectorAttribute(const char* name, double* data)
{
return vtkXMLDataElementVectorAttributeParse(this->GetAttribute(name),
length, data);
data);
}
//----------------------------------------------------------------------------
int vtkXMLDataElement::GetVectorAttribute(const char* name, int length,
unsigned long* data)
int vtkXMLDataElement::GetVectorAttribute(const char* name, unsigned long* data)
{
return vtkXMLDataElementVectorAttributeParse(this->GetAttribute(name),
length, data);
data);
}
//----------------------------------------------------------------------------
#ifdef VTK_USE_64BIT_IDS
int vtkXMLDataElement::GetVectorAttribute(const char* name, int length,
vtkIdType* data)
int vtkXMLDataElement::GetVectorAttribute(const char* name, vtkIdType* data)
{
return vtkXMLDataElementVectorAttributeParse(this->GetAttribute(name),
length, data);
data);
}
#endif
......
......@@ -77,10 +77,10 @@ public:
// Description:
// Get the attribute with the given name and converted to a scalar
// value. Returns length of vector read.
int GetVectorAttribute(const char* name, int length, int* value);
int GetVectorAttribute(const char* name, int length, float* value);
int GetVectorAttribute(const char* name, int length, double* value);
int GetVectorAttribute(const char* name, int length, unsigned long* value);
int GetVectorAttribute(const char* name, int* value);
int GetVectorAttribute(const char* name, float* value);
int GetVectorAttribute(const char* name, double* value);
int GetVectorAttribute(const char* name, unsigned long* value);
// Description:
// Set the attribute with the given name.
......@@ -93,7 +93,7 @@ public:
//BTX
int GetScalarAttribute(const char* name, vtkIdType& value);
void SetIdTypeAttribute(const char* name, vtkIdType value);
int GetVectorAttribute(const char* name, int length, vtkIdType* value);
int GetVectorAttribute(const char* name, vtkIdType* value);
void SetVectorAttribute(const char* name, int length, const vtkIdType* value);
//ETX
#endif
......
......@@ -22,7 +22,7 @@
#include "vtkObjectFactory.h"
#include "vtkXMLDataElement.h"
vtkCxxRevisionMacro(vtkXMLDataParser, "1.28");
vtkCxxRevisionMacro(vtkXMLDataParser, "1.29");
vtkStandardNewMacro(vtkXMLDataParser);
vtkCxxSetObjectMacro(vtkXMLDataParser, Compressor, vtkDataCompressor);
......
......@@ -25,7 +25,9 @@
#include "vtkInformation.h"
#include "vtkExecutive.h"
vtkCxxRevisionMacro(vtkXMLDataReader, "1.15");
#include "assert.h"
vtkCxxRevisionMacro(vtkXMLDataReader, "1.16");
//----------------------------------------------------------------------------
vtkXMLDataReader::vtkXMLDataReader()
......@@ -43,14 +45,35 @@ vtkXMLDataReader::vtkXMLDataReader()
this->DataProgressObserver = vtkCallbackCommand::New();
this->DataProgressObserver->SetCallback(&vtkXMLDataReader::DataProgressCallbackFunction);
this->DataProgressObserver->SetClientData(this);
this->PointDataTimeStep = NULL;
this->PointDataOffset = NULL;
this->CellDataTimeStep = NULL;
this->CellDataOffset = NULL;
}
//----------------------------------------------------------------------------
vtkXMLDataReader::~vtkXMLDataReader()
{
if(this->XMLParser) { this->DestroyXMLParser(); }
if(this->NumberOfPieces) { this->DestroyPieces(); }
if(this->XMLParser)
{
this->DestroyXMLParser();
}
if(this->NumberOfPieces)
{
this->DestroyPieces();
}
this->DataProgressObserver->Delete();
if( this->NumberOfPointArrays )
{
delete[] this->PointDataTimeStep;
delete[] this->PointDataOffset;
}
if( this->NumberOfCellArrays )
{
delete[] this->CellDataTimeStep;
delete[] this->CellDataOffset;
}
}
//----------------------------------------------------------------------------
......@@ -90,7 +113,7 @@ void vtkXMLDataReader::SetupOutputInformation(vtkInformation *outInfo)
return;
}
// Initialize DataArraySelections to anable all that are present
// Initialize DataArraySelections to enable all that are present
this->SetDataArraySelections(this->PointDataElements[0], this->PointDataArraySelection);
this->SetDataArraySelections(this->CellDataElements[0], this->CellDataArraySelection);
......@@ -141,7 +164,10 @@ void vtkXMLDataReader::CopyOutputInformation(vtkInformation *outInfo, int port)
//----------------------------------------------------------------------------
int vtkXMLDataReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary)
{
if(!this->Superclass::ReadPrimaryElement(ePrimary)) { return 0; }
if(!this->Superclass::ReadPrimaryElement(ePrimary))
{
return 0;
}
// Count the number of pieces in the file.
int numNested = ePrimary->GetNumberOfNestedElements();
......@@ -150,7 +176,10 @@ int vtkXMLDataReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary)
for(i=0; i < numNested; ++i)
{
vtkXMLDataElement* eNested = ePrimary->GetNestedElement(i);
if(strcmp(eNested->GetName(), "Piece") == 0) { ++numPieces; }
if(strcmp(eNested->GetName(), "Piece") == 0)
{
++numPieces;
}
}
// Now read each piece. If no "Piece" elements were found, assume
......@@ -164,14 +193,20 @@ int vtkXMLDataReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary)
vtkXMLDataElement* eNested = ePrimary->GetNestedElement(i);
if(strcmp(eNested->GetName(), "Piece") == 0)
{
if(!this->ReadPiece(eNested, piece++)) { return 0; }
if(!this->ReadPiece(eNested, piece++))
{
return 0;
}
}
}
}
else
{
this->SetupPieces(1);
if(!this->ReadPiece(ePrimary, 0)) { return 0; }
if(!this->ReadPiece(ePrimary, 0))
{
return 0;
}
}
return 1;
}
......@@ -179,7 +214,10 @@ int vtkXMLDataReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary)
//----------------------------------------------------------------------------
void vtkXMLDataReader::SetupPieces(int numPieces)
{
if(this->NumberOfPieces) { this->DestroyPieces(); }
if(this->NumberOfPieces)
{
this->DestroyPieces();
}
this->NumberOfPieces = numPieces;
if(numPieces > 0)
{
......@@ -228,7 +266,9 @@ void vtkXMLDataReader::SetupOutputData()
for (i = 0; i < ePointData->GetNumberOfNestedElements(); i++)
{
vtkXMLDataElement* eNested = ePointData->GetNestedElement(i);
if (this->PointDataArrayIsEnabled(eNested))
int idx =
this->PointDataArraySelection->GetArrayIndex(eNested->GetAttribute("Name"));
if (this->PointDataArrayIsEnabled(eNested) && pointData->GetNumberOfArrays() == idx)
{
this->NumberOfPointArrays++;
vtkDataArray* array = this->CreateDataArray(eNested);
......@@ -245,6 +285,7 @@ void vtkXMLDataReader::SetupOutputData()
}
}
}
assert( this->NumberOfPointArrays == this->PointDataArraySelection->GetNumberOfArraysEnabled());
this->NumberOfCellArrays = 0;
if (eCellData)
......@@ -252,7 +293,9 @@ void vtkXMLDataReader::SetupOutputData()
for (i = 0; i < eCellData->GetNumberOfNestedElements(); i++)
{
vtkXMLDataElement* eNested = eCellData->GetNestedElement(i);
if (this->CellDataArrayIsEnabled(eNested))
int idx =
this->CellDataArraySelection->GetArrayIndex(eNested->GetAttribute("Name"));
if (this->CellDataArrayIsEnabled(eNested) && cellData->GetNumberOfArrays() == idx)
{
this->NumberOfCellArrays++;
vtkDataArray* array = this->CreateDataArray(eNested);
......@@ -269,10 +312,29 @@ void vtkXMLDataReader::SetupOutputData()
}
}
}
assert( this->NumberOfCellArrays == this->CellDataArraySelection->GetNumberOfArraysEnabled());
// Setup attribute indices for the point data and cell data.
this->ReadAttributeIndices(ePointData, pointData);
this->ReadAttributeIndices(eCellData, cellData);
// Since NumberOfCellArrays and NumberOfPointArrays are valid
// lets allocate PointDataTimeStep, CellDataTimeStep, PointDataOffset
// CellDataOffset
if( this->NumberOfPointArrays )
{
this->PointDataTimeStep = new int[this->NumberOfPointArrays];
memset(this->PointDataTimeStep, -1, this->NumberOfPointArrays);
this->PointDataOffset = new unsigned long[this->NumberOfPointArrays];
memset(this->PointDataOffset, (unsigned long)-1, this->NumberOfPointArrays);
}
if( this->NumberOfCellArrays )
{
this->CellDataTimeStep = new int[this->NumberOfCellArrays];
memset(this->CellDataTimeStep, -1, this->NumberOfCellArrays);
this->CellDataOffset = new unsigned long[this->NumberOfCellArrays];
memset(this->CellDataOffset, (unsigned long)-1, this->NumberOfCellArrays);
}
}
//----------------------------------------------------------------------------
......@@ -334,19 +396,24 @@ int vtkXMLDataReader::ReadPieceData()
!this->AbortExecute);++i)
{
vtkXMLDataElement* eNested = ePointData->GetNestedElement(i);
if(this->PointDataArrayIsEnabled(eNested))
if (this->PointDataArrayIsEnabled(eNested))
{
// Set the range of progress for this array.
this->SetProgressRange(progressRange, currentArray++, numArrays);
// Read the array.
if(!this->ReadArrayForPoints(eNested, pointData->GetArray(a++)))
assert( strcmp(eNested->GetName(), "DataArray") == 0 );
int needToRead = this->PointDataNeedToReadTimeStep(eNested);
if( needToRead )
{
vtkErrorMacro("Cannot read point data array \""
<< pointData->GetArray(a-1)->GetName() << "\" from "
<< ePointData->GetName() << " in piece " << this->Piece
<< ". The data array in the element may be too short.");
return 0;
// Set the range of progress for this array.
this->SetProgressRange(progressRange, currentArray++, numArrays);
// Read the array.
if(!this->ReadArrayForPoints(eNested, pointData->GetArray(a++)))
{
vtkErrorMacro("Cannot read point data array \""
<< pointData->GetArray(a-1)->GetName() << "\" from "
<< ePointData->GetName() << " in piece " << this->Piece
<< ". The data array in the element may be too short.");
return 0;
}
}
}
}
......@@ -358,19 +425,24 @@ int vtkXMLDataReader::ReadPieceData()
!this->AbortExecute);++i)
{
vtkXMLDataElement* eNested = eCellData->GetNestedElement(i);
if(this->CellDataArrayIsEnabled(eNested))
if (this->CellDataArrayIsEnabled(eNested))
{
// Set the range of progress for this array.
this->SetProgressRange(progressRange, currentArray++, numArrays);
// Read the array.
if(!this->ReadArrayForCells(eNested, cellData->GetArray(a++)))
assert( strcmp(eNested->GetName(), "DataArray") == 0 );
int needToRead = this->CellDataNeedToReadTimeStep(eNested);
if( needToRead )
{
vtkErrorMacro("Cannot read cell data array \""
<< cellData->GetArray(a-1)->GetName() << "\" from "
<< ePointData->GetName() << " in piece " << this->Piece
<< ". The data array in the element may be too short.");
return 0;
// Set the range of progress for this array.
this->SetProgressRange(progressRange, currentArray++, numArrays);
// Read the array.
if(!this->ReadArrayForCells(eNested, cellData->GetArray(a++)))
{
vtkErrorMacro("Cannot read cell data array \""
<< cellData->GetArray(a-1)->GetName() << "\" from "
<< ePointData->GetName() << " in piece " << this->Piece
<< ". The data array in the element may be too short.");
return 0;
}
}
}
}
......@@ -468,7 +540,10 @@ int vtkXMLDataReader::ReadData(vtkXMLDataElement* da, void* data, int wordType,
{
int isAscii = 1;
const char* format = da->GetAttribute("format");
if(format && (strcmp(format, "binary") == 0)) { isAscii = 0; }
if(format && (strcmp(format, "binary") == 0))
{
isAscii = 0;
}
result = (this->XMLParser->ReadInlineData(da, isAscii, data,
startWord, numWords, wordType)
== num);
......@@ -499,3 +574,115 @@ void vtkXMLDataReader::DataProgressCallback()
}
}
}
//----------------------------------------------------------------------------
int vtkXMLDataReader::PointDataNeedToReadTimeStep(vtkXMLDataElement *eNested)
{
// First thing need to find the id of this dataarray from its name:
const char* name = eNested->GetAttribute("Name");
int idx = this->PointDataArraySelection->GetArrayIndex(name);
// Easy case no timestep:
int numTimeSteps = eNested->GetVectorAttribute("TimeStep", this->TimeSteps);
if (!numTimeSteps && this->NumberOfTimeSteps && this->PointDataTimeStep[idx] != -1)
{
return 0;
}
else if(!this->NumberOfTimeSteps && numTimeSteps)
{
vtkErrorMacro( << "TimeStep was specified but no TimeValues associated was found");
return 0;
}
int isCurrentTimeInArray =
vtkXMLReader::IsTimeStepInArray(this->CurrentTimeStep, this->TimeSteps, numTimeSteps);
if( numTimeSteps && !isCurrentTimeInArray)
{
return 0;
}
// let's check our own fields
// Need to check the current 'offset'
unsigned long offset;
if( eNested->GetScalarAttribute("offset", offset) )
{
if( this->PointDataOffset[idx] != offset )
{
// save the pointsOffset
this->PointDataOffset[idx] = offset;
return 1;
}
}
else
{
// Check if CurrentTimeStep is in the array and particular field is also:
int isCurrentTimeInArray =
vtkXMLReader::IsTimeStepInArray(this->CurrentTimeStep, this->TimeSteps, numTimeSteps);
if( !numTimeSteps && this->NumberOfTimeSteps && this->PointDataTimeStep[idx] == -1)
{
return 1;
}
int isLastTimeInArray =
vtkXMLReader::IsTimeStepInArray(this->PointDataTimeStep[idx], this->TimeSteps, numTimeSteps);
// If no time is specified or if time is specified and match then read
if (isCurrentTimeInArray && !isLastTimeInArray) //CurrentTime is in Array but Last is not
{
// Update last PointsTimeStep read
this->PointDataTimeStep[idx] = this->CurrentTimeStep;
return 1;
}
}
// we don't need to read:
return 0;
}
//----------------------------------------------------------------------------
int vtkXMLDataReader::CellDataNeedToReadTimeStep(vtkXMLDataElement *eNested)
{
// First thing need to find the id of this dataarray from its name:
const char* name = eNested->GetAttribute("Name");
int idx = this->CellDataArraySelection->GetArrayIndex(name);
// Easy case no timestep:
int numTimeSteps = eNested->GetVectorAttribute("TimeStep", this->TimeSteps);
if (!numTimeSteps && this->NumberOfTimeSteps && this->CellDataTimeStep[idx] != -1)
{
return 0;
}
else if(!this->NumberOfTimeSteps && numTimeSteps)
{
vtkErrorMacro( << "TimeStep was specified but no TimeValues associated was found");
return 0;
}
// let's check our own fields
// Need to check the current 'offset'
unsigned long offset;
if( eNested->GetScalarAttribute("offset", offset) )
{
if( this->CellDataOffset[idx] != offset )
{
// save the pointsOffset
this->CellDataOffset[idx] = offset;
return 1;
}
}
else
{
// Check if CurrentTimeStep is in the array and particular field is also:
int isCurrentTimeInArray =
vtkXMLReader::IsTimeStepInArray(this->CurrentTimeStep, this->TimeSteps, numTimeSteps);
if( !numTimeSteps && this->NumberOfTimeSteps && this->CellDataTimeStep[idx] == -1)
{
return 1;
}
int isLastTimeInArray =
vtkXMLReader::IsTimeStepInArray(this->CellDataTimeStep[idx], this->TimeSteps, numTimeSteps);
// If no time is specified or if time is specified and match then read
if (isCurrentTimeInArray && !isLastTimeInArray) //CurrentTime is in Array but Last is not
{
// Update last CellsTimeStep read
this->CellDataTimeStep[idx] = this->CurrentTimeStep;
return 1;
}
}
// we don't need to read:
return 0;
}
......@@ -107,7 +107,18 @@ protected:
// The observer to report progress from reading data from XMLParser.
vtkCallbackCommand* DataProgressObserver;
// Specify the last time step read, usefull to know if we need to rearead data
// //PointData
int *PointDataTimeStep;
unsigned long *PointDataOffset;
int PointDataNeedToReadTimeStep(vtkXMLDataElement *eNested);
//CellData
int *CellDataTimeStep;
unsigned long *CellDataOffset;
int CellDataNeedToReadTimeStep(vtkXMLDataElement *eNested);
private:
vtkXMLDataReader(const vtkXMLDataReader&); // Not implemented.