1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkConvertSelectionDomain.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 /*-------------------------------------------------------------------------
16   Copyright 2008 Sandia Corporation.
17   Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
18   the U.S. Government retains certain rights in this software.
19 -------------------------------------------------------------------------*/
20 #include "vtkConvertSelectionDomain.h"
21 
22 #include "vtkAbstractArray.h"
23 #include "vtkAnnotation.h"
24 #include "vtkAnnotationLayers.h"
25 #include "vtkCellData.h"
26 #include "vtkDataSet.h"
27 #include "vtkDataSetAttributes.h"
28 #include "vtkGraph.h"
29 #include "vtkIdList.h"
30 #include "vtkIdTypeArray.h"
31 #include "vtkInformation.h"
32 #include "vtkInformationVector.h"
33 #include "vtkMultiBlockDataSet.h"
34 #include "vtkObjectFactory.h"
35 #include "vtkPointData.h"
36 #include "vtkSelection.h"
37 #include "vtkSelectionNode.h"
38 #include "vtkSmartPointer.h"
39 #include "vtkStringArray.h"
40 #include "vtkTable.h"
41 
42 #include <set>
43 
44 vtkStandardNewMacro(vtkConvertSelectionDomain);
45 //------------------------------------------------------------------------------
vtkConvertSelectionDomain()46 vtkConvertSelectionDomain::vtkConvertSelectionDomain()
47 {
48   this->SetNumberOfInputPorts(3);
49   this->SetNumberOfOutputPorts(2);
50 }
51 
52 //------------------------------------------------------------------------------
53 vtkConvertSelectionDomain::~vtkConvertSelectionDomain() = default;
54 
55 //------------------------------------------------------------------------------
vtkConvertSelectionDomainFindDomains(vtkDataSetAttributes * dsa,std::set<vtkStdString> & domains)56 static void vtkConvertSelectionDomainFindDomains(
57   vtkDataSetAttributes* dsa, std::set<vtkStdString>& domains)
58 {
59   if (dsa->GetAbstractArray("domain"))
60   {
61     vtkStringArray* domainArr = vtkArrayDownCast<vtkStringArray>(dsa->GetAbstractArray("domain"));
62     if (!domainArr)
63     {
64       return; // Do nothing if the array isn't a string array
65     }
66     vtkIdType numTuples = domainArr->GetNumberOfTuples();
67     for (vtkIdType i = 0; i < numTuples; ++i)
68     {
69       vtkStdString d = domainArr->GetValue(i);
70       if (domains.count(d) == 0)
71       {
72         domains.insert(d);
73       }
74     }
75   }
76   else if (dsa->GetPedigreeIds() && dsa->GetPedigreeIds()->GetName())
77   {
78     domains.insert(dsa->GetPedigreeIds()->GetName());
79   }
80 }
81 
vtkConvertSelectionDomainConvertAnnotationDomain(vtkAnnotation * annIn,vtkAnnotation * annOut,std::set<vtkStdString> & domains1,std::set<vtkStdString> & domains2,vtkDataSetAttributes * dsa1,vtkDataSetAttributes * dsa2,int fieldType1,int fieldType2,vtkMultiBlockDataSet * maps)82 static void vtkConvertSelectionDomainConvertAnnotationDomain(vtkAnnotation* annIn,
83   vtkAnnotation* annOut, std::set<vtkStdString>& domains1, std::set<vtkStdString>& domains2,
84   vtkDataSetAttributes* dsa1, vtkDataSetAttributes* dsa2, int fieldType1, int fieldType2,
85   vtkMultiBlockDataSet* maps)
86 {
87   vtkSelection* inputSel = annIn->GetSelection();
88   vtkSmartPointer<vtkSelection> outputSel = vtkSmartPointer<vtkSelection>::New();
89   // Iterate over all input selections
90   for (unsigned int c = 0; c < inputSel->GetNumberOfNodes(); ++c)
91   {
92     vtkSelectionNode* curInput = inputSel->GetNode(c);
93     vtkSmartPointer<vtkSelectionNode> curOutput = vtkSmartPointer<vtkSelectionNode>::New();
94     vtkAbstractArray* inArr = curInput->GetSelectionList();
95 
96     // Start with a shallow copy of the input selection.
97     curOutput->ShallowCopy(curInput);
98 
99     // I don't know how to handle this type of selection,
100     // so pass it through.
101     if (!inArr || !inArr->GetName() || curInput->GetContentType() != vtkSelectionNode::PEDIGREEIDS)
102     {
103       outputSel->AddNode(curOutput);
104       continue;
105     }
106 
107     // If the selection already matches, we are done.
108     if (domains1.count(inArr->GetName()) > 0)
109     {
110       curOutput->SetFieldType(fieldType1);
111       outputSel->AddNode(curOutput);
112       continue;
113     }
114     if (domains2.count(inArr->GetName()) > 0)
115     {
116       curOutput->SetFieldType(fieldType2);
117       outputSel->AddNode(curOutput);
118       continue;
119     }
120 
121     // Select the correct source and destination mapping arrays.
122     vtkAbstractArray* fromArr = nullptr;
123     vtkAbstractArray* toArr = nullptr;
124     unsigned int numMaps = maps->GetNumberOfBlocks();
125     for (unsigned int i = 0; i < numMaps; ++i)
126     {
127       fromArr = nullptr;
128       toArr = nullptr;
129       vtkTable* table = vtkTable::SafeDownCast(maps->GetBlock(i));
130       if (table)
131       {
132         fromArr = table->GetColumnByName(inArr->GetName());
133         std::set<vtkStdString>::iterator it, itEnd;
134         if (dsa1)
135         {
136           it = domains1.begin();
137           itEnd = domains1.end();
138           for (; it != itEnd; ++it)
139           {
140             toArr = table->GetColumnByName(it->c_str());
141             if (toArr)
142             {
143               curOutput->SetFieldType(fieldType1);
144               break;
145             }
146           }
147         }
148         if (!toArr && dsa2)
149         {
150           it = domains2.begin();
151           itEnd = domains2.end();
152           for (; it != itEnd; ++it)
153           {
154             toArr = table->GetColumnByName(it->c_str());
155             if (toArr)
156             {
157               curOutput->SetFieldType(fieldType2);
158               break;
159             }
160           }
161         }
162       }
163       if (fromArr && toArr)
164       {
165         break;
166       }
167     }
168 
169     // Cannot do the conversion, so don't pass this selection
170     // to the output.
171     if (!fromArr || !toArr)
172     {
173       continue;
174     }
175 
176     // Lookup values in the input selection and map them
177     // through the table to the output selection.
178     vtkIdType numTuples = inArr->GetNumberOfTuples();
179     vtkSmartPointer<vtkAbstractArray> outArr;
180     outArr.TakeReference(vtkAbstractArray::CreateArray(toArr->GetDataType()));
181     outArr->SetName(toArr->GetName());
182     vtkSmartPointer<vtkIdList> ids = vtkSmartPointer<vtkIdList>::New();
183     for (vtkIdType i = 0; i < numTuples; ++i)
184     {
185       fromArr->LookupValue(inArr->GetVariantValue(i), ids);
186       vtkIdType numIds = ids->GetNumberOfIds();
187       for (vtkIdType j = 0; j < numIds; ++j)
188       {
189         outArr->InsertNextTuple(ids->GetId(j), toArr);
190       }
191     }
192     curOutput->SetSelectionList(outArr);
193     outputSel->AddNode(curOutput);
194   }
195   // Make sure there is at least something in the output selection.
196   if (outputSel->GetNumberOfNodes() == 0)
197   {
198     vtkSmartPointer<vtkSelectionNode> node = vtkSmartPointer<vtkSelectionNode>::New();
199     node->SetContentType(vtkSelectionNode::INDICES);
200     vtkSmartPointer<vtkIdTypeArray> inds = vtkSmartPointer<vtkIdTypeArray>::New();
201     node->SetSelectionList(inds);
202     outputSel->AddNode(node);
203   }
204 
205   annOut->ShallowCopy(annIn);
206   annOut->SetSelection(outputSel);
207 }
208 
209 //------------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)210 int vtkConvertSelectionDomain::RequestData(vtkInformation* vtkNotUsed(request),
211   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
212 {
213   // Retrieve the input and output.
214   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
215   vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT());
216   vtkAnnotationLayers* inputAnn = vtkAnnotationLayers::SafeDownCast(input);
217 
218   vtkInformation* outInfo = outputVector->GetInformationObject(0);
219   vtkDataObject* output = outInfo->Get(vtkDataObject::DATA_OBJECT());
220   vtkAnnotationLayers* outputAnn = vtkAnnotationLayers::SafeDownCast(output);
221 
222   outInfo = outputVector->GetInformationObject(1);
223   vtkSelection* outputCurrentSel =
224     vtkSelection::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
225 
226   // If we have no mapping table, we are done.
227   vtkInformation* mapInfo = inputVector[1]->GetInformationObject(0);
228   vtkInformation* dataInfo = inputVector[2]->GetInformationObject(0);
229   if (!dataInfo || !mapInfo)
230   {
231     output->ShallowCopy(input);
232     return 1;
233   }
234 
235   // If the input is instead a vtkSelection, wrap it in a vtkAnnotationLayers
236   // object so it can be used uniformly in the function.
237   bool createdInput = false;
238   if (!inputAnn)
239   {
240     vtkSelection* inputSel = vtkSelection::SafeDownCast(input);
241     inputAnn = vtkAnnotationLayers::New();
242     inputAnn->SetCurrentSelection(inputSel);
243     vtkSelection* outputSel = vtkSelection::SafeDownCast(output);
244     outputAnn = vtkAnnotationLayers::New();
245     outputAnn->SetCurrentSelection(outputSel);
246     createdInput = true;
247   }
248 
249   vtkMultiBlockDataSet* maps =
250     vtkMultiBlockDataSet::SafeDownCast(mapInfo->Get(vtkDataObject::DATA_OBJECT()));
251   vtkDataObject* data = dataInfo->Get(vtkDataObject::DATA_OBJECT());
252 
253   vtkDataSetAttributes* dsa1 = nullptr;
254   int fieldType1 = 0;
255   vtkDataSetAttributes* dsa2 = nullptr;
256   int fieldType2 = 0;
257   if (vtkDataSet::SafeDownCast(data))
258   {
259     dsa1 = vtkDataSet::SafeDownCast(data)->GetPointData();
260     fieldType1 = vtkSelectionNode::POINT;
261     dsa2 = vtkDataSet::SafeDownCast(data)->GetCellData();
262     fieldType2 = vtkSelectionNode::CELL;
263   }
264   else if (vtkGraph::SafeDownCast(data))
265   {
266     dsa1 = vtkGraph::SafeDownCast(data)->GetVertexData();
267     fieldType1 = vtkSelectionNode::VERTEX;
268     dsa2 = vtkGraph::SafeDownCast(data)->GetEdgeData();
269     fieldType2 = vtkSelectionNode::EDGE;
270   }
271   else if (vtkTable::SafeDownCast(data))
272   {
273     dsa1 = vtkDataSetAttributes::SafeDownCast(vtkTable::SafeDownCast(data)->GetRowData());
274     fieldType1 = vtkSelectionNode::ROW;
275   }
276 
277   std::set<vtkStdString> domains1;
278   std::set<vtkStdString> domains2;
279   if (dsa1)
280   {
281     vtkConvertSelectionDomainFindDomains(dsa1, domains1);
282   }
283   if (dsa2)
284   {
285     vtkConvertSelectionDomainFindDomains(dsa2, domains2);
286   }
287 
288   for (unsigned int a = 0; a < inputAnn->GetNumberOfAnnotations(); ++a)
289   {
290     vtkSmartPointer<vtkAnnotation> ann = vtkSmartPointer<vtkAnnotation>::New();
291     vtkConvertSelectionDomainConvertAnnotationDomain(inputAnn->GetAnnotation(a), ann, domains1,
292       domains2, dsa1, dsa2, fieldType1, fieldType2, maps);
293     outputAnn->AddAnnotation(ann);
294   }
295 
296   if (inputAnn->GetCurrentAnnotation())
297   {
298     vtkSmartPointer<vtkAnnotation> ann = vtkSmartPointer<vtkAnnotation>::New();
299     vtkConvertSelectionDomainConvertAnnotationDomain(inputAnn->GetCurrentAnnotation(), ann,
300       domains1, domains2, dsa1, dsa2, fieldType1, fieldType2, maps);
301     outputAnn->SetCurrentAnnotation(ann);
302   }
303   else
304   {
305     outputAnn->SetCurrentAnnotation(nullptr);
306   }
307 
308   // Copy current selection to the second output
309   if (outputAnn->GetCurrentSelection())
310   {
311     outputCurrentSel->ShallowCopy(outputAnn->GetCurrentSelection());
312   }
313 
314   if (createdInput)
315   {
316     inputAnn->Delete();
317     outputAnn->Delete();
318   }
319   return 1;
320 }
321 
322 //------------------------------------------------------------------------------
FillInputPortInformation(int port,vtkInformation * info)323 int vtkConvertSelectionDomain::FillInputPortInformation(int port, vtkInformation* info)
324 {
325   if (port == 0)
326   {
327     info->Remove(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE());
328     info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkSelection");
329     info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkAnnotationLayers");
330   }
331   else if (port == 1)
332   {
333     info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkMultiBlockDataSet");
334   }
335   else if (port == 2)
336   {
337     info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
338     info->Remove(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE());
339     info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
340     info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTable");
341     info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGraph");
342   }
343   return 1;
344 }
345 
346 //------------------------------------------------------------------------------
FillOutputPortInformation(int port,vtkInformation * info)347 int vtkConvertSelectionDomain::FillOutputPortInformation(int port, vtkInformation* info)
348 {
349   this->Superclass::FillOutputPortInformation(port, info);
350   if (port == 1)
351   {
352     info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkSelection");
353   }
354   return 1;
355 }
356 
357 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)358 void vtkConvertSelectionDomain::PrintSelf(ostream& os, vtkIndent indent)
359 {
360   this->Superclass::PrintSelf(os, indent);
361 }
362