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)\)):

\[\begin{split}\small \left[\begin{array}{ccccccc} 1 & 0 & & & & & \\ h_2 & h_{1,2} & h_1 & & & & \\ & \ddots & \dots & \ddots & & & \\ & & h_{i+1} & h_{i,i+1} & h_i & & \\ & & & \ddots & \ddots & \ddots & \\ & & & & h_n & h_{n-1,n} & h_{n-1} \\ & & & & & 0 & 1 \\ \end{array}\right] \cdot \left[\begin{array}{c} b_0 \\ b_1 \\ \vdots \\ b_i \\ \vdots \\ b_{n-1} \\ b_n \end{array}\right] = \left[\begin{array}{c} y_0' \\ \dfrac{3}{h_1h_2}(h_1^2(y_2-y_1)\\ \ \ +h_2^2(y_1-y_0)) \\ \vdots \\ \dfrac{3}{h_i h_{i+1}}(h_i^2(y_{i+1}-y_i)+h_{i+1}^2(y_i-y_{i-1})) \\ \vdots\\ \dfrac{3}{h_{n-1}h_n}(h_{n-1}^2(y_{n}-y_{n-1})+h_{n}^2(y_{n-1}-y_{n-2})) \\ y_n' \end{array}\right]\end{split}\]

The spline is said to be clamped because derivatives at ends are imposed.

clamped spine (png)

Other boundary conditions are usual : \(q_1''(t_0)=q_n''(t_n)=0\) leading to natural spline

natural spine (png)

or periodicity conditions : \(q'_1(t_0)=q'_n(t_n)\) and \(q''_1(t_0)=q''_n(t_n)\) leading to periodic spline.

periodic spine (png)

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:

\[Q(t)=\left( \mathcal S_{T,P^1}(t), \mathcal S_{T,P^2}(t), \mathcal S_{T,P^3}(t) \right)\]

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
C2spine xlife (png)

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

\[\begin{split}Q(t)= \left[\begin{array}{cccc} 1 & t & t^2 & t^3\end{array}\right] \cdot \left[\begin{array}{cccc} 0 & 1 & 0 & 0 \\ -\alpha & 0 & \alpha & 0 \\ 2\alpha & \alpha-3 & 3-3\alpha & -\alpha \\ -\alpha & 2-\alpha & \alpha-2 & \alpha \\ \end{array}\right] \cdot \left[\begin{array}{c} P_{i-1} \\ P_{i} \\ P_{i+1} \\ P_{i+2} \\ \end{array}\right]\end{split}\]

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:

\[( P_1 P_2 P_3 \ldots P_{n-2} P_{n-1} P_{n} ) \rightarrow ( P_{n-1} P_n P_1 P_2 P_3 \ldots P_{n-2} P_{n-1} P_{n} P_1 P_2 )\]

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.

Catmull Rom Spline (png)

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.

Catmull Rom per |xlifepp| (png)

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

\[Q(t) = \sum_{i=0}^n B_i^n(t) P_i \quad \forall t \in [0, 1]\]

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}\)

Bézier curve (png)

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]\).

Bézier Spline (png)

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:

\[\begin{split}\begin{array}{rl} \forall 0 \le i \le m−1 & B_{i,0}(t) = \begin{cases} 1 & t_i \le t \le t_{i+1} \\ 0 & \text{otherwise} \end{cases} \\ \forall 1 \le k \le m−1, 0\le i\le m-k-1 & B_{i,k}(t)=\dfrac{t-t_i}{t_{i+k}-t_i}B_{i,k-1}(t)+\dfrac{t_{i+k+1}-t}{t_{i+k+1}-t_{i+1}}B_{i+1,k-1}(t) \\ \end{array}\end{split}\]

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

\[Q(t)=\sum_{i=0}^n B_{i,k}(t)P_i \quad \forall t_k\le t \le t_{n+1}\]

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]\):

B_Spline3_clamped (png)

A rational B-spline is defined as following:

\[Q(t)=\dfrac{\sum^n_{i=0}\omega_i B_{i,k}(t) P_i}{\sum^n_{i=0}\omega_iB_{i,k}(t)} \quad \forall t_k\le t\le t_{n+1}\]

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.

rational Bspline (png)

if \(t_0=t_1=\ldots=t_k < t_{k+1}\) and \(P_0 \neq P_1\) then

\[\begin{split}\begin{array}{l} Q'(t_k)=P_0\\ Q'(t_k)=\dfrac{k}{t_{k+1}-t_k}\dfrac{w_1}{w_0}(P_1-P_0)\\ Q'(t_k)\times Q''(t_k)=\dfrac{k^2(k-1)}{(t{k+1}-t_k)^2(t_{k+2}-t_k)}\dfrac{w_1w_2}{w_0^2}(P_1-P_0)\times (P_2-P_0),\\ \kappa=\dfrac{k-1}{k}\dfrac{t_{k+1}-t_k}{t_{k+2}-tk}\dfrac{w_1w_2}{w_0^2}\dfrac{2A}{c^3} \mathrm{\;(curvature)} \end{array}\end{split}\]

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!

B Spline periodic xlife (png)

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);
interpolation B spline clamped (png)

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

\[\displaystyle (u, v) \rightarrow Q(u,v)=\frac{\sum_{i=0}^m\sum_{j=0}^n w_{ij}B_{i,p}(u)B_{j,q}(v)P_{i,j}}{\sum_{i=0}^m\sum_{j=0}^n w_{ij}B_{i,p}(u)B_{j,q}(u)}\]

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
Nurbs approximation Nurbs approximation
Nurbs interpolation Nurbs interpolation

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