1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkWindowedSincPolyDataFilter.h
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  * @class   vtkWindowedSincPolyDataFilter
17  * @brief   adjust point positions using a windowed sinc function interpolation kernel
18  *
19  * vtkWindowedSincPolyDataFiler adjust point coordinate using a windowed
20  * sinc function interpolation kernel. The effect is to "relax" the mesh,
21  * making the cells better shaped and the vertices more evenly distributed.
22  * Note that this filter operates the lines, polygons, and triangle strips
23  * composing an instance of vtkPolyData. Vertex or poly-vertex cells are
24  * never modified.
25  *
26  * The algorithm proceeds as follows. For each vertex v, a topological and
27  * geometric analysis is performed to determine which vertices are connected
28  * to v, and which cells are connected to v. Then, a connectivity array is
29  * constructed for each vertex. (The connectivity array is a list of lists
30  * of vertices that directly attach to each vertex.) Next, an iteration
31  * phase begins over all vertices. For each vertex v, the coordinates of v
32  * are modified using a windowed sinc function interpolation kernel.
33  * Taubin describes this methodology is the IBM tech report RC-20404
34  * (#90237, dated 3/12/96) "Optimal Surface Smoothing as Filter Design"
35  * G. Taubin, T. Zhang and G. Golub. (Zhang and Golub are at Stanford
36  * University.)
37  *
38  * This report discusses using standard signal processing low-pass filters
39  * (in particular windowed sinc functions) to smooth polyhedra. The
40  * transfer functions of the low-pass filters are approximated by
41  * Chebyshev polynomials. This facilitates applying the filters in an
42  * iterative diffusion process (as opposed to a kernel convolution).  The
43  * more smoothing iterations applied, the higher the degree of polynomial
44  * approximating the low-pass filter transfer function. Each smoothing
45  * iteration, therefore, applies the next higher term of the Chebyshev
46  * filter approximation to the polyhedron. This decoupling of the filter
47  * into an iteratively applied polynomial is possible since the Chebyshev
48  * polynomials are orthogonal, i.e. increasing the order of the
49  * approximation to the filter transfer function does not alter the
50  * previously calculated coefficients for the low order terms.
51  *
52  * Note: Care must be taken to avoid smoothing with too few iterations.
53  * A Chebyshev approximation with too few terms is an poor approximation.
54  * The first few smoothing iterations represent a severe scaling and
55  * translation of the data.  Subsequent iterations cause the smoothed
56  * polyhedron to converge to the true location and scale of the object.
57  * We have attempted to protect against this by automatically adjusting
58  * the filter, effectively widening the pass band. This adjustment is only
59  * possible if the number of iterations is greater than 1.  Note that this
60  * sacrifices some degree of smoothing for model integrity. For those
61  * interested, the filter is adjusted by searching for a value sigma
62  * such that the actual pass band is k_pb + sigma and such that the
63  * filter transfer function evaluates to unity at k_pb, i.e. f(k_pb) = 1
64  *
65  * To improve the numerical stability of the solution and minimize the
66  * scaling the translation effects, the algorithm can translate and
67  * scale the position coordinates to within the unit cube [-1, 1],
68  * perform the smoothing, and translate and scale the position
69  * coordinates back to the original coordinate frame.  This mode is
70  * controlled with the NormalizeCoordinatesOn() /
71  * NormalizeCoordinatesOff() methods.  For legacy reasons, the default
72  * is NormalizeCoordinatesOff.
73  *
74  * This implementation is currently limited to using an interpolation
75  * kernel based on Hamming windows.  Other windows (such as Hann, Blackman,
76  * Kaiser, Lanczos, Gaussian, and exponential windows) could be used
77  * instead.
78  *
79  * There are some special instance variables used to control the execution
80  * of this filter. (These ivars basically control what vertices can be
81  * smoothed, and the creation of the connectivity array.) The
82  * BoundarySmoothing ivar enables/disables the smoothing operation on
83  * vertices that are on the "boundary" of the mesh. A boundary vertex is one
84  * that is surrounded by a semi-cycle of polygons (or used by a single
85  * line).
86  *
87  * Another important ivar is FeatureEdgeSmoothing. If this ivar is
88  * enabled, then interior vertices are classified as either "simple",
89  * "interior edge", or "fixed", and smoothed differently. (Interior
90  * vertices are manifold vertices surrounded by a cycle of polygons; or used
91  * by two line cells.) The classification is based on the number of feature
92  * edges attached to v. A feature edge occurs when the angle between the two
93  * surface normals of a polygon sharing an edge is greater than the
94  * FeatureAngle ivar. Then, vertices used by no feature edges are classified
95  * "simple", vertices used by exactly two feature edges are classified
96  * "interior edge", and all others are "fixed" vertices.
97  *
98  * Once the classification is known, the vertices are smoothed
99  * differently. Corner (i.e., fixed) vertices are not smoothed at all.
100  * Simple vertices are smoothed as before . Interior edge vertices are
101  * smoothed only along their two connected edges, and only if the angle
102  * between the edges is less than the EdgeAngle ivar.
103  *
104  * The total smoothing can be controlled by using two ivars. The
105  * NumberOfIterations determines the maximum number of smoothing passes.
106  * The NumberOfIterations corresponds to the degree of the polynomial that
107  * is used to approximate the windowed sinc function. Ten or twenty
108  * iterations is all the is usually necessary. Contrast this with
109  * vtkSmoothPolyDataFilter which usually requires 100 to 200 smoothing
110  * iterations. vtkSmoothPolyDataFilter is also not an approximation to
111  * an ideal low-pass filter, which can cause the geometry to shrink as the
112  * amount of smoothing increases.
113  *
114  * The second ivar is the specification of the PassBand for the windowed
115  * sinc filter.  By design, the PassBand is specified as a doubling point
116  * number between 0 and 2.  Lower PassBand values produce more smoothing.
117  * A good default value for the PassBand is 0.1 (for those interested, the
118  * PassBand (and frequencies) for PolyData are based on the valence of the
119  * vertices, this limits all the frequency modes in a polyhedral mesh to
120  * between 0 and 2.)
121  *
122  * There are two instance variables that control the generation of error
123  * data. If the ivar GenerateErrorScalars is on, then a scalar value
124  * indicating the distance of each vertex from its original position is
125  * computed. If the ivar GenerateErrorVectors is on, then a vector
126  * representing change in position is computed.
127  *
128  * @warning
129  * The smoothing operation reduces high frequency information in the
130  * geometry of the mesh. With excessive smoothing important details may be
131  * lost. Enabling FeatureEdgeSmoothing helps reduce this effect, but cannot
132  * entirely eliminate it.
133  *
134  * @warning
135  * For maximum performance, do not enable BoundarySmoothing,
136  * NonManifoldSmoothing, or FeatureEdgeSmoothing. FeatureEdgeSmoothing is
137  * particularly expensive as it requires building topological links and
138  * computing local polygon normals which are relatively expensive
139  * operations. BoundarySmoothing and NonManifoldSmoothing have a modest
140  * impact on performance.
141  *
142  * @warning
143  * This class has been threaded with vtkSMPTools. Using TBB or other
144  * non-sequential execution type (set in the CMake variable
145  * VTK_SMP_IMPLEMENTATION_TYPE) may improve performance significantly.
146  *
147  * @sa
148  * Another useful documentation resource is this SIGGRAPH publication:
149  * Gabriel Taubin. "A Signal Processing Approach To Fair Surface Design".
150  *
151  * @sa
152  * vtkSmoothPolyDataFilter vtkPointSmoothingFilter vtkDecimate vtkDecimatePro
153  * vtkQuadricDecimation
154  */
155 
156 #ifndef vtkWindowedSincPolyDataFilter_h
157 #define vtkWindowedSincPolyDataFilter_h
158 
159 #include "vtkFiltersCoreModule.h" // For export macro
160 #include "vtkPolyDataAlgorithm.h"
161 
162 class VTKFILTERSCORE_EXPORT vtkWindowedSincPolyDataFilter : public vtkPolyDataAlgorithm
163 {
164 public:
165   vtkTypeMacro(vtkWindowedSincPolyDataFilter, vtkPolyDataAlgorithm);
166   void PrintSelf(ostream& os, vtkIndent indent) override;
167 
168   /**
169    * Construct object with number of iterations 20; passband .1; feature edge
170    * smoothing turned off; feature angle 45 degrees; edge angle 15 degrees;
171    * and boundary smoothing turned on. Error scalars and vectors are not
172    * generated (by default).
173    */
174   static vtkWindowedSincPolyDataFilter* New();
175 
176   ///@{
177   /**
178    * Specify the number of iterations (i.e., the degree of the polynomial
179    * approximating the windowed sinc function). Typically values around 20
180    * are used.
181    */
182   vtkSetClampMacro(NumberOfIterations, int, 0, VTK_INT_MAX);
183   vtkGetMacro(NumberOfIterations, int);
184   ///@}
185 
186   ///@{
187   /**
188    * Set the passband value for the windowed sinc filter.
189    */
190   vtkSetClampMacro(PassBand, double, 0.0, 2.0);
191   vtkGetMacro(PassBand, double);
192   ///@}
193 
194   ///@{
195   /**
196    * Turn on/off coordinate normalization.  The positions can be translated
197    * and scaled such that they fit within a [-1, 1] prior to the smoothing
198    * computation. The default is off.  The numerical stability of the
199    * solution can be improved by turning normalization on.  If normalization
200    * is on, the coordinates will be rescaled to the original coordinate
201    * system after smoothing has completed.
202    */
203   vtkSetMacro(NormalizeCoordinates, vtkTypeBool);
204   vtkGetMacro(NormalizeCoordinates, vtkTypeBool);
205   vtkBooleanMacro(NormalizeCoordinates, vtkTypeBool);
206   ///@}
207 
208   ///@{
209   /**
210    * Turn on/off smoothing points along sharp interior edges. Enabling this
211    * option has a performance impact on the algorithm since neihborhood
212    * information (cell links) and polygon normals must be computed.
213    */
214   vtkSetMacro(FeatureEdgeSmoothing, vtkTypeBool);
215   vtkGetMacro(FeatureEdgeSmoothing, vtkTypeBool);
216   vtkBooleanMacro(FeatureEdgeSmoothing, vtkTypeBool);
217   ///@}
218 
219   ///@{
220   /**
221    * Specify the feature angle for sharp edge identification. It only affects
222    * the filter when FeatureEdgeSmoothing is enabled.
223    */
224   vtkSetClampMacro(FeatureAngle, double, 0.0, 180.0);
225   vtkGetMacro(FeatureAngle, double);
226   ///@}
227 
228   ///@{
229   /**
230    * Specify the edge angle to control smoothing along edges (either interior
231    * or boundary).
232    */
233   vtkSetClampMacro(EdgeAngle, double, 0.0, 180.0);
234   vtkGetMacro(EdgeAngle, double);
235   ///@}
236 
237   ///@{
238   /**
239    * Turn on/off the smoothing of points on the boundary of the mesh.
240    * Enabled this option has a modest impact on performance.
241    */
242   vtkSetMacro(BoundarySmoothing, vtkTypeBool);
243   vtkGetMacro(BoundarySmoothing, vtkTypeBool);
244   vtkBooleanMacro(BoundarySmoothing, vtkTypeBool);
245   ///@}
246 
247   ///@{
248   /**
249    * Smooth non-manifold points. Enabling this option has a modest
250    * impact on performance.
251    */
252   vtkSetMacro(NonManifoldSmoothing, vtkTypeBool);
253   vtkGetMacro(NonManifoldSmoothing, vtkTypeBool);
254   vtkBooleanMacro(NonManifoldSmoothing, vtkTypeBool);
255   ///@}
256 
257   ///@{
258   /**
259    * Turn on/off the generation of scalar distance values.
260    */
261   vtkSetMacro(GenerateErrorScalars, vtkTypeBool);
262   vtkGetMacro(GenerateErrorScalars, vtkTypeBool);
263   vtkBooleanMacro(GenerateErrorScalars, vtkTypeBool);
264   ///@}
265 
266   ///@{
267   /**
268    * Turn on/off the generation of error vectors.
269    */
270   vtkSetMacro(GenerateErrorVectors, vtkTypeBool);
271   vtkGetMacro(GenerateErrorVectors, vtkTypeBool);
272   vtkBooleanMacro(GenerateErrorVectors, vtkTypeBool);
273   ///@}
274 
275 protected:
276   vtkWindowedSincPolyDataFilter();
277   ~vtkWindowedSincPolyDataFilter() override = default;
278 
279   int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
280 
281   int NumberOfIterations;
282   double PassBand;
283 
284   vtkTypeBool NormalizeCoordinates;
285 
286   vtkTypeBool FeatureEdgeSmoothing;
287   double FeatureAngle;
288   double EdgeAngle;
289   vtkTypeBool BoundarySmoothing;
290   vtkTypeBool NonManifoldSmoothing;
291 
292   vtkTypeBool GenerateErrorScalars;
293   vtkTypeBool GenerateErrorVectors;
294 
295 private:
296   vtkWindowedSincPolyDataFilter(const vtkWindowedSincPolyDataFilter&) = delete;
297   void operator=(const vtkWindowedSincPolyDataFilter&) = delete;
298 };
299 
300 #endif
301