1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package com.buckosoft.fibs.BuckoFIBS.gui.boardTab.boardPane.animateType;
23
24 import java.util.Arrays;
25
26
27
28
29
30
31
32
33
34
35 class _Spline2D {
36
37
38
39
40
41 private double[] t;
42 private Spline splineX;
43 private Spline splineY;
44
45
46
47 private double length;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public _Spline2D(double[] x, double[] y) {
72 init(x, y);
73 }
74
75
76
77
78
79 public int[] getPoint(double t) {
80 int[] result = new int[2];
81 result[0] = (int)splineX.getValue(t);
82 result[1] = (int)splineY.getValue(t);
83
84 return result;
85 }
86
87 private void init(double[] x, double[] y) {
88 if (x.length != y.length) {
89 throw new IllegalArgumentException("Arrays must have the same length.");
90 }
91
92 if (x.length < 2) {
93 throw new IllegalArgumentException("Spline edges must have at least two points.");
94 }
95
96 t = new double[x.length];
97 t[0] = 0.0;
98
99
100
101 for (int i = 1; i < t.length; i++) {
102 double lx = x[i] - x[i-1];
103 double ly = y[i] - y[i-1];
104
105 if ( 0.0 == lx ) {
106 t[i] = Math.abs(ly);
107 } else if ( 0.0 == ly ) {
108 t[i] = Math.abs(lx);
109 } else {
110 t[i] = Math.sqrt(lx*lx+ly*ly);
111 }
112
113 length += t[i];
114 t[i] += t[i-1];
115 }
116
117 for(int i = 1; i< (t.length)-1; i++) {
118 t[i] = t[i] / length;
119 }
120
121 t[(t.length)-1] = 1.0;
122
123 splineX = new Spline(t, x);
124 splineY = new Spline(t, y);
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 }
156
157
158
159
160
161
162
163
164
165 class Spline {
166
167 private double[] xx;
168 private double[] yy;
169
170 private double[] a;
171 private double[] b;
172 private double[] c;
173 private double[] d;
174
175
176 private int storageIndex = 0;
177
178
179
180
181
182
183 public Spline(double[] xx, double[] yy) {
184 setValues(xx, yy);
185 }
186
187
188
189
190
191
192 public void setValues(double[] xx, double[] yy) {
193 this.xx = xx;
194 this.yy = yy;
195 if (xx.length > 1) {
196 calculateCoefficients();
197 }
198 }
199
200
201
202
203
204
205 public double getValue(double x) {
206 if (xx.length == 0) {
207 return Double.NaN;
208 }
209
210 if (xx.length == 1) {
211 if (xx[0] == x) {
212 return yy[0];
213 } else {
214 return Double.NaN;
215 }
216 }
217
218 int index = Arrays.binarySearch(xx, x);
219 if (index > 0) {
220 return yy[index];
221 }
222
223 index = - (index + 1) - 1;
224
225 if (index < 0) {
226 return yy[0];
227 }
228
229 return a[index]
230 + b[index] * (x - xx[index])
231 + c[index] * Math.pow(x - xx[index], 2)
232 + d[index] * Math.pow(x - xx[index], 3);
233 }
234
235
236
237
238
239
240
241
242 public double getFastValue(double x) {
243
244 if (storageIndex > -1 && storageIndex < xx.length-1 && x > xx[storageIndex] && x < xx[storageIndex + 1]) {
245
246 } else {
247 int index = Arrays.binarySearch(xx, x);
248 if (index > 0) {
249 return yy[index];
250 }
251 index = - (index + 1) - 1;
252 storageIndex = index;
253 }
254
255
256 if (storageIndex < 0) {
257 return yy[0];
258 }
259 double value = x - xx[storageIndex];
260 return a[storageIndex]
261 + b[storageIndex] * value
262 + c[storageIndex] * (value * value)
263 + d[storageIndex] * (value * value * value);
264 }
265
266
267
268
269 public boolean checkValues() {
270 if (xx.length < 2) {
271 return false;
272 } else {
273 return true;
274 }
275 }
276
277
278
279
280
281
282 public double getDx(double x) {
283 if (xx.length == 0 || xx.length == 1) {
284 return 0;
285 }
286
287 int index = Arrays.binarySearch(xx, x);
288 if (index < 0) {
289 index = - (index + 1) - 1;
290 }
291
292 return b[index]
293 + 2 * c[index] * (x - xx[index])
294 + 3 * d[index] * Math.pow(x - xx[index], 2);
295 }
296
297
298
299
300 private void calculateCoefficients() {
301 int N = yy.length;
302 a = new double[N];
303 b = new double[N];
304 c = new double[N];
305 d = new double[N];
306
307 if (N == 2) {
308 a[0] = yy[0];
309 b[0] = yy[1] - yy[0];
310 return;
311 }
312
313 double[] h = new double[N - 1];
314 for (int i = 0; i < N - 1; i++) {
315 a[i] = yy[i];
316 h[i] = xx[i + 1] - xx[i];
317
318 if (h[i] == 0.0) {
319 h[i] = 0.01;
320 }
321 }
322 a[N - 1] = yy[N - 1];
323
324 double[][] A = new double[N - 2][N - 2];
325 double[] y = new double[N - 2];
326 for (int i = 0; i < N - 2; i++) {
327 y[i] =
328 3
329 * ((yy[i + 2] - yy[i + 1]) / h[i
330 + 1]
331 - (yy[i + 1] - yy[i]) / h[i]);
332
333 A[i][i] = 2 * (h[i] + h[i + 1]);
334
335 if (i > 0) {
336 A[i][i - 1] = h[i];
337 }
338
339 if (i < N - 3) {
340 A[i][i + 1] = h[i + 1];
341 }
342 }
343 solve(A, y);
344
345 for (int i = 0; i < N - 2; i++) {
346 c[i + 1] = y[i];
347 b[i] = (a[i + 1] - a[i]) / h[i] - (2 * c[i] + c[i + 1]) / 3 * h[i];
348 d[i] = (c[i + 1] - c[i]) / (3 * h[i]);
349 }
350 b[N - 2] =
351 (a[N - 1] - a[N - 2]) / h[N
352 - 2]
353 - (2 * c[N - 2] + c[N - 1]) / 3 * h[N
354 - 2];
355 d[N - 2] = (c[N - 1] - c[N - 2]) / (3 * h[N - 2]);
356 }
357
358
359
360
361 public void solve(double[][] A, double[] b) {
362 int n = b.length;
363 for (int i = 1; i < n; i++) {
364 A[i][i - 1] = A[i][i - 1] / A[i - 1][i - 1];
365 A[i][i] = A[i][i] - A[i - 1][i] * A[i][i - 1];
366 b[i] = b[i] - A[i][i - 1] * b[i - 1];
367 }
368
369 b[n - 1] = b[n - 1] / A[n - 1][n - 1];
370 for (int i = b.length - 2; i >= 0; i--) {
371 b[i] = (b[i] - A[i][i + 1] * b[i + 1]) / A[i][i];
372 }
373 }
374 }