vtkXMLPStructuredGridReader这个类位于/ParaView-v4.2.0-source/VTK/IO/XML。
这个类主要是用于读取PVTK XML StructuredGrid 文件。他读取并行模式的总结文件,并且使用vtkXMLStructuredGridReader从单独的结构化片文件中去读取数据。支持流,这种文件的扩展名为pvts。
这个类继承自vtkXMLPStructuredDataReader
在这个类之中,并没有几个具体的方法:
int vtkXMLPStructuredGridReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary):首先执行父类的这个函数:this->Superclass::ReadPrimaryElement(ePrimary),.然后它需要找到PPoints 元素。从这段找PPointsElement的代码来看,应该在所读文件里,只有叫一个PPoints的项。在里面存了点信息的参数。
void vtkXMLPStructuredGridReader::SetupOutputData():一样,先执行父类的:this->Superclass::SetupOutputData();然后获取一个点组,这里用points这个指针。PPointsElement是包含点信息的参数,这个应该在之前是读到了,设置好的。这个函数应该不是读取函数,而是通过PPointsElement获取所读取的数据中一共有多少Tuple。也就是有多少个Points,然后申请好空间。
int vtkXMLPStructuredGridReader::ReadPieceData():一样的先执行父类的函数:this->Superclass::ReadPieceData()。然后根据现在是哪一片通过创建vtkXMLStructuredGridReader去读数据,有多少片就创建多少个Reader;然后把数据从input复制到output中。(按理说不是还要有个把各个Reader读取的数据合成的函数吗?)
下面我们来看看一个非常重要的类,也就是vtkXMLPStructuredGridReader的父类:vtkXMLPDataReader
这个类他是提供所有通用的PVTK XML文件的Reader的一些方法。
vtkDataSet* vtkXMLPDataReader::GetPieceInputAsDataSet(int piece):很显然,这个函数又是根据所读的片号,用对应的vtkXMLDataReader去读,执行:return static_cast
void vtkXMLPDataReader::SetupOutputData():这里应该是有两种数据,一种是ePointData,一种是eCellData。同样的,这个函数应该也是设置pointData中数组中一共有多少个Tuples,给pointData设置好初始的空间。同理cellData。然后把ePointData和pointData,eCellData和cellData的联系,也就是信息和数据的联系。
int vtkXMLPDataReader::ReadXMLInformation():首先创建文件名组件: this->SplitFileName();。然后再执行父类return this->Superclass::ReadXMLInformation();
void vtkXMLPDataReader::SetupOutputInformation(vtkInformation *outInfo):需要注意的是在这个函数中做的改变,都要复制进CopyOutputInformation中。
首先初始化,然后为PointData创建场信息(Field),我们只需要一片的信息就可以了,因为所有片都相同系列的Array。this->SetFieldDataInfo(this->PPointDataElement,
vtkDataObject::FIELD_ASSOCIATION_POINTS, this->GetNumberOfPoints(), infoVector):根据这个函数创建场信息,然后把其放入outInfo->Set(vtkDataObject::POINT_DATA_VECTOR(), infoVector);同理设置Cell data。
void vtkXMLPDataReader::CopyOutputInformation(vtkInformation *outInfo, int port):把这个Reader的Info复制到outInfo中。
int vtkXMLPDataReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary):一样还是要先执行父类的this->Superclass::ReadPrimaryElement(ePrimary),然后开始读取数据的信息。首先如果标量属性中有没有GhostLevel。然后开始对xml文件中,PPointDataElement,PCellDataElement,numPieces根据一共有 int numNested = ePrimary->GetNumberOfNestedElements();这么多个xml项进行计算存储。然后 this->SetupPieces(numPieces);,建立这么多片。然后再对每一片进行读取。
void vtkXMLPDataReader::SetupPieces(int numPieces):首先如果有了片数据,就要清空。然后分别创建,NumberOfPieces,PieceElements(片的信息)和片的Reader,和CanReadPieceFlag。都是创建数组,根据有多少片就创建多少个。然后每个的数据都先初始化为0.很明显也是一个分配空间的函数。给每一片创建element,reader等等。
void vtkXMLPDataReader::DestroyPieces():摧毁每一片。
int vtkXMLPDataReader::ReadPiece(vtkXMLDataElement* ePiece, int index):根据index获取当前读的是哪一片。this->Piece = index;,然后开始读取片
int vtkXMLPDataReader::ReadPiece(vtkXMLDataElement* ePiece):首先赋值this->PieceElements[this->Piece] = ePiece;然后根据所传过来的信息,获取要读的文件名。然后创建pieceFileName。并且设置这一片的reader的要读的文件名为这个pieceFileName。并且加上Observer。
int vtkXMLPDataReader::ReadPieceData(int index):读取片数据。先设置
vtkDataArraySelection* pds =this->PieceReaders[this->Piece]->GetPointDataArraySelection();
vtkDataArraySelection* cds =this->PieceReaders[this->Piece]->GetCellDataArraySelection();
然后分别复制到(this->PointDataArraySelection)和(this->CellDataArraySelection)中,再执行this->ReadPieceData()
int vtkXMLPDataReader::ReadPieceData():调用this->GetPieceInputAsDataSet(this->Piece)获取input,并且把所有数据从input复制到output上。
int vtkXMLPDataReader::CanReadPiece(int index):测试这一片数据能不能读。肯定是调用下面的reader测试能不能读。
char* vtkXMLPDataReader::CreatePieceFileName(const char* fileName):创建片文件名(每一片数据的文件名?那个pvtk文件到底里面写的啥啊,是不是跟我想的一样的机制,这里面放了各个文件的名字,位置,然后才能让不同的process去读)
void vtkXMLPDataReader::SplitFileName():根据路径获取文件名
void vtkXMLPDataReader::PieceProgressCallbackFunction(vtkObject*, unsigned long, void* clientdata, void*)
void vtkXMLPDataReader::PieceProgressCallback():上面ReadPiece(vtkXMLDataElement* ePiece)Observer的回调方法。
接下来,再来看这个类的父类:vtkXMLReader:
这个类是使用vtkXMLDataParse去解析VTK XML格式的输入文件的。具体的子类接下来还要遍历解析文件结构并且提取数据。
static void ReadStringVersion(const char* version, int& major, int& minor):提取major和minor 版本号
vtkXMLReader::vtkXMLReader():构造函数,我们可以看到,一个vtkXMLReader它有以下属性:文件名,流,文件流,字符串流,从input字符串读取,输入的字符串(String),XML解析,场数据信息,
this->PointDataArraySelection = vtkDataArraySelection::New();
this->CellDataArraySelection = vtkDataArraySelection::New();
错误信息,数据错误,读取错误,进度范围[2],SelectionObserver,设置其回调为&vtkXMLReader::SelectionModifiedCallback,给this->PointDataArraySelection和this->CellDataArraySelection加上Observer。
this->SetNumberOfInputPorts(0);
this->SetNumberOfOutputPorts(1);初始化输入输出端口
AxesEmpty[3]:低维度网格数据支持
时间支持,文件版本,现在的输出端口
vtkDataSet* vtkXMLReader::GetOutputAsDataSet():调用this->GetOutputAsDataSet(0)
vtkDataSet* vtkXMLReader::GetOutputAsDataSet(int index):把this->GetOutputDataObject(index)强制转换为vtkDataSet
int vtkXMLReader::OpenStream():如果this->ReadFromInputString(从字符串读)则 returnthis->OpenVTKString();,否则 return this->OpenVTKFile();
int vtkXMLReader::OpenVTKFile():如果文件流已经存在,那么文件已经打开,报错,如果用户没有已经在使用流,并且文件名读不到,那么报错。如果用户用了用户提供的流,则直接返回。否则开始,首先需要打开一个确保存在的文件。然后得的哦文件流this->FileStream = new ifstream(this->FileName, ios::in);
int vtkXMLReader::OpenVTKString():同理前面一堆判断。最后this->StringStream = new std::istringstream(this->InputString);打开一个字符串流。
void vtkXMLReader::CloseStream():关闭所有流
void vtkXMLReader::CreateXMLParser():创建一个this->XMLParser = vtkXMLDataParser::New();
void vtkXMLReader::SetupCompressor(const char* type):实例化所给类型的压缩器,通过:
vtkObject* object = vtkInstantiator::CreateInstance(type);
vtkDataCompressor* compressor = vtkDataCompressor::SafeDownCast(object);
然后设置为this->XMLParser->SetCompressor(compressor);
int vtkXMLReader::ReadXMLInformation():只有在改变发生的时候才解析。首先要去除之前的解析。然后打开流:this->OpenStream()。然后创建CreateXMLParser(),把得到的流设置到这个xml解析器中: this->XMLParser->SetStream(this->Stream);。然后开始执行解析:this->XMLParser->Parse()
int vtkXMLReader::RequestInformation(vtkInformation *request,vtkInformationVector **vtkNotUsed(inputVector),vtkInformationVector *outputVector):非常关键的函数,得到所读数据的信息。先执行this->ReadXMLInformation()进行解析,设置outputPort。然后设置时间步。然后执行:
vtkInformation* outInfo = outputVector->GetInformationObject(0);
outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(),timeSteps, numTimesteps);
outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2);
这个函数通过这几个方法获得输出信息,完全看不懂啊
int vtkXMLReader::RequestData(vtkInformation *vtkNotUsed(request),vtkInformationVector **vtkNotUsed(inputVector),vtkInformationVector *outputVector):
关键函数,用来从文件中获取数据。首先获得输出流水线信息和数据对象:
vtkInformation* outInfo = outputVector->GetInformationObject(0);
vtkDataObject* output = outInfo->Get(vtkDataObject::DATA_OBJECT());
然后把outInfo中存储的时间值取出到steps中。然后check是否需要一个特定的时间,然后根据steps是否存在并且对其是否有更新的需求。然后获取:
double requestedTimeStep =outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
int length = outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
然后找到第一个比requested time值大的。显然它的意思是找到当数据更新请求之后的第一个发送过来的请求。
然后再把它存入output的info之中:output->GetInformation()->Set( vtkDataObject::DATA_TIME_STEP(), steps[this->CurrentTimeStep]);
从新打开数据流,如果失败报错。给vtkXMLParser实例读取的文件流,使得数据段读取开始工作。this->UpdateProgress(0.);开始读取; this->ReadXMLData(); this->UpdateProgressDiscrete(1);结束读取。
void vtkXMLReader::ReadXMLData():初始化输出数据this->SetupOutputData();
int vtkXMLReader::ReadVTKFile(vtkXMLDataElement* eVTKFile):首先确认版本是不是我们支持的。如果有压缩器则建立一个,然后获得当前主要元素。通过在所有的XML中找到与当前要读的数据集名字相同的块,然后开始读取, return this->ReadPrimaryElement(ePrimary);。
int vtkXMLReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary):首先获得numTimeSteps(在xml中为"TimeValues")。设置this->SetNumberOfTimeSteps( numTimeSteps );最后如果其中有FieldData元素,保存this->FieldDataElement中。
void vtkXMLReader::SetupOutputData():直接执行this->CurrentOutput->Initialize();
int vtkXMLReader::CreateInformationKey(vtkXMLDataElement *eInfoKey, vtkInformation *info):快速合理的从XML数据元素eInfoKey中查找出InformationKey,并且保证它定义合理,参数eInfoKey应该为我们读到的一些数据信息。保证其中有"name"和"location",
分别对于location和name为:"vtkQuadratureSchemeDefinition"和"DICTIONARY","vtkQuadratureSchemeDefinition"和"QUADRATURE_OFFSET_ARRAY_NAME",建立对应的key,然后对于前一种存入 key->RestoreState(info, eInfoKey);,后一种把name和value存入其中key->Set(info, value);。const char *value=eInfoKey->GetAttribute("value");
vtkAbstractArray* vtkXMLReader::CreateArray(vtkXMLDataElement* da):首先在da中一定要找到"type"关键字。然后直接创建一个数组用来存储vtkAbstractArray* array = vtkAbstractArray::CreateArray(dataType);。name设为中name属性,读取组件个数"NumberOfComponents",放入array中。找根据"ComponentName1,2,3,....."找到;对应的compName,compName = da->GetAttribute(buff.str().c_str()),然后给array中每个组件命名为compName。然后对于每一条da中的信息,都加入array进去。最后返回这个数组。
下面一串canreadfile,就不解析。
int vtkXMLReader::IntersectExtents(int* extent1, int* extent2, int* result):相交最大化。
int vtkXMLReader::SetFieldDataInfo(vtkXMLDataElement *eDSA, int association, int numTuples, vtkInformationVector *(&infoVector)):设置场数据信息。参数为eDSA为数据元素,numTuples为其中有几点组,每点组很多点。infoVector为信息组。
最后,我们需要总结猜测一下这种pvtk读取数据的一个流程。