1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkShrinkFilter.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 "vtkShrinkFilter.h"
16 
17 #include "vtkCell.h"
18 #include "vtkCellData.h"
19 #include "vtkIdList.h"
20 #include "vtkInformation.h"
21 #include "vtkInformationVector.h"
22 #include "vtkObjectFactory.h"
23 #include "vtkPointData.h"
24 #include "vtkSmartPointer.h"
25 #include "vtkUnstructuredGrid.h"
26 
27 vtkStandardNewMacro(vtkShrinkFilter);
28 
29 //------------------------------------------------------------------------------
vtkShrinkFilter()30 vtkShrinkFilter::vtkShrinkFilter()
31 {
32   this->ShrinkFactor = 0.5;
33 }
34 
35 //------------------------------------------------------------------------------
36 vtkShrinkFilter::~vtkShrinkFilter() = default;
37 
38 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)39 void vtkShrinkFilter::PrintSelf(ostream& os, vtkIndent indent)
40 {
41   this->Superclass::PrintSelf(os, indent);
42   os << indent << "Shrink Factor: " << this->ShrinkFactor << "\n";
43 }
44 
45 //------------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)46 int vtkShrinkFilter::FillInputPortInformation(int, vtkInformation* info)
47 {
48   // This filter uses the vtkDataSet cell traversal methods so it
49   // suppors any data set type as input.
50   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
51   return 1;
52 }
53 
54 //------------------------------------------------------------------------------
RequestData(vtkInformation *,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)55 int vtkShrinkFilter::RequestData(
56   vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
57 {
58   // Get input and output data.
59   vtkDataSet* input = vtkDataSet::GetData(inputVector[0]);
60   vtkUnstructuredGrid* output = vtkUnstructuredGrid::GetData(outputVector);
61 
62   // We are now executing this filter.
63   vtkDebugMacro("Shrinking cells");
64 
65   // Skip execution if there is no input geometry.
66   vtkIdType numCells = input->GetNumberOfCells();
67   vtkIdType numPts = input->GetNumberOfPoints();
68   if (numCells < 1 || numPts < 1)
69   {
70     vtkDebugMacro("No data to shrink!");
71     return 1;
72   }
73 
74   // Allocate working space for new and old cell point lists.
75   vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New();
76   vtkSmartPointer<vtkIdList> newPtIds = vtkSmartPointer<vtkIdList>::New();
77   ptIds->Allocate(VTK_CELL_SIZE);
78   newPtIds->Allocate(VTK_CELL_SIZE);
79 
80   // Allocate approximately the space needed for the output cells.
81   output->Allocate(numCells);
82 
83   // Allocate space for a new set of points.
84   vtkSmartPointer<vtkPoints> newPts = vtkSmartPointer<vtkPoints>::New();
85   newPts->Allocate(numPts * 8, numPts);
86 
87   // Allocate space for data associated with the new set of points.
88   vtkPointData* inPD = input->GetPointData();
89   vtkPointData* outPD = output->GetPointData();
90   outPD->CopyAllocate(inPD, numPts * 8, numPts);
91 
92   // Support progress and abort.
93   vtkIdType tenth = (numCells >= 10 ? numCells / 10 : 1);
94   double numCellsInv = 1.0 / numCells;
95   int abort = 0;
96 
97   // Point Id map.
98   vtkIdType* pointMap = new vtkIdType[input->GetNumberOfPoints()];
99 
100   // Traverse all cells, obtaining node coordinates.  Compute "center"
101   // of cell, then create new vertices shrunk towards center.
102   for (vtkIdType cellId = 0; cellId < numCells && !abort; ++cellId)
103   {
104     // Get the list of points for this cell.
105     input->GetCellPoints(cellId, ptIds);
106     vtkIdType numIds = ptIds->GetNumberOfIds();
107 
108     // Periodically update progress and check for an abort request.
109     if (cellId % tenth == 0)
110     {
111       this->UpdateProgress((cellId + 1) * numCellsInv);
112       abort = this->GetAbortExecute();
113     }
114 
115     // Compute the center of mass of the cell points.
116     double center[3] = { 0, 0, 0 };
117     for (vtkIdType i = 0; i < numIds; ++i)
118     {
119       double p[3];
120       input->GetPoint(ptIds->GetId(i), p);
121       for (int j = 0; j < 3; ++j)
122       {
123         center[j] += p[j];
124       }
125     }
126     for (int j = 0; j < 3; ++j)
127     {
128       center[j] /= numIds;
129     }
130 
131     // Create new points for this cell.
132     newPtIds->Reset();
133     for (vtkIdType i = 0; i < numIds; ++i)
134     {
135       // Get the old point location.
136       double p[3];
137       input->GetPoint(ptIds->GetId(i), p);
138 
139       // Compute the new point location.
140       double newPt[3];
141       for (int j = 0; j < 3; ++j)
142       {
143         newPt[j] = center[j] + this->ShrinkFactor * (p[j] - center[j]);
144       }
145 
146       // Create the new point for this cell.
147       vtkIdType newId = newPts->InsertNextPoint(newPt);
148 
149       // Copy point data from the old point.
150       vtkIdType oldId = ptIds->GetId(i);
151       outPD->CopyData(inPD, oldId, newId);
152 
153       pointMap[oldId] = newId;
154     }
155 
156     // special handling for polyhedron cells
157     if (vtkUnstructuredGrid::SafeDownCast(input) && input->GetCellType(cellId) == VTK_POLYHEDRON)
158     {
159       vtkUnstructuredGrid::SafeDownCast(input)->GetFaceStream(cellId, newPtIds);
160       vtkUnstructuredGrid::ConvertFaceStreamPointIds(newPtIds, pointMap);
161     }
162     else
163     {
164       for (vtkIdType i = 0; i < numIds; ++i)
165       {
166         newPtIds->InsertId(i, pointMap[ptIds->GetId(i)]);
167       }
168     }
169 
170     // Store the new cell in the output.
171     output->InsertNextCell(input->GetCellType(cellId), newPtIds);
172   }
173 
174   // Store the new set of points in the output.
175   output->SetPoints(newPts);
176 
177   // Just pass cell data through because we still have the same number
178   // and type of cells.
179   output->GetCellData()->PassData(input->GetCellData());
180 
181   // Avoid keeping extra memory around.
182   output->Squeeze();
183 
184   delete[] pointMap;
185 
186   return 1;
187 }
188