1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkMergeFilter.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 "vtkMergeFilter.h"
16 
17 #include "vtkCellData.h"
18 #include "vtkInformation.h"
19 #include "vtkInformationVector.h"
20 #include "vtkObjectFactory.h"
21 #include "vtkPointData.h"
22 #include "vtkPolyData.h"
23 #include "vtkRectilinearGrid.h"
24 #include "vtkStreamingDemandDrivenPipeline.h"
25 #include "vtkStructuredGrid.h"
26 #include "vtkStructuredPoints.h"
27 #include "vtkUnstructuredGrid.h"
28 
29 vtkStandardNewMacro(vtkMergeFilter);
30 
31 class vtkFieldNode
32 {
33 public:
vtkFieldNode(const char * name,vtkDataSet * ptr=nullptr)34   vtkFieldNode(const char* name, vtkDataSet* ptr=nullptr)
35   {
36       size_t length = strlen(name);
37       if (length > 0)
38       {
39         this->Name = new char[length+1];
40         strcpy(this->Name, name);
41       }
42       else
43       {
44         this->Name = nullptr;
45       }
46       this->Ptr = ptr;
47       this->Next = nullptr;
48   }
~vtkFieldNode()49   ~vtkFieldNode()
50   {
51       delete[] this->Name;
52   }
53 
GetName()54   const char* GetName()
55   {
56       return Name;
57   }
58   vtkDataSet* Ptr;
59   vtkFieldNode* Next;
60 private:
61   vtkFieldNode(const vtkFieldNode&) = delete;
62   void operator=(const vtkFieldNode&) = delete;
63   char* Name;
64 };
65 
66 class vtkFieldList
67 {
68 public:
vtkFieldList()69   vtkFieldList()
70   {
71       this->First = nullptr;
72       this->Last = nullptr;
73   }
~vtkFieldList()74   ~vtkFieldList()
75   {
76       vtkFieldNode* node = this->First;
77       vtkFieldNode* next;
78       while(node)
79       {
80         next = node->Next;
81         delete node;
82         node = next;
83       }
84   }
85 
86 
Add(const char * name,vtkDataSet * ptr)87   void Add(const char* name, vtkDataSet* ptr)
88   {
89       vtkFieldNode* newNode = new vtkFieldNode(name, ptr);
90       if (!this->First)
91       {
92         this->First = newNode;
93         this->Last = newNode;
94       }
95       else
96       {
97         this->Last->Next = newNode;
98         this->Last = newNode;
99       }
100   }
101 
102   friend class vtkFieldListIterator;
103 
104 private:
105   vtkFieldNode* First;
106   vtkFieldNode* Last;
107 };
108 
109 class vtkFieldListIterator
110 {
111 public:
vtkFieldListIterator(vtkFieldList * list)112   vtkFieldListIterator(vtkFieldList* list)
113   {
114       this->List = list;
115       this->Position = nullptr;
116   }
Begin()117   void Begin()
118   {
119       this->Position = this->List->First;
120   }
Next()121   void Next()
122   {
123       if (this->Position)
124       {
125         this->Position = this->Position->Next;
126       }
127   }
End()128   int End()
129   {
130       return this->Position ? 0 : 1;
131   }
Get()132   vtkFieldNode* Get()
133   {
134       return this->Position;
135   }
136 
137 private:
138   vtkFieldNode* Position;
139   vtkFieldList* List;
140 };
141 
142 //------------------------------------------------------------------------------
143 
144 // Create object with no input or output.
vtkMergeFilter()145 vtkMergeFilter::vtkMergeFilter()
146 {
147   this->FieldList = new vtkFieldList;
148   this->SetNumberOfInputPorts(6);
149 }
150 
~vtkMergeFilter()151 vtkMergeFilter::~vtkMergeFilter()
152 {
153   delete this->FieldList;
154 }
155 
GetGeometry()156 vtkDataSet* vtkMergeFilter::GetGeometry()
157 {
158   if (this->GetNumberOfInputConnections(0) < 1)
159   {
160     return nullptr;
161   }
162   return vtkDataSet::SafeDownCast(
163     this->GetExecutive()->GetInputData(0, 0));
164 }
165 
SetScalarsData(vtkDataSet * input)166 void vtkMergeFilter::SetScalarsData(vtkDataSet *input)
167 {
168   this->SetInputData(1, input);
169 }
GetScalars()170 vtkDataSet *vtkMergeFilter::GetScalars()
171 {
172   if (this->GetNumberOfInputConnections(1) < 1)
173   {
174     return nullptr;
175   }
176   return vtkDataSet::SafeDownCast(
177     this->GetExecutive()->GetInputData(1, 0));
178 }
179 
SetVectorsData(vtkDataSet * input)180 void vtkMergeFilter::SetVectorsData(vtkDataSet *input)
181 {
182   this->SetInputData(2, input);
183 }
GetVectors()184 vtkDataSet *vtkMergeFilter::GetVectors()
185 {
186   if (this->GetNumberOfInputConnections(2) < 1)
187   {
188     return nullptr;
189   }
190   return vtkDataSet::SafeDownCast(
191     this->GetExecutive()->GetInputData(2, 0));
192 }
193 
SetNormalsData(vtkDataSet * input)194 void vtkMergeFilter::SetNormalsData(vtkDataSet *input)
195 {
196   this->SetInputData(3, input);
197 }
GetNormals()198 vtkDataSet *vtkMergeFilter::GetNormals()
199 {
200   if (this->GetNumberOfInputConnections(3) < 1)
201   {
202     return nullptr;
203   }
204   return vtkDataSet::SafeDownCast(
205     this->GetExecutive()->GetInputData(3, 0));
206 }
207 
SetTCoordsData(vtkDataSet * input)208 void vtkMergeFilter::SetTCoordsData(vtkDataSet *input)
209 {
210   this->SetInputData(4, input);
211 }
GetTCoords()212 vtkDataSet *vtkMergeFilter::GetTCoords()
213 {
214   if (this->GetNumberOfInputConnections(4) < 1)
215   {
216     return nullptr;
217   }
218   return vtkDataSet::SafeDownCast(
219     this->GetExecutive()->GetInputData(4, 0));
220 }
221 
SetTensorsData(vtkDataSet * input)222 void vtkMergeFilter::SetTensorsData(vtkDataSet *input)
223 {
224   this->SetInputData(5, input);
225 }
GetTensors()226 vtkDataSet *vtkMergeFilter::GetTensors()
227 {
228   if (this->GetNumberOfInputConnections(5) < 1)
229   {
230     return nullptr;
231   }
232   return vtkDataSet::SafeDownCast(
233     this->GetExecutive()->GetInputData(5, 0));
234 }
235 
AddField(const char * name,vtkDataSet * input)236 void vtkMergeFilter::AddField(const char* name, vtkDataSet* input)
237 {
238   this->FieldList->Add(name, input);
239 }
240 
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)241 int vtkMergeFilter::RequestData(
242   vtkInformation *vtkNotUsed(request),
243   vtkInformationVector **inputVector,
244   vtkInformationVector *outputVector)
245 {
246   // get the info objects
247   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
248   vtkInformation *outInfo = outputVector->GetInformationObject(0);
249   vtkInformation *scalarsInfo = inputVector[1]->GetInformationObject(0);
250   vtkInformation *vectorsInfo = inputVector[2]->GetInformationObject(0);
251   vtkInformation *normalsInfo = inputVector[3]->GetInformationObject(0);
252   vtkInformation *tCoordsInfo = inputVector[4]->GetInformationObject(0);
253   vtkInformation *tensorsInfo = inputVector[5]->GetInformationObject(0);
254 
255   // get the input and output
256   vtkDataSet *input = vtkDataSet::SafeDownCast(
257     inInfo->Get(vtkDataObject::DATA_OBJECT()));
258   vtkDataSet *output = vtkDataSet::SafeDownCast(
259     outInfo->Get(vtkDataObject::DATA_OBJECT()));
260   vtkDataSet *scalarsData = nullptr;
261   vtkDataSet *vectorsData = nullptr;
262   vtkDataSet *normalsData = nullptr;
263   vtkDataSet *tCoordsData = nullptr;
264   vtkDataSet *tensorsData = nullptr;
265   if (scalarsInfo)
266   {
267     scalarsData = vtkDataSet::SafeDownCast(
268       scalarsInfo->Get(vtkDataObject::DATA_OBJECT()));
269   }
270   if (vectorsInfo)
271   {
272     vectorsData = vtkDataSet::SafeDownCast(
273       vectorsInfo->Get(vtkDataObject::DATA_OBJECT()));
274   }
275   if (normalsInfo)
276   {
277     normalsData = vtkDataSet::SafeDownCast(
278       normalsInfo->Get(vtkDataObject::DATA_OBJECT()));
279   }
280   if (tCoordsInfo)
281   {
282     tCoordsData = vtkDataSet::SafeDownCast(
283       tCoordsInfo->Get(vtkDataObject::DATA_OBJECT()));
284   }
285   if (tensorsInfo)
286   {
287     tensorsData = vtkDataSet::SafeDownCast(
288       tensorsInfo->Get(vtkDataObject::DATA_OBJECT()));
289   }
290 
291   vtkIdType numPts, numScalars=0, numVectors=0, numNormals=0, numTCoords=0;
292   vtkIdType numTensors=0;
293   vtkIdType numCells, numCellScalars=0, numCellVectors=0, numCellNormals=0;
294   vtkIdType numCellTCoords=0, numCellTensors=0;
295   vtkPointData *pd;
296   vtkDataArray *scalars = nullptr;
297   vtkDataArray *vectors = nullptr;
298   vtkDataArray *normals = nullptr;
299   vtkDataArray *tcoords = nullptr;
300   vtkDataArray *tensors = nullptr;
301   vtkCellData *cd;
302   vtkDataArray *cellScalars = nullptr;
303   vtkDataArray *cellVectors = nullptr;
304   vtkDataArray *cellNormals = nullptr;
305   vtkDataArray *cellTCoords = nullptr;
306   vtkDataArray *cellTensors = nullptr;
307   vtkPointData *outputPD = output->GetPointData();
308   vtkCellData *outputCD = output->GetCellData();
309 
310   vtkDebugMacro(<<"Merging data!");
311 
312   // geometry needs to be copied
313   output->CopyStructure(input);
314   if ( (numPts = input->GetNumberOfPoints()) < 1 )
315   {
316     vtkWarningMacro(<<"Nothing to merge!");
317   }
318   numCells = input->GetNumberOfCells();
319 
320   if ( scalarsData )
321   {
322     pd = scalarsData->GetPointData();
323     scalars = pd->GetScalars();
324     if ( scalars != nullptr )
325     {
326       numScalars = scalars->GetNumberOfTuples();
327     }
328     cd = scalarsData->GetCellData();
329     cellScalars = cd->GetScalars();
330     if ( cellScalars != nullptr )
331     {
332       numCellScalars = cellScalars->GetNumberOfTuples();
333     }
334   }
335 
336   if ( vectorsData )
337   {
338     pd = vectorsData->GetPointData();
339     vectors = pd->GetVectors();
340     if ( vectors != nullptr )
341     {
342       numVectors= vectors->GetNumberOfTuples();
343     }
344     cd = vectorsData->GetCellData();
345     cellVectors = cd->GetVectors();
346     if ( cellVectors != nullptr )
347     {
348       numCellVectors = cellVectors->GetNumberOfTuples();
349     }
350   }
351 
352   if ( normalsData )
353   {
354     pd = normalsData->GetPointData();
355     normals = pd->GetNormals();
356     if ( normals != nullptr )
357     {
358       numNormals= normals->GetNumberOfTuples();
359     }
360     cd = normalsData->GetCellData();
361     cellNormals = cd->GetNormals();
362     if ( cellNormals != nullptr )
363     {
364       numCellNormals = cellNormals->GetNumberOfTuples();
365     }
366   }
367 
368   if ( tCoordsData )
369   {
370     pd = tCoordsData->GetPointData();
371     tcoords = pd->GetTCoords();
372     if ( tcoords != nullptr )
373     {
374       numTCoords= tcoords->GetNumberOfTuples();
375     }
376     cd = tCoordsData->GetCellData();
377     cellTCoords = cd->GetTCoords();
378     if ( cellTCoords != nullptr )
379     {
380       numCellTCoords = cellTCoords->GetNumberOfTuples();
381     }
382   }
383 
384   if ( tensorsData )
385   {
386     pd = tensorsData->GetPointData();
387     tensors = pd->GetTensors();
388     if ( tensors != nullptr )
389     {
390       numTensors = tensors->GetNumberOfTuples();
391     }
392     cd = tensorsData->GetCellData();
393     cellTensors = cd->GetTensors();
394     if ( cellTensors != nullptr )
395     {
396       numCellTensors = cellTensors->GetNumberOfTuples();
397     }
398   }
399 
400   // merge data only if it is consistent
401   if ( numPts == numScalars )
402   {
403     outputPD->SetScalars(scalars);
404   }
405   else
406   {
407     vtkWarningMacro("Scalars for point data cannot be merged because the number of points in the input geometry do not match the number of point scalars " << numPts << " != " << numScalars);
408   }
409   if ( numCells == numCellScalars )
410   {
411     outputCD->SetScalars(cellScalars);
412   }
413   else
414   {
415     vtkWarningMacro("Scalars for cell data cannot be merged because the number of cells in the input geometry do not match the number of cell scalars " << numCells << " != " << numCellScalars);
416   }
417 
418   if ( numPts == numVectors )
419   {
420     outputPD->SetVectors(vectors);
421   }
422   else
423   {
424     vtkWarningMacro("Vectors for point data cannot be merged because the number of points in the input geometry do not match the number of point vectors " << numPts << " != " << numVectors);
425   }
426   if ( numCells == numCellVectors )
427   {
428     outputCD->SetVectors(cellVectors);
429   }
430   else
431   {
432     vtkWarningMacro("Vectors for cell data cannot be merged because the number of cells in the input geometry do not match the number of cell vectors " << numCells << " != " << numCellVectors);
433   }
434 
435   if ( numPts == numNormals )
436   {
437     outputPD->SetNormals(normals);
438   }
439   else
440   {
441     vtkWarningMacro("Normals for point data cannot be merged because the number of points in the input geometry do not match the number of point normals " << numPts << " != " << numNormals);
442   }
443   if ( numCells == numCellNormals )
444   {
445     outputCD->SetNormals(cellNormals);
446   }
447   else
448   {
449     vtkWarningMacro("Normals for cell data cannot be merged because the number of cells in the input geometry do not match the number of cell normals " << numCells << " != " << numCellNormals);
450   }
451 
452   if ( numPts == numTCoords )
453   {
454     outputPD->SetTCoords(tcoords);
455   }
456   else
457   {
458     vtkWarningMacro("TCoords for point data cannot be merged because the number of points in the input geometry do not match the number of point tcoords " << numPts << " != " << numTCoords);
459   }
460   if ( numCells == numCellTCoords )
461   {
462     outputCD->SetTCoords(cellTCoords);
463   }
464   else
465   {
466     vtkWarningMacro("TCoords for cell data cannot be merged because the number of cells in the input geometry do not match the number of cell tcoords " << numCells << " != " << numCellTCoords);
467   }
468 
469   if ( numPts == numTensors )
470   {
471     outputPD->SetTensors(tensors);
472   }
473   else
474   {
475     vtkWarningMacro("Tensors for point data cannot be merged because the number of points in the input geometry do not match the number of point tensors " << numPts << " != " << numTensors);
476   }
477 
478   if ( numCells == numCellTensors )
479   {
480     outputCD->SetTensors(cellTensors);
481   }
482   else
483   {
484     vtkWarningMacro("Tensors for cell data cannot be merged because the number of cells in the input geometry do not match the number of cell tcoords " << numCells << " != " << numTCoords);
485   }
486 
487   vtkFieldListIterator it(this->FieldList);
488   vtkDataArray* da;
489   const char* name;
490   vtkIdType num;
491   for(it.Begin(); !it.End() ; it.Next())
492   {
493     pd = it.Get()->Ptr->GetPointData();
494     cd = it.Get()->Ptr->GetCellData();
495     name = it.Get()->GetName();
496     if ( (da=pd->GetArray(name)) )
497     {
498       num = da->GetNumberOfTuples();
499       if (num == numPts)
500       {
501         outputPD->AddArray(da);
502       }
503     }
504     if ( (da=cd->GetArray(name)) )
505     {
506       num = da->GetNumberOfTuples();
507       if (num == numCells)
508       {
509         outputCD->AddArray(da);
510       }
511     }
512   }
513 
514   return 1;
515 }
516 
517 //----------------------------------------------------------------------------
518 //  Trick:  Abstract data types that may or may not be the same type
519 // (structured/unstructured), but the points/cells match up.
520 // Output/Geometry may be structured while ScalarInput may be
521 // unstructured (but really have same triangulation/topology as geometry).
522 // Just request all the input. Always generate all of the output (todo).
RequestUpdateExtent(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))523 int vtkMergeFilter::RequestUpdateExtent(
524   vtkInformation *vtkNotUsed(request),
525   vtkInformationVector **inputVector,
526   vtkInformationVector *vtkNotUsed(outputVector))
527 {
528   vtkInformation *inputInfo;
529   int idx;
530 
531   for (idx = 0; idx < 6; ++idx)
532   {
533     inputInfo = inputVector[idx]->GetInformationObject(0);
534     if (inputInfo)
535     {
536       inputInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(),
537                      0);
538       inputInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(),
539                      1);
540       inputInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(),
541                      0);
542       inputInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1);
543     }
544   }
545   return 1;
546 }
547 
FillInputPortInformation(int port,vtkInformation * info)548 int vtkMergeFilter::FillInputPortInformation(int port, vtkInformation *info)
549 {
550   int retval = this->Superclass::FillInputPortInformation(port, info);
551   if (port > 0)
552   {
553     info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
554   }
555   return retval;
556 }
557 
PrintSelf(ostream & os,vtkIndent indent)558 void vtkMergeFilter::PrintSelf(ostream& os, vtkIndent indent)
559 {
560   this->Superclass::PrintSelf(os,indent);
561 
562 }
563 
564