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