1 /***************************************************************************
2
3 file : spline.cpp
4 created : Mon Apr 17 13:51:00 CET 2000
5 copyright : (C) 2000-2006 by Bernhard Wymann
6 email : berniw@bluewin.ch
7 version : $Id: spline.cpp,v 1.1.2.1 2008/05/31 09:25:28 berniw Exp $
8
9 ***************************************************************************/
10
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 ***************************************************************************/
19
20 #include <math.h>
21 #include <stdlib.h>
22 #include "spline.h"
23
24
25 /* solving tridiagonal nxn matrix with Givens-Rotations in linear time O(n)
26 [ a1 b1 0 0 0 .......... ]
27 [ c1 a2 b2 0 0 ...........]
28 [ 0 c2 a3 b3 0 ...........]
29 [ ...........................]
30 [ ................... b(n-1) ]
31 [ ................ c(n-1) an ]
32 */
33
tridiagonal(int dim,SplineEquationData * tmp,double * x)34 void tridiagonal(int dim, SplineEquationData *tmp, double *x)
35 {
36 double cos, sin, h, t;
37 int i;
38
39 dim--;
40 tmp[dim].b = 0.0;
41 for (i = 0; i < dim; i++) {
42 if (tmp[i].c != 0.0) {
43 t = tmp[i].a / tmp[i].c;
44 sin = 1.0 / sqrt(1.0 + t*t);
45 cos = t * sin;
46 tmp[i].a = tmp[i].a*cos + tmp[i].c*sin;
47 h = tmp[i].b;
48 tmp[i].b = h*cos + tmp[i+1].a*sin;
49 tmp[i+1].a = -h*sin + tmp[i+1].a*cos;
50 tmp[i].c = tmp[i+1].b*sin;
51 tmp[i+1].b = tmp[i+1].b*cos;
52
53 h = x[i];
54 x[i] = h*cos + x[i+1]*sin;
55 x[i+1] = -h*sin + x[i+1]*cos;
56 }
57 }
58
59 x[dim] = x[dim]/tmp[dim].a;
60 x[dim-1] = (x[dim-1] - tmp[dim-1].b*x[dim]) / tmp[dim-1].a;
61
62 for (i = dim - 2; i >= 0; i--) {
63 x[i] = (x[i] - tmp[i].b*x[i+1] - tmp[i].c*x[i+2]) / tmp[i].a;
64 }
65 }
66
67
68 /* solving tridiagonal nxn matrix for two vectors with Givens-Rotations in linear time O(n) */
tridiagonal2(int dim,SplineEquationData2 * tmp)69 void tridiagonal2(int dim, SplineEquationData2 *tmp)
70 {
71 double cos, sin, h, t;
72 int i;
73
74 dim--;
75 tmp[dim].b = 0.0;
76 for (i = 0; i < dim; i++) {
77 if (tmp[i].c != 0.0) {
78 t = tmp[i].a / tmp[i].c;
79 sin = 1.0 / sqrt(1.0 + t*t);
80 cos = t * sin;
81 tmp[i].a = tmp[i].a*cos + tmp[i].c*sin;
82 h = tmp[i].b;
83 tmp[i].b = h*cos + tmp[i+1].a*sin;
84 tmp[i+1].a = -h*sin + tmp[i+1].a*cos;
85 tmp[i].c = tmp[i+1].b*sin;
86 tmp[i+1].b = tmp[i+1].b*cos;
87
88 h = tmp[i].x1;
89 tmp[i].x1 = h*cos + tmp[i+1].x1*sin;
90 tmp[i+1].x1 = -h*sin + tmp[i+1].x1*cos;
91
92 h = tmp[i].x2;
93 tmp[i].x2 = h*cos + tmp[i+1].x2*sin;
94 tmp[i+1].x2 = -h*sin + tmp[i+1].x2*cos;
95 }
96 }
97
98 tmp[dim].x1 = tmp[dim].x1 / tmp[dim].a;
99 tmp[dim-1].x1 = (tmp[dim-1].x1 - tmp[dim-1].b*tmp[dim].x1) / tmp[dim-1].a;
100
101 tmp[dim].x2 = tmp[dim].x2 / tmp[dim].a;
102 tmp[dim-1].x2 = (tmp[dim-1].x2 - tmp[dim-1].b*tmp[dim].x2) / tmp[dim-1].a;
103
104 for (i = dim - 2; i >= 0; i--) {
105 tmp[i].x1 = (tmp[i].x1 - tmp[i].b*tmp[i+1].x1 - tmp[i].c*tmp[i+2].x1) / tmp[i].a;
106 tmp[i].x2 = (tmp[i].x2 - tmp[i].b*tmp[i+1].x2 - tmp[i].c*tmp[i+2].x2) / tmp[i].a;
107 }
108 }
109
110
111 /* compute the slopes of the spline points with periodic constraints */
slopesp(int dim,const double * const x,const double * const y,double * const ys)112 void slopesp(int dim, const double *const x, const double *const y, double *const ys)
113 {
114 SplineEquationData2 *tmp = (SplineEquationData2 *) malloc(sizeof(SplineEquationData2)*dim);
115 int i;
116
117 dim--;
118 for (i = 0; i < dim; i++) {
119 tmp[i].h = x[i+1] - x[i];
120 tmp[i].d = (y[i+1]-y[i]) / (tmp[i].h*tmp[i].h);
121 }
122
123 for (i = 1; i < dim; i++) {
124 tmp[i].a = 2.0/tmp[i-1].h + 2.0/tmp[i].h;
125 tmp[i].b = 1.0/tmp[i].h;
126 tmp[i].c = tmp[i].b;
127 ys[i] = 3.0 * (tmp[i].d+tmp[i-1].d);
128 }
129
130 tmp[0].b = 1.0/tmp[0].h;
131 tmp[0].c = tmp[0].b;
132 tmp[0].a = (2.0*tmp[0].b + 1.0/tmp[dim-1].h);
133 tmp[dim-1].a = 2.0/tmp[dim-2].h + 1.0/tmp[dim-1].h;
134
135 for (i = 1; i < dim; i++) {
136 tmp[i].x1 = 0.0; tmp[i].x2 = 3.0 * (tmp[i].d+tmp[i-1].d);
137 }
138
139 tmp[0].x1 = 1.0;
140 tmp[dim-1].x1 = 1.0;
141 tmp[0].x2 = 3.0 * (tmp[0].d+tmp[dim-1].d);
142
143 tridiagonal2(dim, tmp);
144
145 double factor = (tmp[0].x2+tmp[dim-1].x2) / (tmp[0].x1+tmp[dim-1].x1+tmp[dim-1].h);
146 for (i = 0; i < dim; i++) {
147 ys[i] = tmp[i].x2 - factor*tmp[i].x1;
148 }
149 ys[dim] = ys[0];
150
151 free(tmp);
152 }
153
154
155 /* compute the slopes of the spline points with natural constraints */
slopesn(int dim,const double * const x,const double * const y,double * const ys)156 void slopesn(int dim, const double *const x, const double *const y, double *const ys)
157 {
158 SplineEquationData *tmp = (SplineEquationData *) malloc(sizeof(SplineEquationData)*dim);
159 int i;
160
161 dim--;
162 for (i = 0; i < dim; i++) {
163 tmp[i].h = x[i+1]-x[i];
164 tmp[i].d = (y[i+1]-y[i]) / (tmp[i].h*tmp[i].h);
165 }
166
167 for (i = 1; i < dim; i++) {
168 tmp[i].a = 2.0/tmp[i-1].h + 2.0/tmp[i].h;
169 tmp[i].b = 1.0/tmp[i].h;
170 tmp[i].c = tmp[i].b;
171 ys[i] = 3.0 * (tmp[i].d+tmp[i-1].d);
172 }
173
174 tmp[0].b = 1.0/tmp[0].h;
175 tmp[0].c = tmp[0].b;
176 tmp[0].a = 2.0*tmp[0].b;
177 tmp[dim].a = 2.0/tmp[dim-1].h;
178 ys[0] = 3.0*tmp[0].d;
179 ys[dim] = 3.0*tmp[dim-1].d;
180
181 tridiagonal(dim+1, tmp, ys);
182
183 free(tmp);
184 }
185
186
187 /* compute the slopes for 2-dim curve, sums euclidian distances as parameter, periodic */
parametricslopesp(int dim,const double * const x,const double * const y,double * const xs,double * const ys,double * const s)188 void parametricslopesp(
189 int dim,
190 const double *const x,
191 const double *const y,
192 double *const xs,
193 double *const ys,
194 double *const s
195 )
196 {
197 s[0] = 0.0;
198 for (int i = 1; i < dim; i++) {
199 s[i] = s[i-1] + sqrt((x[i]-x[i-1])*(x[i]-x[i-1]) + (y[i]-y[i-1])*(y[i]-y[i-1]));
200 }
201 slopesp(dim, s, x, xs);
202 slopesp(dim, s, y, ys);
203 }
204
205
206 /* compute the slopes for 2-dim curve, sums euclidian distances as parameter, natural */
parametricslopesn(int dim,const double * const x,const double * const y,double * const xs,double * const ys,double * const s)207 void parametricslopesn(
208 int dim,
209 const double *const x,
210 const double *const y,
211 double *const xs,
212 double *const ys,
213 double *const s
214 )
215 {
216 s[0] = 0.0;
217 for (int i = 1; i < dim; i++) {
218 s[i] = s[i-1] + sqrt((x[i]-x[i-1])*(x[i]-x[i-1]) + (y[i]-y[i-1])*(y[i]-y[i-1]));
219 }
220 slopesn(dim, s, x, xs);
221 slopesn(dim, s, y, ys);
222 }
223
224
225 /* compute the y value for a given z */
spline(int dim,double z,const double * const x,const double * const y,const double * const ys)226 double spline(
227 int dim,
228 double z,
229 const double *const x,
230 const double *const y,
231 const double *const ys
232 )
233 {
234 int i, a, b;
235 double t, a0, a1, a2, a3, h;
236
237 a = 0; b = dim-1;
238 do {
239 i = (a + b) / 2;
240 if (x[i] <= z) {
241 a = i;
242 } else {
243 b = i;
244 }
245 } while ((a + 1) != b);
246 i = a;
247 h = x[i+1] - x[i];
248 t = (z-x[i]) / h;
249 a0 = y[i];
250 a1 = y[i+1] - a0;
251 a2 = a1 - h*ys[i];
252 a3 = h * ys[i+1] - a1;
253 a3 -= a2;
254 return a0 + (a1 + (a2 + a3*t) * (t-1.0))*t;
255 }
256
257