5837
|
1 ## Copyright (C) 2000 Kai Habel |
|
2 ## |
|
3 ## This file is part of Octave. |
|
4 ## |
|
5 ## Octave is free software; you can redistribute it and/or modify it |
|
6 ## under the terms of the GNU General Public License as published by |
|
7 ## the Free Software Foundation; either version 2, or (at your option) |
|
8 ## any later version. |
|
9 ## |
|
10 ## Octave is distributed in the hope that it will be useful, but |
|
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 ## General Public License for more details. |
|
14 ## |
|
15 ## You should have received a copy of the GNU General Public License |
|
16 ## along with Octave; see the file COPYING. If not, write to the Free |
|
17 ## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
18 ## 02110-1301, USA. |
|
19 |
|
20 ## -*- texinfo -*- |
|
21 ## @deftypefn {Function File} {@var{zi}=} interp2 (@var{x}, @var{y}, @var{z}, @var{xi}, @var{yi}) |
|
22 ## @deftypefnx {Function File} {@var{zi}=} interp2 (@var{Z}, @var{xi}, @var{yi}) |
|
23 ## @deftypefnx {Function File} {@var{zi}=} interp2 (@var{Z}, @var{n}) |
|
24 ## @deftypefnx {Function File} {@var{zi}=} interp2 (@dots{}, @var{method}) |
|
25 ## @deftypefnx {Function File} {@var{zi}=} interp2 (@dots{}, @var{method}, @var{extrapval}) |
|
26 ## |
|
27 ## Two-dimensional interpolation. @var{x}, @var{y} and @var{z} describe a |
|
28 ## surface function. If @var{x} and @var{y} are vectors their length |
6248
|
29 ## must correspondent to the size of @var{z}. @var{x} and @var{Yy} must be |
5837
|
30 ## monotonic. If they are matrices they must have the @code{meshgrid} |
|
31 ## format. |
|
32 ## |
|
33 ## @table @code |
|
34 ## @item interp2 (@var{x}, @var{y}, @var{Z}, @var{xi}, @var{yi}, @dots{}) |
|
35 ## Returns a matrix corresponding to the points described by the |
|
36 ## matrices @var{XI}, @var{YI}. |
|
37 ## |
|
38 ## If the last argument is a string, the interpolation method can |
|
39 ## be specified. The method can be 'linear', 'nearest' or 'cubic'. |
|
40 ## If it is omitted 'linear' interpolation is assumed. |
|
41 ## |
|
42 ## @item interp2 (@var{z}, @var{xi}, @var{yi}) |
|
43 ## Assumes @code{@var{x} = 1:rows (@var{z})} and @code{@var{y} = |
|
44 ## 1:columns (@var{z})} |
|
45 ## |
|
46 ## @item interp2 (@var{z}, @var{n}) |
|
47 ## Interleaves the Matrix @var{z} n-times. If @var{n} is ommited a value |
|
48 ## of @code{@var{n} = 1} is assumed. |
|
49 ## @end table |
|
50 ## |
|
51 ## The variable @var{method} defines the method to use for the |
|
52 ## interpolation. It can take one of the values |
|
53 ## |
|
54 ## @table @asis |
|
55 ## @item 'nearest' |
6218
|
56 ## Return the nearest neighbor. |
5837
|
57 ## @item 'linear' |
6218
|
58 ## Linear interpolation from nearest neighbors. |
5837
|
59 ## @item 'pchip' |
6218
|
60 ## Piece-wise cubic hermite interpolating polynomial (not implemented yet). |
5837
|
61 ## @item 'cubic' |
6218
|
62 ## Cubic interpolation from four nearest neighbors. |
5837
|
63 ## @item 'spline' |
|
64 ## Cubic spline interpolation--smooth first and second derivatives |
6702
|
65 ## throughout the curve. |
5837
|
66 ## @end table |
|
67 ## |
|
68 ## If a scalar value @var{extrapval} is defined as the final value, then |
|
69 ## values outside the mesh as set to this value. Note that in this case |
|
70 ## @var{method} must be defined as well. If @var{extrapval} is not |
|
71 ## defined then NaN is assumed. |
|
72 ## |
|
73 ## @seealso{interp1} |
|
74 ## @end deftypefn |
|
75 |
|
76 ## Author: Kai Habel <kai.habel@gmx.de> |
|
77 ## 2005-03-02 Thomas Weber <weber@num.uni-sb.de> |
|
78 ## * Add test cases |
|
79 ## 2005-03-02 Paul Kienzle <pkienzle@users.sf.net> |
|
80 ## * Simplify |
|
81 ## 2005-04-23 Dmitri A. Sergatskov <dasergatskov@gmail.com> |
|
82 ## * Modified demo and test for new gnuplot interface |
|
83 ## 2005-09-07 Hoxide <hoxide_dirac@yahoo.com.cn> |
|
84 ## * Add bicubic interpolation method |
5838
|
85 ## * Fix the eat line bug when the last element of XI or YI is |
|
86 ## negative or zero. |
5837
|
87 ## 2005-11-26 Pierre Baldensperger <balden@libertysurf.fr> |
|
88 ## * Rather big modification (XI,YI no longer need to be |
|
89 ## "meshgridded") to be consistent with the help message |
|
90 ## above and for compatibility. |
|
91 |
|
92 function ZI = interp2 (varargin) |
5838
|
93 Z = X = Y = XI = YI = n = []; |
5837
|
94 method = "linear"; |
|
95 extrapval = NaN; |
|
96 |
5838
|
97 switch (nargin) |
|
98 case 1 |
|
99 Z = varargin{1}; |
|
100 case 2 |
|
101 if (ischar (varargin{2})) |
|
102 [Z, method] = deal (varargin{:}); |
|
103 else |
|
104 [Z, n] = deal (varargin{:}); |
|
105 endif |
|
106 case 3 |
|
107 if (ischar (varargin{3})) |
|
108 [Z, n, method] = deal (varargin{:}); |
|
109 else |
|
110 [Z, XI, YI] = deal (varargin{:}); |
|
111 endif |
|
112 case 4 |
|
113 if (ischar (varargin{4})) |
|
114 [Z, XI, YI, method] = deal (varargin{:}); |
|
115 else |
|
116 [Z, n, method, extrapval] = deal (varargin{:}); |
|
117 endif |
|
118 case 5 |
|
119 if (ischar (varargin{4})) |
|
120 [Z, XI, YI, method, extrapval] = deal (varargin{:}); |
|
121 else |
|
122 [X, Y, Z, XI, YI] = deal (varargin{:}); |
|
123 endif |
|
124 case 6 |
|
125 [X, Y, Z, XI, YI, method] = deal (varargin{:}); |
|
126 case 7 |
|
127 [X, Y, Z, XI, YI, method, extrapval] = deal (varargin{:}); |
|
128 otherwise |
|
129 print_usage (); |
5837
|
130 endswitch |
|
131 |
|
132 ## Type checking. |
5838
|
133 if (!ismatrix (Z)) |
|
134 error ("interp2 expected matrix Z"); |
5837
|
135 endif |
5838
|
136 if (!isempty (n) && !isscalar (n)) |
|
137 error ("interp2 expected scalar n"); |
5837
|
138 endif |
5838
|
139 if (!ischar (method)) |
|
140 error ("interp2 expected string 'method'"); |
5837
|
141 endif |
5838
|
142 if (!isscalar (extrapval)) |
|
143 error ("interp2 expected n extrapval"); |
5837
|
144 endif |
|
145 |
5838
|
146 ## Define X, Y, XI, YI if needed |
5837
|
147 [zr, zc] = size (Z); |
5838
|
148 if (isempty (X)) |
|
149 X = 1:zc; |
|
150 Y = 1:zr; |
5837
|
151 endif |
5838
|
152 if (! isnumeric (X) || ! isnumeric (Y)) |
|
153 error ("interp2 expected numeric X, Y"); |
5837
|
154 endif |
5838
|
155 if (! isempty (n)) |
|
156 p = 2^n; |
|
157 XI = (p:p*zc)/p; |
|
158 YI = (p:p*zr)'/p; |
5837
|
159 endif |
5838
|
160 if (! isnumeric (XI) || ! isnumeric (YI)) |
|
161 error ("interp2 expected numeric XI, YI"); |
5837
|
162 endif |
|
163 |
6702
|
164 |
|
165 if (strcmp (method, "linear") || strcmp (method, "nearest")) |
|
166 |
|
167 ## If X and Y vectors produce a grid from them |
|
168 if (isvector (X) && isvector (Y)) |
|
169 [X, Y] = meshgrid (X, Y); |
|
170 elseif (! size_equal (X, Y)) |
|
171 error ("X and Y must be matrices of same size"); |
|
172 endif |
|
173 if (! size_equal (X, Z)) |
|
174 error ("X and Y size must match Z dimensions"); |
|
175 endif |
|
176 |
|
177 ## If Xi and Yi are vectors of different orientation build a grid |
|
178 if ((rows (XI) == 1 && columns (YI) == 1) |
|
179 || (columns (XI) == 1 && rows (YI) == 1)) |
|
180 [XI, YI] = meshgrid (XI, YI); |
|
181 elseif (! size_equal (XI, YI)) |
|
182 error ("XI and YI must be matrices of same size"); |
|
183 endif |
5837
|
184 |
6702
|
185 shape = size (XI); |
|
186 XI = reshape (XI, 1, prod (shape)); |
|
187 YI = reshape (YI, 1, prod (shape)); |
|
188 |
|
189 xidx = lookup (X(1, 2:end-1), XI) + 1; |
|
190 yidx = lookup (Y(2:end-1, 1), YI) + 1; |
5837
|
191 |
6702
|
192 if (strcmp (method, "linear")) |
|
193 ## each quad satisfies the equation z(x,y)=a+b*x+c*y+d*xy |
|
194 ## |
|
195 ## a-b |
|
196 ## | | |
|
197 ## c-d |
|
198 a = Z(1:(zr - 1), 1:(zc - 1)); |
|
199 b = Z(1:(zr - 1), 2:zc) - a; |
|
200 c = Z(2:zr, 1:(zc - 1)) - a; |
|
201 d = Z(2:zr, 2:zc) - a - b - c; |
5837
|
202 |
6702
|
203 idx = sub2ind (size (a), yidx, xidx); |
|
204 |
|
205 ## scale XI, YI values to a 1-spaced grid |
|
206 Xsc = (XI - X(1, xidx)) ./ (X(1, xidx + 1) - X(1, xidx)); |
|
207 Ysc = (YI - Y(yidx, 1)') ./ (Y(yidx + 1, 1) - Y(yidx, 1))'; |
|
208 |
|
209 ## apply plane equation |
|
210 ZI = a(idx) + b(idx).*Xsc + c(idx).*Ysc + d(idx).*Xsc.*Ysc; |
5837
|
211 |
6702
|
212 elseif (strcmp (method, "nearest")) |
|
213 xtable = X(1, :); |
|
214 ytable = Y(:, 1)'; |
|
215 ii = (XI - xtable(xidx) > xtable(xidx + 1) - XI); |
|
216 jj = (YI - ytable(yidx) > ytable(yidx + 1) - YI); |
|
217 idx = sub2ind (size (Z), yidx+jj, xidx+ii); |
|
218 ZI = Z(idx); |
|
219 endif |
5837
|
220 |
6702
|
221 ## set points outside the table to NaN |
|
222 ZI (XI < X(1,1) | XI > X(1,end) | YI < Y(1,1) | YI > Y(end,1)) = extrapval; |
|
223 ZI = reshape (ZI, shape); |
|
224 else |
5837
|
225 |
6702
|
226 ## If X and Y vectors produce a grid from them |
|
227 if (isvector (X) && isvector (Y)) |
|
228 X = X(:).'; |
|
229 Y = Y(:); |
|
230 if (!isequal ([length(X), length(Y)], size(Z))) |
|
231 error ("X and Y size must match Z dimensions"); |
|
232 endif |
|
233 elseif (!size_equal (X, Y)) |
|
234 error ("X and Y must be matrices of same size"); |
|
235 if (! size_equal (X, Z)) |
|
236 error ("X and Y size must match Z dimensions"); |
|
237 endif |
|
238 endif |
5837
|
239 |
6702
|
240 ## If Xi and Yi are vectors of different orientation build a grid |
|
241 if ((rows (XI) == 1 && columns (YI) == 1) |
|
242 || (columns (XI) == 1 && rows (YI) == 1)) |
|
243 ## Do nothing |
|
244 elseif (! size_equal (XI, YI)) |
|
245 error ("XI and YI must be matrices of same size"); |
|
246 endif |
5837
|
247 |
6702
|
248 ## FIXME bicubic/__splinen__ don't handle arbitrary XI, YI |
|
249 if (strcmp (method, "cubic")) |
|
250 ZI = bicubic (X, Y, Z, XI(1,:), YI(:,1), extrapval); |
5837
|
251 |
6702
|
252 elseif (strcmp (method, "spline")) |
|
253 ZI = __splinen__ ({Y(:,1).', X(1,:)}, Z, {YI(:,1), XI(1,:)}, extrapval, |
|
254 "spline"); |
|
255 else |
|
256 error ("interpolation method not recognized"); |
|
257 endif |
5837
|
258 |
6702
|
259 endif |
5837
|
260 endfunction |
|
261 |
|
262 %!demo |
|
263 %! A=[13,-1,12;5,4,3;1,6,2]; |
|
264 %! x=[0,1,4]; y=[10,11,12]; |
|
265 %! xi=linspace(min(x),max(x),17); |
|
266 %! yi=linspace(min(y),max(y),26)'; |
|
267 %! mesh(xi,yi,interp2(x,y,A,xi,yi,'linear')); |
|
268 %! [x,y] = meshgrid(x,y); |
|
269 %! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; |
|
270 |
|
271 %!demo |
|
272 %! A=[13,-1,12;5,4,3;1,6,2]; |
|
273 %! x=[0,1,4]; y=[10,11,12]; |
|
274 %! xi=linspace(min(x),max(x),17); |
|
275 %! yi=linspace(min(y),max(y),26)'; |
|
276 %! mesh(xi,yi,interp2(x,y,A,xi,yi,'nearest')); |
|
277 %! [x,y] = meshgrid(x,y); |
|
278 %! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; |
|
279 |
6702
|
280 %!demo |
5837
|
281 %! A=[13,-1,12;5,4,3;1,6,2]; |
|
282 %! x=[0,1,2]; y=[10,11,12]; |
|
283 %! xi=linspace(min(x),max(x),17); |
6702
|
284 %! yi=linspace(min(y),max(y),26)'; |
5837
|
285 %! mesh(xi,yi,interp2(x,y,A,xi,yi,'cubic')); |
|
286 %! [x,y] = meshgrid(x,y); |
|
287 %! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; |
|
288 |
6702
|
289 %!demo |
|
290 %! A=[13,-1,12;5,4,3;1,6,2]; |
|
291 %! x=[0,1,2]; y=[10,11,12]; |
|
292 %! xi=linspace(min(x),max(x),17); |
|
293 %! yi=linspace(min(y),max(y),26)'; |
|
294 %! mesh(xi,yi,interp2(x,y,A,xi,yi,'spline')); |
|
295 %! [x,y] = meshgrid(x,y); |
|
296 %! hold on; plot3(x(:),y(:),A(:),"b*"); hold off; |
|
297 |
5837
|
298 %!test % simple test |
|
299 %! x = [1,2,3]; |
|
300 %! y = [4,5,6,7]; |
|
301 %! [X, Y] = meshgrid(x,y); |
|
302 %! Orig = X.^2 + Y.^3; |
|
303 %! xi = [1.2,2, 1.5]; |
|
304 %! yi = [6.2, 4.0, 5.0]'; |
|
305 %! |
|
306 %! Expected = ... |
|
307 %! [243, 245.4, 243.9; |
|
308 %! 65.6, 68, 66.5; |
|
309 %! 126.6, 129, 127.5]; |
|
310 %! Result = interp2(x,y,Orig, xi, yi); |
|
311 %! |
|
312 %! assert(Result, Expected, 1000*eps); |
|
313 |
|
314 %!test % 2^n form |
|
315 %! x = [1,2,3]; |
|
316 %! y = [4,5,6,7]; |
|
317 %! [X, Y] = meshgrid(x,y); |
|
318 %! Orig = X.^2 + Y.^3; |
|
319 %! xi = [1:0.25:3]; yi = [4:0.25:7]'; |
|
320 %! Expected = interp2(x,y,Orig, xi, yi); |
|
321 %! Result = interp2(Orig,2); |
|
322 %! |
|
323 %! assert(Result, Expected, 10*eps); |
|
324 |
|
325 %!test % matrix slice |
|
326 %! A = eye(4); |
|
327 %! assert(interp2(A,[1:4],[1:4]),[1,1,1,1]); |
|
328 |
|
329 %!test % non-gridded XI,YI |
|
330 %! A = eye(4); |
|
331 %! assert(interp2(A,[1,2;3,4],[1,3;2,4]),[1,0;0,1]); |
|
332 |
|
333 %!test % for values outside of boundaries |
|
334 %! x = [1,2,3]; |
|
335 %! y = [4,5,6,7]; |
|
336 %! [X, Y] = meshgrid(x,y); |
|
337 %! Orig = X.^2 + Y.^3; |
|
338 %! xi = [0,4]; |
|
339 %! yi = [3,8]'; |
|
340 %! assert(interp2(x,y,Orig, xi, yi),[nan,nan;nan,nan]); |
|
341 %! assert(interp2(x,y,Orig, xi, yi,'linear', 0),[0,0;0,0]); |
|
342 |
|
343 %!test % for values at boundaries |
|
344 %! A=[1,2;3,4]; |
|
345 %! x=[0,1]; |
|
346 %! y=[2,3]'; |
|
347 %! assert(interp2(x,y,A,x,y,'linear'), A); |
|
348 %! assert(interp2(x,y,A,x,y,'nearest'), A); |
|
349 |