comparison +grid/Curve.m @ 103:bc5db54f9efd feature/arclen-param

fzero_vec, integral_vec and spline are now local functions in Curve. Renamed arcLengthStretch to arcLengthParametrization. Removed plot_derivative. Added some comments and extra lines + removed unneccesary lines. arcLength is now a method and not static. Constructor does not accept difference operator anymore.
author Martin Almquist <martin.almquist@it.uu.se>
date Mon, 07 Dec 2015 17:24:28 +0100
parents ecf77a50d4fe
children ffd9e68f63cc
comparison
equal deleted inserted replaced
99:ecf77a50d4fe 103:bc5db54f9efd
13 % Concatenation of curves 13 % Concatenation of curves
14 % Subsections of curves 14 % Subsections of curves
15 % Stretching of curve parameter - semi-done 15 % Stretching of curve parameter - semi-done
16 % Curve to cell array of linesegments 16 % Curve to cell array of linesegments
17 17
18 % Can supply either derivative or a difference operator D1 18 % The curve parameter t must be in [0,1].
19 function obj = Curve(g,gp,transformation,D1) 19 % Can supply derivative.
20 function obj = Curve(g,gp,transformation)
20 default_arg('gp',[]); 21 default_arg('gp',[]);
21 default_arg('transformation',[]); 22 default_arg('transformation',[]);
22 default_arg('D1',[]);
23 p_test = g(0); 23 p_test = g(0);
24 assert(all(size(p_test) == [2,1]), 'A curve parametrization must return a 2x1 vector.'); 24 assert(all(size(p_test) == [2,1]), 'A curve parametrization must return a 2x1 vector.');
25
26 if(isempty(gp) && ~isempty(D1))
27 gp = grid.Curve.numerical_derivative(g,D1);
28 end
29 25
30 if ~isempty(transformation) 26 if ~isempty(transformation)
31 transformation.base_g = g; 27 transformation.base_g = g;
32 transformation.base_gp = gp; 28 transformation.base_gp = gp;
33 [g,gp] = grid.Curve.transform_g(g,gp,transformation); 29 [g,gp] = grid.Curve.transform_g(g,gp,transformation);
51 function h = plot(obj,n) 47 function h = plot(obj,n)
52 default_arg('n',100); 48 default_arg('n',100);
53 49
54 t = linspace(0,1,n); 50 t = linspace(0,1,n);
55 p = obj.g(t); 51 p = obj.g(t);
56 h = line(p(1,:),p(2,:));
57 end
58
59 % Plots the derivative gp(t) for 0<t<1, using n points. Returns a handle h to the plotted curve.
60 % h = plot_curve(gp,n)
61 function h = plot_derivative(obj,n)
62 default_arg('n',100);
63
64 t = linspace(0,1,n);
65 p = obj.gp(t);
66 h = line(p(1,:),p(2,:)); 52 h = line(p(1,:),p(2,:));
67 end 53 end
68 54
69 function h= plot_normals(obj,l,n,m) 55 function h= plot_normals(obj,l,n,m)
70 default_arg('l',0.1); 56 default_arg('l',0.1);
95 81
96 obj.plot(); 82 obj.plot();
97 end 83 end
98 % Shows curve with name and arrow for direction. 84 % Shows curve with name and arrow for direction.
99 85
86 % Length of arc from parameter t0 to t1 (which may be vectors).
87 % Computed using derivative.
88 function L = arcLength(obj,t0,t1)
89 assert(~isempty(obj.gp),'Curve has no derivative!');
90 speed = @(t) sqrt(sum(obj.gp(t).^2,1));
91 L = integral_vec(speed,t0,t1);
92 end
100 93
101 % Arc length parameterization. 94 % Arc length parameterization.
102 function curve = arcLengthStretch(obj,N) 95 function curve = arcLengthParametrization(obj,N)
103 default_arg('N',100); 96 default_arg('N',100);
104 assert(~isempty(obj.gp),'This curve does not yet have a derivative added.')
105 97
106 % Construct arcLength function using splines 98 % Construct arcLength function using splines
107 tvec = linspace(0,1,N); 99 tvec = linspace(0,1,N);
108 arcVec = grid.Curve.arcLength(obj.gp,0,tvec); 100 arcVec = obj.arcLength(0,tvec);
109 arcLength = grid.Curve.spline(tvec,arcVec); 101 arcLength = spline(tvec,arcVec);
110 102
111 % Stretch the parameter, construct function with splines 103 % Stretch the parameter, construct function with splines
112 arcParVec = util.fzero_vec(@(s)arcLength(s) - tvec*arcLength(1),[0-10*eps,1+10*eps]); 104 arcParVec = fzero_vec(@(s)arcLength(s) - tvec*arcLength(1),[0-10*eps,1+10*eps]);
113 arcPar = grid.Curve.spline(tvec,arcParVec); 105 arcPar = spline(tvec,arcParVec);
114 106
115 % New function and derivative 107 % New function and derivative
116 g_new = @(t)obj.g(arcPar(t)); 108 g_new = @(t)obj.g(arcPar(t));
117 gp_old = obj.gp; 109 gp_new = @(t) normalize(obj.gp(arcPar(t)));
118 gp_new = @(t) normalize(gp_old(arcPar(t)));
119
120 curve = grid.Curve(g_new,gp_new); 110 curve = grid.Curve(g_new,gp_new);
121 111
122 end 112 end
123 113
124 % how to make it work for methods without returns 114 % how to make it work for methods without returns
257 end 247 end
258 end 248 end
259 249
260 methods (Static) 250 methods (Static)
261 251
262 % Length of arc from parameter t0 to t1 (which may be vectors).
263 % Computed using derivative.
264 function L = arcLength(deriv,t0,t1)
265 speed = @(t) sp(deriv(t));
266
267 function s = sp(deriv)
268 s = sqrt(sum(deriv.^2,1));
269 end
270 L = util.integral_vec(speed,t0,t1);
271 end
272
273 function gp_out = numerical_derivative(g,D1) 252 function gp_out = numerical_derivative(g,D1)
274 m = length(D1); L = 1; % Assume curve parameter from 0 to 1. 253 m = length(D1); L = 1; % Assume curve parameter from 0 to 1.
275 t = linspace(0,L,m); 254 t = linspace(0,L,m);
276 g = g(t)'; 255 gVec = g(t)';
277 gp = (D1*g)'; 256 gpVec = (D1*gVec)';
278 257
279 gp1_fun = grid.Curve.spline(t,gp(1,:)); 258 gp1_fun = spline(t,gpVec(1,:));
280 gp2_fun = grid.Curve.spline(t,gp(2,:)); 259 gp2_fun = spline(t,gpVec(2,:));
281 gp_out = @(t) [gp1_fun(t);gp2_fun(t)]; 260 gp_out = @(t) [gp1_fun(t);gp2_fun(t)];
282 261
283 end
284
285 % Returns a function handle to the spline.
286 function f = spline(tval,fval,spline_order)
287 default_arg('spline_order',4);
288 [m,~] = size(tval);
289 assert(m==1,'Need row vectors.');
290
291 % make vectors longer to be safe slightly beyond edges.
292 dt0 = tval(2)-tval(1); dt1 = tval(end)-tval(end-1);
293 df0 = fval(2)-fval(1); df1 = fval(end)-fval(end-1);
294 tval = [tval(1)-dt0, tval, tval(end)+dt1];
295 fval = [fval(1)-df0, fval, fval(end)+df1];
296
297 f_spline = spapi( optknt(tval,spline_order), tval, fval );
298 f = @(t) fnval(f_spline,t);
299 end 262 end
300 263
301 function obj = line(p1, p2) 264 function obj = line(p1, p2)
302 265
303 function v = g_fun(t) 266 function v = g_fun(t)
378 341
379 end 342 end
380 end 343 end
381 344
382 function g_norm = normalize(g0) 345 function g_norm = normalize(g0)
383 g1 = g0(1,:); g2 = g0(2,:); 346 g1 = g0(1,:);
347 g2 = g0(2,:);
384 normalization = sqrt(sum(g0.^2,1)); 348 normalization = sqrt(sum(g0.^2,1));
385 g_norm = [g1./normalization; g2./normalization]; 349 g_norm = [g1./normalization; g2./normalization];
386 end 350 end
387 351
352 function I = integral_vec(f,a,b)
353 % Wrapper around the built-in function integral that
354 % handles multiple limits.
355
356 Na = length(a);
357 Nb = length(b);
358 assert(Na == 1 || Nb == 1 || Na==Nb,...
359 'a and b must have same length, unless one is a scalar.');
360
361 if(Na>Nb);
362 I = zeros(size(a));
363 for i = 1:Na
364 I(i) = integral(f,a(i),b);
365 end
366 elseif(Nb>Na)
367 I = zeros(size(b));
368 for i = 1:Nb
369 I(i) = integral(f,a,b(i));
370 end
371 else
372 I = zeros(size(b));
373 for i = 1:Nb
374 I(i) = integral(f,a(i),b(i));
375 end
376 end
377 end
378
379 function I = fzero_vec(f,lim)
380 % Wrapper around the built-in function fzero that
381 % handles multiple functions (vector-valued f).
382
383 fval = f(lim(1));
384 I = zeros(size(fval));
385
386 for i = 1:length(fval)
387 e = zeros(size(fval));
388 e(i) = 1;
389 I(i) = fzero(@(t) sum(e.*f(t)),lim);
390 end
391
392 end
393
394 % Returns a function handle to the spline.
395 function f = spline(tval,fval,spline_order)
396 default_arg('spline_order',4);
397 [m,~] = size(tval);
398 assert(m==1,'Need row vectors.');
399
400 % make vectors longer to be safe slightly beyond edges.
401 dt0 = tval(2)-tval(1); dt1 = tval(end)-tval(end-1);
402 df0 = fval(2)-fval(1); df1 = fval(end)-fval(end-1);
403 tval = [tval(1)-dt0, tval, tval(end)+dt1];
404 fval = [fval(1)-df0, fval, fval(end)+df1];
405
406 f_spline = spapi( optknt(tval,spline_order), tval, fval );
407 f = @(t) fnval(f_spline,t);
408 end
409
388 410
389 411