1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math4.legacy.analysis.interpolation;
18
19 import java.util.Arrays;
20
21 import org.apache.commons.math4.legacy.analysis.BivariateFunction;
22 import org.apache.commons.math4.legacy.analysis.polynomials.PolynomialSplineFunction;
23 import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
24 import org.apache.commons.math4.legacy.exception.InsufficientDataException;
25 import org.apache.commons.math4.legacy.exception.NoDataException;
26 import org.apache.commons.math4.legacy.exception.NonMonotonicSequenceException;
27 import org.apache.commons.math4.legacy.exception.NullArgumentException;
28 import org.apache.commons.math4.legacy.exception.OutOfRangeException;
29 import org.apache.commons.math4.legacy.core.MathArrays;
30
31
32
33
34
35
36
37
38
39
40
41
42 public class PiecewiseBicubicSplineInterpolatingFunction
43 implements BivariateFunction {
44
45 private static final int MIN_NUM_POINTS = 5;
46
47 private final double[] xval;
48
49 private final double[] yval;
50
51 private final double[][] fval;
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public PiecewiseBicubicSplineInterpolatingFunction(double[] x,
66 double[] y,
67 double[][] f)
68 throws DimensionMismatchException,
69 NullArgumentException,
70 NoDataException,
71 NonMonotonicSequenceException {
72 if (x == null ||
73 y == null ||
74 f == null ||
75 f[0] == null) {
76 throw new NullArgumentException();
77 }
78
79 final int xLen = x.length;
80 final int yLen = y.length;
81
82 if (xLen == 0 ||
83 yLen == 0 ||
84 f.length == 0 ||
85 f[0].length == 0) {
86 throw new NoDataException();
87 }
88
89 if (xLen < MIN_NUM_POINTS ||
90 yLen < MIN_NUM_POINTS ||
91 f.length < MIN_NUM_POINTS ||
92 f[0].length < MIN_NUM_POINTS) {
93 throw new InsufficientDataException();
94 }
95
96 if (xLen != f.length) {
97 throw new DimensionMismatchException(xLen, f.length);
98 }
99
100 if (yLen != f[0].length) {
101 throw new DimensionMismatchException(yLen, f[0].length);
102 }
103
104 MathArrays.checkOrder(x);
105 MathArrays.checkOrder(y);
106
107 xval = x.clone();
108 yval = y.clone();
109 fval = f.clone();
110 }
111
112
113
114
115 @Override
116 public double value(double x,
117 double y)
118 throws OutOfRangeException {
119 final AkimaSplineInterpolator interpolator = new AkimaSplineInterpolator();
120 final int offset = 2;
121 final int count = offset + 3;
122 final int i = searchIndex(x, xval, offset, count);
123 final int j = searchIndex(y, yval, offset, count);
124
125 final double[] xArray = new double[count];
126 final double[] yArray = new double[count];
127 final double[] zArray = new double[count];
128 final double[] interpArray = new double[count];
129
130 for (int index = 0; index < count; index++) {
131 xArray[index] = xval[i + index];
132 yArray[index] = yval[j + index];
133 }
134
135 for (int zIndex = 0; zIndex < count; zIndex++) {
136 for (int index = 0; index < count; index++) {
137 zArray[index] = fval[i + index][j + zIndex];
138 }
139 final PolynomialSplineFunction spline = interpolator.interpolate(xArray, zArray);
140 interpArray[zIndex] = spline.value(x);
141 }
142
143 final PolynomialSplineFunction spline = interpolator.interpolate(yArray, interpArray);
144
145 return spline.value(y);
146 }
147
148
149
150
151
152
153
154
155
156 public boolean isValidPoint(double x,
157 double y) {
158 return !(x < xval[0] ||
159 x > xval[xval.length - 1] ||
160 y < yval[0] ||
161 y > yval[yval.length - 1]);
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175 private int searchIndex(double c,
176 double[] val,
177 int offset,
178 int count) {
179 int r = Arrays.binarySearch(val, c);
180
181 if (r == -1 || r == -val.length - 1) {
182 throw new OutOfRangeException(c, val[0], val[val.length - 1]);
183 }
184
185 if (r < 0) {
186
187
188
189 r = -r - offset - 1;
190 } else {
191 r -= offset;
192 }
193
194 if (r < 0) {
195 r = 0;
196 }
197
198 if ((r + count) >= val.length) {
199
200
201 r = val.length - count;
202 }
203
204 return r;
205 }
206 }