Mercurial > repos > public > sbplib
changeset 97:33dba20b4b9d feature/arclen-param
Merged with deafult.
author | Martin Almquist <martin.almquist@it.uu.se> |
---|---|
date | Wed, 02 Dec 2015 16:29:54 +0100 |
parents | 7b092f0fd620 (diff) 19d0c9325a3e (current diff) |
children | b30f3d8845f4 |
files | +multiblock/equal_step_size.m |
diffstat | 4 files changed, 224 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/+grid/Curve.m Wed Dec 02 16:21:16 2015 +0100 +++ b/+grid/Curve.m Wed Dec 02 16:29:54 2015 +0100 @@ -3,32 +3,60 @@ g gp transformation + arc_length_fun + + % arc_length_fun: + % function handle. arc_length(s)=distance + % between t=0 and t=s. end methods %TODO: % Errors or FD if there is no derivative function added. + % -semi-done % Concatenation of curves % Subsections of curves - % Stretching of curve paramter + % Stretching of curve paramter - semi-done % Curve to cell array of linesegments - % Should accept derivative of curve. - function obj = Curve(g,gp,transformation) + % Should supply either derivative or a difference operator D1 + function obj = Curve(g,gp,transformation,D1,arc_length_fun) default_arg('gp',[]); default_arg('transformation',[]); + default_arg('D1',[]); + default_arg('arc_length_fun',[]); p_test = g(0); assert(all(size(p_test) == [2,1]), 'A curve parametrization must return a 2x1 vector.'); + if(isempty(gp) && isempty(D1)); + % Should be error instead of disp. + disp(['You really should supply either the exact derivative ',... + 'or a suitable difference operator to compute an approximation.']); + elseif(isempty(gp)) + gp = grid.Curve.numerical_derivative(g,D1); + end + if ~isempty(transformation) transformation.base_g = g; transformation.base_gp = gp; [g,gp] = grid.Curve.transform_g(g,gp,transformation); end + if(isempty(arc_length_fun)) + if(~isempty(D1)); N = length(D1); % Same accuracy as for deriv. + else N = 101; % Best way to let user choose? + end + tvec = linspace(0,1,N); + arc_vec = grid.Curve.arc_length(gp,0,tvec); + arc_length_fun = grid.Curve.spline(tvec,arc_vec); + end + obj.g = g; obj.gp = gp; obj.transformation = transformation; + obj.arc_length_fun = arc_length_fun; + + end % Made up length calculation!! Science this before actual use!! @@ -82,16 +110,40 @@ end - % Plots a curve g(t) for 0<t<1, using n points. Retruns a handle h to the plotted curve. + % Plots a curve g(t) for 0<t<1, using n points. Returns a handle h to the plotted curve. % h = plot_curve(g,n) - function h = plot(obj,n) + function h = plot(obj,n,marker) default_arg('n',100); + default_arg('marker','line') t = linspace(0,1,n); p = obj.g(t); - h = line(p(1,:),p(2,:)); + switch marker + case 'line' + h = line(p(1,:),p(2,:)); + otherwise + h = plot(p(1,:),p(2,:),marker); + end + end + + % Plots the derivative gp(t) for 0<t<1, using n points. Returns a handle h to the plotted curve. + % h = plot_curve(gp,n) + function h = plot_derivative(obj,n,marker) + default_arg('n',100); + default_arg('marker','line') + + t = linspace(0,1,n); + + p = obj.gp(t); + + switch marker + case 'line' + h = line(p(1,:),p(2,:)); + otherwise + h = plot(p(1,:),p(2,:),marker); + end end function h= plot_normals(obj,l,n,m) @@ -125,7 +177,27 @@ end % Shows curve with name and arrow for direction. - + + function curve = stretch_parameter(obj,type) + default_arg('type','arc_length'); + switch type + % Arc length parameterization. + case 'arc_length' + arcLength = obj.arc_length_fun; + arcPar = @(t) util.fzero_vec(@(s)arcLength(s) - t*arcLength(1),[0-10*eps,1+10*eps]); + g_new = @(t)obj.g(arcPar(t)); + gp_old = obj.gp; + gp_new = @(t) normalize(gp_old(arcPar(t))); + + arc_len_new = @(t) t; + curve = grid.Curve(g_new,gp_new,[],[],arc_len_new); + + otherwise + error('That stretching is not implemented.'); + end + + end + % how to make it work for methods without returns function p = subsref(obj,S) %Should i add error checking here? @@ -265,6 +337,46 @@ end methods (Static) + + % Length of arc from parameter t0 to t1 (which may be vectors). + % Computed using derivative. + function L = arc_length(deriv,t0,t1) + speed = @(t) sp(deriv(t)); + + function s = sp(deriv) + s = sqrt(sum(deriv.^2,1)); + end + L = util.integral_vec(speed,t0,t1); + end + + function gp_out = numerical_derivative(g,D1) + m = length(D1); L = 1; % Assume curve parameter from 0 to 1. + t = linspace(0,L,m); + g = g(t)'; + gp = (D1*g)'; + + gp1_fun = grid.Curve.spline(t,gp(1,:)); + gp2_fun = grid.Curve.spline(t,gp(2,:)); + gp_out = @(t) [gp1_fun(t);gp2_fun(t)]; + + end + + % Returns a function handle to the spline. + function f = spline(tval,fval,spline_order) + default_arg('spline_order',4); + [m,~] = size(tval); + assert(m==1,'Need row vectors.'); + + % make vectors longer to be safe slightly beyond edges. + dt0 = tval(2)-tval(1); dt1 = tval(end)-tval(end-1); + df0 = fval(2)-fval(1); df1 = fval(end)-fval(end-1); + tval = [tval(1)-dt0, tval, tval(end)+dt1]; + fval = [fval(1)-df0, fval, fval(end)+df1]; + + f_spline = spapi( optknt(tval,spline_order), tval, fval ); + f = @(t) fnval(f_spline,t); + end + function obj = line(p1, p2) function v = g_fun(t) @@ -343,5 +455,14 @@ end end - end + end end + +function g_norm = normalize(g0) + g1 = g0(1,:); g2 = g0(2,:); + normalization = sqrt(sum(g0.^2,1)); + g_norm = [g1./normalization; g2./normalization]; +end + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/+util/fzero_vec.m Wed Dec 02 16:29:54 2015 +0100 @@ -0,0 +1,14 @@ +function I = fzero_vec(f,lim) +% Wrapper around the built-in function fzero that +% handles multiple functions (vector-valued f). + + fval = f(lim(1)); + I = zeros(size(fval)); + + for i = 1:length(fval) + e = zeros(size(fval)); + e(i) = 1; + I(i) = fzero(@(t) sum(e.*f(t)),lim); + end + +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/+util/integral_vec.m Wed Dec 02 16:29:54 2015 +0100 @@ -0,0 +1,26 @@ +function I = integral_vec(f,a,b) +% Wrapper around the built-in function integral that +% handles multiple limits. + + Na = length(a); + Nb = length(b); + assert(Na == 1 || Nb == 1 || Na==Nb,... + 'a and b must have same length, unless one is a scalar.'); + + if(Na>Nb); + I = zeros(size(a)); + for i = 1:Na + I(i) = integral(f,a(i),b); + end + elseif(Nb>Na) + I = zeros(size(b)); + for i = 1:Nb + I(i) = integral(f,a,b(i)); + end + else + I = zeros(size(b)); + for i = 1:Nb + I(i) = integral(f,a(i),b(i)); + end + end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testArcLength.m Wed Dec 02 16:29:54 2015 +0100 @@ -0,0 +1,55 @@ +m = 201; L = 1; order = 4; +close all; +tic + +g1 = @(t) 2*pi*t.*sin(2*pi*t); +g2 = @(t) 2*pi*t.*cos(2*pi*t); +g = @(t) [g1(t);g2(t)]; + +t = linspace(0,L,m)'; dt = L/(m-1); +ops = sbp.Ordinary(m,dt,order); +D = ops.derivatives.D1; + +C = grid.Curve(g,[],[],D); + +% Function +figure; +C.plot([],'bo'); +hold on +plot(g1(t),g2(t),'r-'); +drawnow + +% Derivative +figure +C.plot_derivative([],'bo'); +hold on; +plot(2*pi*sin(2*pi*t) + (2*pi)^2*t.*cos(2*pi*t),... + 2*pi*cos(2*pi*t) - (2*pi)^2*t.*sin(2*pi*t),'r-') +drawnow + +% Arc length +L = C.arc_length_fun(t); +figure; +plot(t,L) +drawnow + +% Stretch curve +C2 = C.stretch_parameter(); +z = linspace(0,1,m); +gnew = C2.g(z); +gpnew = C2.gp(z); + +% Compare stretched and unstretched curves. +figure +plot(g1(t),g2(t),'b*',gnew(1,:),gnew(2,:),'ro'); + +% Compare stretched and unstretched derivatives. +figure +theta = linspace(0,2*pi,100); +plot(cos(theta),sin(theta),'-b',gpnew(1,:),gpnew(2,:),'rx'); + +toc + + + +