Mercurial > repos > public > sbplib
comparison +parametrization/Curve.m @ 151:3a3cf386bb7e feature/grids
Moved Curves and Tis from package grid to package parametrization.
author | Jonatan Werpers <jonatan@werpers.com> |
---|---|
date | Mon, 21 Dec 2015 15:09:32 +0100 |
parents | +grid/Curve.m@06c3034966b7 |
children | 81e0ead29431 |
comparison
equal
deleted
inserted
replaced
150:d5a794c734bc | 151:3a3cf386bb7e |
---|---|
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] = grid.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 p = obj.g(1/2); | |
72 n = obj.normal(1/2); | |
73 p = p + n*0.1; | |
74 | |
75 % Add arrow | |
76 | |
77 h = text(p(1),p(2),name); | |
78 h.HorizontalAlignment = 'center'; | |
79 h.VerticalAlignment = 'middle'; | |
80 | |
81 obj.plot(); | |
82 end | |
83 % Shows curve with name and arrow for direction. | |
84 | |
85 % Length of arc from parameter t0 to t1 (which may be vectors). | |
86 % Computed using derivative. | |
87 function L = arcLength(obj,t0,t1) | |
88 assert(~isempty(obj.gp),'Curve has no derivative!'); | |
89 speed = @(t) sqrt(sum(obj.gp(t).^2,1)); | |
90 L = integral_vec(speed,t0,t1); | |
91 end | |
92 | |
93 % Creates the arc length parameterization of a curve. | |
94 % N -- number of points used to approximate the arclength function | |
95 function curve = arcLengthParametrization(obj,N) | |
96 default_arg('N',100); | |
97 assert(~isempty(obj.gp),'Curve has no derivative!'); | |
98 | |
99 % Construct arcLength function using splines | |
100 tvec = linspace(0,1,N); | |
101 arcVec = obj.arcLength(0,tvec); | |
102 tFunc = spline(arcVec,tvec); % t as a function of arcLength | |
103 L = obj.arcLength(0,1); | |
104 arcPar = @(s) tFunc(s*L); | |
105 | |
106 % New function and derivative | |
107 g_new = @(t)obj.g(arcPar(t)); | |
108 gp_new = @(t) normalize(obj.gp(arcPar(t))); | |
109 curve = grid.Curve(g_new,gp_new); | |
110 | |
111 end | |
112 | |
113 % how to make it work for methods without returns | |
114 function p = subsref(obj,S) | |
115 %Should i add error checking here? | |
116 %Maybe if you want performance you fetch obj.g and then use that | |
117 switch S(1).type | |
118 case '()' | |
119 p = obj.g(S.subs{1}); | |
120 % case '.' | |
121 | |
122 % p = obj.(S.subs); | |
123 otherwise | |
124 p = builtin('subsref',obj,S); | |
125 % error() | |
126 end | |
127 end | |
128 | |
129 | |
130 %% TRANSFORMATION OF A CURVE | |
131 function D = reverse(C) | |
132 % g = C.g; | |
133 % gp = C.gp; | |
134 % D = grid.Curve(@(t)g(1-t),@(t)-gp(1-t)); | |
135 D = C.transform([],[],-1); | |
136 end | |
137 | |
138 function D = transform(C,A,b,flip) | |
139 default_arg('A',[1 0; 0 1]); | |
140 default_arg('b',[0; 0]); | |
141 default_arg('flip',1); | |
142 if isempty(C.transformation) | |
143 g = C.g; | |
144 gp = C.gp; | |
145 transformation.A = A; | |
146 transformation.b = b; | |
147 transformation.flip = flip; | |
148 else | |
149 g = C.transformation.base_g; | |
150 gp = C.transformation.base_gp; | |
151 A_old = C.transformation.A; | |
152 b_old = C.transformation.b; | |
153 flip_old = C.transformation.flip; | |
154 | |
155 transformation.A = A*A_old; | |
156 transformation.b = A*b_old + b; | |
157 transformation.flip = flip*flip_old; | |
158 end | |
159 | |
160 D = grid.Curve(g,gp,transformation); | |
161 | |
162 end | |
163 | |
164 function D = translate(C,a) | |
165 g = C.g; | |
166 gp = C.gp; | |
167 | |
168 % function v = g_fun(t) | |
169 % x = g(t); | |
170 % v(1,:) = x(1,:)+a(1); | |
171 % v(2,:) = x(2,:)+a(2); | |
172 % end | |
173 | |
174 % D = grid.Curve(@g_fun,gp); | |
175 | |
176 D = C.transform([],a); | |
177 end | |
178 | |
179 function D = mirror(C, a, b) | |
180 assert_size(a,[2,1]); | |
181 assert_size(b,[2,1]); | |
182 | |
183 g = C.g; | |
184 gp = C.gp; | |
185 | |
186 l = b-a; | |
187 lx = l(1); | |
188 ly = l(2); | |
189 | |
190 | |
191 % fprintf('Singular?\n') | |
192 | |
193 A = [lx^2-ly^2 2*lx*ly; 2*lx*ly ly^2-lx^2]/(l'*l); | |
194 | |
195 % function v = g_fun(t) | |
196 % % v = a + A*(g(t)-a) | |
197 % x = g(t); | |
198 | |
199 % ax1 = x(1,:)-a(1); | |
200 % ax2 = x(2,:)-a(2); | |
201 % v(1,:) = a(1)+A(1,:)*[ax1;ax2]; | |
202 % v(2,:) = a(2)+A(2,:)*[ax1;ax2]; | |
203 % end | |
204 | |
205 % function v = gp_fun(t) | |
206 % v = A*gp(t); | |
207 % end | |
208 | |
209 % D = grid.Curve(@g_fun,@gp_fun); | |
210 | |
211 % g = A(g-a)+a = Ag - Aa + a; | |
212 b = - A*a + a; | |
213 D = C.transform(A,b); | |
214 | |
215 end | |
216 | |
217 function D = rotate(C,a,rad) | |
218 assert_size(a, [2,1]); | |
219 assert_size(rad, [1,1]); | |
220 g = C.g; | |
221 gp = C.gp; | |
222 | |
223 | |
224 A = [cos(rad) -sin(rad); sin(rad) cos(rad)]; | |
225 | |
226 % function v = g_fun(t) | |
227 % % v = a + A*(g(t)-a) | |
228 % x = g(t); | |
229 | |
230 % ax1 = x(1,:)-a(1); | |
231 % ax2 = x(2,:)-a(2); | |
232 % v(1,:) = a(1)+A(1,:)*[ax1;ax2]; | |
233 % v(2,:) = a(2)+A(2,:)*[ax1;ax2]; | |
234 % end | |
235 | |
236 % function v = gp_fun(t) | |
237 % v = A*gp(t); | |
238 % end | |
239 | |
240 % D = grid.Curve(@g_fun,@gp_fun); | |
241 | |
242 | |
243 % g = A(g-a)+a = Ag - Aa + a; | |
244 b = - A*a + a; | |
245 D = C.transform(A,b); | |
246 end | |
247 end | |
248 | |
249 methods (Static) | |
250 | |
251 % Computes the derivative of g: R -> R^2 using an operator D1 | |
252 function gp_out = numericalDerivative(g,D1) | |
253 m = length(D1); | |
254 t = linspace(0,1,m); | |
255 gVec = g(t)'; | |
256 gpVec = (D1*gVec)'; | |
257 | |
258 gp1_fun = spline(t,gpVec(1,:)); | |
259 gp2_fun = spline(t,gpVec(2,:)); | |
260 gp_out = @(t) [gp1_fun(t);gp2_fun(t)]; | |
261 end | |
262 | |
263 function obj = line(p1, p2) | |
264 | |
265 function v = g_fun(t) | |
266 v(1,:) = p1(1) + t.*(p2(1)-p1(1)); | |
267 v(2,:) = p1(2) + t.*(p2(2)-p1(2)); | |
268 end | |
269 g = @g_fun; | |
270 | |
271 obj = grid.Curve(g); | |
272 end | |
273 | |
274 function obj = circle(c,r,phi) | |
275 default_arg('phi',[0; 2*pi]) | |
276 default_arg('c',[0; 0]) | |
277 default_arg('r',1) | |
278 | |
279 function v = g_fun(t) | |
280 w = phi(1)+t*(phi(2)-phi(1)); | |
281 v(1,:) = c(1) + r*cos(w); | |
282 v(2,:) = c(2) + r*sin(w); | |
283 end | |
284 | |
285 function v = g_fun_deriv(t) | |
286 w = phi(1)+t*(phi(2)-phi(1)); | |
287 v(1,:) = -(phi(2)-phi(1))*r*sin(w); | |
288 v(2,:) = (phi(2)-phi(1))*r*cos(w); | |
289 end | |
290 | |
291 obj = grid.Curve(@g_fun,@g_fun_deriv); | |
292 end | |
293 | |
294 function obj = bezier(p0, p1, p2, p3) | |
295 function v = g_fun(t) | |
296 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); | |
297 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); | |
298 end | |
299 | |
300 function v = g_fun_deriv(t) | |
301 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)); | |
302 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)); | |
303 end | |
304 | |
305 obj = grid.Curve(@g_fun,@g_fun_deriv); | |
306 end | |
307 | |
308 | |
309 function [g_out,gp_out] = transform_g(g,gp,tr) | |
310 A = tr.A; | |
311 b = tr.b; | |
312 flip = tr.flip; | |
313 | |
314 function v = g_fun_noflip(t) | |
315 % v = A*g + b | |
316 x = g(t); | |
317 | |
318 v(1,:) = A(1,:)*x+b(1); | |
319 v(2,:) = A(2,:)*x+b(2); | |
320 end | |
321 | |
322 function v = g_fun_flip(t) | |
323 % v = A*g + b | |
324 x = g(1-t); | |
325 | |
326 v(1,:) = A(1,:)*x+b(1); | |
327 v(2,:) = A(2,:)*x+b(2); | |
328 end | |
329 | |
330 | |
331 switch flip | |
332 case 1 | |
333 g_out = @g_fun_noflip; | |
334 gp_out = @(t)A*gp(t); | |
335 case -1 | |
336 g_out = @g_fun_flip; | |
337 gp_out = @(t)-A*gp(1-t); | |
338 end | |
339 end | |
340 | |
341 end | |
342 end | |
343 | |
344 | |
345 | |
346 function g_norm = normalize(g0) | |
347 g1 = g0(1,:); | |
348 g2 = g0(2,:); | |
349 normalization = sqrt(sum(g0.^2,1)); | |
350 g_norm = [g1./normalization; g2./normalization]; | |
351 end | |
352 | |
353 function I = integral_vec(f,a,b) | |
354 % Wrapper around the built-in function integral that | |
355 % handles multiple limits. | |
356 | |
357 Na = length(a); | |
358 Nb = length(b); | |
359 assert(Na == 1 || Nb == 1 || Na==Nb,... | |
360 'a and b must have same length, unless one is a scalar.'); | |
361 | |
362 if(Na>Nb); | |
363 I = zeros(size(a)); | |
364 for i = 1:Na | |
365 I(i) = integral(f,a(i),b); | |
366 end | |
367 elseif(Nb>Na) | |
368 I = zeros(size(b)); | |
369 for i = 1:Nb | |
370 I(i) = integral(f,a,b(i)); | |
371 end | |
372 else | |
373 I = zeros(size(b)); | |
374 for i = 1:Nb | |
375 I(i) = integral(f,a(i),b(i)); | |
376 end | |
377 end | |
378 end | |
379 | |
380 % Returns a function handle to the spline. | |
381 function f = spline(tval,fval,spline_order) | |
382 default_arg('spline_order',4); | |
383 [m,~] = size(tval); | |
384 assert(m==1,'Need row vectors.'); | |
385 | |
386 f_spline = spapi( optknt(tval,spline_order), tval, fval ); | |
387 f = @(t) fnval(f_spline,t); | |
388 end |