Mercurial > repos > public > sbplib
changeset 102:2fd0fd3e75eb feature/arclen-param
Merged default into feature/arclen-param
author | Martin Almquist <martin.almquist@it.uu.se> |
---|---|
date | Mon, 07 Dec 2015 16:47:13 +0100 |
parents | ecf77a50d4fe (diff) 9933169d2651 (current diff) |
children | eb7f592b9512 |
files | |
diffstat | 3 files changed, 136 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- a/+grid/Curve.m Fri Dec 04 16:46:32 2015 +0100 +++ b/+grid/Curve.m Mon Dec 07 16:47:13 2015 +0100 @@ -3,76 +3,40 @@ g gp transformation + 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 parameter - semi-done % Curve to cell array of linesegments - % Should accept derivative of curve. - function obj = Curve(g,gp,transformation) + % Can supply either derivative or a difference operator D1 + function obj = Curve(g,gp,transformation,D1) default_arg('gp',[]); default_arg('transformation',[]); + default_arg('D1',[]); p_test = g(0); assert(all(size(p_test) == [2,1]), 'A curve parametrization must return a 2x1 vector.'); + if(isempty(gp) && ~isempty(D1)) + 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 - + obj.g = g; obj.gp = gp; obj.transformation = transformation; - end - - % Made up length calculation!! Science this before actual use!! - % Calculates the length of the curve. Makes sure the longet segment used is shorter than h_max. - function [L,t] = curve_length(C,h_max) - default_arg('h_max',0.001); - g = C.g; - h = 0.1; - m = 1/h+1; - t = linspace(0,1,m); - - [p,d] = get_d(t,g); - - while any(d>h_max) - I = find(d>h_max); - - % plot(p(1,:),p(2,:),'.') - % waitforbuttonpress - - new_t = []; - for i = I - new_t(end +1) = (t(i)+t(i+1))/2; - end - t = [t new_t]; - t = sort(t); - - [p,d] = get_d(t,g); - end - - L = sum(d); - - function [p,d] = get_d(t,g) - n = length(t); - - p = zeros(2,n); - for i = 1:n - p(:,i) = g(t(i)); - end - - d = zeros(1,n-1); - for i = 1:n-1 - d(i) = norm(p(:,i) - p(:,i+1)); - end - end + end function n = normal(obj,t) @@ -82,15 +46,23 @@ 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) default_arg('n',100); t = linspace(0,1,n); + p = obj.g(t); + h = line(p(1,:),p(2,:)); + 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) + default_arg('n',100); - p = obj.g(t); - + t = linspace(0,1,n); + p = obj.gp(t); h = line(p(1,:),p(2,:)); end @@ -125,7 +97,30 @@ end % Shows curve with name and arrow for direction. + + % Arc length parameterization. + function curve = arcLengthStretch(obj,N) + default_arg('N',100); + assert(~isempty(obj.gp),'This curve does not yet have a derivative added.') + + % Construct arcLength function using splines + tvec = linspace(0,1,N); + arcVec = grid.Curve.arcLength(obj.gp,0,tvec); + arcLength = grid.Curve.spline(tvec,arcVec); + + % Stretch the parameter, construct function with splines + arcParVec = util.fzero_vec(@(s)arcLength(s) - tvec*arcLength(1),[0-10*eps,1+10*eps]); + arcPar = grid.Curve.spline(tvec,arcParVec); + + % New function and derivative + g_new = @(t)obj.g(arcPar(t)); + gp_old = obj.gp; + gp_new = @(t) normalize(gp_old(arcPar(t))); + curve = grid.Curve(g_new,gp_new); + + end + % how to make it work for methods without returns function p = subsref(obj,S) %Should i add error checking here? @@ -143,8 +138,6 @@ end - - %% TRANSFORMATION OF A CURVE function D = reverse(C) % g = C.g; @@ -265,6 +258,46 @@ end methods (Static) + + % Length of arc from parameter t0 to t1 (which may be vectors). + % Computed using derivative. + function L = arcLength(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 +376,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 Mon Dec 07 16:47:13 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 Mon Dec 07 16:47:13 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