diff --git a/Documentation/release/dev/json-exporter-arrays.md b/Documentation/release/dev/json-exporter-arrays.md new file mode 100644 index 0000000000000000000000000000000000000000..9ad252f304a8da35b277bca30a6497180b82aa34 --- /dev/null +++ b/Documentation/release/dev/json-exporter-arrays.md @@ -0,0 +1,3 @@ +## JSONSceneExporter: Support exporting a list of named actors and arrays selections + +vtkJSONSceneExporter is now able to export a list of named actors instead of extracting them from a renderer. With these named actors, you can select which arrays are to be exported for each actor. vtkJSONDataSetWriter now also support point and cell array selection. The protected methods `vtkJSONSceneExporter::WriteDataObject` and `vtkJSONSceneExporter::WriteDataSet` are now private. diff --git a/IO/Export/vtkExporter.cxx b/IO/Export/vtkExporter.cxx index 97c244efe64eb6b26f626f097e060e813dce041a..f45226c2b64a360f6b7ee4a8135503a2ed12692e 100644 --- a/IO/Export/vtkExporter.cxx +++ b/IO/Export/vtkExporter.cxx @@ -9,6 +9,7 @@ VTK_ABI_NAMESPACE_BEGIN vtkCxxSetObjectMacro(vtkExporter, RenderWindow, vtkRenderWindow); vtkCxxSetObjectMacro(vtkExporter, ActiveRenderer, vtkRenderer); +//------------------------------------------------------------------------------ // Construct with no start and end write methods or arguments. vtkExporter::vtkExporter() { @@ -22,6 +23,7 @@ vtkExporter::vtkExporter() this->EndWriteArg = nullptr; } +//------------------------------------------------------------------------------ vtkExporter::~vtkExporter() { this->SetRenderWindow(nullptr); @@ -37,6 +39,7 @@ vtkExporter::~vtkExporter() } } +//------------------------------------------------------------------------------ // Write data to output. Method executes subclasses WriteData() method, as // well as StartWrite() and EndWrite() methods. void vtkExporter::Write() @@ -64,12 +67,14 @@ void vtkExporter::Write() } } +//------------------------------------------------------------------------------ // Convenient alias for Write() method. void vtkExporter::Update() { this->Write(); } +//------------------------------------------------------------------------------ // Specify a function to be called before data is written. // Function will be called with argument provided. void vtkExporter::SetStartWrite(void (*f)(void*), void* arg) @@ -87,6 +92,7 @@ void vtkExporter::SetStartWrite(void (*f)(void*), void* arg) } } +//------------------------------------------------------------------------------ // Set the arg delete method. This is used to free user memory. void vtkExporter::SetStartWriteArgDelete(void (*f)(void*)) { @@ -97,6 +103,7 @@ void vtkExporter::SetStartWriteArgDelete(void (*f)(void*)) } } +//------------------------------------------------------------------------------ // Set the arg delete method. This is used to free user memory. void vtkExporter::SetEndWriteArgDelete(void (*f)(void*)) { @@ -107,6 +114,7 @@ void vtkExporter::SetEndWriteArgDelete(void (*f)(void*)) } } +//------------------------------------------------------------------------------ // Specify a function to be called after data is written. // Function will be called with argument provided. void vtkExporter::SetEndWrite(void (*f)(void*), void* arg) @@ -124,6 +132,7 @@ void vtkExporter::SetEndWrite(void (*f)(void*), void* arg) } } +//------------------------------------------------------------------------------ void vtkExporter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); @@ -165,6 +174,7 @@ void vtkExporter::PrintSelf(ostream& os, vtkIndent indent) } } +//------------------------------------------------------------------------------ vtkMTimeType vtkExporter::GetMTime() { vtkMTimeType mTime = this->vtkObject::GetMTime(); diff --git a/IO/Export/vtkJSONDataSetWriter.cxx b/IO/Export/vtkJSONDataSetWriter.cxx index 81eec8fd74834afd98cc1a9fcad17f1076422a7c..0a29070dd083f47285f674d2d669b38cc4a5271a 100644 --- a/IO/Export/vtkJSONDataSetWriter.cxx +++ b/IO/Export/vtkJSONDataSetWriter.cxx @@ -39,6 +39,8 @@ vtkJSONDataSetWriter::vtkJSONDataSetWriter() { this->Archiver = vtkArchiver::New(); this->ValidStringCount = 1; + this->GetPointArraySelection()->SetUnknownArraySetting(1); + this->GetCellArraySelection()->SetUnknownArraySetting(1); } //------------------------------------------------------------------------------ @@ -94,6 +96,23 @@ std::string vtkJSONDataSetWriter::WriteDataSetAttributes( continue; } + if (std::string(className) == "pointData") + { + if (!this->GetPointArraySelection()->ArrayIsEnabled(field->GetName())) + { + vtkDebugMacro("Skipping writing point array " << field->GetName()); + continue; + } + } + else if (std::string(className) == "cellData") + { + if (!this->GetCellArraySelection()->ArrayIsEnabled(field->GetName())) + { + vtkDebugMacro("Skipping cell array " << field->GetName()); + continue; + } + } + if (nbArrayWritten) { jsonSnippet << ",\n"; @@ -384,6 +403,15 @@ bool vtkJSONDataSetWriter::WriteArrayAsRAW(vtkDataArray* array, const char* file void vtkJSONDataSetWriter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); + + os << indent << "Archiver:" << endl; + this->Archiver->PrintSelf(os, indent.GetNextIndent()); + + os << indent << "PointArraySelection:" << endl; + this->PointArraySelection->PrintSelf(os, indent.GetNextIndent()); + + os << indent << "CelltArraySelection:" << endl; + this->CellArraySelection->PrintSelf(os, indent.GetNextIndent()); } //------------------------------------------------------------------------------ diff --git a/IO/Export/vtkJSONDataSetWriter.h b/IO/Export/vtkJSONDataSetWriter.h index 29510cceaf9646c1485f0c243eb01de56b976d24..e3628f687210221e78ac1fdf7a34ee746a227345 100644 --- a/IO/Export/vtkJSONDataSetWriter.h +++ b/IO/Export/vtkJSONDataSetWriter.h @@ -32,6 +32,9 @@ #include <string> // std::string used as parameters in a few methods +#include "vtkDataArraySelection.h" // Instantiated +#include "vtkNew.h" // Used for DataArray selection + VTK_ABI_NAMESPACE_BEGIN class vtkDataSet; class vtkDataArray; @@ -118,6 +121,16 @@ public: vtkGetObjectMacro(Archiver, vtkArchiver); ///@} + /** + * Specify which point arrays should be written. + */ + vtkGetObjectMacro(PointArraySelection, vtkDataArraySelection); + + /** + * Specify which cell arrays should be written. + */ + vtkGetObjectMacro(CellArraySelection, vtkDataArraySelection); + void Write(vtkDataSet*); bool IsDataSetValid() { return this->ValidDataSet; } @@ -139,6 +152,9 @@ protected: private: vtkJSONDataSetWriter(const vtkJSONDataSetWriter&) = delete; void operator=(const vtkJSONDataSetWriter&) = delete; + + vtkNew<vtkDataArraySelection> PointArraySelection; + vtkNew<vtkDataArraySelection> CellArraySelection; }; VTK_ABI_NAMESPACE_END diff --git a/IO/Export/vtkJSONSceneExporter.cxx b/IO/Export/vtkJSONSceneExporter.cxx index 476f169895c3e7cd7187e3b4d364b72c90a8344c..503d60212a06f449100abfa3b0e3e35dd22a6ae6 100644 --- a/IO/Export/vtkJSONSceneExporter.cxx +++ b/IO/Export/vtkJSONSceneExporter.cxx @@ -47,7 +47,6 @@ VTK_ABI_NAMESPACE_BEGIN vtkStandardNewMacro(vtkJSONSceneExporter); //------------------------------------------------------------------------------ - vtkJSONSceneExporter::vtkJSONSceneExporter() { this->FileName = nullptr; @@ -61,7 +60,6 @@ vtkJSONSceneExporter::vtkJSONSceneExporter() } //------------------------------------------------------------------------------ - vtkJSONSceneExporter::~vtkJSONSceneExporter() { this->SetFileName(nullptr); @@ -70,9 +68,21 @@ vtkJSONSceneExporter::~vtkJSONSceneExporter() } //------------------------------------------------------------------------------ +void vtkJSONSceneExporter::SetNamedActorsMap(std::map<std::string, vtkActor*>& map) +{ + this->NamedActorsMap = map; + this->Modified(); +} + +//------------------------------------------------------------------------------ +std::map<std::string, vtkActor*> vtkJSONSceneExporter::GetNamedActorsMap() +{ + return this->NamedActorsMap; +} +//------------------------------------------------------------------------------ void vtkJSONSceneExporter::WriteDataObject( - ostream& os, vtkDataObject* dataObject, vtkActor* actor = nullptr, vtkVolume* volume = nullptr) + ostream& os, vtkDataObject* dataObject, vtkActor* actor, vtkVolume* volume, const char* name) { // Skip if nothing to process if (dataObject == nullptr) @@ -107,7 +117,7 @@ void vtkJSONSceneExporter::WriteDataObject( } std::string addOnMeta = renderingSetup + texturesString + "\n"; std::string dsMeta = - this->WriteDataSet(vtkDataSet::SafeDownCast(dataObject), addOnMeta.c_str()); + this->WriteDataSet(vtkDataSet::SafeDownCast(dataObject), addOnMeta.c_str(), name); if (!dsMeta.empty()) { os << dsMeta; @@ -125,7 +135,7 @@ void vtkJSONSceneExporter::WriteDataObject( iter->InitTraversal(); while (!iter->IsDoneWithTraversal()) { - this->WriteDataObject(os, iter->GetCurrentDataObject(), actor, volume); + this->WriteDataObject(os, iter->GetCurrentDataObject(), actor, volume, name); iter->GoToNextItem(); } @@ -198,13 +208,12 @@ void vtkJSONSceneExporter::WriteDataObject( normalFilter->Update(); // Write tubes and spheres - this->WriteDataObject(os, stickFilter->GetOutput(), actor, volume); - this->WriteDataObject(os, normalFilter->GetOutput(), actor, volume); + this->WriteDataObject(os, stickFilter->GetOutput(), actor, volume, name); + this->WriteDataObject(os, normalFilter->GetOutput(), actor, volume, name); } } //------------------------------------------------------------------------------ - std::string vtkJSONSceneExporter::ExtractColorTransferFunctionSetup( vtkColorTransferFunction* function) { @@ -260,7 +269,6 @@ std::string vtkJSONSceneExporter::ExtractColorTransferFunctionSetup( } //------------------------------------------------------------------------------ - std::string vtkJSONSceneExporter::ExtractPiecewiseFunctionSetup(vtkPiecewiseFunction* function) { bool clamping = function->GetClamping(); @@ -429,12 +437,12 @@ std::string vtkJSONSceneExporter::ExtractActorRenderingSetup(vtkActor* actor) } //------------------------------------------------------------------------------ - std::string vtkJSONSceneExporter::GetTemporaryPath() const { return std::string(this->FileName) + ".pvtmp"; } +//------------------------------------------------------------------------------ std::string vtkJSONSceneExporter::CurrentDataSetPath() const { std::stringstream path; @@ -443,8 +451,8 @@ std::string vtkJSONSceneExporter::CurrentDataSetPath() const } //------------------------------------------------------------------------------ - -std::string vtkJSONSceneExporter::WriteDataSet(vtkDataSet* dataset, const char* addOnMeta = nullptr) +std::string vtkJSONSceneExporter::WriteDataSet( + vtkDataSet* dataset, const char* addOnMeta, const char* name) { if (!dataset) { @@ -467,6 +475,32 @@ std::string vtkJSONSceneExporter::WriteDataSet(vtkDataSet* dataset, const char* vtkNew<vtkJSONDataSetWriter> dsWriter; dsWriter->SetInputData(dataset); dsWriter->GetArchiver()->SetArchiveName(dsPath.c_str()); + + // Parse MapPointArrays's list of arrays, filter the ones that start with "propName:X", and + // forward information about X to the writer + for (int id = 0; id < this->PointArraySelection->GetNumberOfArrays(); id++) + { + std::string currentName = this->PointArraySelection->GetArrayName(id); + if (currentName.find(name) != std::string::npos && currentName[std::string(name).size()] == ':') + { + std::string arrayName = currentName.substr(std::string(name).size() + 1); + dsWriter->GetPointArraySelection()->SetArraySetting( + arrayName.c_str(), this->PointArraySelection->ArrayIsEnabled(currentName.c_str())); + } + } + + // Same for cell arrays + for (int id = 0; id < this->CellArraySelection->GetNumberOfArrays(); id++) + { + std::string currentName = this->CellArraySelection->GetArrayName(id); + if (currentName.find(name) != std::string::npos && currentName[std::string(name).size()] == ':') + { + std::string arrayName = currentName.substr(std::string(name).size() + 1); + dsWriter->GetCellArraySelection()->SetArraySetting( + arrayName.c_str(), this->CellArraySelection->ArrayIsEnabled(currentName.c_str())); + } + } + dsWriter->Write(); if (!dsWriter->IsDataSetValid()) @@ -485,8 +519,9 @@ std::string vtkJSONSceneExporter::WriteDataSet(vtkDataSet* dataset, const char* meta << "\n"; } constexpr const char* INDENT = " "; + std::string dsName = (name ? name : std::to_string(this->DatasetCount)); meta << INDENT << "{\n" - << INDENT << " \"name\": \"" << this->DatasetCount << "\",\n" + << INDENT << " \"name\": \"" << dsName << "\",\n" << INDENT << " \"type\": \"vtkHttpDataSetReader\",\n" << INDENT << " \"vtkHttpDataSetReader\": { \"url\": \"" << this->DatasetCount << "\" }"; @@ -502,7 +537,6 @@ std::string vtkJSONSceneExporter::WriteDataSet(vtkDataSet* dataset, const char* } //------------------------------------------------------------------------------ - void vtkJSONSceneExporter::WriteLookupTable(const char* name, vtkScalarsToColors* lookupTable) { if (lookupTable == nullptr) @@ -572,7 +606,7 @@ void vtkJSONSceneExporter::WritePropCollection( vtkMapper* mapper = actor->GetMapper(); vtkDataObject* dataObject = mapper->GetInputDataObject(0, 0); - this->WriteDataObject(sceneComponents, dataObject, actor); + this->WriteDataObject(sceneComponents, dataObject, actor, nullptr, nullptr); this->WriteLookupTable(mapper->GetArrayName(), mapper->GetLookupTable()); } } @@ -594,7 +628,33 @@ void vtkJSONSceneExporter::WriteVolumeCollection( vtkAbstractVolumeMapper* mapper = volume->GetMapper(); vtkDataObject* dataObject = mapper->GetInputDataObject(0, 0); - this->WriteDataObject(sceneComponents, dataObject, nullptr, volume); + this->WriteDataObject(sceneComponents, dataObject, nullptr, volume, nullptr); + } +} + +//------------------------------------------------------------------------------ +void vtkJSONSceneExporter::WriteNamedActors( + std::map<std::string, vtkActor*>& actorMap, std::ostream& sceneComponents) +{ + for (auto it = actorMap.begin(); it != actorMap.end(); it++) + { + vtkProp* prop = vtkProp::SafeDownCast(it->second); + // Skip non-visible actors + if (!prop || !prop->GetVisibility()) + { + continue; + } + + // Skip actors with no geometry + vtkActor* actor = vtkActor::SafeDownCast(prop); + if (actor) + { + vtkMapper* mapper = actor->GetMapper(); + + vtkDataObject* dataObject = mapper->GetInputDataObject(0, 0); + this->WriteDataObject(sceneComponents, dataObject, actor, nullptr, it->first.c_str()); + this->WriteLookupTable(mapper->GetArrayName(), mapper->GetLookupTable()); + } } } @@ -631,8 +691,16 @@ void vtkJSONSceneExporter::WriteData() std::stringstream sceneComponents; vtkPropCollection* renProps = renderer->GetViewProps(); - this->WritePropCollection(renProps, sceneComponents); - this->WriteVolumeCollection(renderer->GetVolumes(), sceneComponents); + auto actorMap = this->GetNamedActorsMap(); + if (!actorMap.empty()) + { + this->WriteNamedActors(actorMap, sceneComponents); + } + else + { + this->WritePropCollection(renProps, sceneComponents); + this->WriteVolumeCollection(renderer->GetVolumes(), sceneComponents); + } std::stringstream sceneJsonFile; sceneJsonFile << "{\n" @@ -685,6 +753,7 @@ void vtkJSONSceneExporter::WriteData() } } +//------------------------------------------------------------------------------ namespace { @@ -710,7 +779,6 @@ size_t getFileSize(const std::string& path) } // end anon namespace //------------------------------------------------------------------------------ - std::string vtkJSONSceneExporter::WriteTexture(vtkTexture* texture) { // If this texture has already been written, just re-use the one @@ -747,7 +815,6 @@ std::string vtkJSONSceneExporter::WriteTexture(vtkTexture* texture) } //------------------------------------------------------------------------------ - std::string vtkJSONSceneExporter::WriteTextureLODSeries(vtkTexture* texture) { // If this texture has already been written, just re-use the one @@ -838,7 +905,6 @@ std::string vtkJSONSceneExporter::WriteTextureLODSeries(vtkTexture* texture) } //------------------------------------------------------------------------------ - vtkSmartPointer<vtkPolyData> vtkJSONSceneExporter::WritePolyLODSeries( vtkPolyData* dataset, std::string& polyLODsConfig) { @@ -1034,7 +1100,6 @@ vtkSmartPointer<vtkPolyData> vtkJSONSceneExporter::WritePolyLODSeries( } //------------------------------------------------------------------------------ - void vtkJSONSceneExporter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); diff --git a/IO/Export/vtkJSONSceneExporter.h b/IO/Export/vtkJSONSceneExporter.h index ef81e7e971b7b80a8b074f30b58f4493e746fd81..892300f5610a6753e91519fa9934ac2bc1f61b54 100644 --- a/IO/Export/vtkJSONSceneExporter.h +++ b/IO/Export/vtkJSONSceneExporter.h @@ -13,8 +13,10 @@ #ifndef vtkJSONSceneExporter_h #define vtkJSONSceneExporter_h +#include "vtkDataArraySelection.h" // Instantiated #include "vtkExporter.h" #include "vtkIOExportModule.h" // For export macro +#include "vtkNew.h" // For vtkDataArraySelection #include "vtkSmartPointer.h" // For vtkSmartPointer #include <map> // For member variables @@ -133,6 +135,29 @@ public: vtkGetStringMacro(PolyLODsBaseUrl); ///@} + ///@{ + /** + * Return the object used for point/array selection. + * This can only be used when using `WriteNamedActors`: an array is selected for a source by + * enabling the array `actorName:arrayName` in here. + */ + vtkGetObjectMacro(PointArraySelection, vtkDataArraySelection); + vtkGetObjectMacro(CellArraySelection, vtkDataArraySelection); + ///@} + + ///@{ + /** + * Instead of using a render window that contains a scene to be written, use a map of named actors + * whose source datasets need to be written. This allows for point and cell array selections using + * PointArraySelection and CellArraySelection. + * + * If this map is specified and has non-null size, the render widows/renderer passed will be + * ignored, and the map used instead as the export content. + */ + void SetNamedActorsMap(std::map<std::string, vtkActor*>& map); + std::map<std::string, vtkActor*> GetNamedActorsMap(); + ///@} + protected: vtkJSONSceneExporter(); ~vtkJSONSceneExporter() override; @@ -140,12 +165,10 @@ protected: void WritePropCollection(vtkPropCollection* collection, std::ostream& sceneComponents); void WriteVolumeCollection(vtkVolumeCollection* volumeCollection, std::ostream& sceneComponents); - void WriteDataObject(ostream& os, vtkDataObject* dataObject, vtkActor* actor, vtkVolume* volume); std::string ExtractPiecewiseFunctionSetup(vtkPiecewiseFunction* pwf); std::string ExtractColorTransferFunctionSetup(vtkColorTransferFunction* volume); std::string ExtractVolumeRenderingSetup(vtkVolume* volume); std::string ExtractActorRenderingSetup(vtkActor* actor); - std::string WriteDataSet(vtkDataSet* dataset, const char* addOnMeta); void WriteLookupTable(const char* name, vtkScalarsToColors* lookupTable); void WriteData() override; @@ -185,6 +208,31 @@ protected: private: vtkJSONSceneExporter(const vtkJSONSceneExporter&) = delete; void operator=(const vtkJSONSceneExporter&) = delete; + + /** + * Write a collection of datasets as inputs of named actors to the output stream. + */ + void WriteNamedActors(std::map<std::string, vtkActor*>& actorMap, std::ostream& sceneComponents); + + /** + * Write named dataset to file + */ + std::string WriteDataSet(vtkDataSet* dataset, const char* addOnMeta, const char* name); + + /** + * Write a dataobject to the exported file. If associated to an actor, write its texture as well + * as rendering setup. If associated to a volume, write its rendering setup too. + * + * The exported data object can be named, otherwise its name in the file will be the next + * available positive integer. + */ + void WriteDataObject( + ostream& os, vtkDataObject* dataObject, vtkActor* actor, vtkVolume* volume, const char* name); + + // Map named sources with their data array selection + vtkNew<vtkDataArraySelection> PointArraySelection; + vtkNew<vtkDataArraySelection> CellArraySelection; + std::map<std::string, vtkActor*> NamedActorsMap; }; VTK_ABI_NAMESPACE_END