FEM: Multiframe adoptions

- To support timedata and the relevant filters the pipeline needs to be fully setup, hence not only working on data
 - Multiblock source algorithm is needed to supply the time data for the algorithms
This commit is contained in:
Stefan Tröger
2024-11-24 16:11:53 +01:00
committed by Benjamin Nauck
parent 2119f9dfb4
commit 1cff507a7f
28 changed files with 1752 additions and 249 deletions

View File

@@ -33,6 +33,8 @@
#include <vtkUniformGrid.h>
#include <vtkUnstructuredGrid.h>
#include <vtkXMLDataSetWriter.h>
#include <vtkXMLMultiBlockDataWriter.h>
#include <vtkXMLMultiBlockDataReader.h>
#include <vtkXMLImageDataReader.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkXMLRectilinearGridReader.h>
@@ -49,6 +51,12 @@
#include <Base/Writer.h>
#include <CXX/Objects.hxx>
#ifdef _MSC_VER
#include <zipios++/zipios-config.h>
#endif
#include <zipios++/zipoutputstream.h>
#include "PropertyPostDataObject.h"
@@ -246,11 +254,11 @@ void PropertyPostDataObject::getPaths(std::vector<App::ObjectIdentifier>& /*path
void PropertyPostDataObject::Save(Base::Writer& writer) const
{
std::string extension;
if (!m_dataObject) {
return;
}
std::string extension;
switch (m_dataObject->GetDataObjectType()) {
case VTK_POLY_DATA:
@@ -268,16 +276,9 @@ void PropertyPostDataObject::Save(Base::Writer& writer) const
case VTK_UNIFORM_GRID:
extension = "vti"; // image data
break;
// TODO:multi-datasets use multiple files, this needs to be implemented specially
// case VTK_COMPOSITE_DATA_SET:
// prop->m_dataObject = vtkCompositeDataSet::New();
// break;
// case VTK_MULTIBLOCK_DATA_SET:
// prop->m_dataObject = vtkMultiBlockDataSet::New();
// break;
// case VTK_MULTIPIECE_DATA_SET:
// prop->m_dataObject = vtkMultiPieceDataSet::New();
// break;
case VTK_MULTIBLOCK_DATA_SET:
extension = "zip";
break;
default:
break;
};
@@ -297,13 +298,29 @@ void PropertyPostDataObject::Restore(Base::XMLReader& reader)
}
std::string file(reader.getAttribute("file"));
if (!file.empty()) {
// initiate a file read
reader.addFile(file.c_str(), this);
}
}
void add_to_zip(Base::FileInfo path, int zip_path_idx, zipios::ZipOutputStream& ZipWriter) {
if (path.isDir()) {
for(auto file : path.getDirectoryContent()) {
add_to_zip(file, zip_path_idx, ZipWriter);
}
}
else {
ZipWriter.putNextEntry(path.filePath().substr(zip_path_idx));
Base::ifstream file(path, std::ios::in | std::ios::binary);
if (file) {
std::streambuf* buf = file.rdbuf();
ZipWriter << buf;
}
}
}
void PropertyPostDataObject::SaveDocFile(Base::Writer& writer) const
{
// If the shape is empty we simply store nothing. The file size will be 0 which
@@ -315,12 +332,41 @@ void PropertyPostDataObject::SaveDocFile(Base::Writer& writer) const
// create a temporary file and copy the content to the zip stream
// once the tmp. filename is known use always the same because otherwise
// we may run into some problems on the Linux platform
static Base::FileInfo fi(App::Application::getTempFileName());
static Base::FileInfo fi = Base::FileInfo(App::Application::getTempFileName());
bool success = false;
vtkSmartPointer<vtkXMLDataSetWriter> xmlWriter = vtkSmartPointer<vtkXMLDataSetWriter>::New();
xmlWriter->SetInputDataObject(m_dataObject);
xmlWriter->SetFileName(fi.filePath().c_str());
xmlWriter->SetDataModeToBinary();
if (m_dataObject->IsA("vtkMultiBlockDataSet")) {
// create a tmp directory to write in
auto datafolder = Base::FileInfo(App::Application::getTempPath() + "vtk_datadir");
datafolder.createDirectories();
auto datafile = Base::FileInfo(datafolder.filePath() + "/datafile.vtm");
//create the data: vtm file and subfolder with the subsequent data files
auto xmlWriter = vtkSmartPointer<vtkXMLMultiBlockDataWriter>::New();
xmlWriter->SetInputDataObject(m_dataObject);
xmlWriter->SetFileName(datafile.filePath().c_str());
xmlWriter->SetDataModeToBinary();
success = xmlWriter->Write() == 1;
if (success) {
// ZIP file we store all data in
zipios::ZipOutputStream ZipWriter(fi.filePath());
ZipWriter.putNextEntry("dummy"); //need to add a dummy first, as the read stream always omits the first entry for unknown reasons
add_to_zip(datafolder, datafolder.filePath().length(), ZipWriter);
ZipWriter.close();
datafolder.deleteDirectoryRecursive();
}
}
else {
auto xmlWriter = vtkSmartPointer<vtkXMLDataSetWriter>::New();
xmlWriter->SetInputDataObject(m_dataObject);
xmlWriter->SetFileName(fi.filePath().c_str());
xmlWriter->SetDataModeToBinary();
success = xmlWriter->Write() == 1;
}
#ifdef VTK_CELL_ARRAY_V2
// Looks like an invalid data object that causes a crash with vtk9
@@ -331,7 +377,7 @@ void PropertyPostDataObject::SaveDocFile(Base::Writer& writer) const
}
#endif
if (xmlWriter->Write() != 1) {
if (!success) {
// Note: Do NOT throw an exception here because if the tmp. file could
// not be created we should not abort.
// We only print an error message but continue writing the next files to the
@@ -352,6 +398,7 @@ void PropertyPostDataObject::SaveDocFile(Base::Writer& writer) const
writer.addError(ss.str());
}
Base::ifstream file(fi, std::ios::in | std::ios::binary);
if (file) {
std::streambuf* buf = file.rdbuf();
@@ -368,6 +415,7 @@ void PropertyPostDataObject::RestoreDocFile(Base::Reader& reader)
Base::FileInfo xml(reader.getFileName());
// create a temporary file and copy the content from the zip stream
Base::FileInfo fi(App::Application::getTempFileName());
Base::FileInfo fo;
// read in the ASCII file and write back to the file stream
Base::ofstream file(fi, std::ios::out | std::ios::binary);
@@ -402,11 +450,50 @@ void PropertyPostDataObject::RestoreDocFile(Base::Reader& reader)
else if (extension == "vti") {
xmlReader = vtkSmartPointer<vtkXMLImageDataReader>::New();
}
else if (extension == "zip") {
// first unzip the file into a datafolder
zipios::ZipInputStream ZipReader(fi.filePath());
fo = Base::FileInfo(App::Application::getTempPath() + "vtk_extract_datadir");
fo.createDirectories();
try {
zipios::ConstEntryPointer entry = ZipReader.getNextEntry();
while(entry->isValid()) {
Base::FileInfo entry_path(fo.filePath() + entry->getName());
if (entry->isDirectory()) {
// seems not to be called
entry_path.createDirectories();
}
else {
auto entry_dir = Base::FileInfo(entry_path.dirPath());
if(!entry_dir.exists()) {
entry_dir.createDirectories();
}
Base::ofstream file(entry_path, std::ios::out | std::ios::binary);
std::streambuf* buf = file.rdbuf();
ZipReader >> buf;
file.flush();
file.close();
}
entry = ZipReader.getNextEntry();
}
}
catch (const std::exception&) {
// there is no further entry
}
// create the reader, and change the file for it to read. Also delete zip file, not needed anymore
fi.deleteFile();
fi = Base::FileInfo(fo.filePath() + "/datafile.vtm");
xmlReader = vtkSmartPointer<vtkXMLMultiBlockDataReader>::New();
}
xmlReader->SetFileName(fi.filePath().c_str());
xmlReader->Update();
if (!xmlReader->GetOutputAsDataSet()) {
if (!xmlReader->GetOutputDataObject(0)) {
// Note: Do NOT throw an exception here because if the tmp. created file could
// not be read it's NOT an indication for an invalid input stream 'reader'.
// We only print an error message but continue reading the next files from the
@@ -425,12 +512,15 @@ void PropertyPostDataObject::RestoreDocFile(Base::Reader& reader)
}
else {
aboutToSetValue();
createDataObjectByExternalType(xmlReader->GetOutputAsDataSet());
m_dataObject->DeepCopy(xmlReader->GetOutputAsDataSet());
createDataObjectByExternalType(xmlReader->GetOutputDataObject(0));
m_dataObject->DeepCopy(xmlReader->GetOutputDataObject(0));
hasSetValue();
}
}
// delete the temp file
fi.deleteFile();
if (xml.extension() == "zip") {
fo.deleteDirectoryRecursive();
}
}