1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkGroupDataSetsFilter.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 "vtkGroupDataSetsFilter.h"
16 
17 #include "vtkInformation.h"
18 #include "vtkInformationVector.h"
19 #include "vtkMultiBlockDataSet.h"
20 #include "vtkMultiPieceDataSet.h"
21 #include "vtkObjectFactory.h"
22 #include "vtkPartitionedDataSet.h"
23 #include "vtkPartitionedDataSetCollection.h"
24 #include "vtkSmartPointer.h"
25 #include "vtkStreamingDemandDrivenPipeline.h"
26 #include "vtkType.h"
27 
28 #include <cmath>
29 #include <string>
30 #include <vector>
31 #include <vtk_fmt.h>
32 
33 // clang-format off
34 #include VTK_FMT(fmt/core.h)
35 // clang-format on
36 
37 class vtkGroupDataSetsFilter::vtkInternals
38 {
39 public:
40   std::vector<std::string> Names;
41 
GetName(int index,int dataType,int precision) const42   std::string GetName(int index, int dataType, int precision) const
43   {
44     if (dataType == VTK_PARTITIONED_DATA_SET)
45     {
46       // VTK_PARTITIONED_DATA_SET doesn't use names.
47       return {};
48     }
49 
50     if (index >= 0 && index < static_cast<int>(this->Names.size()) && !this->Names[index].empty())
51     {
52       return this->Names[index];
53     }
54 
55     return fmt::format("Block {:0{}d}", index, precision);
56   }
57 };
58 
59 vtkStandardNewMacro(vtkGroupDataSetsFilter);
60 //----------------------------------------------------------------------------
vtkGroupDataSetsFilter()61 vtkGroupDataSetsFilter::vtkGroupDataSetsFilter()
62   : OutputType(VTK_PARTITIONED_DATA_SET_COLLECTION)
63   , Internals(new vtkGroupDataSetsFilter::vtkInternals())
64 {
65 }
66 
67 //----------------------------------------------------------------------------
68 vtkGroupDataSetsFilter::~vtkGroupDataSetsFilter() = default;
69 
70 //----------------------------------------------------------------------------
SetOutputTypeToPartitionedDataSet()71 void vtkGroupDataSetsFilter::SetOutputTypeToPartitionedDataSet()
72 {
73   this->SetOutputType(VTK_PARTITIONED_DATA_SET);
74 }
75 
76 //----------------------------------------------------------------------------
SetOutputTypeToPartitionedDataSetCollection()77 void vtkGroupDataSetsFilter::SetOutputTypeToPartitionedDataSetCollection()
78 {
79   this->SetOutputType(VTK_PARTITIONED_DATA_SET_COLLECTION);
80 }
81 
82 //----------------------------------------------------------------------------
SetOutputTypeToMultiBlockDataSet()83 void vtkGroupDataSetsFilter::SetOutputTypeToMultiBlockDataSet()
84 {
85   this->SetOutputType(VTK_MULTIBLOCK_DATA_SET);
86 }
87 
88 //----------------------------------------------------------------------------
SetInputName(int index,const char * name)89 void vtkGroupDataSetsFilter::SetInputName(int index, const char* name)
90 {
91   if (index < 0)
92   {
93     vtkErrorMacro("Invalid index specified '" << index << "'.");
94     return;
95   }
96 
97   const std::string safeName(name ? name : "");
98   auto& internals = (*this->Internals);
99   try
100   {
101     auto& currentName = internals.Names.at(index);
102     if (currentName != safeName)
103     {
104       currentName = safeName;
105       this->Modified();
106     }
107   }
108   catch (std::out_of_range&)
109   {
110     internals.Names.resize(index + 1);
111     internals.Names[index] = safeName;
112     this->Modified();
113   }
114 }
115 
116 //----------------------------------------------------------------------------
GetInputName(int index) const117 const char* vtkGroupDataSetsFilter::GetInputName(int index) const
118 {
119   auto& internals = (*this->Internals);
120   return (index >= 0 && index < static_cast<int>(internals.Names.size()))
121     ? internals.Names.at(index).c_str()
122     : nullptr;
123 }
124 
125 //----------------------------------------------------------------------------
ClearInputNames()126 void vtkGroupDataSetsFilter::ClearInputNames()
127 {
128   auto& internals = (*this->Internals);
129   if (!internals.Names.empty())
130   {
131     internals.Names.clear();
132     this->Modified();
133   }
134 }
135 
136 //----------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)137 int vtkGroupDataSetsFilter::FillInputPortInformation(int, vtkInformation* info)
138 {
139   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject");
140   info->Set(vtkAlgorithm::INPUT_IS_REPEATABLE(), 1);
141   info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
142   return 1;
143 }
144 
145 //------------------------------------------------------------------------------
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)146 int vtkGroupDataSetsFilter::RequestInformation(vtkInformation* vtkNotUsed(request),
147   vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
148 {
149   vtkInformation* info = outputVector->GetInformationObject(0);
150   info->Remove(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
151   return 1;
152 }
153 
154 //----------------------------------------------------------------------------
RequestDataObject(vtkInformation *,vtkInformationVector **,vtkInformationVector * outputVector)155 int vtkGroupDataSetsFilter::RequestDataObject(
156   vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector)
157 {
158   // create output of specified type.
159   return vtkDataObjectAlgorithm::SetOutputDataObject(
160            this->OutputType, outputVector->GetInformationObject(0), /*exact = */ true)
161     ? 1
162     : 0;
163 }
164 
165 //----------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)166 int vtkGroupDataSetsFilter::RequestData(vtkInformation* vtkNotUsed(request),
167   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
168 {
169   const auto& internals = (*this->Internals);
170   std::vector<std::pair<std::string, vtkSmartPointer<vtkDataObject>>> inputs;
171 
172   const int numInputs = inputVector[0]->GetNumberOfInformationObjects();
173   const int precision = numInputs > 0 ? static_cast<int>(std::log10(numInputs) + 1) : 1;
174   for (int cc = 0; cc < numInputs; ++cc)
175   {
176     auto dObject = vtkDataObject::GetData(inputVector[0], cc);
177     auto name = internals.GetName(cc, this->OutputType, precision);
178     inputs.emplace_back(name, dObject);
179   }
180 
181   if (this->OutputType == VTK_PARTITIONED_DATA_SET)
182   {
183     unsigned int next = 0;
184     auto output = vtkPartitionedDataSet::GetData(outputVector, 0);
185     for (auto& input : inputs)
186     {
187       const auto datasets = vtkCompositeDataSet::GetDataSets<vtkDataObject>(input.second);
188       for (auto& ds : datasets)
189       {
190         output->SetPartition(next++, ds);
191       }
192     }
193   }
194   else if (this->OutputType == VTK_MULTIBLOCK_DATA_SET)
195   {
196     unsigned int next = 0;
197     auto output = vtkMultiBlockDataSet::GetData(outputVector, 0);
198     for (auto& input : inputs)
199     {
200       if (vtkPartitionedDataSetCollection::SafeDownCast(input.second) ||
201         vtkPartitionedDataSet::SafeDownCast(input.second))
202       {
203         vtkErrorMacro("Cannot group " << input.second->GetClassName()
204                                       << " as a vtkMultiBlockDataSet. Skipping.");
205         continue;
206       }
207 
208       const auto idx = next++;
209       output->SetBlock(idx, input.second);
210       output->GetMetaData(idx)->Set(vtkCompositeDataSet::NAME(), input.first.c_str());
211     }
212   }
213   else if (this->OutputType == VTK_PARTITIONED_DATA_SET_COLLECTION)
214   {
215     unsigned int next = 0;
216     auto output = vtkPartitionedDataSetCollection::GetData(outputVector, 0);
217     for (auto& input : inputs)
218     {
219       if (vtkPartitionedDataSetCollection::SafeDownCast(input.second) ||
220         vtkMultiBlockDataSet::SafeDownCast(input.second))
221       {
222         vtkErrorMacro("Cannot group " << input.second->GetClassName()
223                                       << " as a vtkPartitionedDataSetCollection. Skipping.");
224         continue;
225       }
226 
227       const auto idx = next++;
228       output->SetNumberOfPartitionedDataSets(idx + 1);
229       output->GetMetaData(idx)->Set(vtkCompositeDataSet::NAME(), input.first.c_str());
230       if (auto pd = vtkPartitionedDataSet::SafeDownCast(input.second))
231       {
232         unsigned int piece = 0;
233         const auto datasets = vtkCompositeDataSet::GetDataSets<vtkDataObject>(pd);
234         for (auto& ds : datasets)
235         {
236           output->SetPartition(idx, piece++, ds);
237         }
238       }
239       else
240       {
241         output->SetPartition(idx, 0, input.second);
242       }
243     }
244   }
245   else
246   {
247     vtkErrorMacro("Unsupported output type: " << this->OutputType);
248     return 0;
249   }
250   return 1;
251 }
252 
253 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)254 void vtkGroupDataSetsFilter::PrintSelf(ostream& os, vtkIndent indent)
255 {
256   this->Superclass::PrintSelf(os, indent);
257 }
258