2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Cubic spline interpolation functions
18
TCubicSplineMatrix = array of array [0..3] of Single;
20
{ 3D cubic spline handler class.
21
This class allows to describe and calculate values of a time-based,
22
three-dimensionnal cubic spline.
23
Cubic spline pass through all given points and tangent on point N is
24
given by the (N-1) to (N+1) vector.
25
Note : X, Y & Z are actually interpolated independently. }
26
TCubicSpline = class (TObject)
29
matX, matY, matZ, matW : TCubicSplineMatrix;
34
{ Creates the spline and declares interpolation points.
35
Time references go from 0 (first point) to nb-1 (last point), the
36
first and last reference matrices respectively are used when T is
37
used beyond this range.
38
Note : "nil" single arrays are accepted, in this case the axis is
39
disabled and calculus will return 0 (zero) for this component. }
40
constructor Create(const X, Y, Z, W : PFloatArray; const nb : Integer); {$ifdef CLR}unsafe;{$endif}
41
destructor Destroy; override;
43
{ Calculates X component at time t. }
44
function SplineX(const t : Single): Single;
45
{ Calculates Y component at time t. }
46
function SplineY(const t : single): Single;
47
{ Calculates Z component at time t. }
48
function SplineZ(const t : single): Single;
49
{ Calculates W component at time t. }
50
function SplineW(const t : single): Single;
52
{ Calculates X and Y components at time t. }
53
procedure SplineXY(const t : single; var X, Y : Single);
54
{ Calculates X, Y and Z components at time t. }
55
procedure SplineXYZ(const t : single; var X, Y, Z : Single);
56
{ Calculates X, Y, Z and W components at time t. }
57
procedure SplineXYZW(const t : single; var X, Y, Z, W : Single);
59
{ Calculates affine vector at time t. }
60
function SplineAffineVector(const t : single) : TAffineVector; overload;
61
{ Calculates affine vector at time t. }
62
procedure SplineAffineVector(const t : single; var vector : TAffineVector); overload;
63
{ Calculates vector at time t. }
64
function SplineVector(const t : single) : TVector; overload;
65
{ Calculates vector at time t. }
66
procedure SplineVector(const t : single; var vector : TVector); overload;
68
{ Calculates X component slope at time t. }
69
function SplineSlopeX(const t : Single): Single;
70
{ Calculates Y component slope at time t. }
71
function SplineSlopeY(const t : single): Single;
72
{ Calculates Z component slope at time t. }
73
function SplineSlopeZ(const t : single): Single;
74
{ Calculates W component slope at time t. }
75
function SplineSlopeW(const t : single): Single;
76
{ Calculates the spline slope at time t. }
77
function SplineSlopeVector(const t : single) : TAffineVector; overload;
79
{ Calculates the intersection of the spline with the YZ plane.
80
Returns True if an intersection was found. }
81
function SplineIntersecYZ(X: Single; var Y, Z: Single): Boolean;
82
{ Calculates the intersection of the spline with the XZ plane.
83
Returns True if an intersection was found. }
84
function SplineIntersecXZ(Y: Single; var X, Z: Single): Boolean;
85
{ Calculates the intersection of the spline with the XY plane.
86
Returns True if an intersection was found. }
87
function SplineIntersecXY(Z: Single; var X, Y: Single): Boolean;
90
// ------------------------------------------------------------------
91
// ------------------------------------------------------------------
92
// ------------------------------------------------------------------
94
// ------------------------------------------------------------------
95
// ------------------------------------------------------------------
96
// ------------------------------------------------------------------
98
// VECCholeskyTriDiagResol
100
procedure VECCholeskyTriDiagResol(const b : array of Single; const nb : Integer;
101
var Result : array of Single);
103
Y, LDiag, LssDiag : array of Single;
104
i, k, Debut, Fin: Integer;
109
SetLength(LDiag, nb);
110
SetLength(LssDiag, nb-1);
111
LDiag[Debut]:=1.4142135; // = sqrt(2)
112
LssDiag[Debut]:=1.0/1.4142135;
113
for K:=Debut+1 to Fin-1 do begin
114
LDiag[K]:=Sqrt(4-LssDiag[K-1]*LssDiag[K-1]);
115
LssDiag[K]:=1.0/LDiag[K];
117
LDiag[Fin]:=Sqrt(2-LssDiag[Fin-1]*LssDiag[Fin-1]);
119
Y[Debut]:=B[Debut]/LDiag[Debut];
120
for I:=Debut+1 to Fin do
121
Y[I]:=(B[I]-Y[I-1]*LssDiag[I-1])/LDiag[I];
122
Assert(Length(Result)=nb);
123
Result[Fin]:=Y[Fin]/LDiag[Fin];
124
for i:=Fin-1 downto Debut do
125
Result[I]:=(Y[I]-Result[I+1]*LssDiag[I])/LDiag[I];
128
// MATInterpolationHermite
130
procedure MATInterpolationHermite(const ordonnees : PFloatArray; const nb : Integer;
131
var Result : TCubicSplineMatrix); {$ifdef CLR}unsafe;{$endif}
135
bb, deriv : array of Single;
138
if Assigned(Ordonnees) and (nb>0) then begin
141
bb[0]:=3*(ordonnees[1]-ordonnees[0]);
142
bb[n]:=3*(ordonnees[n]-ordonnees[n-1]);
144
bb[I]:=3*(ordonnees[I+1]-ordonnees[I-1]);
145
SetLength(deriv, nb);
146
VECCholeskyTriDiagResol(bb, nb, deriv);
147
SetLength(Result, n);
148
for i:=0 to n-1 do begin
151
c:=3*(ordonnees[I+1]-ordonnees[I])-2*deriv[I]-deriv[I+1];
152
d:=-2*(ordonnees[I+1]-ordonnees[I])+deriv[I]+deriv[I+1];
153
Result[I][3]:=a+I*(I*(c-I*d)-b);
154
Result[I][2]:=b+I*(3*I*d-2*c);
155
Result[I][1]:=c-3*I*d;
163
function MATValeurSpline(const spline : TCubicSplineMatrix; const x : Single;
164
const nb : Integer) : Single;
168
if Length(Spline)>0 then begin
173
else i:=Integer(Trunc(x));
174
{ TODO : the following line looks like a bug... }
175
if i=(nb-1) then Dec(i);
176
Result:=((spline[i][0]*x+spline[i][1])*x+spline[i][2])*x+spline[i][3];
180
// MATValeurSplineSlope
182
function MATValeurSplineSlope(const spline : TCubicSplineMatrix; const x : Single;
183
const nb : Integer) : Single;
187
if Length(Spline)>0 then begin
192
else i:=Integer(Trunc(x));
193
{ TODO : the following line looks like a bug... }
194
if i=(nb-1) then Dec(i);
195
Result:=(3*spline[i][0]*x+2*spline[i][1])*x+spline[i][2];
200
// ------------------ TCubicSpline ------------------
205
constructor TCubicSpline.Create(const X, Y, Z, W: PFloatArray; const nb : Integer); {$ifdef CLR}unsafe;{$endif}
208
MATInterpolationHermite(X, nb, matX);
209
MATInterpolationHermite(Y, nb, matY);
210
MATInterpolationHermite(Z, nb, matZ);
211
MATInterpolationHermite(W, nb, matW);
217
destructor TCubicSpline.Destroy;
224
function TCubicSpline.SplineX(const t : single): Single;
226
Result:=MATValeurSpline(MatX, t, FNb);
231
function TCubicSpline.SplineY(const t : single): Single;
233
Result:=MATValeurSpline(MatY, t, FNb);
238
function TCubicSpline.SplineZ(const t : single): Single;
240
Result:=MATValeurSpline(MatZ, t, FNb);
245
function TCubicSpline.SplineW(const t : single): Single;
247
Result:=MATValeurSpline(MatW, t, FNb);
252
procedure TCubicSpline.SplineXY(const t : single; var X, Y : Single);
254
X:=MATValeurSpline(MatX, T, FNb);
255
Y:=MATValeurSpline(MatY, T, FNb);
260
procedure TCubicSpline.SplineXYZ(const t : single; var X, Y, Z : Single);
262
X:=MATValeurSpline(MatX, T, FNb);
263
Y:=MATValeurSpline(MatY, T, FNb);
264
Z:=MATValeurSpline(MatZ, T, FNb);
269
procedure TCubicSpline.SplineXYZW(const t : single; var X, Y, Z, W : Single);
271
X:=MATValeurSpline(MatX, T, FNb);
272
Y:=MATValeurSpline(MatY, T, FNb);
273
Z:=MATValeurSpline(MatZ, T, FNb);
274
W:=MATValeurSpline(MatW, T, FNb);
279
function TCubicSpline.SplineAffineVector(const t : single) : TAffineVector;
281
Result.V[0]:=MATValeurSpline(MatX, t, FNb);
282
Result.V[1]:=MATValeurSpline(MatY, t, FNb);
283
Result.V[2]:=MATValeurSpline(MatZ, t, FNb);
288
procedure TCubicSpline.SplineAffineVector(const t : single; var vector : TAffineVector);
290
vector.V[0]:=MATValeurSpline(MatX, t, FNb);
291
vector.V[1]:=MATValeurSpline(MatY, t, FNb);
292
vector.V[2]:=MATValeurSpline(MatZ, t, FNb);
297
function TCubicSpline.SplineVector(const t : single) : TVector;
299
Result.V[0]:=MATValeurSpline(MatX, t, FNb);
300
Result.V[1]:=MATValeurSpline(MatY, t, FNb);
301
Result.V[2]:=MATValeurSpline(MatZ, t, FNb);
302
Result.V[3]:=MATValeurSpline(MatW, t, FNb);
307
procedure TCubicSpline.SplineVector(const t : single; var vector : TVector);
309
vector.V[0]:=MATValeurSpline(MatX, t, FNb);
310
vector.V[1]:=MATValeurSpline(MatY, t, FNb);
311
vector.V[2]:=MATValeurSpline(MatZ, t, FNb);
312
vector.V[3]:=MATValeurSpline(MatW, t, FNb);
317
function TCubicSpline.SplineSlopeX(const t : Single): Single;
319
Result:=MATValeurSplineSlope(MatX, t, FNb);
324
function TCubicSpline.SplineSlopeY(const t : single): Single;
326
Result:=MATValeurSplineSlope(MatY, t, FNb);
331
function TCubicSpline.SplineSlopeZ(const t : single): Single;
333
Result:=MATValeurSplineSlope(MatZ, t, FNb);
338
function TCubicSpline.SplineSlopeW(const t : single): Single;
340
Result:=MATValeurSplineSlope(MatW, t, FNb);
345
function TCubicSpline.SplineSlopeVector(const t : single) : TAffineVector;
347
Result.V[0]:=MATValeurSplineSlope(MatX, t, FNb);
348
Result.V[1]:=MATValeurSplineSlope(MatY, t, FNb);
349
Result.V[2]:=MATValeurSplineSlope(MatZ, t, FNb);
354
function TCubicSpline.SplineIntersecYZ(X: Single; var Y, Z: Single): Boolean;
356
Sup, Inf, Mid : Single;
357
SSup, Sinf, Smid : Single;
366
if SSup>Sinf then begin
367
if (SSup<X) or (Sinf>X) then Exit;
368
while Abs(SSup-Sinf)>1e-4 do begin
379
Y:=SplineY((Sup+Inf)*0.5);
380
Z:=SplineZ((Sup+Inf)*0.5);
382
if (Sinf<X) or (SSup>X) then Exit;
383
while Abs(SSup-Sinf)>1e-4 do begin
394
Y:=SplineY((Sup+Inf)*0.5);
395
Z:=SplineZ((Sup+Inf)*0.5);
402
function TCubicSpline.SplineIntersecXZ(Y: Single; var X, Z: Single): Boolean;
404
Sup, Inf, Mid : Single;
405
SSup, Sinf, Smid : Single;
414
if SSup>Sinf then begin
415
if (SSup<Y) or (Sinf>Y) then Exit;
416
while Abs(SSup-Sinf)>1e-4 do begin
427
X:=SplineX((Sup+Inf)*0.5);
428
Z:=SplineZ((Sup+Inf)*0.5);
430
if (Sinf<Y) or (SSup>Y) then Exit;
431
while Abs(SSup-Sinf)>1e-4 do begin
442
X:=SplineX((Sup+Inf)*0.5);
443
Z:=SplineZ((Sup+Inf)*0.5);
450
function TCubicSpline.SplineIntersecXY(Z: Single; var X, Y: Single): Boolean;
452
Sup, Inf, Mid : Single;
453
SSup, Sinf, Smid : Single;
462
if SSup>Sinf then begin
463
if (SSup<Z) or (Sinf>Z) then Exit;
464
while Abs(SSup-Sinf)>1e-4 do begin
475
X:=SplineX((Sup+Inf)*0.5);
476
Y:=SplineY((Sup+Inf)*0.5);
478
if (Sinf<Z) or (SSup>Z) then Exit;
479
while Abs(SSup-Sinf)>1e-4 do begin
490
X:=SplineX((Sup+Inf)*0.5);
491
Y:=SplineY((Sup+Inf)*0.5);