#smoothing #spline #curve #spline-interpolation #data-points #fitting #interpolation

splinify

Rust-wrapper for Dierckx' B-Splines Curve and Surface Fortran Library

1 unstable release

0.1.0 Dec 27, 2021

#1171 in Algorithms


Used in spliny

MIT/Apache

695KB
4.5K SLoC

FORTRAN Legacy 3.5K SLoC // 0.5% comments Rust 655 SLoC // 0.2% comments

Splinify: Fit Curve and Surface Splines



A Splinify generated b-Spline curve, with 15 control points
See lissajous example for how this was generated

Introduction

Warning: this library uses a Fortran library as fitting engine, and requires ---in addition to Rust--- a Fortran compiler

Splinify fits curve and surface B-Splines to sets of data points, using Dierckx' Fortran FITPACK library written by Paul Dierckx in the mid 1980s. Dierckx' library is still one of the the most advanced general B-spline fitting libraries available today --- its mathematical foundations and algorithms are described in detail in Paul Dierckx' book: Curve and Surface Fitting with Splines.

With all its features --- and being programmed in a somewhat limited language, at least as concerned to API design --- Dierckx' FITPACK is difficult to use: for example, its concur subroutine has 28 numerical arguments! This aim of this library is to make it more accessible from Rust by implementing a high level Rustacean application interface.

Its intended use is scientific analysis and modeling, for example to represent spectral distributions in colorimetry, or to interpolate positional data and use spline derivatives to get speed and acceleration of moving objects in one or more dimensions.

Although Dierckx' Fortran library covers fitting a spline evaluation methods for Univariate and Bivariate B-Splines, currently only its univariate, or single input-parameter fitting methods are implemented.

Fortran

As this crate is a Fortran wrapper, you need a Fortran compiler on your system to use it: in specific it requires the Gnu Fortran GFortran to be installed. See Installing GFortran for instructions.

Having to install a Fortran compiler is a big restriction, so I recommend not using it as a dependency in projects for generic use.

Instructions

Splinify is part of a family of three crates:

  • splinify fits (non-uniform) B-Spline curves to input data, and results in a fitted as a spliny-crate CurveSpline. Data inputs are x and y vectors for 1 dimensional curves, and u and xyn vectors in case of N-dimensional curves.

  • Use spliny to to use the generated splines, for example to calculate curve coordinates, or a spline-curve's derivatives. This package also implements basic tools for input and output of spline representations in form of JSON files, and spline plots. It is completely written in Rust, and does not require a Fortran compiler.

  • dierckx-sys contains Fortran foreign function interfaces to Paul Dierckx' FITPACK library. It is used by splinify, but ---unless you want to explore Paul Dierckx library yourself--- can be ignored as concerned to using splinify and spliny.

To use this library add this to your Cargo.toml file:

[dependencies]
splinify= "0.1"

Examples

B-Splines

Some use for B-Spline representations are:

  • interpolation in one or more dimensions, for example when data is needed between a set of measured data points to make line plots,
  • calculate derivatives for measured data, such as the momentary speed and acceleration of a car from a set of time and distance values,
  • smoothing, to calculate a smooth line or shape through noisy data, for example to smooth the hand written script on a tablet.

B-splines --or basis splines-- are polynomials, not fitted to to the whole set of data, but fitted to segments of the data set, and connecting at the ends. The collection of all the polynomials for all the segments is a curve (or surface) B-Spline representation. Besides that the polynomials are all connected, to form a continuous line, they are also constructed to have the same first, second, or higher (depending on the degrees polynomial) derivatives, to form smooth curves and surfaces.

Here is a quote from Wikipedia with regard to B-Splines:

A spline function of order n is a piecewise polynomial function of degree n−1 in a variable x. The places where the pieces meet are known as knots.

B-Splines can be used to:

  • fit curves, in which case they are called Univariate B-Splines, to fit one or more outputs to a single input,
  • or can be used to fit surfaces, called Bivariate B-Splines, used to fit one or more outputs to two inputs,
  • or can be used to fit "volumes" using Multivariate B-Splines, by fitting one or more outputs to three or more inputs.

For example, the speed of a car as function of time could be described by a univariate spline, and weather-forecast barometric air-pressure distribution can be described by a bivariate spline. An example of a multivariate B-Spline representation would be a spline fit of 3D-temperature measurements in a room.

Curve Fitting

This wrapper provides various interface objects to Dierckx' library:

  • CurveSplineFit<K>, which wraps curfit, used to fit a curve, with degree *K, to a set of (xi,yi) data points, with the condition xi+1>xi+1; an example of this type of data set would be an array with time and temperatures, measured over a period of time, and,

  • ParameterCurveSplineFit<K,N>, wrapping concur, to fit an --optionally constrained-- parametrized curve, with degree K, to data points consisting of a input-parameter value ui, also with the condition that ui+1>ui+1, and a set of (xi,yi) in two dimensions (N=2), or a set of (xi,yi,zi) in three dimensions (N=3), or even more dimensions (N<=10); an example of this is a trajectory of a fly flying over a dinner table.

Both of these are generic spline implementations, using spline degree K and space dimension N as type parameters. Dierckx strongly recommends to use only odd degree linear (N=1), cubic (N=3), and quintic (N=5) spline functions. To avoid using type parameters, the following type aliases have been defined:

  • Type aliases for CurveSplineFit<K>
Alias K
LinearSplineFit 1
CubicSplineFit 3
QuinticSplineFit 5
  • Type aliases for ParameterCurveSplineFit<K,N>
Alias K N
LinearSplineFit2D 1 2
CubicSplineFit2D 3 2
QuinticSplineFit2D 5 2
LinearSplineFit3D 1 3
CubicSplineFit3D 3 3
QuinticSplineFit3D 5 3

To use a constrained spline-fit for one-dimensional curves, you can use a parametrized curve representation (use x as 'u', and y as 'xn') to use Dierckx' concur instead of the default curfit subroutine:

Alias K N
LinearSplineFit1D 1 1
CubicSplineFit1D 3 1
QuinticSplineFit1D 5 1

Spline Fit Types

For a dataset, the following spline-types can be generated:

  • Interpolating Splines
    These splines fit the given data exactly, with no error, with the knots at the location of the input parameter values. Besides the input data, no further input is needed, unless you want to set specific boundary conditions.

  • Least-Squares Splines
    These are obtained when you specify the location of the knots. The splines will be fitted to minimize the square deviation between the spline and data points. The resulting spline values can deviate from the given output data values. It is common to use equidistant locations of the knots, in which case the spline is referred to as a cardinal spline*. Additional input data here are the location of the knots, and optional boundary conditions.

  • Smoothing spline
    Smoothing splines are generated by supplying a measure for the estimated 'noise' in the data, in form of an RMS error (Root Mean Square noise value). The smoothing spline algorithm will add knots until the fit error is less than the given RMS noise estimate. A weighting factor can be added to each datapoint too, to limit the effect of those points on the fit result.

License

All content in this repository is ©2021 Harbers Bik LLC, and licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~6–9MB
~156K SLoC