Mercurial > repos > public > sbplib
comparison +grid/Curve.m @ 87:0a29a60e0b21
In Curve: Rearranged for speed. arc_length_fun is now a property of Curve. If it is not supplied, it is computed via the derivative and spline fitting. Switching to the arc length parameterization is much faster now. The new stuff can be tested with testArcLength.m (which should be deleted after that).
author | Martin Almquist <martin.almquist@it.uu.se> |
---|---|
date | Sun, 29 Nov 2015 22:23:09 +0100 |
parents | 3c39dd714fb6 |
children | b30f3d8845f4 |
comparison
equal
deleted
inserted
replaced
86:3c39dd714fb6 | 87:0a29a60e0b21 |
---|---|
1 classdef Curve | 1 classdef Curve |
2 properties | 2 properties |
3 g | 3 g |
4 gp | 4 gp |
5 transformation | 5 transformation |
6 arc_length_fun | |
7 | |
8 % arc_length_fun: | |
9 % function handle. arc_length(s)=distance | |
10 % between t=0 and t=s. | |
6 end | 11 end |
7 methods | 12 methods |
8 %TODO: | 13 %TODO: |
9 % Errors or FD if there is no derivative function added. | 14 % Errors or FD if there is no derivative function added. |
10 % -semi-done | 15 % -semi-done |
13 % Subsections of curves | 18 % Subsections of curves |
14 % Stretching of curve paramter - semi-done | 19 % Stretching of curve paramter - semi-done |
15 % Curve to cell array of linesegments | 20 % Curve to cell array of linesegments |
16 | 21 |
17 % Should supply either derivative or a difference operator D1 | 22 % Should supply either derivative or a difference operator D1 |
18 function obj = Curve(g,gp,transformation,D1) | 23 function obj = Curve(g,gp,transformation,D1,arc_length_fun) |
19 default_arg('gp',[]); | 24 default_arg('gp',[]); |
20 default_arg('transformation',[]); | 25 default_arg('transformation',[]); |
21 default_arg('D1',[]); | 26 default_arg('D1',[]); |
27 default_arg('arc_length_fun',[]); | |
22 p_test = g(0); | 28 p_test = g(0); |
23 assert(all(size(p_test) == [2,1]), 'A curve parametrization must return a 2x1 vector.'); | 29 assert(all(size(p_test) == [2,1]), 'A curve parametrization must return a 2x1 vector.'); |
24 | 30 |
25 if(isempty(gp) && isempty(D1)); | 31 if(isempty(gp) && isempty(D1)); |
26 % Should be error instead of disp. | 32 % Should be error instead of disp. |
27 disp(['You really should supply either the exact derivative ',... | 33 disp(['You really should supply either the exact derivative ',... |
28 'or a suitable difference operator to compute it.']); | 34 'or a suitable difference operator to compute an approximation.']); |
29 elseif(isempty(gp)) | 35 elseif(isempty(gp)) |
30 gp = grid.Curve.numerical_derivative(g,D1); | 36 gp = grid.Curve.numerical_derivative(g,D1); |
31 end | 37 end |
32 | 38 |
33 if ~isempty(transformation) | 39 if ~isempty(transformation) |
34 transformation.base_g = g; | 40 transformation.base_g = g; |
35 transformation.base_gp = gp; | 41 transformation.base_gp = gp; |
36 [g,gp] = grid.Curve.transform_g(g,gp,transformation); | 42 [g,gp] = grid.Curve.transform_g(g,gp,transformation); |
37 end | 43 end |
38 | 44 |
45 if(isempty(arc_length_fun)) | |
46 if(~isempty(D1)); N = length(D1); % Same accuracy as for deriv. | |
47 else N = 101; % Best way to let user choose? | |
48 end | |
49 tvec = linspace(0,1,N); | |
50 arc_vec = grid.Curve.arc_length(gp,0,tvec); | |
51 arc_length_fun = grid.Curve.spline(tvec,arc_vec); | |
52 end | |
53 | |
39 obj.g = g; | 54 obj.g = g; |
40 obj.gp = gp; | 55 obj.gp = gp; |
41 obj.transformation = transformation; | 56 obj.transformation = transformation; |
42 end | 57 obj.arc_length_fun = arc_length_fun; |
43 | 58 |
44 % Length of arc from parameter t0 to t1 (which may be vectors). | 59 |
45 % Computed using derivative. | |
46 function L = arc_length(obj,t0,t1) | |
47 deriv = obj.gp; | |
48 speed = @(t) sp(deriv(t)); | |
49 | |
50 function s = sp(deriv) | |
51 s = sqrt(sum(deriv.^2,1)); | |
52 end | |
53 L = util.integral_vec(speed,t0,t1); | |
54 end | 60 end |
55 | 61 |
56 % Made up length calculation!! Science this before actual use!! | 62 % Made up length calculation!! Science this before actual use!! |
57 % Calculates the length of the curve. Makes sure the longet segment used is shorter than h_max. | 63 % Calculates the length of the curve. Makes sure the longet segment used is shorter than h_max. |
58 function [L,t] = curve_length(C,h_max) | 64 function [L,t] = curve_length(C,h_max) |
102 normalization = sqrt(sum(deriv.^2,1)); | 108 normalization = sqrt(sum(deriv.^2,1)); |
103 n = [-deriv(2,:)./normalization; deriv(1,:)./normalization]; | 109 n = [-deriv(2,:)./normalization; deriv(1,:)./normalization]; |
104 end | 110 end |
105 | 111 |
106 | 112 |
107 % Plots a curve g(t) for 0<t<1, using n points. Retruns a handle h to the plotted curve. | 113 % Plots a curve g(t) for 0<t<1, using n points. Returns a handle h to the plotted curve. |
108 % h = plot_curve(g,n) | 114 % h = plot_curve(g,n) |
109 function h = plot(obj,n) | 115 function h = plot(obj,n,marker) |
110 default_arg('n',100); | 116 default_arg('n',100); |
117 default_arg('marker','line') | |
111 | 118 |
112 t = linspace(0,1,n); | 119 t = linspace(0,1,n); |
113 | 120 |
114 p = obj.g(t); | 121 p = obj.g(t); |
115 | 122 |
116 h = line(p(1,:),p(2,:)); | 123 switch marker |
124 case 'line' | |
125 h = line(p(1,:),p(2,:)); | |
126 otherwise | |
127 h = plot(p(1,:),p(2,:),marker); | |
128 end | |
129 end | |
130 | |
131 % Plots the derivative gp(t) for 0<t<1, using n points. Returns a handle h to the plotted curve. | |
132 % h = plot_curve(gp,n) | |
133 function h = plot_derivative(obj,n,marker) | |
134 default_arg('n',100); | |
135 default_arg('marker','line') | |
136 | |
137 t = linspace(0,1,n); | |
138 | |
139 p = obj.gp(t); | |
140 | |
141 switch marker | |
142 case 'line' | |
143 h = line(p(1,:),p(2,:)); | |
144 otherwise | |
145 h = plot(p(1,:),p(2,:),marker); | |
146 end | |
117 end | 147 end |
118 | 148 |
119 function h= plot_normals(obj,l,n,m) | 149 function h= plot_normals(obj,l,n,m) |
120 default_arg('l',0.1); | 150 default_arg('l',0.1); |
121 default_arg('n',10); | 151 default_arg('n',10); |
146 obj.plot(); | 176 obj.plot(); |
147 end | 177 end |
148 % Shows curve with name and arrow for direction. | 178 % Shows curve with name and arrow for direction. |
149 | 179 |
150 | 180 |
151 % Should this be in the transformation method? | |
152 function curve = stretch_parameter(obj,type) | 181 function curve = stretch_parameter(obj,type) |
153 default_arg('type','arc_length'); | 182 default_arg('type','arc_length'); |
154 switch type | 183 switch type |
155 % Arc length parameterization. WARNING: slow. | 184 % Arc length parameterization. |
156 case 'arc_length' | 185 case 'arc_length' |
157 arcLength = @(t) obj.arc_length(0,t); | 186 arcLength = obj.arc_length_fun; |
158 arcPar = @(t) util.fzero_vec(@(s)arcLength(s) - t*arcLength(1),0); | 187 arcPar = @(t) util.fzero_vec(@(s)arcLength(s) - t*arcLength(1),[0-10*eps,1+10*eps]); |
159 g_new = @(t)obj.g(arcPar(t)); | 188 g_new = @(t)obj.g(arcPar(t)); |
160 gp_old = obj.gp; | 189 gp_old = obj.gp; |
161 gp_new = @(t) normalize(gp_old(arcPar(t))); | 190 gp_new = @(t) normalize(gp_old(arcPar(t))); |
162 | 191 |
163 curve = grid.Curve(g_new,gp_new); | 192 arc_len_new = @(t) t; |
193 curve = grid.Curve(g_new,gp_new,[],[],arc_len_new); | |
164 | 194 |
165 otherwise | 195 otherwise |
166 error('That stretching is not implemented.'); | 196 error('That stretching is not implemented.'); |
167 end | 197 end |
168 | 198 |
306 end | 336 end |
307 end | 337 end |
308 | 338 |
309 methods (Static) | 339 methods (Static) |
310 | 340 |
341 % Length of arc from parameter t0 to t1 (which may be vectors). | |
342 % Computed using derivative. | |
343 function L = arc_length(deriv,t0,t1) | |
344 speed = @(t) sp(deriv(t)); | |
345 | |
346 function s = sp(deriv) | |
347 s = sqrt(sum(deriv.^2,1)); | |
348 end | |
349 L = util.integral_vec(speed,t0,t1); | |
350 end | |
351 | |
311 function gp_out = numerical_derivative(g,D1) | 352 function gp_out = numerical_derivative(g,D1) |
312 m = length(D1); L = 1; % Assume curve parameter from 0 to 1. | 353 m = length(D1); L = 1; % Assume curve parameter from 0 to 1. |
313 dt = L/(m-1); | |
314 t = linspace(0,L,m); | 354 t = linspace(0,L,m); |
315 g = g(t)'; | 355 g = g(t)'; |
316 gp = (D1*g)'; | 356 gp = (D1*g)'; |
317 | 357 |
318 % Make vectors longer to make sure splines are | 358 gp1_fun = grid.Curve.spline(t,gp(1,:)); |
319 % reasonable at 1+eps. | 359 gp2_fun = grid.Curve.spline(t,gp(2,:)); |
320 t_l = linspace(0,L+dt,m+1); | |
321 gp_l = [gp,gp(:,end)+gp(:,end)-gp(:,end-1)]; | |
322 | |
323 % 4:th order splines. | |
324 spline_order = 4; | |
325 gp1 = spapi( optknt(t_l,spline_order), t_l, gp_l(1,:) ); | |
326 gp2 = spapi( optknt(t_l,spline_order), t_l, gp_l(2,:) ); | |
327 gp1_fun = @(t) fnval(gp1,t); gp2_fun = @(t) fnval(gp2,t); | |
328 gp_out = @(t) [gp1_fun(t);gp2_fun(t)]; | 360 gp_out = @(t) [gp1_fun(t);gp2_fun(t)]; |
329 | 361 |
362 end | |
363 | |
364 % Returns a function handle to the spline. | |
365 function f = spline(tval,fval,spline_order) | |
366 default_arg('spline_order',4); | |
367 [m,~] = size(tval); | |
368 assert(m==1,'Need row vectors.'); | |
369 | |
370 % make vectors longer to be safe slightly beyond edges. | |
371 dt0 = tval(2)-tval(1); dt1 = tval(end)-tval(end-1); | |
372 df0 = fval(2)-fval(1); df1 = fval(end)-fval(end-1); | |
373 tval = [tval(1)-dt0, tval, tval(end)+dt1]; | |
374 fval = [fval(1)-df0, fval, fval(end)+df1]; | |
375 | |
376 f_spline = spapi( optknt(tval,spline_order), tval, fval ); | |
377 f = @(t) fnval(f_spline,t); | |
330 end | 378 end |
331 | 379 |
332 function obj = line(p1, p2) | 380 function obj = line(p1, p2) |
333 | 381 |
334 function v = g_fun(t) | 382 function v = g_fun(t) |