comparison +parametrization/Curve.m @ 886:8894e9c49e40 feature/timesteppers

Merge with default for latest changes
author Vidar Stiernström <vidar.stiernstrom@it.uu.se>
date Thu, 15 Nov 2018 16:36:21 -0800
parents 0776fa4754ff
children acf19ecd1338 465fc81e12e8
comparison
equal deleted inserted replaced
816:b5e5b195da1e 886:8894e9c49e40
1 classdef Curve
2 properties
3 g
4 gp
5 transformation
6 end
7
8 methods
9 %TODO:
10 % Concatenation of curves
11 % Subsections of curves
12 % Stretching of curve parameter - done for arc length.
13 % Curve to cell array of linesegments
14
15 % Returns a curve object.
16 % g -- curve parametrization for parameter between 0 and 1
17 % gp -- parametrization of curve derivative
18 function obj = Curve(g,gp,transformation)
19 default_arg('gp',[]);
20 default_arg('transformation',[]);
21 p_test = g(0);
22 assert(all(size(p_test) == [2,1]), 'A curve parametrization must return a 2x1 vector.');
23
24 if ~isempty(transformation)
25 transformation.base_g = g;
26 transformation.base_gp = gp;
27 [g,gp] = parametrization.Curve.transform_g(g,gp,transformation);
28 end
29
30 obj.g = g;
31 obj.gp = gp;
32 obj.transformation = transformation;
33
34 end
35
36 function n = normal(obj,t)
37 assert(~isempty(obj.gp),'Curve has no derivative!');
38 deriv = obj.gp(t);
39 normalization = sqrt(sum(deriv.^2,1));
40 n = [-deriv(2,:)./normalization; deriv(1,:)./normalization];
41 end
42
43
44 % Plots a curve g(t) for 0<t<1, using n points. Returns a handle h to the plotted curve.
45 % h = plot_curve(g,n)
46 function h = plot(obj,n)
47 default_arg('n',100);
48
49 t = linspace(0,1,n);
50 p = obj.g(t);
51 h = line(p(1,:),p(2,:));
52 end
53
54 function h= plot_normals(obj,l,n,m)
55 default_arg('l',0.1);
56 default_arg('n',10);
57 default_arg('m',100);
58 t_n = linspace(0,1,n);
59
60 normals = obj.normal(t_n)*l;
61
62 n0 = obj.g(t_n);
63 n1 = n0 + normals;
64
65 h = line([n0(1,:); n1(1,:)],[n0(2,:); n1(2,:)]);
66 set(h,'Color',Color.red);
67 obj.plot(m);
68 end
69
70 function h= show(obj,name)
71 default_arg('name', '')
72 p = obj.g(1/2);
73 n = obj.normal(1/2);
74 p = p + n*0.1;
75
76 % Add arrow
77
78
79 if ~isempty(name)
80 h = text(p(1),p(2),name);
81 h.HorizontalAlignment = 'center';
82 h.VerticalAlignment = 'middle';
83 end
84
85 h = obj.plot();
86 end
87 % Shows curve with name and arrow for direction.
88
89 % Length of arc from parameter t0 to t1 (which may be vectors).
90 % Computed using derivative.
91 function L = arcLength(obj,t0,t1)
92 assert(~isempty(obj.gp),'Curve has no derivative!');
93 speed = @(t) sqrt(sum(obj.gp(t).^2,1));
94 L = integral_vec(speed,t0,t1);
95 end
96
97 % Creates the arc length parameterization of a curve.
98 % N -- number of points used to approximate the arclength function
99 function curve = arcLengthParametrization(obj,N)
100 default_arg('N',100);
101 assert(~isempty(obj.gp),'Curve has no derivative!');
102
103 % Construct arcLength function using splines
104 tvec = linspace(0,1,N);
105 arcVec = obj.arcLength(0,tvec);
106 tFunc = spline(arcVec,tvec); % t as a function of arcLength
107 L = obj.arcLength(0,1);
108 arcPar = @(s) tFunc(s*L);
109
110 % New function and derivative
111 g_new = @(t)obj.g(arcPar(t));
112 gp_new = @(t) normalize(obj.gp(arcPar(t)));
113 curve = parametrization.Curve(g_new,gp_new);
114
115 end
116
117 % how to make it work for methods without returns
118 function p = subsref(obj,S)
119 %Should i add error checking here?
120 %Maybe if you want performance you fetch obj.g and then use that
121 switch S(1).type
122 case '()'
123 p = obj.g(S.subs{1});
124 % case '.'
125
126 % p = obj.(S.subs);
127 otherwise
128 p = builtin('subsref',obj,S);
129 % error()
130 end
131 end
132
133
134 %% TRANSFORMATION OF A CURVE
135 function D = reverse(C)
136 % g = C.g;
137 % gp = C.gp;
138 % D = parametrization.Curve(@(t)g(1-t),@(t)-gp(1-t));
139 D = C.transform([],[],-1);
140 end
141
142 function D = transform(C,A,b,flip)
143 default_arg('A',[1 0; 0 1]);
144 default_arg('b',[0; 0]);
145 default_arg('flip',1);
146 if isempty(C.transformation)
147 g = C.g;
148 gp = C.gp;
149 transformation.A = A;
150 transformation.b = b;
151 transformation.flip = flip;
152 else
153 g = C.transformation.base_g;
154 gp = C.transformation.base_gp;
155 A_old = C.transformation.A;
156 b_old = C.transformation.b;
157 flip_old = C.transformation.flip;
158
159 transformation.A = A*A_old;
160 transformation.b = A*b_old + b;
161 transformation.flip = flip*flip_old;
162 end
163
164 D = parametrization.Curve(g,gp,transformation);
165
166 end
167
168 function D = translate(C,a)
169 g = C.g;
170 gp = C.gp;
171
172 % function v = g_fun(t)
173 % x = g(t);
174 % v(1,:) = x(1,:)+a(1);
175 % v(2,:) = x(2,:)+a(2);
176 % end
177
178 % D = parametrization.Curve(@g_fun,gp);
179
180 D = C.transform([],a);
181 end
182
183 function D = mirror(C, a, b)
184 assertSize(a,[2,1]);
185 assertSize(b,[2,1]);
186
187 g = C.g;
188 gp = C.gp;
189
190 l = b-a;
191 lx = l(1);
192 ly = l(2);
193
194
195 % fprintf('Singular?\n')
196
197 A = [lx^2-ly^2 2*lx*ly; 2*lx*ly ly^2-lx^2]/(l'*l);
198
199 % function v = g_fun(t)
200 % % v = a + A*(g(t)-a)
201 % x = g(t);
202
203 % ax1 = x(1,:)-a(1);
204 % ax2 = x(2,:)-a(2);
205 % v(1,:) = a(1)+A(1,:)*[ax1;ax2];
206 % v(2,:) = a(2)+A(2,:)*[ax1;ax2];
207 % end
208
209 % function v = gp_fun(t)
210 % v = A*gp(t);
211 % end
212
213 % D = parametrization.Curve(@g_fun,@gp_fun);
214
215 % g = A(g-a)+a = Ag - Aa + a;
216 b = - A*a + a;
217 D = C.transform(A,b);
218
219 end
220
221 function D = rotate(C,a,rad)
222 assertSize(a, [2,1]);
223 assertSize(rad, [1,1]);
224 g = C.g;
225 gp = C.gp;
226
227
228 A = [cos(rad) -sin(rad); sin(rad) cos(rad)];
229
230 % function v = g_fun(t)
231 % % v = a + A*(g(t)-a)
232 % x = g(t);
233
234 % ax1 = x(1,:)-a(1);
235 % ax2 = x(2,:)-a(2);
236 % v(1,:) = a(1)+A(1,:)*[ax1;ax2];
237 % v(2,:) = a(2)+A(2,:)*[ax1;ax2];
238 % end
239
240 % function v = gp_fun(t)
241 % v = A*gp(t);
242 % end
243
244 % D = parametrization.Curve(@g_fun,@gp_fun);
245
246
247 % g = A(g-a)+a = Ag - Aa + a;
248 b = - A*a + a;
249 D = C.transform(A,b);
250 end
251 end
252
253 methods (Static)
254
255 % Computes the derivative of g: R -> R^2 using an operator D1
256 function gp_out = numericalDerivative(g,D1)
257 m = length(D1);
258 t = linspace(0,1,m);
259 gVec = g(t)';
260 gpVec = (D1*gVec)';
261
262 gp1_fun = spline(t,gpVec(1,:));
263 gp2_fun = spline(t,gpVec(2,:));
264 gp_out = @(t) [gp1_fun(t);gp2_fun(t)];
265 end
266
267 function obj = line(p1, p2)
268
269 function v = g_fun(t)
270 v(1,:) = p1(1) + t.*(p2(1)-p1(1));
271 v(2,:) = p1(2) + t.*(p2(2)-p1(2));
272 end
273
274 function v = g_fun_deriv(t)
275 v(1,:) = t.*0 + (p2(1)-p1(1));
276 v(2,:) = t.*0 + (p2(2)-p1(2));
277 end
278
279 obj = parametrization.Curve(@g_fun, @g_fun_deriv);
280 end
281
282 function obj = circle(c,r,phi)
283 default_arg('phi',[0; 2*pi])
284 default_arg('c',[0; 0])
285 default_arg('r',1)
286
287 function v = g_fun(t)
288 w = phi(1)+t*(phi(2)-phi(1));
289 v(1,:) = c(1) + r*cos(w);
290 v(2,:) = c(2) + r*sin(w);
291 end
292
293 function v = g_fun_deriv(t)
294 w = phi(1)+t*(phi(2)-phi(1));
295 v(1,:) = -(phi(2)-phi(1))*r*sin(w);
296 v(2,:) = (phi(2)-phi(1))*r*cos(w);
297 end
298
299 obj = parametrization.Curve(@g_fun,@g_fun_deriv);
300 end
301
302 function obj = bezier(p0, p1, p2, p3)
303 function v = g_fun(t)
304 v(1,:) = (1-t).^3*p0(1) + 3*(1-t).^2.*t*p1(1) + 3*(1-t).*t.^2*p2(1) + t.^3*p3(1);
305 v(2,:) = (1-t).^3*p0(2) + 3*(1-t).^2.*t*p1(2) + 3*(1-t).*t.^2*p2(2) + t.^3*p3(2);
306 end
307
308 function v = g_fun_deriv(t)
309 v(1,:) = 3*(1-t).^2*(p1(1)-p0(1)) + 6*(1-t).*t*(p2(1)-p1(1)) + 3*t.^2*(p3(1)-p2(1));
310 v(2,:) = 3*(1-t).^2*(p1(2)-p0(2)) + 6*(1-t).*t*(p2(2)-p1(2)) + 3*t.^2*(p3(2)-p2(2));
311 end
312
313 obj = parametrization.Curve(@g_fun,@g_fun_deriv);
314 end
315
316
317 function [g_out,gp_out] = transform_g(g,gp,tr)
318 A = tr.A;
319 b = tr.b;
320 flip = tr.flip;
321
322 function v = g_fun_noflip(t)
323 % v = A*g + b
324 x = g(t);
325
326 v(1,:) = A(1,:)*x+b(1);
327 v(2,:) = A(2,:)*x+b(2);
328 end
329
330 function v = g_fun_flip(t)
331 % v = A*g + b
332 x = g(1-t);
333
334 v(1,:) = A(1,:)*x+b(1);
335 v(2,:) = A(2,:)*x+b(2);
336 end
337
338
339 switch flip
340 case 1
341 g_out = @g_fun_noflip;
342 gp_out = @(t)A*gp(t);
343 case -1
344 g_out = @g_fun_flip;
345 gp_out = @(t)-A*gp(1-t);
346 end
347 end
348
349 end
350 end
351
352
353
354 function g_norm = normalize(g0)
355 g1 = g0(1,:);
356 g2 = g0(2,:);
357 normalization = sqrt(sum(g0.^2,1));
358 g_norm = [g1./normalization; g2./normalization];
359 end
360
361 function I = integral_vec(f,a,b)
362 % Wrapper around the built-in function integral that
363 % handles multiple limits.
364
365 Na = length(a);
366 Nb = length(b);
367 assert(Na == 1 || Nb == 1 || Na==Nb,...
368 'a and b must have same length, unless one is a scalar.');
369
370 if(Na>Nb);
371 I = zeros(size(a));
372 for i = 1:Na
373 I(i) = integral(f,a(i),b);
374 end
375 elseif(Nb>Na)
376 I = zeros(size(b));
377 for i = 1:Nb
378 I(i) = integral(f,a,b(i));
379 end
380 else
381 I = zeros(size(b));
382 for i = 1:Nb
383 I(i) = integral(f,a(i),b(i));
384 end
385 end
386 end
387
388 % Returns a function handle to the spline.
389 function f = spline(tval,fval,spline_order)
390 default_arg('spline_order',4);
391 [m,~] = size(tval);
392 assert(m==1,'Need row vectors.');
393
394 f_spline = spapi( optknt(tval,spline_order), tval, fval );
395 f = @(t) fnval(f_spline,t);
396 end