The SmoothSurface class in the ILNumerics.Drawing.Plotting namespace (ILNumerics.Toolboxes.Drawing2 assembly) allows to quickly create a 3D surface plot from scattered data and to smooth the result. Optionally, the smoothed surface is displayed together with the original scattered points. The mesh is generated by kriging interpolation. Smoothing is performed by low-pass filtering in the frequency domain.
The following example selects 50 points from the terrain data provided with ILNumerics - at random positions. The points are used as scattered data input for SmoothSurface. The surface resolution and smoothing factor are specified. This example can also be downloaded as a runnable app from our examples section.
In this article:
- SmoothSurface Configuration
- Recommendations on finding optimal values.
- A note on the Computational Effort.
Want to see it in action? Watch this short video:
SmoothSurface creates a regular grid from scattered 3D points. The points are specified by two arrays in the SmoothSurface constructor:
- XYPoints - scattered data points positions as matrix of size [2 x n]. Each column defines the (x,y) coordinates of a scattered data point.
- Z - vector of length XYPoints, holding the Z values for the scattered points defined by XYPoints.
The definition of the scattered data defining the shape of the resulting smooth surface is only possible at the time the SmoothSurface object is constructed. Once the instance was created this data cannot change anymore.
In difference to that, the following properties can be configured in the constructor and for an existing instance:
- Margin - The resulting surface will always cover a rectangular area in the XY plane. Its size and position is determined by the extent of the scattered data points provided. This is: the smallest rectangle in the XY plane tightly fitting around the scattered data. This rectangle is marked green in the following plot:
The SmoothSurface.Margin property defines an additional area by which the tight extent is extended. The extension is determined as a fraction of the tight rectangle and can be configured for X and Y direction independently. SmoothSurface performs extrapolation on this area.
The following example creates a smooth surface with an extent of 1 in X and of 2 into the Y direction. It adds a margin of width 0.5 to both: to the beginning and to the end in X direction. Into Y direction the surface is extended by 1 tenth of the tight rectangles length: 0.2 – again: to the beginning and to the end:
margin is an optional constructor parameter. The default value is 0.1. The margin can also be configured after the surface was created. Therefore, the SmoothSurface.Margin property is used.
- Resolution - SmoothSurface computes a regular grid from your scattered data points. This grid consists out of 150 x 150 points by default. The resolution can be specified at the time the surface is constructed. Or it can be adjusted later on by using the SmoothSurface.Resolution parameter. The number of points is configurable in X and Y direction independently:
- SmoothingFactor - if SmoothSurface.Resolution is high enough, the resulting surface runs through the data points. This may or may not be intended. Often, the disturbing effect of measurement errors is to be decreased. SmoothSurface performs smoothing of the regular grid as a postprocessing step. Smoothing is archieved by filtering high frequencies from the surface spectrum. The effect is similar to the well known 'moving average' windowing technique. It computes the height (Z value) of a final data point based on the values of neighboring data points. The number of neighbor points to consider is configurable and determines the smoothness of the result. The smoothingFactor argument to the SmoothSurface constructor is optional. By default no smoothing is performed (value: 0). The SmoothSurface.SmoothingFactor property allows to adjust this value for an existing surface.
- Surface - SmoothSurface consists out of a ILNumerics.Drawing.Group, wrapping - among others - a regular Surface object. This Surface is used to display the interpolated, smoothed grid. It is accessed by the SmoothSurface.Surface property. All configuration options are available. See: surface documentation.
- PointsOriginal - the original, scattered data points used to create the instance of SmoothSurface can optionally be displayed together with the smoothed surface. The shape object used for rendering these points is accessible via the SmoothSurface.PointsOriginal property. All configuration options common to ILNumerics shapes are available. See: Visualization API
- Further configuration - SmoothSurface - like almost all objects in ILNumerics derives from ILNumerics.Drawing.Group. All properties of group objects are directly available for flexible configuration. Also, one can add more visual objects to the group and enhance the object in arbitrary ways. See: Group API documentation
SmoothSurface makes it really easy to get a fully connected surface from scattered data points. Optionally, the surface can be smoothed further. Measurement errors and outliers are eliminated to great degree.
Note, that there are two major factors controlling the smoothness of the result: the Resolution and the SmoothingFactor. While SmoothingFactor directly deals with the smoothness of the surface the smoothing effect of Resolution can be rather subtle. Consider a point cloud of 1000 points being 'sampled' at 10x10 positions. The resulting grid corresponds to the original points with little error at the grid points only. Between the grid points each surface tile performs linear interpolation. This neglects the values of nearby, scattered points, hence, may increases the error in between the grid points. On the other hand, the disturbing effect of those points to the resulting curve is less dominant - the curve is 'smoothed', too. In the following plot this undersampling is clearly visible for a grid of 10x10 points. Change the resolution to 100x100 and see the surface becoming 'sharper'!
Keep in mind that for a good result both parameters must be adjusted to meet your requirements.
- First, based on your specific data find a margin and a resolution which reassemble the interesting shape of your data. Often, a surface ought to have small enough tiles (i.e.: large enough grid resolution) so that no sharp edges between the tiles are visible.
- Now, incrementally increase the SmoothingFactor for your surface until unwanted peaks are sufficiently eliminated.
The creation of a regular grid from n scattered points comes with a memory requirement of O(n²). In many setups this puts a limits on the number of scattered points at approx. n ~1000. Also, higher resolutions require more clock cycles to compute, which must be considered in dynamic setups. Increased values of SmoothingFactor, on the other hand, do not increase the computational effort (compared to SmoothingFactor 0). Therefore, by balancing both: Resolution and SmoothingFactor one can create very smooth surfaces at a moderate resolution setting.