1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkConnectivityFilter.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 "vtkConnectivityFilter.h"
16 
17 #include "vtkCell.h"
18 #include "vtkCellData.h"
19 #include "vtkDataSet.h"
20 #include "vtkDemandDrivenPipeline.h"
21 #include "vtkFloatArray.h"
22 #include "vtkIdList.h"
23 #include "vtkIdTypeArray.h"
24 #include "vtkInformation.h"
25 #include "vtkInformationVector.h"
26 #include "vtkMath.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkPointData.h"
29 #include "vtkPoints.h"
30 #include "vtkPolyData.h"
31 #include "vtkUnstructuredGrid.h"
32 
33 #include <map>
34 
35 vtkObjectFactoryNewMacro(vtkConnectivityFilter);
36 
37 // Construct with default extraction mode to extract largest regions.
vtkConnectivityFilter()38 vtkConnectivityFilter::vtkConnectivityFilter()
39 {
40   this->RegionSizes = vtkIdTypeArray::New();
41   this->ExtractionMode = VTK_EXTRACT_LARGEST_REGION;
42   this->ColorRegions = 0;
43   this->RegionIdAssignmentMode = UNSPECIFIED;
44 
45   this->ScalarConnectivity = 0;
46   this->ScalarRange[0] = 0.0;
47   this->ScalarRange[1] = 1.0;
48 
49   this->ClosestPoint[0] = this->ClosestPoint[1] = this->ClosestPoint[2] = 0.0;
50 
51   this->CellScalars = vtkFloatArray::New();
52   this->CellScalars->Allocate(8);
53 
54   this->NeighborCellPointIds = vtkIdList::New();
55   this->NeighborCellPointIds->Allocate(8);
56 
57   this->Seeds = vtkIdList::New();
58   this->SpecifiedRegionIds = vtkIdList::New();
59 
60   this->NewScalars = nullptr;
61   this->NewCellScalars = nullptr;
62 
63   this->OutputPointsPrecision = vtkAlgorithm::DEFAULT_PRECISION;
64 }
65 
~vtkConnectivityFilter()66 vtkConnectivityFilter::~vtkConnectivityFilter()
67 {
68   this->RegionSizes->Delete();
69   this->CellScalars->Delete();
70   this->NeighborCellPointIds->Delete();
71   this->Seeds->Delete();
72   this->SpecifiedRegionIds->Delete();
73 }
74 
RequestDataObject(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)75 int vtkConnectivityFilter::RequestDataObject(vtkInformation* vtkNotUsed(request),
76   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
77 {
78   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
79   if (!inInfo)
80   {
81     return 0;
82   }
83 
84   vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT());
85   if (input)
86   {
87     // for each output
88     for (int i = 0; i < this->GetNumberOfOutputPorts(); ++i)
89     {
90       vtkInformation* info = outputVector->GetInformationObject(i);
91       vtkDataObject* output = info->Get(vtkDataObject::DATA_OBJECT());
92 
93       if (!output || !output->IsA(input->GetClassName()))
94       {
95         vtkDataObject* newOutput = nullptr;
96         if (input->IsA("vtkPolyData"))
97         {
98           newOutput = input->NewInstance();
99         }
100         else
101         {
102           newOutput = vtkUnstructuredGrid::New();
103         }
104 
105         info->Set(vtkDataObject::DATA_OBJECT(), newOutput);
106         newOutput->Delete();
107         this->GetOutputPortInformation(0)->Set(
108           vtkDataObject::DATA_EXTENT_TYPE(), newOutput->GetExtentType());
109       }
110     }
111     return 1;
112   }
113 
114   return 0;
115 }
116 
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)117 int vtkConnectivityFilter::RequestData(vtkInformation* vtkNotUsed(request),
118   vtkInformationVector** inputVector, vtkInformationVector* outputVector)
119 {
120   // get the info objects
121   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
122   vtkInformation* outInfo = outputVector->GetInformationObject(0);
123 
124   // get the input and output
125   vtkDataSet* input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
126   vtkPointSet* output = vtkPointSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
127 
128   vtkPolyData* pdOutput = vtkPolyData::SafeDownCast(output);
129   vtkUnstructuredGrid* ugOutput = vtkUnstructuredGrid::SafeDownCast(output);
130 
131   vtkIdType numPts, numCells, cellId, i, j, pt;
132   vtkPoints* newPts;
133   vtkIdType id;
134   vtkIdType maxCellsInRegion;
135   vtkIdType largestRegionId = 0;
136   vtkPointData *pd = input->GetPointData(), *outputPD = output->GetPointData();
137   vtkCellData *cd = input->GetCellData(), *outputCD = output->GetCellData();
138 
139   vtkDebugMacro(<< "Executing connectivity filter.");
140 
141   //  Check input/allocate storage
142   //
143   numCells = input->GetNumberOfCells();
144   if ((numPts = input->GetNumberOfPoints()) < 1 || numCells < 1)
145   {
146     vtkDebugMacro(<< "No data to connect!");
147     return 1;
148   }
149 
150   if (pdOutput)
151   {
152     pdOutput->AllocateExact(numCells, 3);
153   }
154   if (ugOutput)
155   {
156     ugOutput->Allocate(numCells, numCells);
157   }
158 
159   // See whether to consider scalar connectivity
160   //
161   this->InScalars = input->GetPointData()->GetScalars();
162   if (!this->ScalarConnectivity)
163   {
164     this->InScalars = nullptr;
165   }
166   else
167   {
168     if (this->ScalarRange[1] < this->ScalarRange[0])
169     {
170       this->ScalarRange[1] = this->ScalarRange[0];
171     }
172   }
173 
174   // Initialize.  Keep track of points and cells visited.
175   //
176   this->RegionSizes->Reset();
177   this->Visited = new vtkIdType[numCells];
178   for (i = 0; i < numCells; i++)
179   {
180     this->Visited[i] = -1;
181   }
182   this->PointMap = new vtkIdType[numPts];
183   for (i = 0; i < numPts; i++)
184   {
185     this->PointMap[i] = -1;
186   }
187 
188   this->NewScalars = vtkIdTypeArray::New();
189   this->NewScalars->SetName("RegionId");
190   this->NewScalars->SetNumberOfTuples(numPts);
191 
192   this->NewCellScalars = vtkIdTypeArray::New();
193   this->NewCellScalars->SetName("RegionId");
194   this->NewCellScalars->SetNumberOfTuples(numCells);
195 
196   newPts = vtkPoints::New();
197 
198   // Set the desired precision for the points in the output.
199   if (this->OutputPointsPrecision == vtkAlgorithm::DEFAULT_PRECISION)
200   {
201     vtkPointSet* inputPointSet = vtkPointSet::SafeDownCast(input);
202     if (inputPointSet)
203     {
204       newPts->SetDataType(inputPointSet->GetPoints()->GetDataType());
205     }
206     else
207     {
208       newPts->SetDataType(VTK_FLOAT);
209     }
210   }
211   else if (this->OutputPointsPrecision == vtkAlgorithm::SINGLE_PRECISION)
212   {
213     newPts->SetDataType(VTK_FLOAT);
214   }
215   else if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION)
216   {
217     newPts->SetDataType(VTK_DOUBLE);
218   }
219 
220   newPts->Allocate(numPts);
221 
222   // Traverse all cells marking those visited.  Each new search
223   // starts a new connected region. Connected region grows
224   // using a connected wave propagation.
225   //
226   this->Wave = vtkIdList::New();
227   this->Wave->Allocate(numPts / 4 + 1, numPts);
228   this->Wave2 = vtkIdList::New();
229   this->Wave2->Allocate(numPts / 4 + 1, numPts);
230 
231   this->PointNumber = 0;
232   this->RegionNumber = 0;
233   maxCellsInRegion = 0;
234 
235   this->CellIds = vtkIdList::New();
236   this->CellIds->Allocate(8, VTK_CELL_SIZE);
237   this->PointIds = vtkIdList::New();
238   this->PointIds->Allocate(8, VTK_CELL_SIZE);
239 
240   if (this->ExtractionMode != VTK_EXTRACT_POINT_SEEDED_REGIONS &&
241     this->ExtractionMode != VTK_EXTRACT_CELL_SEEDED_REGIONS &&
242     this->ExtractionMode != VTK_EXTRACT_CLOSEST_POINT_REGION)
243   { // visit all cells marking with region number
244     for (cellId = 0; cellId < numCells; cellId++)
245     {
246       if (cellId && !(cellId % 5000))
247       {
248         this->UpdateProgress(0.1 + 0.8 * cellId / numCells);
249       }
250 
251       if (this->Visited[cellId] < 0)
252       {
253         this->NumCellsInRegion = 0;
254         this->Wave->InsertNextId(cellId);
255         this->TraverseAndMark(input);
256 
257         if (this->NumCellsInRegion > maxCellsInRegion)
258         {
259           maxCellsInRegion = this->NumCellsInRegion;
260           largestRegionId = this->RegionNumber;
261         }
262 
263         this->RegionSizes->InsertValue(this->RegionNumber++, this->NumCellsInRegion);
264         this->Wave->Reset();
265         this->Wave2->Reset();
266       }
267     }
268   }
269   else // regions have been seeded, everything considered in same region
270   {
271     this->NumCellsInRegion = 0;
272 
273     if (this->ExtractionMode == VTK_EXTRACT_POINT_SEEDED_REGIONS)
274     {
275       for (i = 0; i < this->Seeds->GetNumberOfIds(); i++)
276       {
277         pt = this->Seeds->GetId(i);
278         if (pt >= 0)
279         {
280           input->GetPointCells(pt, this->CellIds);
281           for (j = 0; j < this->CellIds->GetNumberOfIds(); j++)
282           {
283             this->Wave->InsertNextId(this->CellIds->GetId(j));
284           }
285         }
286       }
287     }
288     else if (this->ExtractionMode == VTK_EXTRACT_CELL_SEEDED_REGIONS)
289     {
290       for (i = 0; i < this->Seeds->GetNumberOfIds(); i++)
291       {
292         cellId = this->Seeds->GetId(i);
293         if (cellId >= 0)
294         {
295           this->Wave->InsertNextId(cellId);
296         }
297       }
298     }
299     else if (this->ExtractionMode == VTK_EXTRACT_CLOSEST_POINT_REGION)
300     { // loop over points, find closest one
301       double minDist2, dist2, x[3];
302       vtkIdType minId = 0;
303       for (minDist2 = VTK_DOUBLE_MAX, i = 0; i < numPts; i++)
304       {
305         input->GetPoint(i, x);
306         dist2 = vtkMath::Distance2BetweenPoints(x, this->ClosestPoint);
307         if (dist2 < minDist2)
308         {
309           minId = i;
310           minDist2 = dist2;
311         }
312       }
313       input->GetPointCells(minId, this->CellIds);
314       for (j = 0; j < this->CellIds->GetNumberOfIds(); j++)
315       {
316         this->Wave->InsertNextId(this->CellIds->GetId(j));
317       }
318     }
319     this->UpdateProgress(0.5);
320 
321     // mark all seeded regions
322     this->TraverseAndMark(input);
323     this->RegionSizes->InsertValue(this->RegionNumber, this->NumCellsInRegion);
324     this->UpdateProgress(0.9);
325   }
326 
327   vtkDebugMacro(<< "Extracted " << this->RegionNumber << " region(s)");
328   this->Wave->Delete();
329   this->Wave2->Delete();
330 
331   // Now that points and cells have been marked, traverse these lists pulling
332   // everything that has been visited.
333   //
334   // Pass through point data that has been visited
335   outputPD->CopyAllocate(pd);
336   outputCD->CopyAllocate(cd);
337 
338   for (i = 0; i < numPts; i++)
339   {
340     if (this->PointMap[i] > -1)
341     {
342       newPts->InsertPoint(this->PointMap[i], input->GetPoint(i));
343       outputPD->CopyData(pd, i, this->PointMap[i]);
344     }
345   }
346 
347   // if coloring regions; send down new scalar data
348   if (this->ColorRegions)
349   {
350     this->OrderRegionIds(this->NewScalars, this->NewCellScalars);
351 
352     int idx = outputPD->AddArray(this->NewScalars);
353     outputPD->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS);
354     idx = outputCD->AddArray(this->NewCellScalars);
355     outputCD->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS);
356   }
357   this->NewScalars->Delete();
358   this->NewCellScalars->Delete();
359 
360   output->SetPoints(newPts);
361   newPts->Delete();
362 
363   // Create output cells
364   //
365   if (this->ExtractionMode == VTK_EXTRACT_POINT_SEEDED_REGIONS ||
366     this->ExtractionMode == VTK_EXTRACT_CELL_SEEDED_REGIONS ||
367     this->ExtractionMode == VTK_EXTRACT_CLOSEST_POINT_REGION ||
368     this->ExtractionMode == VTK_EXTRACT_ALL_REGIONS)
369   { // extract any cell that's been visited
370     for (cellId = 0; cellId < numCells; cellId++)
371     {
372       if (this->Visited[cellId] >= 0)
373       {
374         // special handling for polyhedron cells
375         if (vtkUnstructuredGrid::SafeDownCast(input) &&
376           input->GetCellType(cellId) == VTK_POLYHEDRON)
377         {
378           vtkUnstructuredGrid::SafeDownCast(input)->GetFaceStream(cellId, this->PointIds);
379           vtkUnstructuredGrid::ConvertFaceStreamPointIds(this->PointIds, this->PointMap);
380         }
381         else
382         {
383           input->GetCellPoints(cellId, this->PointIds);
384           for (i = 0; i < this->PointIds->GetNumberOfIds(); i++)
385           {
386             id = this->PointMap[this->PointIds->GetId(i)];
387             this->PointIds->InsertId(i, id);
388           }
389         }
390         vtkIdType newCellId = -1;
391         if (pdOutput)
392         {
393           newCellId = pdOutput->InsertNextCell(input->GetCellType(cellId), this->PointIds);
394         }
395         else if (ugOutput)
396         {
397           newCellId = ugOutput->InsertNextCell(input->GetCellType(cellId), this->PointIds);
398         }
399         if (newCellId >= 0)
400         {
401           outputCD->CopyData(cd, cellId, newCellId);
402         }
403       }
404     }
405   }
406   else if (this->ExtractionMode == VTK_EXTRACT_SPECIFIED_REGIONS)
407   {
408     for (cellId = 0; cellId < numCells; cellId++)
409     {
410       int inReg, regionId;
411       if ((regionId = this->Visited[cellId]) >= 0)
412       {
413         for (inReg = 0, i = 0; i < this->SpecifiedRegionIds->GetNumberOfIds(); i++)
414         {
415           if (regionId == this->SpecifiedRegionIds->GetId(i))
416           {
417             inReg = 1;
418             break;
419           }
420         }
421         if (inReg)
422         {
423           // special handling for polyhedron cells
424           if (vtkUnstructuredGrid::SafeDownCast(input) &&
425             input->GetCellType(cellId) == VTK_POLYHEDRON)
426           {
427             vtkUnstructuredGrid::SafeDownCast(input)->GetFaceStream(cellId, this->PointIds);
428             vtkUnstructuredGrid::ConvertFaceStreamPointIds(this->PointIds, this->PointMap);
429           }
430           else
431           {
432             input->GetCellPoints(cellId, this->PointIds);
433             for (i = 0; i < this->PointIds->GetNumberOfIds(); i++)
434             {
435               id = this->PointMap[this->PointIds->GetId(i)];
436               this->PointIds->InsertId(i, id);
437             }
438           }
439           vtkIdType newCellId = -1;
440           if (pdOutput)
441           {
442             newCellId = pdOutput->InsertNextCell(input->GetCellType(cellId), this->PointIds);
443           }
444           else if (ugOutput)
445           {
446             newCellId = ugOutput->InsertNextCell(input->GetCellType(cellId), this->PointIds);
447           }
448           if (newCellId >= 0)
449           {
450             outputCD->CopyData(cd, cellId, newCellId);
451           }
452         }
453       }
454     }
455   }
456   else // extract largest region
457   {
458     for (cellId = 0; cellId < numCells; cellId++)
459     {
460       if (this->Visited[cellId] == largestRegionId)
461       {
462         // special handling for polyhedron cells
463         if (vtkUnstructuredGrid::SafeDownCast(input) &&
464           input->GetCellType(cellId) == VTK_POLYHEDRON)
465         {
466           vtkUnstructuredGrid::SafeDownCast(input)->GetFaceStream(cellId, this->PointIds);
467           vtkUnstructuredGrid::ConvertFaceStreamPointIds(this->PointIds, this->PointMap);
468         }
469         else
470         {
471           input->GetCellPoints(cellId, this->PointIds);
472           for (i = 0; i < this->PointIds->GetNumberOfIds(); i++)
473           {
474             id = this->PointMap[this->PointIds->GetId(i)];
475             this->PointIds->InsertId(i, id);
476           }
477         }
478         vtkIdType newCellId = -1;
479         if (pdOutput)
480         {
481           newCellId = pdOutput->InsertNextCell(input->GetCellType(cellId), this->PointIds);
482         }
483         else if (ugOutput)
484         {
485           newCellId = ugOutput->InsertNextCell(input->GetCellType(cellId), this->PointIds);
486         }
487         if (newCellId >= 0)
488         {
489           outputCD->CopyData(cd, cellId, newCellId);
490         }
491       }
492     }
493   }
494 
495   delete[] this->Visited;
496   delete[] this->PointMap;
497   this->PointIds->Delete();
498   this->CellIds->Delete();
499   output->Squeeze();
500   vtkDataArray* outScalars = nullptr;
501   if (this->ColorRegions && (outScalars = output->GetPointData()->GetScalars()))
502   {
503     outScalars->Resize(output->GetNumberOfPoints());
504   }
505 
506   int num = this->GetNumberOfExtractedRegions();
507   int count = 0;
508 
509   for (int ii = 0; ii < num; ii++)
510   {
511     count += this->RegionSizes->GetValue(ii);
512   }
513   vtkDebugMacro(<< "Total # of cells accounted for: " << count);
514   vtkDebugMacro(<< "Extracted " << output->GetNumberOfCells() << " cells");
515 
516   return 1;
517 }
518 
519 // Mark current cell as visited and assign region number.  Note:
520 // traversal occurs across shared vertices.
521 //
TraverseAndMark(vtkDataSet * input)522 void vtkConnectivityFilter::TraverseAndMark(vtkDataSet* input)
523 {
524   vtkIdType i, j, k, cellId, numIds, ptId, numPts, numCells;
525   vtkIdList* tmpWave;
526 
527   while ((numIds = this->Wave->GetNumberOfIds()) > 0)
528   {
529     for (i = 0; i < numIds; i++)
530     {
531       cellId = this->Wave->GetId(i);
532       if (this->Visited[cellId] < 0)
533       {
534         this->NewCellScalars->SetValue(cellId, this->RegionNumber);
535         this->Visited[cellId] = this->RegionNumber;
536         this->NumCellsInRegion++;
537         input->GetCellPoints(cellId, this->PointIds);
538 
539         numPts = this->PointIds->GetNumberOfIds();
540         for (j = 0; j < numPts; j++)
541         {
542           if (this->PointMap[ptId = this->PointIds->GetId(j)] < 0)
543           {
544             this->PointMap[ptId] = this->PointNumber++;
545             this->NewScalars->SetValue(this->PointMap[ptId], this->RegionNumber);
546           }
547 
548           input->GetPointCells(ptId, this->CellIds);
549 
550           // check connectivity criterion (geometric + scalar)
551           numCells = this->CellIds->GetNumberOfIds();
552           for (k = 0; k < numCells; k++)
553           {
554             cellId = this->CellIds->GetId(k);
555             if (this->InScalars)
556             {
557               int numScalars, ii;
558               double s, range[2];
559 
560               input->GetCellPoints(cellId, this->NeighborCellPointIds);
561               numScalars = this->NeighborCellPointIds->GetNumberOfIds();
562               this->CellScalars->SetNumberOfComponents(this->InScalars->GetNumberOfComponents());
563               this->CellScalars->SetNumberOfTuples(numScalars);
564               this->InScalars->GetTuples(this->NeighborCellPointIds, this->CellScalars);
565               range[0] = VTK_DOUBLE_MAX;
566               range[1] = -VTK_DOUBLE_MAX;
567               for (ii = 0; ii < numScalars; ii++)
568               {
569                 s = this->CellScalars->GetComponent(ii, 0);
570                 if (s < range[0])
571                 {
572                   range[0] = s;
573                 }
574                 if (s > range[1])
575                 {
576                   range[1] = s;
577                 }
578               }
579               if (range[1] >= this->ScalarRange[0] && range[0] <= this->ScalarRange[1])
580               {
581                 this->Wave2->InsertNextId(cellId);
582               }
583             }
584             else
585             {
586               this->Wave2->InsertNextId(cellId);
587             }
588           } // for all cells using this point
589         }   // for all points of this cell
590       }     // if cell not yet visited
591     }       // for all cells in this wave
592 
593     tmpWave = this->Wave;
594     this->Wave = this->Wave2;
595     this->Wave2 = tmpWave;
596     tmpWave->Reset();
597   } // while wave is not empty
598 }
599 
OrderRegionIds(vtkIdTypeArray * pointRegionIds,vtkIdTypeArray * cellRegionIds)600 void vtkConnectivityFilter::OrderRegionIds(
601   vtkIdTypeArray* pointRegionIds, vtkIdTypeArray* cellRegionIds)
602 {
603   if (this->ColorRegions)
604   {
605     if (this->RegionIdAssignmentMode == CELL_COUNT_DESCENDING ||
606       this->RegionIdAssignmentMode == CELL_COUNT_ASCENDING)
607     {
608       // Use a multimap to handle cases where more than one region has the same number of cells.
609       std::multimap<vtkIdType, vtkIdType> cellCountToRegionId;
610       typedef std::multimap<vtkIdType, vtkIdType>::value_type ValueType;
611       vtkIdType numRegions = this->RegionSizes->GetNumberOfTuples();
612       for (vtkIdType regionId = 0; regionId < numRegions; ++regionId)
613       {
614         ValueType value(this->RegionSizes->GetValue(regionId), regionId);
615         cellCountToRegionId.insert(value);
616       }
617 
618       // Now reverse iterate through the sorted multimap to process the RegionIds
619       // from largest to smallest and create a map from the old RegionId to the new
620       // RegionId
621       std::map<vtkIdType, vtkIdType> oldToNew;
622       vtkIdType counter = 0;
623       if (this->RegionIdAssignmentMode == CELL_COUNT_ASCENDING)
624       {
625         for (auto iter = cellCountToRegionId.begin(); iter != cellCountToRegionId.end(); ++iter)
626         {
627           auto regionCount = iter->first;
628           auto regionId = iter->second;
629 
630           // Re-order the region sizes based on the sorting
631           this->RegionSizes->SetValue(counter, regionCount);
632 
633           // Create map from old to new RegionId
634           oldToNew[regionId] = counter++;
635         }
636       }
637       else // CELL_COUNT_DESCENDING
638       {
639         for (auto iter = cellCountToRegionId.rbegin(); iter != cellCountToRegionId.rend(); ++iter)
640         {
641           auto regionCount = iter->first;
642           auto regionId = iter->second;
643 
644           // Re-order the region sizes based on the sorting
645           this->RegionSizes->SetValue(counter, regionCount);
646 
647           // Create map from old to new RegionId
648           oldToNew[regionId] = counter++;
649         }
650       }
651 
652       vtkIdType numPts = pointRegionIds->GetNumberOfTuples();
653       for (vtkIdType i = 0; i < numPts; ++i)
654       {
655         vtkIdType oldValue = pointRegionIds->GetValue(i);
656         pointRegionIds->SetValue(i, oldToNew[oldValue]);
657       }
658 
659       vtkIdType numCells = cellRegionIds->GetNumberOfTuples();
660       for (vtkIdType i = 0; i < numCells; ++i)
661       {
662         vtkIdType oldValue = cellRegionIds->GetValue(i);
663         cellRegionIds->SetValue(i, oldToNew[oldValue]);
664       }
665     }
666     // else UNSPECIFIED mode
667   }
668 }
669 
670 // Obtain the number of connected regions.
GetNumberOfExtractedRegions()671 int vtkConnectivityFilter::GetNumberOfExtractedRegions()
672 {
673   return this->RegionSizes->GetMaxId() + 1;
674 }
675 
ProcessRequest(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)676 vtkTypeBool vtkConnectivityFilter::ProcessRequest(
677   vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
678 {
679   if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA_OBJECT()))
680   {
681     return this->RequestDataObject(request, inputVector, outputVector);
682   }
683 
684   return this->Superclass::ProcessRequest(request, inputVector, outputVector);
685 }
686 
687 // Initialize list of point ids/cell ids used to seed regions.
InitializeSeedList()688 void vtkConnectivityFilter::InitializeSeedList()
689 {
690   this->Modified();
691   this->Seeds->Reset();
692 }
693 
694 // Add a seed id (point or cell id). Note: ids are 0-offset.
AddSeed(vtkIdType id)695 void vtkConnectivityFilter::AddSeed(vtkIdType id)
696 {
697   this->Modified();
698   this->Seeds->InsertNextId(id);
699 }
700 
701 // Delete a seed id (point or cell id). Note: ids are 0-offset.
DeleteSeed(vtkIdType id)702 void vtkConnectivityFilter::DeleteSeed(vtkIdType id)
703 {
704   this->Modified();
705   this->Seeds->DeleteId(id);
706 }
707 
708 // Initialize list of region ids to extract.
InitializeSpecifiedRegionList()709 void vtkConnectivityFilter::InitializeSpecifiedRegionList()
710 {
711   this->Modified();
712   this->SpecifiedRegionIds->Reset();
713 }
714 
715 // Add a region id to extract. Note: ids are 0-offset.
AddSpecifiedRegion(int id)716 void vtkConnectivityFilter::AddSpecifiedRegion(int id)
717 {
718   this->Modified();
719   this->SpecifiedRegionIds->InsertNextId(id);
720 }
721 
722 // Delete a region id to extract. Note: ids are 0-offset.
DeleteSpecifiedRegion(int id)723 void vtkConnectivityFilter::DeleteSpecifiedRegion(int id)
724 {
725   this->Modified();
726   this->SpecifiedRegionIds->DeleteId(id);
727 }
728 
FillInputPortInformation(int,vtkInformation * info)729 int vtkConnectivityFilter::FillInputPortInformation(int, vtkInformation* info)
730 {
731   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
732   return 1;
733 }
734 
FillOutputPortInformation(int vtkNotUsed (port),vtkInformation * info)735 int vtkConnectivityFilter::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info)
736 {
737   info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkDataSet");
738   return 1;
739 }
740 
PrintSelf(ostream & os,vtkIndent indent)741 void vtkConnectivityFilter::PrintSelf(ostream& os, vtkIndent indent)
742 {
743   this->Superclass::PrintSelf(os, indent);
744 
745   os << indent << "Extraction Mode: ";
746   os << this->GetExtractionModeAsString() << "\n";
747 
748   os << indent << "Closest Point: (" << this->ClosestPoint[0] << ", " << this->ClosestPoint[1]
749      << ", " << this->ClosestPoint[2] << ")\n";
750 
751   os << indent << "Color Regions: " << (this->ColorRegions ? "On\n" : "Off\n");
752 
753   os << indent << "Scalar Connectivity: " << (this->ScalarConnectivity ? "On\n" : "Off\n");
754 
755   double* range = this->GetScalarRange();
756   os << indent << "Scalar Range: (" << range[0] << ", " << range[1] << ")\n";
757   os << indent << "Output Points Precision: " << this->OutputPointsPrecision << "\n";
758 }
759