plotimp2.red 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. module plotimp2; % Implicit plot: compute the varity {x,y|f(x,y)=c}.
  2. % Author: Herbert Melenk, ZIB Berlin.
  3. % data structure:
  4. %
  5. % point = {x,y,f(x,y),t1,t2,t3,...}
  6. % where ti are the numbers of the triangles which
  7. % have this point as a node.
  8. % The point list is unique - adjacent triangles share
  9. % the list for equal nodes. The node numbers are
  10. % updated in place.
  11. %
  12. % triangle = {t#,p1,p2,p3}
  13. % triangles are stored in triangle vector by number
  14. %
  15. fluid '(imp2!-triacount!* imp2!-trias!* !*imp2!-trace);
  16. fluid '(!*show_grid !*test_plot plot!-contour* plot!-refine!*);
  17. imp2!-triacount!*:=0;
  18. symbolic procedure ploteval2xyimpl(rx,ry,f,x,y);
  19. begin scalar ll,l,form,g;
  20. for each c in plot!-contour!* do
  21. << form := plot!-form!-prep({'difference,cdr f,c},x,y);
  22. l:=imp2!-plot(car rx,cadr rx, car ry,cadr ry,
  23. plot!-points(nil),form);
  24. ll:=append(ll,l);
  25. >>;
  26. if !*show_grid and null cdr plot!-contour!*
  27. then g:= imp2!-show!-meshes();
  28. plotdriver(plot!-2imp,x,y,ll,g,car rx,cadr rx,car ry,cadr ry);
  29. end;
  30. symbolic procedure imp2!-init();
  31. << imp2!-finit();
  32. if null imp2!-trias!* then imp2!-trias!* :=mkxvect()>>;
  33. symbolic procedure imp2!-finit();
  34. <<if imp2!-trias!* then
  35. for i:=0:imp2!-triacount!* do xputv(imp2!-trias!*,i,nil);
  36. imp2!-triacount!*:=0;
  37. >>;
  38. symbolic procedure mk!-point(x0,y0,fcn);
  39. {x0,y0,apply2(fcn,x0,y0)};
  40. !#if (member 'csl lispsystem!*)
  41. symbolic procedure deletip1 (u,v);
  42. % Auxiliary function for DeletIP.
  43. pairp cdr v and
  44. (if u=cadr v then rplacd(v,cddr v) else deletip1(u,cdr v));
  45. symbolic procedure deletip (u,v);
  46. % Destructive DELETE.
  47. if not pairp v then v
  48. else if u=car v then cdr v
  49. else <<deletip1(u,v); v>>;
  50. !#endif
  51. symbolic procedure imp2!-delete!-pt!-reference(i,p);
  52. cdr cddr p := deletip(i,cdddr p);
  53. symbolic procedure mk!-tria(i,p1,p2,p3);
  54. % make a triangle from 3 points. If the number is given,
  55. % reuse it. Otherwise generate a fresh number.
  56. begin scalar p; integer i;
  57. i := i or (imp2!-triacount!* := imp2!-triacount!* #+1);
  58. p:={i,p1,p2,p3,imp2!-tria!-zerop!*(p1,p2,p3)};
  59. xputv(imp2!-trias!*,i,p);
  60. aconc(p1,i); aconc(p2,i); aconc(p3,i);
  61. if !*imp2!-trace then print!-tria("new triangle ",p);
  62. return p;
  63. end;
  64. symbolic procedure print!-tria(tx,w);
  65. <<prin2 tx; prin2 car w; w:=cdr w;
  66. prin2l {{car car w,cadr car w,{caddr car w}},
  67. {car cadr w,cadr cadr w,{caddr cadr w}},
  68. {car caddr w,cadr caddr w,{caddr caddr w}}};
  69. terpri();
  70. >>;
  71. symbolic procedure imp2!-tria!-zerop!*(p1,p2,p3);
  72. % Here I test whether the triangle contains a zero line.
  73. begin scalar f1,f2,f3;
  74. f1 := caddr p1;
  75. f2 := caddr p2;
  76. f3 := caddr p3;
  77. return f1*f2 <= 0.0 or f1*f3 <= 0.0;
  78. end;
  79. symbolic procedure imp2!-tria!-zerop(w);
  80. % Fast access to stored zerop property.
  81. cadddr cdr w;
  82. symbolic procedure imp2!-neighbours p;
  83. % Compute the direct neighbours of p - the traingles which have
  84. % two nodes respectively one complete edge in common with p.
  85. begin scalar l,p1,p2,p3; integer n;
  86. if fixp p then p:=xgetv(imp2!-trias!*,p);
  87. n:= car p; p:=cdr p;
  88. p1:=delete(n,cdddr car p);
  89. p2:=delete(n,cdddr cadr p);
  90. p3:=delete(n,cdddr caddr p);
  91. l:={find!-one!-common(p1,p2),
  92. find!-one!-common(p2,p3),
  93. find!-one!-common(p3,p1)};
  94. while nil memq l do l:=deletip(nil,l);
  95. return for each w in l collect xgetv(imp2!-trias!*,w);
  96. end;
  97. symbolic procedure imp2!-edge!-length(p1,p2);
  98. begin scalar dx,dy;
  99. fdeclare('imp2!-edge!-length,dx,dy);
  100. dx:=thefloat car p1 - thefloat car p2;
  101. dy:=thefloat cadr p1 - thefloat cadr p2;
  102. return sqrt(dx*dx + dy*dy)
  103. end;
  104. symbolic procedure imp2!-tria!-surface w;
  105. begin scalar x1,x2,x3,y1,y2,y3,p1,p2,p3;
  106. fdeclare('imp2!-tria!-surface,x1,x2,x3,y1,y2,y3);
  107. w:=cdr w;
  108. x1:=car (p1:=car w); y1:=cadr p1;
  109. x2:=car (p2:=cadr w); y2:=cadr p2;
  110. x3:=car (p3:=caddr w); y3:=cadr p3;
  111. return abs ((0.5*(x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2))));
  112. end;
  113. symbolic procedure imp2!-tria!-length w;
  114. begin scalar p1,p2,p3;
  115. w:=cdr w;
  116. p1:=car w; p2:=cadr w; p3:=caddr w;
  117. return
  118. (0.3*(imp2!-edge!-length(p1,p2)
  119. + imp2!-edge!-length(p2,p3)
  120. + imp2!-edge!-length(p3,p1)));
  121. end;
  122. symbolic procedure imp2!-tria!-midpoint(w);
  123. <<w:= cdr w;
  124. {(thefloat car car w
  125. + thefloat car cadr w
  126. + thefloat car caddr w)/3.0,
  127. (thefloat cadr car w
  128. + thefloat cadr cadr w
  129. + thefloat cadr caddr w)/3.0}
  130. >>;
  131. symbolic procedure imp2!-tria!-goodpoint(w,fn);
  132. % Here I assume that there is a zero in the triangle. Compute
  133. % a point inside the triangle which is as close as possible
  134. % to the desired line, but without local recomputation of
  135. % function values.
  136. begin scalar p1,p2,p3,f1,f2,f3,s1,s2,s3;
  137. w:=cdr w;
  138. p1:=car w; p2:=cadr w; p3:=caddr w;
  139. if (f1:=caddr p1)=0.0 then return {car p1,cadr p1} else
  140. if (f2:=caddr p2)=0.0 then return {car p2,cadr p2} else
  141. if (f3:=caddr p3)=0.0 then return {car p3,cadr p3};
  142. s1:=f1<0.0; s2:=f2<0.0; s3:=f3<0.0;
  143. return if s1=s2 then
  144. imp2!-tria!-goodpoint1(p1,f1,p3,f3,p2,f2,fn)
  145. else if s1=s3 then
  146. imp2!-tria!-goodpoint1(p1,f1,p2,f2,p3,f3,fn)
  147. else
  148. imp2!-tria!-goodpoint1(p2,f2,p1,f1,p3,f3,fn)
  149. end;
  150. %symbolic procedure imp2!-tria!-goodpoint1(p1,f1,p2,f2,p3,f3,fn);
  151. % % Now I know that f2 has the opposite sign to f1 and f3.
  152. % % I take the linearly interpolated zero of f on p1-p2 and p2-p3
  153. % % return their arithmetic mean value which lies inside the
  154. % % triangle.
  155. % begin scalar x1,x2,y1,y2,s;
  156. % fdeclare (x1,x2,y1,y2,s,f1,f2,f3);
  157. % s:=f1-f2;
  158. % x1:=(f1*thefloat car p2 - f2*thefloat car p1)/s;
  159. % y1:=(f1*thefloat cadr p2 - f2*thefloat cadr p1)/s;
  160. % s:=f3-f2;
  161. % x2:=(f3*thefloat car p2 - f2*thefloat car p3)/s;
  162. % y2:=(f3*thefloat cadr p2 - f2*thefloat cadr p3)/s;
  163. % return {(x1+x2)*0.5, (y1+y2)*0.5};
  164. % end;
  165. symbolic procedure imp2!-tria!-goodpoint1(p1,f1,p2,f2,p3,f3,fn);
  166. % Now I know that f2 has the opposite sign to f1 and f3.
  167. % F1 and f3 are non-zero.
  168. % I use the midpoint of the p1-p3 edge and look for an
  169. % approximation of a zero on the connection of the midpoint
  170. % and p2 using regula falsi.
  171. begin scalar x1,x2,y1,y2,x3,y3,s;
  172. fdeclare (x1,x2,x3,y1,y2,y3,s,f1,f2,f3);
  173. f1:=(f1+f3)*0.5;
  174. x1:=(thefloat car p1 + thefloat car p3)*0.5;
  175. y1:=(thefloat cadr p1 + thefloat cadr p3)*0.5;
  176. x2:=car p2; y2:=cadr p2;
  177. s:=f2-f1;
  178. x3:=(x1*f2 - x2*f1)/s;
  179. y3:=(y1*f2 - y2*f1)/s;
  180. f3:=apply2(fn,x3,y3);
  181. if f2*f3>=0 then
  182. <<s:=f1-f3; x3:=(x3*f1-x1*f3)/s; y3:=(y3*f1-y1*f3)/s>>
  183. else
  184. <<s:=f2-f3; x3:=(x3*f2-x2*f3)/s; y3:=(y3*f2-y2*f3)/s>>;
  185. done:
  186. return{x3,y3};
  187. end;
  188. symbolic procedure imp2!-tri!-refine!-one!-tria (w,fn);
  189. % Refine one triangle by inserting a new point in the mid
  190. % of the longest edge. Also, refine the triangle adjacent
  191. % to that edge with the same point.
  192. begin scalar p1,p2,p3,pn,xn,yn,new,nb,y; integer i;
  193. scalar x1,x2,y1,y2,d1,d2,d3,s;
  194. fdeclare (x1,x2,y1,y2,s,d1,d2,d3);
  195. if fixp w then w :=xgetv(imp2!-trias!*,w); % record.
  196. if !*imp2!-trace then print!-tria("refine ",w);
  197. i:=car w; w :=cdr w;
  198. % delete reference to this triangle.
  199. imp2!-delete!-pt!-reference(i,car w);
  200. imp2!-delete!-pt!-reference(i,cadr w);
  201. imp2!-delete!-pt!-reference(i,caddr w);
  202. % find longest edge
  203. d1:=imp2!-edge!-length(car w,cadr w);
  204. d2:=imp2!-edge!-length(cadr w,caddr w);
  205. d3:=imp2!-edge!-length(car w,caddr w);
  206. if d1>=d2 and d1>=d3 then
  207. <<p1:=car w; p2:=cadr w; p3:=caddr w>>
  208. else if d2>=d1 and d2>=d3 then
  209. <<p1:=cadr w; p2:=caddr w; p3:=car w>>
  210. else
  211. <<p1:=car w; p2:=caddr w, p3:=cadr w>>;
  212. % identify the neighbour triangle.
  213. nb := find!-one!-common(cdddr p1,cdddr p2);
  214. % compute new point almost at the mid.
  215. s:=0.45+0.01*random(10);
  216. x1:=car p1; y1:=cadr p1;
  217. x2:=car p2; y2:=cadr p2;
  218. xn:=x1*s+x2*(1.0-s);
  219. yn:=y1*s+y2*(1.0-s);
  220. pn:=mk!-point(xn,yn,fn);
  221. construct:
  222. % construct new triangles
  223. new:=mk!-tria(i,p1,pn,p3).new;
  224. new:=mk!-tria(nil,p2,pn,p3).new;
  225. % update the neighbour, if there is one
  226. if null nb then return new;
  227. w:=nb; nb:=nil;
  228. if fixp w then w :=xgetv(imp2!-trias!*,w); % record.
  229. i:=car w; w:=cdr w;
  230. imp2!-delete!-pt!-reference(i,car w);
  231. imp2!-delete!-pt!-reference(i,cadr w);
  232. imp2!-delete!-pt!-reference(i,caddr w);
  233. % find the far point
  234. p3 := if not((y:=car w) eq p1 or y eq p2) then y else
  235. if not((y:=cadr w) eq p1 or y eq p2) then y else
  236. caddr w;
  237. goto construct;
  238. end;
  239. %symbolic procedure imp2!-tri!-refine!-one!-tria!-center (w,fn);
  240. % % Refine one triangle by inserting a new point in the center.
  241. % begin scalar p1,p2,p3,pn,xn,yn,new,nb,y; integer i;
  242. % scalar x1,x2,x3,y1,y2,y3;
  243. % fdeclare (x1,x2,x3,y1,y2,y3);
  244. % if fixp w then w :=xgetv(imp2!-trias!*,w); % record.
  245. % if !*imp2!-trace then print!-tria("refine ",w);
  246. % i:=car w; w :=cdr w;
  247. %
  248. % % delete reference to this triangle.
  249. % imp2!-delete!-pt!-reference(i,car w);
  250. % imp2!-delete!-pt!-reference(i,cadr w);
  251. % imp2!-delete!-pt!-reference(i,caddr w);
  252. %
  253. % % compute center.
  254. % p1:=car w; p2:=cadr w; p3:=caddr w;
  255. % x1:=car p1; y1:=cadr p1;
  256. % x2:=car p2; y2:=cadr p2;
  257. % x3:=car p3; y3:=cadr p3;
  258. % xn:=(x1+x2+x3)*0.33333;
  259. % yn:=(y1+y2+y3)*0.33333;
  260. % pn:=mk!-point(xn,yn,fn);
  261. %construct:
  262. % % construct new triangles
  263. % new:=mk!-tria(i,p1,p2,pn).new;
  264. % new:=mk!-tria(nil,p2,p3,pn).new;
  265. % new:=mk!-tria(nil,p1,p3,pn).new;
  266. % return new;
  267. % end;
  268. symbolic procedure find!-one!-common(u,v);
  269. % fast equivalent to "car intersection(u,v)".
  270. if null u then nil else
  271. if memq(car u,v) then car u else
  272. find!-one!-common(cdr u,v);
  273. %%%%%% Main program for implicit plot.
  274. symbolic procedure imp2!-plot(xlo,xhi,ylo,yhi,pts,fcn);
  275. begin scalar p1,p2,p3,p4,sf,z;
  276. imp2!-init();
  277. % setup initial triangularization.
  278. p1:=mk!-point(xlo,ylo,fcn);
  279. p2:=mk!-point(xhi,ylo,fcn);
  280. p3:=mk!-point(xhi,yhi,fcn);
  281. p4:=mk!-point(xlo,yhi,fcn);
  282. mk!-tria(nil,p1,p2,p3);
  283. mk!-tria(nil,p1,p3,p4);
  284. sf:=((xhi-xlo)+(yhi-ylo))*1.5/float pts;
  285. z:=imp2!-plot!-refine(sf,fcn);
  286. if !*imp2!-trace then
  287. for each w in z do print!-tria("zero triangle:",w);
  288. if !*test_plot then print "collect";
  289. z:=imp2!-plot!-collect(z);
  290. if !*test_plot then print "draw";
  291. z:=imp2!-plot!-draw(z,fcn);
  292. if not !*show_grid then imp2!-finit();
  293. return z;
  294. end;
  295. symbolic procedure imp2!-plot!-refine(sflimit,fcn);
  296. begin scalar z,zn,w,s,limit2,again;
  297. integer i,j;
  298. limit2 := 0.15*sflimit;
  299. % In the first stage I refine all triangles until they
  300. % are fine enough for a coarse overview.
  301. again := t;
  302. if !*test_plot then print "phase1";
  303. phase1:
  304. z:=nil; again:=nil;
  305. for i:=imp2!-triacount!* step -1 until 1 do
  306. << w := xgetv(imp2!-trias!*,i);
  307. if imp2!-tria!-length w > sflimit then
  308. <<again:=t; imp2!-tri!-refine!-one!-tria (w,fcn)>>
  309. else if not again and imp2!-tria!-zerop w
  310. then z:=car w.z;
  311. >>;
  312. j:=j #+ 1;
  313. if j+j #< plot!-refine!* or again then goto phase1;
  314. % Next I refine further only the triangles which contain a zero.
  315. % I must store in z only the numbers of triangles because these
  316. % may be modified as side effects by copying.
  317. if !*test_plot then print "phase2";
  318. phase2:
  319. for each w in z do
  320. if (s:=imp2!-tria!-length (w:=xgetv(imp2!-trias!*,w))) >limit2
  321. then <<for each q in imp2!-tri!-refine!-one!-tria (w,fcn) do
  322. if imp2!-tria!-zerop q and not memq(car q,zn)
  323. then zn:=car q.zn>>;
  324. z:=zn; zn:=nil;
  325. if z then goto phase2;
  326. % In the third phase I refine those critical triangles futher:
  327. % non-zeros with two zero neighbours. These may be turning points
  328. % or bifurcations.
  329. if !*test_plot then print "phase3";
  330. phase3:
  331. for i:=imp2!-triacount!* step -1 until 1 do
  332. imp2!-refine!-phase3(i,i,plot!-refine!*/2,fcn,limit2*0.3);
  333. % Return the final list of zeros in ascending order.
  334. z:=for i:=1:imp2!-triacount!* join
  335. if imp2!-tria!-zerop(w:=xgetv(imp2!-trias!*,i)) then {w};
  336. return z;
  337. end;
  338. symbolic procedure imp2!-refine!-phase3(i,low,lev,fn,lth);
  339. begin scalar w; integer c;
  340. if lev=0 then return nil;
  341. w:=if numberp i then xgetv(imp2!-trias!*,i) else i;
  342. if car w<low or imp2!-tria!-length w < lth then return nil;
  343. lev:=lev-1;
  344. for each q in imp2!-neighbours w do
  345. if imp2!-tria!-zerop q then c:=c+1;
  346. if imp2!-tria!-zerop w
  347. then (if eqn(c,2) then return nil)
  348. else (if c #< 2 then return nil);
  349. for each q in imp2!-tri!-refine!-one!-tria (w,fn) do
  350. imp2!-refine!-phase3(q,low,lev,fn,lth);
  351. end;
  352. symbolic procedure imp2!-plot!-collect(z);
  353. begin scalar lines,l,q,p,s;
  354. for each w1 in z do
  355. for each w2 in imp2!-neighbours w1 do
  356. if car w2 > car w1 and imp2!-tria!-zerop w2 then
  357. q:=(w1.w2) . q;
  358. lineloop:
  359. if null q then return lines;
  360. l:={caar q, (p:=cdar q)}; q:= cdr q;
  361. % first I extend the back end.
  362. while q and p do
  363. <<
  364. if(s:= atsoc(p,q)) then l:=nconc(l,{p:=cdr s}) else
  365. if(s:=rassoc(p,q)) then l:=nconc(l,{p:=car s});
  366. if s then q:=delete(s,q) else p:=nil;
  367. >>;
  368. % next I extend the front end.
  369. p:=car l;
  370. while q and p do
  371. <<
  372. if(s:=rassoc(p,q)) then l:=(p:=car s).l else
  373. if(s:= atsoc(p,q)) then l:=(p:=cdr s).l;
  374. if s then q:=delete(s,q) else p:=nil;
  375. >>;
  376. lines := l.lines;
  377. goto lineloop;
  378. end;
  379. symbolic procedure imp2!-plot!-draw(l,fn);
  380. begin scalar r,s,q;
  381. q:=for each w in l collect
  382. <<r:=nil;
  383. for each q in w join
  384. <<s:=imp2!-tria!-goodpoint(q,fn);
  385. if r neq s then {r:=s}>>
  386. >>;
  387. return q;
  388. end;
  389. symbolic procedure imp2!-show!-meshes();
  390. % generate plot of meshes;
  391. begin scalar d,l,w,s,p1,p2; integer i;
  392. i:=1;
  393. loop:
  394. w:=xgetv(imp2!-trias!*,i);
  395. if null w then
  396. <<imp2!-finit(); return l>>;
  397. w:=cdr w;
  398. d:= {{car car w, cadr car w},
  399. {car cadr w,cadr cadr w},
  400. {car caddr w,cadr caddr w},
  401. {car car w, cadr car w}} ;
  402. while d and cdr d do
  403. <<p1:=car d; p2:=cadr d; d:=cdr d;
  404. if car p1 > car p2 then <<w:=p2;p2:=p1;p1:=w>>;
  405. s:={p1,p2};
  406. if not member(s,l) then l:=s.l
  407. >>;
  408. i:=i+1;
  409. goto loop;
  410. end;
  411. endmodule; % plotimp2
  412. end;