Splines#
Generally speaking, a spline is a piecewise polynomial curve that approaches, in a sense to be specified, an ordered list of points. The simplest one is the spline of degree 1 (linear spline) which connects the points by segments. XLiFE++ provides the Hermite cubic spline (C2), the Catmull-Row spline (C1), the B-spline and rational B-Spline (Ck) and the Bézier curve (Ck). The two first ones are interpolation splines while the last ones are approximation spline. Combining two rational B-splines in two directions gives a surface approximation, named NURBS acronym of Non Uniform Rational B-Spline.
C2 spline#
Let \((t_i)_{0\le i\le n}\) and \((y_i)_{0\le i\le n}\). There exists a unique C2 piecewise cubic polynomial such that \(q(t_i)=y_i\) for \(0\le i\le n\) and \(q'(t_0)=y'_0,q'(t_n)=y'_n\) . Each cubic polynomial may be constructed from the knowledge of \(b_i=q'(t_i), 0\le i\le n\) which is the solution of the following linear system (\(h_i=t_i−t_{i−1}\), \(h_{i,j}=2(h_i+h_j)\)):
The spline is said to be clamped because derivatives at ends are imposed.
Other boundary conditions are usual : \(q_1''(t_0)=q_n''(t_n)=0\) leading to natural spline
or periodicity conditions : \(q'_1(t_0)=q'_n(t_n)\) and \(q''_1(t_0)=q''_n(t_n)\) leading to periodic spline.
To interpolate any set of points \((P_i)_{0\le i\le n}\) in \(\mathbb R^2\) or \(\mathbb R^3\) , the previous method is extended as following. Let \(T=(t_i)_{0\le i\le n}\) a set of parameters (knots) and a set of scalar values \(Y=(y_i)_{0\le i\le n}\) , we denote \(\mathcal S_{T,Y}\) the spline function related to the sets \(T,Y\) . The C2 spline related to the set of points (Pi) is defined as:
where \(P^k=(P_i^k)_{i=0,n}\) with \(P_i^k\) the \(k^{th}\) coordinate of the point \(P_i\).
The usual choices of parametrization are
the x-parametrization: \(t_i=P^1_i, 0\le i\le n\) (gives the original C2 spline).
the uniform parametrization: \(t_i=i, 0\le i\le n\).
the chordal parametrization: \(t_0=0,t_i=t_{i−1}+\|P_i−P_{i−1}\|, \; 1\le i\le n\).
the centripetal parametrization: \(t_0=0,t_i=t_{i−1}+\|P_i−P_{i−1}\|^{\frac{1}{2}}, \; 1\le i\le n\).
Hint
To make the user life easier, the parameter is pullback to the interval \([0,1]\) . In other words, user addresses the spline parametrization using \(s\in [0,1]\) that is mapped to \(t=t_0+(1−s)t_n\) where \(t_0\) , \(t_n\) are the spline parameter bounds . All splines work in the same way.
XLiFE++ provides the C2Spline
class. There are two ways to construct a C2 spline, either by giving two vectors of reals \((T,Y)\) (classical C2 spline) or giving a vector of points \(P\) (extended C2 spline). The following optional parameters may be given at construction:
the type of parametrization : one of _xParametrization, _uniformParametrization, _chordalParametrization, _centripetalParametrization
the boundary conditions : two of _naturalBC, _clampedBC, _periodicBC
the derivatives at end points (vector of reals) required when using clamped conditions
Number n=5;
Real x=0, dx=pi_/n;
vector<Point> points(n+1);
for(Number i=0;i<=n;i++, x+=dx) points[i]=Point(x,sin(x));
C2Spline csn(points,_xParametrization); //natural spline
C2Spline csc(points,_xParametrization,_clampedBC,_clampedBC,
Reals(1.,1.),Reals(1.,-1.)); //clamped spline
C2Spline csp(points, _xParametrization, _periodicBC); //periodic spline
Warning
When _xParametrization
is selected, the curve is regarded as \(x \mapsto y(x)\) curve and the returned “values” are 1D points.
In contrast when an other parametrization is selected, the curve is regarded as \(t\rightarrow (x(t),y(t))\) and the returned “values” are 2D points.
Warning
Be cautious with periodic conditions. For a periodic open curve (e.g \(sinx\) on \([0,2\pi]\)) use only the _xParametrization
mode and for a closed periodic curve use other parametrization mode.
Once a C2Spline
object is constructed, using either the function evaluate or the operator (), it can be evaluated at any parameter \(t\in [0,1]\).
...
C2Spline csn(points,_xParametrization);
Real t=0.5; //midle parameter
Point P=csn(t); //value
Point dP=csn(t,_dt); //first derivative (vector as a point)
Point d2P=csn(t,_dt2); //second derivative (vector as a point)
C2Spline
allocates also a Parametrization
object related to the spline parametrization.
Using this object, other quantities such as curvilinear abscissa, normal or tangent vector, curvatures are available (see The Parametrization class and Parametrization
class):
...
C2Spline csn(points,_xParametrization);
Real t=0.5; //midle parameter
const Parametrization& pa=csn.parametrization();
Real c=pa.curvature(t);
Real s=pa.curabc(t);
Reals no=pa.normal(t);
Reals ta=pa.tangent(t);
Catmull-Rom spline#
Another way to construct interpolation spline consists in imposing also the tangent vectors \((T_i)\) at control points \(P_i\). Several methods have been proposed and the Catmull-Rom method is one of them. On the interval \([t_i,t_{i+1}]\) the spline \(Q\) is defined by
where \(\alpha\) is a tension parameter which is related to the underlying parametrization. The standard choices of \(\alpha\) are:
\(\alpha=0\): the standard Catmull-Rom spline,
\(\alpha=1\): the chordal Catmull-Rom spline,
\(\alpha=\dfrac{1}{2}\): the centripetal Catmull-Rom spline.
The Catmull-Rom spline are local (moving a point modifies only the curve in the neighborhood of the point), the approximation is \(C^1\) but not \(C^2\), the computation is fast. The centripetal Catmull-Rom spline has additional properties : there is no self-intersection, cusp will never occur and it follows the control points in a better way.
Note that to close a curve, it is sufficient to add the two last points at the beginning and the two first points at the end:
and build Catmull-Rom spline on segments \([P_n, P_1,\;[P_1, P_2,\; , \ldots , [P_{n-2}, P_{n-1}] , [P_{n-1}, P_{n}]\) .
On the next figure, the influence of the parameter \(\alpha\) may be observed; the value \(\alpha=0.5\) giving the best result.
XLiFE++ provides the CatmullRomSpline
class.
It has only one constructor from a vector of points \(P\) and optional parameters are available:
the type of parametrization : one of
_xParametrization
,_uniformParametrization
,_chordalParametrization
,_centripetalParametrization
the tension parameter \(\alpha\) (default value: \(0.5\))
the boundary conditions : two of
_undefBC
,_naturalBC
,_clampedBC
,_periodicBC
the tangent vectors at end points (vector of reals) required when using clamped conditions
In this example, as the last point is the same as the first point, the curve will be automatically closed.
Once a CatmullRomSpline
object is constructed, using either the function evaluate
or the operator ()
,
it can be evaluated at any parameter \(t \in [0,1]\)
...
CatmullRomSpline cat(pts);
Real t=0.5 //midle parameter
Point P=cat(t); //value
Point dP=cat(t,_dt); //first derivative (vector as a point)
Point d2P=cat(t,_dt2); //second derivative (vector as a point)
CatmullRomSpline
allocates also a Parametrization
object related to the spline parametrization.
Using this object, other quantities such as curvilinear abscissa, normal or tangent vector, curvatures are available (see The Parametrization class and Parametrization
class):
...
CatmullRomSpline cat(pts);
Real t=0.5 //midle parameter
const Parametrization& pa=cat.parametrization();
Real c=pa.curvature(t);
Real s=pa.curabc(t);
Reals no=pa.normal(t);
Reals ta=pa.tangent(t);
Bézier curve#
For the set of control points \((P_i) 0\le i\le n\) , the Bézier curve is defined by
where \(B^n_i=C^i_n t^i(1−t)^{n−i}\) are the Bernstein polynomials (\(\sum_{i=0}^n B_i=1)\) . Note that the degree of polynomials is equal to the number of points minus 1. There are the following properties
\(Q_0 = P_0\) and \(Q_1 = P_n\) but the curve does not interpolate the interior points \(P_1,\ldots , P_{n-1}\)
\(P_0P_1\) (resp. \(P_{n−1}P_n)\) is a tangent vector to the curve at \(P_0\) (resp. \(P_n\)),
the curve is inside the convex hull of the control points,
the curve is \(Ĉ^{\infty}\)
XLiFE++ provides the BezierSpline
class with only one simple constructor from a vector of points \(P\) :
Number n=5;
vector<Point> points(n+1);
Real x=0, dx=pi_/n;
for(Number i=0;i<=n;i++, x+=dx) points[i]=Point(x,sin(x));
BezierSpline bz(points);
The parameter \(t\) lives always in the interval \([0,1]\).
Once a BezierSpline
object is constructed, using either the function evaluate
or the operator ()
,
it can be evaluated at any parameter \(t\in [0,1]\) :
...
BezierSpline bz(points);
Real t=0.5; //midle parameter
Point P=bz(t); //value
Point dP=bz(t,_dt); //first derivative (vector as a point)
Point d2P=bz(t,_dt2); //second derivative (vector as a point)
BezierSpline
allocates also a Parametrization
object related to the spline parametrization.
Using this object, other quantities such as curvilinear abscissa, normal or tangent vector, curvatures are available (see The Parametrization class and Parametrization
class):
...
BezierSpline bz(points);
Real t=0.5;
const Parametrization& pa=bz.parametrization();
Real c=pa.curvature(t);
Real s=pa.curabc(t);
Reals no=pa.normal(t);
Reals ta=pa.tangent(t)
B-Spline#
The B-spline curve is a generalization of the Bézier curve. Let \(t_0\le t_1\le \ldots \le t_m\) a set of \(m+1\) knots and the B-spline functions of degree \(k\) defined by recurrence:
with the convention \(\dfrac{\bullet}{0}=0\).
The B-spline functions have a lot of properties, in particular
\(B_{i,k}\) is a polynomial of order \(k\) on intervals \([t_j,t_{j+1}]\) with support \([t_i,t_{i+k+1}]\),
\(0 < B_{i,k} < 1\) for \(t\in [t_i, t_{i+k+1}]\),
\(B_{i,k}\) is \(C^{\infty}\) at tight and is \(C^{k-r}\) at knots of multiplicity \(r\)
For the set of \(n+1\) control points \(P_0,P_1, \ldots , P_n\) and the set of knots \(t_0 \le t_1 \le \ldots \le t_m\) with \(m\ge n+k+1\), the B-spline curve is defined by
The B-spline curve is inside the convex hull of the control points, it is \(C^{k−1}\) if all the knots are of multiplicity 1, moving a point \(P_i\) induces a modification of the points related to the interval \([t_i,t_{i+k}]\). A Bézier curve is a B-Spline with a knots vector of the form \([0,0,\ldots,0,1,1,\ldots,1]\).
To clamp the curve at \(P_0\) choose \(t_0=t_1=\ldots=t_k<t_{k+1}\) and to close the curve duplicate the \(k+1\) first points at the end of the set of points.
\(\bullet\) Clamped B-spline of degree 3 with 6 control points and knots \([0,0,0,0,1,2,3,3,3,3]\) plotted on \([0,3]\):
A rational B-spline is defined as following:
where \((\omega_i)_{i=0,n}\) are some weights. When the weight \(\omega_i\) is large, the curve goes to the control point \(P_i\). When all the weights are equal to 1, the rational B-spline coincides with the B-spline.
if \(t_0=t_1=\ldots=t_k < t_{k+1}\) and \(P_0 \neq P_1\) then
with \(A\) the surface of the triangle \((P_0, P_1,, P_2)\) and \(c=\|P_1-P_0\|\). That gives a way to match the rational B-spline to another curve up to \(C^2\).
By solving a linear inverse problem, the control points may be calculated in order to interpolate a given set of points. In that case, the spline is named interpolation B-spline. For such spline, it is possible to impose the derivative vectors at the endpoints when the spline is clamped.
XLiFE++ provides the BSpline
class with constructors that takes a vector of points \(P\) and some optional data.
the type of B-spline, either _splineApproximation or _splineInterpolation
the degree of B-spline, default value 3
the type of parametrization : one of
_uniformParametrization
,_chordalParametrization
,_centripetalParametrization
the boundary conditions : two of _undefBC , _naturalBC , _clampedBC , _periodicBC
derivative vectors at end points when clamped B-spline is selected
the vector of weights (default 1)
The given vector of points is either the list of control points (approximation B-spline) or the list of interpolation points (interpolation B-spline). When the type of B-spline is not given, it is assumed to be an approximation B-spline:
Number n=6;
vector<Point> pts(n+1);
Real s=0, ds=2*pi_/n;
for(Number i=0;i<=n;i++,s+=ds) pts[i]=Point(2*cos(s),sin(s)); //points on ellipse
Spline bs(points,3,_periodicBC);
Specifying a periodic condition at starting point stands obviously for periodic condition at ending point!
To use some weights, define a vector of weights of the size of vector of control points:
vector<Real> we(pts.size(),1.);
for(Number k=0;k<we.size();k+=2) we[k]=0.5;
BSpline bsw(pts,3,_periodicBC,_periodicBC,we);
Because of the signature of the constructor, both boundary conditions have to be specified even they are redundant!
Once a BSpline
object is constructed, using either the function evaluate or the operator (), it can be evaluated at any parameter \(t\in [0,1]\).
...
BSpline bs(points,3,_periodicBC);
Real t=0.5; //midle parameter
Point P=bs(t); //value
Point dP=bs(t,_dt); //first derivative (vector as a point)
Point d2P=bs(t,_dt2); //second derivative (vector as a point)
BSpline
allocates also a Parametrization
object related to the spline parametrization.
Using this object, other quantities such as curvilinear abscissa, normal or tangent vector, curvatures are available (see The Parametrization class section and Parametrization
class):
...
BSpline bs(points,3,_periodicBC);
Real t=0.5; //midle parameter
const Parametrization& pa=bs.parametrization();
Real c=pa.curvature(t);
Real s=pa.curabc(t);
Reals no=pa.normal(t);
Reals ta=pa.tangent(t);
The following example shows how to build a clamped interpolation B-spline with a uniform parametrization from 5 points located on the sine curve:
...
vector<Point> pts(5,Point(0.,0.));
pts[1]=Point(pi_/4,sqrt(2)/2.);pts[2]=Point(pi_/2,1.);
pts[3]=Point(3*pi_/4,sqrt(2)/2.);pts[4]=Point(pi_,0.);
Reals d0(2,1.),d1=d0; d1[1]=-1.; //derivatives at end points
BSpline bs(_SplineInterpolation, pts, 3,_uniformParametrization, _clampedBC,_clampedBC,d0,d1);
When specifying only _splineInterpolation and a set of points in constructor, the B-spline will be a natural interpolation B-spline of degree 3 with a uniform parametrization (not rational).
Spline surface (nurbs)#
The most common method to approximate surface are NURBS (non uniform rational B-spline) that are no more than the cross-product of two rational B-splines. Let
a set of \((m+1)\times (n+1)\) control points \(P_{ij}, 0\le i\le m\) and \(0\le j \le n\)
a knot vector in u-direction and v-direction : \(U=[u_0, u_1, \ldots , u_k ]\) and \(V=[v_0, v_1, \ldots , v_l ]\)
the degree \(p\) in u-direction and the degree \(q\) in v-direction
\(k=m+p+1\) and \(l=n+q+1\)
The NURBS surface is defined by
To deal with nurbs, XLiFE++ provides the Nurbs
class. There is only one constructor from a vector of vectors of points (control
points) and optional parameters:
the degrees of B-spline along u /v parameter (default is 3)
the boundary conditions along \(u /v\) parameter, for each parameter, two of _naturalBC, _clampedBC, _periodicBC
the vector of vectors of weights (default no weight)
Number n=4;
Real ds=pi_/(2*n), u=-pi_/2, v=0;
PointMatrix pts(2*n+1,Points(n+1));
for(Number i=0;i<=2*n;i++,u+=ds) // points on the quarter of unit sphere
{
v=0;
for(Number j=0;j<=n;j++,v+=ds)
pts[i][j]=Point(cos(u)*cos(v),cos(u)*sin(v),sin(u));
}
Nurbs nuA(_splineApproximation, pts); //create approximation nurbs
Nurbs nuI(_splineInterpolation, pts); //create interpolation nurbs
Once a Nurbs
object is constructed, using either the function evaluate or the operator (),
it can be evaluated at any parameter \((u,v)\in [0,1]\times[0,1]\):
...
Point P=nu(0.5,0.5); //value
Point duP=nu(0.5,0.5,_d1); //first derivative (vector as a point)
Point dvP=nu(0.5,0.5,_d2); //first derivative (vector as a point)
Nurbs allocates also a Parametrization
object related to the spline parametrization.
Using this object, other quantities such as curvilinear abscissa, normal or tangent vector, curvatures are available (see The Parametrization class section and Parametrization
class):
...
const Parametrization& pa=nu.parametrization();
Real u=0.5, v=0.5;
Reals cu=pa.curvatures(u,v); //two main curvatures
Reals no=pa.normal(u,v); //normal vector
Reals ta=pa.tangents(u,v); //two orthogonal tangent vectors in a same Vector