plot.red 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651
  1. From hearn@rand.orgSat Feb 3 09:55:22 1996
  2. Date: Sat, 03 Feb 96 01:00:05 -0800
  3. From: Tony Hearn <hearn@rand.org>
  4. To: shar-list@rand.org
  5. Subject: Shar File
  6. # This is a shell archive. Remove anything before this line, then
  7. # unpack it by saving it in a file and typing "sh file". (Files
  8. # unpacked will be owned by you and have default permissions.)
  9. #
  10. # This archive contains:
  11. # plot/plot.red
  12. echo x - plot/plot.red
  13. if [ -f plot/plot.red ]
  14. then
  15. mv plot/plot.red \
  16. plot/plot.red.old
  17. else
  18. echo "*** New file plot/plot.red created"
  19. fi
  20. cat > "plot/plot.red" \
  21. << '//E*O*F plot/plot.red//'
  22. module plot; % device and driver independent plot services.
  23. % Author: Herbert Melenk.
  24. % Minor corrections by Winfried Neun (October 1995)
  25. create!-package('(plot),nil);
  26. global '(
  27. plotdriver!* % modulename of the actual driver.
  28. plotmax!* % maximal floating point number which
  29. % gnuplot supports on the machine
  30. % (mostly IEEE double or single precision).
  31. plotmin!* % lower bound (=1/plotmax!*)
  32. variation!* % defintion of y-bigstep for smooth
  33. plotoptions!* % list for collecting the options.
  34. );
  35. fluid '(
  36. plotderiv!* % derivative for 2d plot
  37. );
  38. !#if(or (errorp (errorset '!*writingfaslfile nil nil))
  39. (not !*writingfaslfile)
  40. (errorp (errorset '(load fcomp) nil nil)))
  41. prin2t "no support for fast float!";
  42. eval'(dm fdeclare (x) nil);
  43. eval'(dm thefloat (x)(cadr x));
  44. !#endif
  45. endmodule;
  46. module plotsynt; % Support for the syntax of the plot command.
  47. % Author: Herbert Melenk.
  48. % Create .. as the infix operator if not yet done.
  49. !*msg := nil; % prevent message ".. redefined" during load
  50. newtok '( (!. !.) !*interval!*);
  51. if not(gettype '!*interval!* = 'operator) then
  52. <<
  53. precedence .., or;
  54. algebraic operator ..;
  55. put('!*interval!*,'PRTCH,'! !.!.! );
  56. >>;
  57. mkop 'point;
  58. !*msg := t;
  59. fluid '(plot!-points!* plot!-refine!* plot!-contour!*);
  60. global '(plot_xrange plot_yrange plot_zrange);
  61. share plot_xmesh,plot_ymesh,plot_xrange,plot_yrange,plot_zrange;
  62. fluid '(plotprecision!*);
  63. plotprecision!* := 0.9995;
  64. fluid '(!*show_grid test_plot);
  65. switch show_grid;
  66. switch test_plot; % for test printouts
  67. if null plotmax!* then
  68. <<
  69. load!-package 'arith;
  70. if not !!plumax then roundconstants();
  71. plotmax!* := !!plumax; % IEEE double precision
  72. >>;
  73. plotmin!*:= 1.0/plotmax!*;
  74. fluid '(plotranges!* plotfunctions!* plotstyle!* !*plotoverflow
  75. !*roundbf);
  76. put('plot,'psopfn,'ploteval);
  77. % I need the following definition only at compile time.
  78. macro procedure plotdriver u;
  79. {'apply,{'get,'plotdriver!*,mkquote cadr u},'list.cddr u};
  80. symbolic procedure ploteval u;
  81. begin scalar m,!*exp;
  82. if null plotdriver!* then
  83. rederr "no active device driver for PLOT";
  84. m:=plotrounded(nil);
  85. plot!-points!* := {20};
  86. plot!-refine!* := 8;
  87. !*plotoverflow := nil;
  88. plotranges!* := plotfunctions!* := nil;
  89. plotstyle!* := 'lines;
  90. plotdriver(init);
  91. for each option in u do ploteval1 plot!-reval option;
  92. errorset('(ploteval2),t,nil);
  93. plotrounded(m);
  94. end;
  95. symbolic procedure plot!-reval u;
  96. % Protected call reval: simplify u, but don't call any
  97. % algebraic procedure.
  98. begin scalar w;
  99. w:={nil};
  100. u:=plot!-reval1(u,w);
  101. return car w and u or reval u;
  102. end;
  103. symbolic procedure plot!-reval1(u,w);
  104. if idp u then reval u else
  105. if atom u or eqcar(u,'!:dn!:) or get(car u,'dname) then u else %WN
  106. if eq(car u,'!*sq) then plot!-reval1 (reval u,w) else %WN
  107. <<if flagp(car u,'opfn) and
  108. memq(car u,'(first second rest rhs lhs)) then
  109. << u := reval u; %WN
  110. plot!-reval1(u,w)>> else
  111. << if flagp(car u,'opfn) then car w:=t;
  112. car u . for each q in cdr u collect plot!-reval1(q,w) >> >>;
  113. symbolic procedure ploteval1 option;
  114. begin scalar x,do;
  115. do := get(plotdriver!*,'do);
  116. if pairp option and (x:=get(car option,do))
  117. then apply(x,list option) else
  118. if pairp option and (x:=get(car option,'plot!-do))
  119. then apply(x,list option) else
  120. if eqcar(option,'equal) and (x:=get(cadr option,do))
  121. then apply(x,list caddr option) else
  122. if eqcar(option,'equal) and (x:=get(cadr option,'plot!-do))
  123. then apply(x,list caddr option)
  124. else ploteval0 option;
  125. end;
  126. symbolic procedure ploteval0 option;
  127. begin scalar l,r,opt,w;
  128. opt:=get(plotdriver!*,'option);
  129. if flagp(option,opt) then
  130. <<plotoptions!*:=option . plotoptions!*; return>>;
  131. if eqcar(option,'list) then
  132. <<option := cdr option;
  133. if option and eqcar(car option,'list) then
  134. return (plotfunctions!*:=
  135. ('points.plotpoints option).plotfunctions!*);
  136. for each o in option do ploteval0 o; return;
  137. >>;
  138. if eqcar(option,'equal) and flagp(cadr option,opt) then
  139. <<plotoptions!*:=(cadr option.caddr option). plotoptions!*;
  140. return>>;
  141. if not eqcar(option,'equal) then
  142. <<plotfunctions!*:= (nil.option) . plotfunctions!*; return>>;
  143. % Handle equations.
  144. l:=plot!-reval cadr option;
  145. r:=plot!-reval caddr option;
  146. if plot!-checkcontour(l,r) then return
  147. plotfunctions!*:=('implicit.l) . plotfunctions!*;
  148. if not idp l then typerr(option,"illegal option in PLOT");
  149. if l memq '(size terminal view) then
  150. <<plotoptions!*:=(l.r).plotoptions!*; return>>;
  151. % iteration over a range?
  152. if eqcar(r,'times) and eqcar(caddr r,'!*interval!*)
  153. and evalnumberp(w:=cadr r) and evalgreaterp(w,0) and
  154. not evalgreaterp(w,1)
  155. then <<plot!-points!*:=append(plot!-points!*,
  156. {l.reval{'floor,{'quotient,1,w}}});
  157. r:=caddr r>>;
  158. if eqcar(r,'quotient) and eqcar(cadr r,'!*interval!*)
  159. and fixp caddr r and caddr r > 0
  160. then <<plot!-points!*:=append(plot!-points!*,{l.caddr r});
  161. r:=cadr r>>;
  162. % range?
  163. if eqcar(r,'!*interval!*) then
  164. <<r:='!*interval!* . revalnuminterval(r,t);
  165. plotranges!* := (l . r) . plotranges!*>>
  166. else
  167. plotfunctions!* := (l . r) . plotfunctions!*;
  168. end;
  169. symbolic procedure ploteval2 ();
  170. % all options are collected now;
  171. begin scalar dvar,ivars,para,impl;
  172. for each u in plotfunctions!* do
  173. <<impl:=impl or car u eq 'implicit;
  174. para:=eqcar(cdr u,'point);
  175. if impl and dvar and dvar neq car u then
  176. rederr "mixture of implicit and regular plot not supported";
  177. dvar:=car u or dvar;
  178. ivars := plotindepvars(cdr u,ivars)>>;
  179. % classify
  180. if null dvar then
  181. <<dvar:='(x y z);
  182. for each x in ivars do dvar:=delete(x,dvar);
  183. if dvar then dvar:=if 'y memq dvar then 'y else car dvar;
  184. >>;
  185. if para and length ivars=1 then plotevalpara1(car ivars) else
  186. if para and length ivars=2 then plotevalpara2(car ivars,cadr ivars)
  187. else if length ivars=1 then ploteval2x(car ivars,dvar) else
  188. if length ivars=2 then ploteval3xy(car ivars,cadr ivars,dvar) else
  189. if length ivars=3 and impl then
  190. ploteval3impl(car ivars,cadr ivars,caddr ivars)
  191. else typerr('list . for each p in plotfunctions!* collect
  192. if null car p then cdr p else
  193. {'equal,car p,cdr p},
  194. " plot option or function");
  195. plotdriver(show);
  196. end;
  197. symbolic procedure plot!-checkcontour(l,r);
  198. % true if the job is a contour expression.
  199. if length plotindepvars(l,nil)=2 then
  200. if r=0 then <<plot!-contour!*:={0};t>>
  201. else eqcar(r,'list) and
  202. <<plot!-contour!*:= for each x in cdr r collect
  203. <<x:=plot!-reval x; l:=l and adomainp x; x>>;
  204. l>>;
  205. symbolic procedure plotrange(x,d);
  206. begin scalar y;
  207. y:=assoc(x,plotranges!*);
  208. y:=if y then cdr y else d;
  209. if y=0 or null y then % return nil;
  210. y:={'!*INTERVAL!*, - plotmax!*, plotmax!*};
  211. if not eqcar(y,'!*INTERVAL!*) then
  212. typerr(y,"plot range");
  213. return {plotevalform0(rdwrap cadr y,nil) ,
  214. plotevalform0(rdwrap caddr y,nil)};
  215. end;
  216. symbolic procedure plot!-points(x);
  217. (if w then cdr w else car plot!-points!*)
  218. where w=assoc(x,cdr plot!-points!*);
  219. symbolic procedure plotseteq(u,v);
  220. null u and null v or car u member v
  221. and plotseteq(cdr u,delete(car u,v));
  222. symbolic procedure plotindepvars(u,v);
  223. if idp u then
  224. if member(u,v) or member(u,'(e pi))
  225. or u eq 'i and !*complex then v
  226. else u . v
  227. else if eqcar(u,'file) then cddr u
  228. else if pairp u then
  229. if eqcar(u,'!:dn!:) or get(car u,'dname) then v else
  230. if member(car u,'(plus minus difference times quotient expt)) or
  231. get(car u,'!:RD!:) or get(car u,'simpfn)
  232. or eqcar(getd(car u),'expr)
  233. then <<for each x in cdr u do v:=plotindepvars(x,v); v>>
  234. else typerr(u,"expression in function to plot")
  235. else v;
  236. remprop('plotshow,'stat);
  237. symbolic procedure plotshow();
  238. plotdriver(show);
  239. put('plotshow,'stat,'endstat);
  240. remprop('plotreset,'stat);
  241. symbolic procedure plotreset();
  242. plotdriver(reset);
  243. put('plotreset,'stat,'endstat);
  244. put('points,'plot!-do,
  245. function(lambda(x);car plot!-points!*:=ieval x));
  246. put('refine,'plot!-do,
  247. function(lambda(x);plot!-refine!*:=ieval x));
  248. endmodule; % plotsynt.
  249. module plotexp2; % Compute explicit 2-dim graph y=f(x);
  250. symbolic procedure ploteval2x(x,y);
  251. begin scalar xlo,xhi,ylo,yhi,rx,ry,fp,fcn,fcns,pts;
  252. if y='implicit then
  253. rederr "no implicit plot in one dimension";
  254. rx:=plotrange(x,
  255. reval(plot_xrange or '(!*interval!* -10 10)));
  256. xlo:=car rx;
  257. xhi:=cadr rx;
  258. fcns:= reverse plotfunctions!*;
  259. ry:=plotrange(y, reval(plot_yrange or nil));
  260. if ry then <<ylo:=car ry; yhi:=cadr ry>>;
  261. while fcns do
  262. <<fcn := car fcns; fcns := cdr fcns;
  263. if eqcar(fcn,'points) then fp:=caddr fcn else
  264. pts:=ploteval2x1(cdr fcn,x,xlo,xhi,ylo,yhi).pts;
  265. >>;
  266. plotdriver(plot!-2exp,x,y,pts,fp);
  267. end;
  268. symbolic procedure ploteval2x1(f,x,xlo,xhi,ylo,yhi);
  269. begin scalar plotsynerr!*,l,d,d0,u,v,vv,p,mx,mn,ff;
  270. scalar plotderiv!*;
  271. integer nx;
  272. % compute algebraic derivative.
  273. ff:= errorset({'reval,mkquote {'df,f,x}},nil,nil);
  274. if not errorp ff and not smemq('df,car ff) then
  275. % Hier irrte Goethe. % This comment is for Herbert, please keep it
  276. % plotderiv!*:= rdwrap plotderiv!* . plotderiv!*;
  277. plotderiv!*:= rdwrap car ff . car ff;
  278. ff:=rdwrap f;
  279. p:=float (nx:=plot!-points(x));
  280. d:=(d0:=(xhi-xlo))/p;
  281. v:=xlo;
  282. for i:=0:nx do
  283. <<vv:=if i=0 or i=nx then v
  284. else v+d*(random(100)-50)*0.001;
  285. u:= plotevalform(ff,f,{x.vv});
  286. if plotsynerr!* then typerr(f,"function to plot");
  287. if eqcar(u,'overflow) then u:=nil;
  288. if u then
  289. <<
  290. if yhi and u>yhi then u:=yhi else
  291. if ylo and u<ylo then u:=ylo;;
  292. if null mx or u>mx then mx:=u;
  293. if null mn or u<mn then mn:=u
  294. >>;
  295. l:=(vv.u).l;
  296. v:=v+d;
  297. >>;
  298. if null mx or null mn then rederr "plot, sampling failed";
  299. variation!* :=
  300. if yhi and not(yhi=plotmax!*) then (yhi-ylo) else
  301. (mx-mn); % ploteval2xvariation l;
  302. if plot!-refine!*>0 then
  303. l:=smooth(reversip l,ff,f,x,mx,mn,ylo,yhi,d);
  304. return {for each x in l collect {car x,cdr x}};
  305. end;
  306. symbolic procedure ploteval2xvariation l;
  307. begin scalar u;
  308. % compute geometric mean value.
  309. integer m;
  310. u:=1.0;
  311. for each p in l do
  312. <<m:=m+1; p:=cdr p;
  313. if p and p neq 0.0 then u:=u*abs p;
  314. >>;
  315. return expt(u,1/float m);
  316. end;
  317. symbolic procedure smooth(l,ff,f,x,maxv,minv,ylo,yhi,d);
  318. begin scalar rat,grain,cutmax,cutmin,z,z0;
  319. z:=l;
  320. cutmax := yhi or (- 2*minv + 3*maxv);
  321. cutmin := ylo or (3*minv - 2*maxv);
  322. grain := variation!* *0.05;
  323. rat := d / if numberp maxv and maxv > minv then (maxv - minv)
  324. else 1;
  325. % Delete empty points in front of the point list.
  326. while z and null cdar z and cdr z and null cdadr z do z:=cdr z;
  327. % Find left starting point if there is no one yet.
  328. if z and null cdar z and cdr z then
  329. <<z0:= findsing(ff,f,x,ylo,yhi,cadr z,car z);
  330. if z0 then l:=z:=z0.cdr z;
  331. >>;
  332. while z and cdr z do
  333. <<z0:=z; z:=cdr z;
  334. smooth1(z0,ff,f,x,cutmin,cutmax,grain,rat,0,plot!-refine!*)
  335. >>;
  336. return l;
  337. end;
  338. symbolic procedure smooth1(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  339. smooth2(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  340. symbolic procedure smooth2(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  341. if lev >= ml then
  342. smooth3(l,ff,f,x,minv,maxv,g,rat,lev,ml)
  343. else
  344. if null cdar l then t else
  345. begin scalar p0,p1,p2,p3,x1,x2,x3,y1,y2,y3,d;
  346. scalar dy12,dy32,dx12,dx32,z,a,w;
  347. %%%%% fdeclare(x1,x2,x3,y1,y2,y3,rat,d,dx12,dx32,dy12,dy32);
  348. lev:= add1 lev;
  349. p1:=car l; p3:=cadr l;
  350. x1:=car p1; y1:=cdr p1;
  351. x3:=car p3; y3:=cdr p3;
  352. nopoint:
  353. if null y3 then
  354. <<if null cddr l then return(cdr l:=nil);
  355. x2:=x3; y2:=y3; cdr l:=cddr l;
  356. p3:=cadr l; x3:=car p3; y3:=cdr p3;
  357. if y3 then goto outside else goto nopoint;
  358. >>;
  359. % Generate a new point
  360. x2:=(x1+x3)*0.5;
  361. if null (y2 := plotevalform(ff,f,{x.x2}))
  362. or eqcar(y2,'overflow) then goto outside;
  363. if y2 < minv or y2 > maxv then goto outside;
  364. dy32 := (y3 - y2) * rat; dx32 := x3 - x2;
  365. dy12 := (y1 - y2) * rat; dx12 := x1 - x2;
  366. d := sqrt((dy32**2 + dx32**2) * (dy12**2 + dx12**2));
  367. if zerop d then return t;
  368. w := (dy32*dy12 + dx32*dx12);
  369. d:= errorset({'quotient,w,d},nil,nil);
  370. % d is cos of angle between the vectors p2p1 and p2p3.
  371. % d near to 1 means that the angle is almost 0 (needle).
  372. if ploterrorp d then goto disc else d:=car d;
  373. a:=abs(y3-y1)<g;
  374. if d > plotprecision!* and a and lev=ml then goto disc;
  375. % I have a good point, insert it with destructive replacement.
  376. cdr l := (x2 . y2) . cdr l;
  377. % When I have an almost 180 degree angle, I compare the
  378. % derivative at the midpoint with the difference quotient.
  379. % If these are close to each other, I stop the refinement.
  380. if -d > plotprecision!*
  381. and (null plotderiv!*
  382. or
  383. ((w:=plotevalform(car plotderiv!*,cdr plotderiv!*,{x.x2}))
  384. and abs (w - (y3-y1)/(x3-x1))*rat <0.1))
  385. then return t;
  386. smooth2(cdr l,ff,f,x,minv,maxv,g,rat,lev,ml);
  387. smooth2(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  388. return t;
  389. % Function has exceeded the boundaries. I try to locate the screen
  390. % crossing point.
  391. outside:
  392. cdr l := (x2 . nil) . cdr l;
  393. z := cdr l; % insert a break
  394. p2:= (x2 . y2); % artificial midpoint
  395. p0:=findsing(ff,f,x, minv, maxv, p1, p2);
  396. if p0 then
  397. << cdr l := p0 . z;
  398. smooth2(l,ff,f,x,minv,maxv,g,rat,lev,ml) >>;
  399. p0 := findsing(ff,f,x, minv, maxv, p3, p2);
  400. if p0 then
  401. << cdr z := p0 . cdr z;
  402. smooth2(cdr z,ff,f,x,minv,maxv,g,rat,lev,ml) >>;
  403. return;
  404. disc: % look for discontinuities.
  405. return smooth3(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  406. end;
  407. symbolic procedure smooth3(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  408. % detect discontinuities.
  409. begin scalar p1,p2,p3,x1,x2,x3,y1,y2,y3,d;
  410. scalar x2hi,y2hi,x2lo,y2lo,dir,hidir,chi,clo;
  411. scalar lobound,hibound;
  412. integer n;
  413. %%%%% fdeclare(x1,x2,x3,y1,y2,y3,d,hidir);
  414. p1:=car l; p3:=cadr l;
  415. x1:=car p1; y1:=cdr p1;
  416. x3:=car p3; y3:=cdr p3;
  417. if abs(y3-y1)<variation!* then return t;
  418. % Bigstep found.
  419. hibound:=variation!**10.0; lobound:=-hibound;
  420. if y1>y3 then
  421. <<x2hi:=x1; y2hi:=y1; x2lo:= x3; y2lo:=y3; hidir:=-1.0>>
  422. else
  423. <<x2hi:=x3; y2hi:=y3; x2lo:= x1; y2lo:=y1; hidir:=1.0>>;
  424. n:=0; d:= (x3-x1)*0.5; x2:=x1+d;
  425. % intersection loop. Cut remaining interval into two parts.
  426. % If there is again a high increase in one direction we assume
  427. % a pole.
  428. next_point:
  429. if null (y2 := plotevalform(ff,f,{x.x2}))
  430. or eqcar(y2,'overflow) then goto outside;
  431. if y2 < minv then
  432. <<x2lo:=x2;y2lo:=minv;dir:=hidir>>
  433. else if y2 < y2lo then
  434. <<if y2lo<0.0 and y2<y2lo+y2lo and y2<lobound then clo:=t;
  435. x2lo:=x2;y2lo:=y2;dir:=hidir;>>
  436. else if y2 > maxv then
  437. <<x2hi:=x2;y2hi:=maxv;dir:=-hidir>>
  438. else if y2 > y2hi then
  439. <<if y2hi>0.0 and y2>y2hi+y2hi and y2>hibound then chi:=t;
  440. x2hi:=x2;y2hi:=y2;dir:=-hidir;>> else
  441. goto no_disc;
  442. if dir and (n:=n+1)<20 and (not clo or not chi) then
  443. <<d:=d/2; x2:=x2+d*dir; goto next_point>>;
  444. no_disc:
  445. if null dir then return t;
  446. if clo then y2lo:=minv;
  447. if chi then y2hi:=maxv;
  448. outside:
  449. p1:=(x2hi.y2hi); p3:=(x2lo.y2lo);
  450. if hidir=1.0 then <<p2:=p3;p3:=p1;p1:=p2>>;
  451. cdr l := p1 . (car p1.nil) . p3 . cdr l;
  452. return;
  453. brk:
  454. cdr l := (car p1.nil) . cdr l;
  455. return;
  456. end;
  457. symbolic procedure findsing(ff,f,x,minv,maxv,p1,p3);
  458. % P3 is a point with a singularity.
  459. % Try to locate the point where we exceed minv/maxv by subdivision.
  460. begin scalar p1, p2, p3, x1, x2, x3, y1, y2, y3, d, x2n;
  461. x1:=car p1; y1:=cdr p1;
  462. x3:=car p3; y3:=cdr p3;
  463. d := (x3-x1)*0.5; x2n:=x1+d;
  464. for i:=1:5 do
  465. << d:=d*0.5; x2:= x2n;
  466. if null(y2 := plotevalform(ff,f,{x.x2}))
  467. or eqcar(y2,'overflow)
  468. or y2 < minv or y2 > maxv
  469. then x2n := x2n - d
  470. else << p2 := (x2 . y2); x2n := x2n + d>>
  471. >>;
  472. if null p2 then return nil;
  473. % generate uniform maxima/minima
  474. x2 := car p2; y2 := cdr p2;
  475. y2 := if (eqcar(y2,'overflow) and cdr y2<0) or y2<minv
  476. then minv
  477. else if eqcar(y2,'overflow) or y2>maxv then maxv else y2;
  478. return (x2 . y2)
  479. end;
  480. endmodule; % plotexp2
  481. module pltpara; % Computing parametric curve.
  482. % (x,y) = (x(t),y(t))
  483. % or
  484. % (x,y,z) = (x(t),y(t),z(t))
  485. % or
  486. % (x,y,z) = (x(t,u),y(t,u),z(t,u))
  487. % Author: Herbert Melenk, ZIB Berlin.
  488. symbolic procedure plotevalpara1(x);
  489. begin scalar xlo,xhi,ylo,yhi,rx,ry,fcn,fcns,pts;
  490. rx:=plotrange(x,
  491. reval(plot_xrange or '(!*interval!* -10 10)));
  492. xlo:=car rx;
  493. xhi:=cadr rx;
  494. fcns:= reverse plotfunctions!*;
  495. % ry:=plotrange(y, reval(plot_yrange or nil));
  496. if ry then <<ylo:=car ry; yhi:=cadr ry>>;
  497. while fcns do
  498. <<fcn := cddar fcns; fcns := cdr fcns;
  499. pts:=plotevalpara11(fcn,x,xlo,xhi).pts;
  500. >>;
  501. if length fcn=2 then plotdriver(plot!-2exp,'x,'y,list pts,nil)
  502. else plotdriver(plot!-3exp!-reg,'x,'y,'z,pts)
  503. end;
  504. symbolic procedure plotevalpara11(fm,x,xlo,xhi);
  505. begin scalar plotsynerr!*,l,d,d0,u,v,p,fl;
  506. scalar plotderiv!*;
  507. integer nx;
  508. fl:= for each f in fm collect rdwrap f.f;
  509. p:=float (nx:=plot!-points(x));
  510. d:=(d0:=(xhi-xlo))/p;
  511. v:=xlo;
  512. for i:=0:nx do
  513. <<u:= for each f in fl collect plotevalform(car f,cdr f,{x.v});
  514. if plotsynerr!* then typerr(fm,"function to plot");
  515. if smemq('overflow,u) then u:=nil;
  516. l:=u.l;
  517. v:=v+d;
  518. >>;
  519. return reversip l;
  520. end;
  521. symbolic procedure plotevalpara2(x,y);
  522. begin scalar xlo,xhi,ylo,yhi,rx,ry,fcn,fcns,pts;
  523. rx:=plotrange(x,
  524. reval(plot_xrange or '(!*interval!* -10 10)));
  525. xlo:=car rx; xhi:=cadr rx;
  526. fcns:= reverse plotfunctions!*;
  527. ry:=plotrange(y,
  528. reval(plot_yrange or '(!*interval!* -10 10)));
  529. ylo:=car ry; yhi:=cadr ry;
  530. fcn := cddar fcns; fcns := cdr fcns;
  531. if length fcn neq 3 then typerr(cdar fcns,"function to plot");
  532. pts:=plotevalpara21(fcn,x,xlo,xhi,y,ylo,yhi);
  533. plotdriver(plot!-3exp!-reg,'x,'y,'z,pts)
  534. end;
  535. symbolic procedure plotevalpara21(fm,x,xlo,xhi,y,ylo,yhi);
  536. begin scalar plotsynerr!*,l,ll,dx,dy,u,v,p,fl,w;
  537. scalar plotderiv!*;
  538. integer nx,ny;
  539. fl:= for each f in fm collect rdwrap f.f;
  540. p:=float(nx:=plot!-points(x));
  541. dx:=(xhi-xlo)/p;
  542. p:=float(ny:=plot!-points(y));
  543. dy:=(yhi-ylo)/p;
  544. v:=xlo;
  545. for i:=0:nx do
  546. <<w:= ylo; l:=nil;
  547. for j:=0:ny do
  548. <<u:= for each f in fl collect
  549. plotevalform(car f,cdr f,{x.v,y.w});
  550. if plotsynerr!* then typerr(fm,"function to plot");
  551. if smemq('overflow,u) then u:=nil;
  552. l:=u.l;
  553. w:=w+dy
  554. >>;
  555. v:=v+dx;
  556. ll:=l.ll;
  557. >>;
  558. return ll;
  559. end;
  560. endmodule;
  561. module plotexp3; % Computing surface z=f(x,y) with regular grid.
  562. % Author: Herbert Melenk, ZIB Berlin.
  563. % A rectangular grid is encoded as list of rows.
  564. % A row is a list of points.
  565. % A point is a list {v,h,x,y,z} where
  566. % z,y are the coordinates and z is the function value.
  567. % The boolean values v ("vertical" = y direction) and
  568. % h ("horizontal" = x direction) are true,
  569. % if the connection to the neighbour point in that
  570. % direction is valid, nil if the connection is broken.
  571. symbolic procedure ploteval3xy(x,y,z);
  572. begin scalar rx,ry,rz,f,fcn;
  573. rx:=plotrange(x,
  574. reval(plot_xrange or '(!*interval!* -10 10)));
  575. ry:=plotrange(y,
  576. reval(plot_yrange or '(!*interval!* -10 10)));
  577. rz:=plotrange(z, reval(plot_zrange or nil));
  578. fcn := car reverse plotfunctions!*;
  579. if z='implicit then
  580. return ploteval2xyimpl(rx,ry,fcn,x,y);
  581. f:= if eqcar(fcn,'points) then caddr fcn else
  582. ploteval3xy1(cdar plotfunctions!*,
  583. z,if rz then car rz, if rz then cadr rz,
  584. x,car rx,cadr rx,
  585. y,car ry,cadr ry);
  586. plotdriver(plot!-3exp!-reg,x,y,z,f);
  587. end;
  588. symbolic procedure ploteval3xy1(f,z,zlo,zhi,x,xlo,xhi,y,ylo,yhi);
  589. begin scalar u,l,ll,ff,p,r,w;
  590. % scalar x1,x2,y1,y2,xx,yy,p1,p2,p3,p4,f1,f2,f3,f4;
  591. integer nx,ny;
  592. ff := rdwrap f;
  593. xlo:=rdwrap xlo; xhi:=rdwrap xhi;
  594. ylo:=rdwrap ylo; yhi:=rdwrap yhi;
  595. nx:=plot!-points(x); ny:=plot!-points(y);
  596. % compute the basic grid.
  597. r:=ploteval3xy1pts(f,ff,z,zlo,zhi,x,xlo,xhi,nx,y,ylo,yhi,ny);
  598. l:=cdr r;
  599. w:=car r;
  600. r:={l};
  601. % create refined environments for the bad points
  602. for each q in w do
  603. r:=cdr
  604. ploteval3xy1pts(f,ff,z,zlo,zhi,x,car q,cadr q,4,y,caddr q,
  605. cadddr q,4)
  606. .r;
  607. % % look for singularities or points of big variation
  608. % ll:=l;
  609. % while ll and cdr ll do
  610. % <<p := pair(car ll,cadr ll); ll:=cdr ll;
  611. % while p and cdr p do
  612. % <<p1:=caar p; p2:=caadr p; p3:=cdar p; p4:=cdadr p; p:=cdr p;
  613. % if (f1:=car cdddr p1) and (f2:=car cdddr p2)
  614. % and (f3:=car cdddr p3) and (f4:=car cdddr p4) then
  615. % <<xx:=((x1:=caddr p1) + (x2:=caddr p2))*0.5;
  616. % yy:=((y1:=cadddr p1) + (y2:=cadddr p3))*0.5;
  617. % u:=plotevalform(ff,f,{x . xx,y . yy});
  618. % if null u or eqcar(u,'overflow) or
  619. % numberp u and abs u > (abs f1+abs f2+abs f3+abs f4)*0.5
  620. % then
  621. % <<r:=cdr
  622. % ploteval3xy1pts(f,ff,z,zlo,zhi,x,x1,x2,3,y,y1,y2,3)
  623. % .r;
  624. % % cut connections
  625. % %car p1:= nil; cadr p1:= nil;
  626. % >>;
  627. % >>;
  628. % >>;
  629. % >>;
  630. return ploteval3xy3 r;
  631. end;
  632. symbolic procedure ploteval3xy1pts
  633. (f,ff,z,zlo,zhi,x,xlo,xhi,nx,y,ylo,yhi,ny);
  634. % Compute orthogonal graph over ordinary grid. Return additionally
  635. % a list of inner rectangles with singular points.
  636. begin scalar u,dx,dy,xx,yy,l,w;
  637. dx:=float(xhi-xlo)/float(nx);
  638. dy:=float(yhi-ylo)/float(ny);
  639. l:=
  640. for j:=0:nx collect
  641. <<
  642. for i:=0:ny collect
  643. <<
  644. xx:=(xlo+i*dx); yy:=(ylo+j*dy);
  645. u:=plotevalform(ff,f,{x . xx,y . yy});
  646. if null u or eqcar(u,'overflow)
  647. or numberp u and
  648. (zhi and u>zhi or zlo and u<zlo) then
  649. <<u:=nil;
  650. if 0<j and j<nx and 0<i and i<ny then
  651. w:={xx-dx,xx+dx,yy-dy,yy+dy}.w;
  652. >>;
  653. {t,t,xx,yy,u}
  654. >>
  655. >>;
  656. return w.l;
  657. end;
  658. symbolic procedure ploteval3xy2 l;
  659. ploteval3xy3 {l};
  660. symbolic procedure ploteval3xy3 ll;
  661. % Decompose ll into maximal regular grids.
  662. begin scalar l,lr,c,w,y,r,nw;
  663. integer n,m;
  664. while ll do
  665. <<l:=car ll; ll:=cdr ll;
  666. % find stripe with maximal lower left rectangle.
  667. w:={car l,cadr l}; l:=cdr l;
  668. n:=min(ploteval3xybkpt(car w,0,nil), % hor. only
  669. ploteval3xybkpt(cadr w,0,t)); % hor. and vert
  670. c := t;
  671. while c and l and cdr l do
  672. <<m:=ploteval3xybkpt(cadr l,0,t);
  673. if izerop n and izerop m or n #>0 and not(n #> m) then
  674. <<l:= cdr l; w:=nconc(w,{car l})>>
  675. else c:=nil;
  676. >>;
  677. if cdr l then ll:=l . ll;
  678. % cut off subnet
  679. l:=nil; r:=nil; nw:=nil;
  680. for each row in w do
  681. <<if izerop n then row := cdr row
  682. else
  683. r:=(for i:=1:n collect <<y:=cddar row; row:=cdr row; y>>).r;
  684. if row then nw:=row.nw;
  685. >>;
  686. nw:= reversip nw;
  687. %print n;print{"streifen",length w,cddr caar w,
  688. % cddr lastcar lastcar w};
  689. %print "gut";print r;print "rest";print nw;
  690. %if yesp "kill" then rederr "schluss";
  691. if nw then ll:=nw.ll;
  692. if r and cdr r then lr:=r.lr;
  693. >>;
  694. return lr;
  695. end;
  696. symbolic procedure ploteval3xybkpt(w,n,m);
  697. % m=t: look for horizontal and vertical interrupts. Otherwise
  698. % look only for horizontal interrupts.
  699. if null w then n else
  700. if nil memq cddar w then n % undefined point
  701. else
  702. if null cadar w % x - break.
  703. or (m and null caar w) % y - break
  704. then n+1 else
  705. ploteval3xybkpt(cdr w,n#+1,m);
  706. endmodule;
  707. module plotimp2; % Implicit plot: compute the varity {x,y|f(x,y)=c}.
  708. % Author: Herbert Melenk, ZIB Berlin.
  709. % data structure:
  710. %
  711. % point = {x,y,f(x,y),t1,t2,t3,...}
  712. % where ti are the numbers of the triangles which
  713. % have this point as a node.
  714. % The point list is unique - adjacent triangles share
  715. % the list for equal nodes. The node numbers are
  716. % updated in place.
  717. %
  718. % triangle = {t#,p1,p2,p3}
  719. % triangles are stored in triangle vector by number
  720. %
  721. fluid '(imp2!-triacount!* imp2!-trias!* !*imp2!-trace);
  722. imp2!-triacount!*:=0;
  723. symbolic procedure ploteval2xyimpl(rx,ry,f,x,y);
  724. begin scalar ll,l,form,g;
  725. for each c in plot!-contour!* do
  726. << form := plot!-form!-prep({'difference,cdr f,c},x,y);
  727. l:=imp2!-plot(car rx,cadr rx, car ry,cadr ry,
  728. plot!-points(nil),form);
  729. ll:=append(ll,l);
  730. >>;
  731. if !*show_grid and null cdr plot!-contour!*
  732. then g:= imp2!-show!-meshes();
  733. plotdriver(plot!-2imp,x,y,ll,g,car rx,cadr rx,car ry,cadr ry);
  734. end;
  735. symbolic procedure imp2!-init();
  736. << imp2!-finit();
  737. if null imp2!-trias!* then imp2!-trias!* :=mkxvect()>>;
  738. symbolic procedure imp2!-finit();
  739. <<if imp2!-trias!* then
  740. for i:=0:imp2!-triacount!* do xputv(imp2!-trias!*,i,nil);
  741. imp2!-triacount!*:=0;
  742. >>;
  743. symbolic procedure mk!-point(x0,y0,fcn);
  744. {x0,y0,apply2(fcn,x0,y0)};
  745. symbolic procedure imp2!-delete!-pt!-reference(i,p);
  746. cdr cddr p := deletip(i,cdddr p);
  747. symbolic procedure mk!-tria(i,p1,p2,p3);
  748. % make a triangle from 3 points. If the number is given,
  749. % reuse it. Otherwise generate a fresh number.
  750. begin scalar p; integer i;
  751. i := i or (imp2!-triacount!* := imp2!-triacount!* #+1);
  752. p:={i,p1,p2,p3,imp2!-tria!-zerop!*(p1,p2,p3)};
  753. xputv(imp2!-trias!*,i,p);
  754. aconc(p1,i); aconc(p2,i); aconc(p3,i);
  755. if !*imp2!-trace then print!-tria("new triangle ",p);
  756. return p;
  757. end;
  758. symbolic procedure print!-tria(tx,w);
  759. <<prin2 tx; prin2 car w; w:=cdr w;
  760. prin2l {{car car w,cadr car w,{caddr car w}},
  761. {car cadr w,cadr cadr w,{caddr cadr w}},
  762. {car caddr w,cadr caddr w,{caddr caddr w}}};
  763. terpri();
  764. >>;
  765. symbolic procedure imp2!-tria!-zerop!*(p1,p2,p3);
  766. % Here I test whether the triangle contains a zero line.
  767. begin scalar f1,f2,f3;
  768. f1 := caddr p1;
  769. f2 := caddr p2;
  770. f3 := caddr p3;
  771. return f1*f2 <= 0.0 or f1*f3 <= 0.0;
  772. end;
  773. symbolic procedure imp2!-tria!-zerop(w);
  774. % Fast access to stored zerop property.
  775. cadddr cdr w;
  776. symbolic procedure imp2!-neighbours p;
  777. % Compute the direct neighbours of p - the traingles which have
  778. % two nodes respectively one complete edge in common with p.
  779. begin scalar l,p1,p2,p3; integer n;
  780. if fixp p then p:=xgetv(imp2!-trias!*,p);
  781. n:= car p; p:=cdr p;
  782. p1:=delete(n,cdddr car p);
  783. p2:=delete(n,cdddr cadr p);
  784. p3:=delete(n,cdddr caddr p);
  785. l:={find!-one!-common(p1,p2),
  786. find!-one!-common(p2,p3),
  787. find!-one!-common(p3,p1)};
  788. while nil memq l do l:=deletip(nil,l);
  789. return for each w in l collect xgetv(imp2!-trias!*,w);
  790. end;
  791. symbolic procedure imp2!-edge!-length(p1,p2);
  792. begin scalar dx,dy;
  793. fdeclare('imp2!-edge!-length,dx,dy);
  794. dx:=thefloat car p1 - thefloat car p2;
  795. dy:=thefloat cadr p1 - thefloat cadr p2;
  796. return sqrt(dx*dx + dy*dy)
  797. end;
  798. symbolic procedure imp2!-tria!-surface w;
  799. begin scalar x1,x2,x3,y1,y2,y3,p1,p2,p3;
  800. fdeclare('imp2!-tria!-surface,x1,x2,x3,y1,y2,y3);
  801. w:=cdr w;
  802. x1:=car (p1:=car w); y1:=cadr p1;
  803. x2:=car (p2:=cadr w); y2:=cadr p2;
  804. x3:=car (p3:=caddr w); y3:=cadr p3;
  805. return abs ((0.5*(x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2))));
  806. end;
  807. symbolic procedure imp2!-tria!-length w;
  808. begin scalar p1,p2,p3;
  809. w:=cdr w;
  810. p1:=car w; p2:=cadr w; p3:=caddr w;
  811. return
  812. (0.3*(imp2!-edge!-length(p1,p2)
  813. + imp2!-edge!-length(p2,p3)
  814. + imp2!-edge!-length(p3,p1)));
  815. end;
  816. symbolic procedure imp2!-tria!-midpoint(w);
  817. <<w:= cdr w;
  818. {(thefloat car car w
  819. + thefloat car cadr w
  820. + thefloat car caddr w)/3.0,
  821. (thefloat cadr car w
  822. + thefloat cadr cadr w
  823. + thefloat cadr caddr w)/3.0}
  824. >>;
  825. symbolic procedure imp2!-tria!-goodpoint(w,fn);
  826. % Here I assume that there is a zero in the triangle. Compute
  827. % a point inside the triangle which is as close as possible
  828. % to the desired line, but without local recomputation of
  829. % function values.
  830. begin scalar p1,p2,p3,f1,f2,f3,s1,s2,s3;
  831. w:=cdr w;
  832. p1:=car w; p2:=cadr w; p3:=caddr w;
  833. if (f1:=caddr p1)=0.0 then return {car p1,cadr p1} else
  834. if (f2:=caddr p2)=0.0 then return {car p2,cadr p2} else
  835. if (f3:=caddr p3)=0.0 then return {car p3,cadr p3};
  836. s1:=f1<0.0; s2:=f2<0.0; s3:=f3<0.0;
  837. return if s1=s2 then
  838. imp2!-tria!-goodpoint1(p1,f1,p3,f3,p2,f2,fn)
  839. else if s1=s3 then
  840. imp2!-tria!-goodpoint1(p1,f1,p2,f2,p3,f3,fn)
  841. else
  842. imp2!-tria!-goodpoint1(p2,f2,p1,f1,p3,f3,fn)
  843. end;
  844. %symbolic procedure imp2!-tria!-goodpoint1(p1,f1,p2,f2,p3,f3,fn);
  845. % % Now I know that f2 has the opposite sign to f1 and f3.
  846. % % I take the linearly interpolated zero of f on p1-p2 and p2-p3
  847. % % return their arithmetic mean value which lies inside the
  848. % % triangle.
  849. % begin scalar x1,x2,y1,y2,s;
  850. % fdeclare (x1,x2,y1,y2,s,f1,f2,f3);
  851. % s:=f1-f2;
  852. % x1:=(f1*thefloat car p2 - f2*thefloat car p1)/s;
  853. % y1:=(f1*thefloat cadr p2 - f2*thefloat cadr p1)/s;
  854. % s:=f3-f2;
  855. % x2:=(f3*thefloat car p2 - f2*thefloat car p3)/s;
  856. % y2:=(f3*thefloat cadr p2 - f2*thefloat cadr p3)/s;
  857. % return {(x1+x2)*0.5, (y1+y2)*0.5};
  858. % end;
  859. symbolic procedure imp2!-tria!-goodpoint1(p1,f1,p2,f2,p3,f3,fn);
  860. % Now I know that f2 has the opposite sign to f1 and f3.
  861. % F1 and f3 are non-zero.
  862. % I use the midpoint of the p1-p3 edge and look for an
  863. % approximation of a zero on the connection of the midpoint
  864. % and p2 using regula falsi.
  865. begin scalar x1,x2,y1,y2,x3,y3,s;
  866. fdeclare (x1,x2,x3,y1,y2,y3,s,f1,f2,f3);
  867. f1:=(f1+f3)*0.5;
  868. x1:=(thefloat car p1 + thefloat car p3)*0.5;
  869. y1:=(thefloat cadr p1 + thefloat cadr p3)*0.5;
  870. x2:=car p2; y2:=cadr p2;
  871. s:=f2-f1;
  872. x3:=(x1*f2 - x2*f1)/s;
  873. y3:=(y1*f2 - y2*f1)/s;
  874. f3:=apply2(fn,x3,y3);
  875. if f2*f3>=0 then
  876. <<s:=f1-f3; x3:=(x3*f1-x1*f3)/s; y3:=(y3*f1-y1*f3)/s>>
  877. else
  878. <<s:=f2-f3; x3:=(x3*f2-x2*f3)/s; y3:=(y3*f2-y2*f3)/s>>;
  879. done:
  880. return{x3,y3};
  881. end;
  882. symbolic procedure imp2!-tri!-refine!-one!-tria (w,fn);
  883. % Refine one triangle by inserting a new point in the mid
  884. % of the longest edge. Also, refine the triangle adjacent
  885. % to that edge with the same point.
  886. begin scalar p1,p2,p3,pn,xn,yn,new,nb,y; integer i;
  887. scalar x1,x2,y1,y2,d1,d2,d3,s;
  888. fdeclare (x1,x2,y1,y2,s,d1,d2,d3);
  889. if fixp w then w :=xgetv(imp2!-trias!*,w); % record.
  890. if !*imp2!-trace then print!-tria("refine ",w);
  891. i:=car w; w :=cdr w;
  892. % delete reference to this triangle.
  893. imp2!-delete!-pt!-reference(i,car w);
  894. imp2!-delete!-pt!-reference(i,cadr w);
  895. imp2!-delete!-pt!-reference(i,caddr w);
  896. % find longest edge
  897. d1:=imp2!-edge!-length(car w,cadr w);
  898. d2:=imp2!-edge!-length(cadr w,caddr w);
  899. d3:=imp2!-edge!-length(car w,caddr w);
  900. if d1>=d2 and d1>=d3 then
  901. <<p1:=car w; p2:=cadr w; p3:=caddr w>>
  902. else if d2>=d1 and d2>=d3 then
  903. <<p1:=cadr w; p2:=caddr w; p3:=car w>>
  904. else
  905. <<p1:=car w; p2:=caddr w, p3:=cadr w>>;
  906. % identify the neighbour triangle.
  907. nb := find!-one!-common(cdddr p1,cdddr p2);
  908. % compute new point almost at the mid.
  909. s:=0.45+0.01*random(10);
  910. x1:=car p1; y1:=cadr p1;
  911. x2:=car p2; y2:=cadr p2;
  912. xn:=x1*s+x2*(1.0-s);
  913. yn:=y1*s+y2*(1.0-s);
  914. pn:=mk!-point(xn,yn,fn);
  915. construct:
  916. % construct new triangles
  917. new:=mk!-tria(i,p1,pn,p3).new;
  918. new:=mk!-tria(nil,p2,pn,p3).new;
  919. % update the neighbour, if there is one
  920. if null nb then return new;
  921. w:=nb; nb:=nil;
  922. if fixp w then w :=xgetv(imp2!-trias!*,w); % record.
  923. i:=car w; w:=cdr w;
  924. imp2!-delete!-pt!-reference(i,car w);
  925. imp2!-delete!-pt!-reference(i,cadr w);
  926. imp2!-delete!-pt!-reference(i,caddr w);
  927. % find the far point
  928. p3 := if not((y:=car w) eq p1 or y eq p2) then y else
  929. if not((y:=cadr w) eq p1 or y eq p2) then y else
  930. caddr w;
  931. goto construct;
  932. end;
  933. %symbolic procedure imp2!-tri!-refine!-one!-tria!-center (w,fn);
  934. % % Refine one triangle by inserting a new point in the center.
  935. % begin scalar p1,p2,p3,pn,xn,yn,new,nb,y; integer i;
  936. % scalar x1,x2,x3,y1,y2,y3;
  937. % fdeclare (x1,x2,x3,y1,y2,y3);
  938. % if fixp w then w :=xgetv(imp2!-trias!*,w); % record.
  939. % if !*imp2!-trace then print!-tria("refine ",w);
  940. % i:=car w; w :=cdr w;
  941. %
  942. % % delete reference to this triangle.
  943. % imp2!-delete!-pt!-reference(i,car w);
  944. % imp2!-delete!-pt!-reference(i,cadr w);
  945. % imp2!-delete!-pt!-reference(i,caddr w);
  946. %
  947. % % compute center.
  948. % p1:=car w; p2:=cadr w; p3:=caddr w;
  949. % x1:=car p1; y1:=cadr p1;
  950. % x2:=car p2; y2:=cadr p2;
  951. % x3:=car p3; y3:=cadr p3;
  952. % xn:=(x1+x2+x3)*0.33333;
  953. % yn:=(y1+y2+y3)*0.33333;
  954. % pn:=mk!-point(xn,yn,fn);
  955. %construct:
  956. % % construct new triangles
  957. % new:=mk!-tria(i,p1,p2,pn).new;
  958. % new:=mk!-tria(nil,p2,p3,pn).new;
  959. % new:=mk!-tria(nil,p1,p3,pn).new;
  960. % return new;
  961. % end;
  962. symbolic procedure find!-one!-common(u,v);
  963. % fast equivalent to "car intersection(u,v)".
  964. if null u then nil else
  965. if memq(car u,v) then car u else
  966. find!-one!-common(cdr u,v);
  967. %%%%%% Main program for implicit plot.
  968. symbolic procedure imp2!-plot(xlo,xhi,ylo,yhi,pts,fcn);
  969. begin scalar p1,p2,p3,p4,sf,z;
  970. imp2!-init();
  971. % setup initial triangularization.
  972. p1:=mk!-point(xlo,ylo,fcn);
  973. p2:=mk!-point(xhi,ylo,fcn);
  974. p3:=mk!-point(xhi,yhi,fcn);
  975. p4:=mk!-point(xlo,yhi,fcn);
  976. mk!-tria(nil,p1,p2,p3);
  977. mk!-tria(nil,p1,p3,p4);
  978. sf:=((xhi-xlo)+(yhi-ylo))*1.5/float pts;
  979. z:=imp2!-plot!-refine(sf,fcn);
  980. if !*imp2!-trace then
  981. for each w in z do print!-tria("zero triangle:",w);
  982. if !*test_plot then print "collect";
  983. z:=imp2!-plot!-collect(z);
  984. if !*test_plot then print "draw";
  985. z:=imp2!-plot!-draw(z,fcn);
  986. if not !*show_grid then imp2!-finit();
  987. return z;
  988. end;
  989. symbolic procedure imp2!-plot!-refine(sflimit,fcn);
  990. begin scalar z,zn,w,s,limit2,again;
  991. integer i,j;
  992. limit2 := 0.15*sflimit;
  993. % In the first stage I refine all triangles until they
  994. % are fine enough for a coarse overview.
  995. again := t;
  996. if !*test_plot then print "phase1";
  997. phase1:
  998. z:=nil; again:=nil;
  999. for i:=imp2!-triacount!* step -1 until 1 do
  1000. << w := xgetv(imp2!-trias!*,i);
  1001. if imp2!-tria!-length w > sflimit then
  1002. <<again:=t; imp2!-tri!-refine!-one!-tria (w,fcn)>>
  1003. else if not again and imp2!-tria!-zerop w
  1004. then z:=car w.z;
  1005. >>;
  1006. j:=j #+ 1;
  1007. if j+j #< plot!-refine!* or again then goto phase1;
  1008. % Next I refine further only the triangles which contain a zero.
  1009. % I must store in z only the numbers of triangles because these
  1010. % may be modified as side effects by copying.
  1011. if !*test_plot then print "phase2";
  1012. phase2:
  1013. for each w in z do
  1014. if (s:=imp2!-tria!-length (w:=xgetv(imp2!-trias!*,w))) >limit2
  1015. then <<for each q in imp2!-tri!-refine!-one!-tria (w,fcn) do
  1016. if imp2!-tria!-zerop q and not memq(car q,zn)
  1017. then zn:=car q.zn>>;
  1018. z:=zn; zn:=nil;
  1019. if z then goto phase2;
  1020. % In the third phase I refine those critical triangles futher:
  1021. % non-zeros with two zero neighbours. These may be turning points
  1022. % or bifurcations.
  1023. if !*test_plot then print "phase3";
  1024. phase3:
  1025. for i:=imp2!-triacount!* step -1 until 1 do
  1026. imp2!-refine!-phase3(i,i,plot!-refine!*/2,fcn,limit2*0.3);
  1027. % Return the final list of zeros in ascending order.
  1028. z:=for i:=1:imp2!-triacount!* join
  1029. if imp2!-tria!-zerop(w:=xgetv(imp2!-trias!*,i)) then {w};
  1030. return z;
  1031. end;
  1032. symbolic procedure imp2!-refine!-phase3(i,low,lev,fn,lth);
  1033. begin scalar w; integer c;
  1034. if lev=0 then return nil;
  1035. w:=if numberp i then xgetv(imp2!-trias!*,i) else i;
  1036. if car w<low or imp2!-tria!-length w < lth then return nil;
  1037. lev:=lev-1;
  1038. for each q in imp2!-neighbours w do
  1039. if imp2!-tria!-zerop q then c:=c+1;
  1040. if imp2!-tria!-zerop w
  1041. then (if c eq 2 then return nil)
  1042. else (if c #< 2 then return nil);
  1043. for each q in imp2!-tri!-refine!-one!-tria (w,fn) do
  1044. imp2!-refine!-phase3(q,low,lev,fn,lth);
  1045. end;
  1046. symbolic procedure imp2!-plot!-collect(z);
  1047. begin scalar lines,l,q,p,s;
  1048. for each w1 in z do
  1049. for each w2 in imp2!-neighbours w1 do
  1050. if car w2 > car w1 and imp2!-tria!-zerop w2 then
  1051. q:=(w1.w2) . q;
  1052. lineloop:
  1053. if null q then return lines;
  1054. l:={caar q, (p:=cdar q)}; q:= cdr q;
  1055. % first I extend the back end.
  1056. while q and p do
  1057. <<
  1058. if(s:= atsoc(p,q)) then l:=nconc(l,{p:=cdr s}) else
  1059. if(s:=rassoc(p,q)) then l:=nconc(l,{p:=car s});
  1060. if s then q:=delete(s,q) else p:=nil;
  1061. >>;
  1062. % next I extend the front end.
  1063. p:=car l;
  1064. while q and p do
  1065. <<
  1066. if(s:=rassoc(p,q)) then l:=(p:=car s).l else
  1067. if(s:= atsoc(p,q)) then l:=(p:=cdr s).l;
  1068. if s then q:=delete(s,q) else p:=nil;
  1069. >>;
  1070. lines := l.lines;
  1071. goto lineloop;
  1072. end;
  1073. symbolic procedure imp2!-plot!-draw(l,fn);
  1074. begin scalar r,s,q;
  1075. q:=for each w in l collect
  1076. <<r:=nil;
  1077. for each q in w join
  1078. <<s:=imp2!-tria!-goodpoint(q,fn);
  1079. if r neq s then {r:=s}>>
  1080. >>;
  1081. return q;
  1082. end;
  1083. symbolic procedure imp2!-show!-meshes();
  1084. % generate plot of meshes;
  1085. begin scalar d,l,w,s,p1,p2; integer i;
  1086. i:=1;
  1087. loop:
  1088. w:=xgetv(imp2!-trias!*,i);
  1089. if null w then
  1090. <<imp2!-finit(); return l>>;
  1091. w:=cdr w;
  1092. d:= {{car car w, cadr car w},
  1093. {car cadr w,cadr cadr w},
  1094. {car caddr w,cadr caddr w},
  1095. {car car w, cadr car w}} ;
  1096. while d and cdr d do
  1097. <<p1:=car d; p2:=cadr d; d:=cdr d;
  1098. if car p1 > car p2 then <<w:=p2;p2:=p1;p1:=w>>;
  1099. s:={p1,p2};
  1100. if not member(s,l) then l:=s.l
  1101. >>;
  1102. i:=i+1;
  1103. goto loop;
  1104. end;
  1105. endmodule; % plotimp2
  1106. module plotimp3; % Implicit plot: compute the varity {x,y,z|f(x,y,z)=0}.
  1107. % Author: Herbert Melenk, ZIB Berlin.
  1108. % data structure: cubes.
  1109. symbolic procedure ploteval3impl(x,y,z);
  1110. begin scalar rx,ry,rz,f,fcn;
  1111. rx:=plotrange(x,
  1112. reval(plot_xrange or '(!*interval!* -10 10)));
  1113. ry:=plotrange(y,
  1114. reval(plot_yrange or '(!*interval!* -10 10)));
  1115. rz:=plotrange(z,
  1116. reval(plot_zrange or '(!*interval!* -10 10)));
  1117. fcn := car reverse plotfunctions!*;
  1118. f:= ploteval3impl1(cdar plotfunctions!*,
  1119. x,car rx,cadr rx,
  1120. y,car ry,cadr ry,
  1121. z,car rz,cadr rz);
  1122. plotdriver(plot!-3exp!-reg,x,y,z,f);
  1123. end;
  1124. symbolic procedure ploteval3impl1(f,x,xlo,xhi,y,ylo,yhi,z,zlo,zhi);
  1125. begin scalar u,dx,dy,dz,xx,yy,zz,l,ff,pts,val,w,q,qq,pt,found,done;
  1126. integer nx,ny,nz;
  1127. ff := rdwrap f;
  1128. xlo:=rdwrap xlo; xhi:=rdwrap xhi;
  1129. ylo:=rdwrap ylo; yhi:=rdwrap yhi;
  1130. dx:=float(xhi-xlo)/float(nx:=plot!-points(x));
  1131. dy:=float(yhi-ylo)/float(ny:=plot!-points(y));
  1132. dz:=float(zhi-zlo)/float(nz:=plot!-points(z));
  1133. pts := mk!-p!-array3(nx,ny,nz);
  1134. val:= mk!-p!-array3(nx,ny,nz);
  1135. % Step 1: compute a complete grid in 3d.
  1136. for i:=0:nx do
  1137. <<
  1138. xx:=(xlo+i*dx);
  1139. for j:=0:ny do
  1140. <<
  1141. yy:=(ylo+j*dy);
  1142. for k:=0:nz do
  1143. <<
  1144. zz:=(zlo+k*dz);
  1145. p!-put3(pts,i,j,k,{xx,yy,zz});
  1146. u:=plotevalform(ff,f,{x . xx,y . yy,z . zz});
  1147. if eqcar(u,'overflow) then u:=1.0;
  1148. p!-put3(val,i,j,k,u);
  1149. >>;
  1150. >>
  1151. >>;
  1152. % Step 2: extract zero points.
  1153. done := t;
  1154. while done do
  1155. <<done := nil; w:=
  1156. for i:=0:nx #-1 collect
  1157. for j:=0:ny #-1 collect
  1158. <<q:=nil; found:=nil;
  1159. pt := p!-get3(pts,i,j,1);
  1160. for k:=nz step -1 until 0 do
  1161. if null found then
  1162. <<if null q then q:=p!-get3(val,i,j,k);
  1163. qq:=p!-get3(val,i,j,k);
  1164. if q and qq and q*qq <= 0.0 then
  1165. found := if q=0.0 then caddr p!-get3(pts,i,j,k)
  1166. else ploteval3impl3(caddr p!-get3(pts,i,j,k),qq,
  1167. caddr p!-get3(pts,i,j,k#+1),q);
  1168. if q=0.0 or qq=0.0 or not found then p!-put3(val,i,j,k,nil);
  1169. done:=done or found;
  1170. q:=qq;
  1171. >>;
  1172. {t,t,car pt,cadr pt,found}
  1173. >>;
  1174. if done then l:=w.l;
  1175. >>;
  1176. return ploteval3xy3 l;
  1177. end;
  1178. symbolic procedure ploteval3impl3(p1,f1,p2,f2);
  1179. % linear interpolation
  1180. <<
  1181. fdeclare(f1,f2,p1,p2);
  1182. (f1*p2 - f2*p1)/(f1-f2)>>;
  1183. endmodule;
  1184. module plotnum; % Numeric evaluation of algebraic expressions.
  1185. fluid '(plotsynerr!* ploteval!-alist2!*);
  1186. global '(!*plotinterrupts);
  1187. flag('(plus plus2 difference times times2 quotient exp expt expt!-int
  1188. minus sin cos tan cot asin acos acot atan log),'plotevallisp);
  1189. symbolic procedure plotrounded d;
  1190. % Switching rounded mode safely on and off.
  1191. begin scalar o,!*protfg,c,r,!*msg;
  1192. !*protfg:=t;
  1193. if null d then
  1194. <<c:=!*complex; r:=!*rounded;
  1195. if c then <<setdmode('complex,nil); !*complex := nil>>;
  1196. if not r and dmode!* then
  1197. <<o:=get(dmode!*,'dname); setdmode(o,nil)>>;
  1198. o:={o,r,!*roundbf,c,precision 0};
  1199. if not r then <<!*rounded:=t; setdmode('rounded,t)>>;
  1200. !*roundbf:=nil;
  1201. if c then <<setdmode('complex,t); !*complex := t>>;
  1202. return o;
  1203. >>
  1204. else
  1205. <<
  1206. % reconstruct the previous configuration.
  1207. if !*complex then setdmode('complex,nil);
  1208. if null(!*rounded:=cadr d) then setdmode('rounded,nil);
  1209. !*roundbf:=caddr d;
  1210. if car(d) then setdmode(car d,t);
  1211. if !*complex then setdmode('complex,t);
  1212. precision car cddddr d;
  1213. >>;
  1214. end;
  1215. symbolic procedure adomainp u;
  1216. % numberp test in an algebraic form.
  1217. numberp u or (pairp u and idp car u and get(car u,'dname))
  1218. or eqcar(u,'minus) and adomainp cadr u;
  1219. symbolic procedure revalnuminterval(u,num);
  1220. % Evaluate u as interval; numeric bounds required if num=T.
  1221. begin scalar l;
  1222. if not eqcar(u,'!*interval!*) then typerr(u,"interval");
  1223. l:={reval cadr u,reval caddr u};
  1224. if null num or(adomainp car l and adomainp cadr l)then return l;
  1225. typerr(u,"numeric interval");
  1226. end;
  1227. ploteval!-alist2!*:={{'x . 1},{'y . 2}};
  1228. symbolic procedure plot!-form!-prep(f,x,y);
  1229. % f is a REDUCE function expression depending of x and y.
  1230. % Compute a form which allows me to evaluate "f(x,y)" as
  1231. % a LISP expr.
  1232. {'lambda,'(!&1 !&2),
  1233. {'plot!-form!-call2,mkquote rdwrap f,mkquote f,
  1234. mkquote x,'!&1,
  1235. mkquote y,'!&2}};
  1236. symbolic procedure plot!-form!-call2(ff,f,x,x0,y,y0);
  1237. % Here I hack into the statically allocated a-list in order
  1238. % to save cons cells.
  1239. begin scalar a;
  1240. a:=car ploteval!-alist2!*;
  1241. car a := x; cdr a := x0;
  1242. a:=cadr ploteval!-alist2!*;
  1243. car a:= y; cdr a:= y0;
  1244. return plotevalform(ff,f,ploteval!-alist2!*);
  1245. end;
  1246. % The following routines are used to transform a REDUCE algebraic
  1247. % expression into a form which can be evaluated directly in LISP.
  1248. symbolic procedure rdwrap f;
  1249. begin scalar r,!*msg,!*protfg;
  1250. !*protfg:=t;
  1251. r:=errorset({'rdwrap1,mkquote f},nil,nil);
  1252. return if errorp r then 'failed else car r;
  1253. end;
  1254. symbolic procedure rdwrap1 f;
  1255. if numberp f then float f
  1256. else if f='pi then 3.141592653589793238462643
  1257. else if f='e then 2.7182818284590452353602987
  1258. else if f='i and !*complex then rederr "i not LISP evaluable"
  1259. else if atom f then f
  1260. else if get(car f,'dname) then rdwrap!-dm f
  1261. else if eqcar(f, 'MINUS) then
  1262. begin scalar x;
  1263. x := rdwrap1 cadr f;
  1264. return if numberp x then minus float x else {'MINUS, x}
  1265. end
  1266. else if eqcar(f,'expt) then rdwrap!-expt f
  1267. else
  1268. begin scalar a,w;
  1269. if null getd car f or not flagp(car f,'plotevallisp)
  1270. then typerr(car f,"Lisp arithmetic function (warning)");
  1271. a:=for each c in cdr f collect rdwrap1 c;
  1272. if (w:=atsoc(car f,'((plus.plus2)(times.times2))))
  1273. then return rdwrapn(cdr w,a);
  1274. return car f . a;
  1275. end;
  1276. symbolic procedure rdwrapn(f,a);
  1277. % Unfold a n-ary arithmetic call.
  1278. if null cdr a then car a else {f,car a,rdwrapn(f,cdr a)};
  1279. symbolic procedure rdwrap!-dm f;
  1280. % f is a domain element.
  1281. if car f eq '!:RD!: then
  1282. if atom cdr f then cdr f else bf2flr f
  1283. else if car f eq '!:CR!: then rdwrap!-cr f
  1284. else if car f eq '!:GI!:
  1285. then rdwrap!-cmplex(f,float cadr f,float cddr f)
  1286. else if car f eq '!:DN!: then rdwrap2 cdr f
  1287. else << plotsynerr!*:=t;
  1288. rerror(PLOTPACKAGE, 32, {get(car f, 'DNAME),
  1289. "illegal domain for PLOT"})
  1290. >>;
  1291. symbolic procedure rdwrap!-cr f;
  1292. begin scalar re,im;
  1293. re := cadr f;
  1294. if not atom re then re := bf2flr re;
  1295. im := cddr f;
  1296. if not atom im then im := bf2flr im;
  1297. return rdwrap!-cmplx(f,re,im);
  1298. end;
  1299. symbolic procedure rdwrap!-cmplx(f,re,im);
  1300. if abs im * 1000.0 > abs re then typerr(f,"real number") else re;
  1301. symbolic procedure plotrepart u;
  1302. if car u eq '!:rd!: then u else
  1303. if car u memq '(!:gi!: !:cr!:) then '!:rd!: . cadr u;
  1304. symbolic procedure rdwrap!-expt f;
  1305. % preserve integer second argument.
  1306. if fixp caddr f then
  1307. if caddr f>0 then {'expt!-int,rdwrap1 cadr f,caddr f}
  1308. else {'quotient,1,{'expt!-int,rdwrap1 cadr f,-caddr f}}
  1309. else {'expt,rdwrap1 cadr f, rdwrap caddr f};
  1310. symbolic procedure rdwrap2 f;
  1311. % Convert from domain to LISP evaluable value.
  1312. if atom f then f else float car f * 10^cdr f;
  1313. symbolic procedure rdwrap!* f;
  1314. % convert a domain element to float.
  1315. if null f then 0.0 else rdwrap f;
  1316. symbolic procedure rdunwrap f;
  1317. if f=0.0 then 0 else if f=1.0 then 1 else '!:rd!: . f;
  1318. symbolic procedure expt!-int(a,b); expt(a,fix b);
  1319. symbolic procedure plotevalform(ff,f,a);
  1320. % ff is LISP evaluable,f REDUCE evaluable.
  1321. begin scalar u,w,!*protfg,mn,r,!*msg;
  1322. !*protfg := t;
  1323. if ff='failed then goto non_lisp;
  1324. u:= errorset({'plotevalform1,mkquote ff,mkquote a},nil,nil);
  1325. if not ploterrorp u and numberp (u:=car u) then
  1326. <<if abs u > plotmax!* then return plotoverflow plotmax!* else
  1327. return u;
  1328. >>;
  1329. non_lisp:
  1330. w := {'simp, mkquote
  1331. sublis(
  1332. for each p in a collect (car p.rdunwrap cdr p),
  1333. f)};
  1334. u := errorset(w,nil,nil);
  1335. if ploterrorp u or (u:=car u) eq 'failed then return nil;
  1336. if denr u neq 1 then return nil;
  1337. u:=numr u;
  1338. if null u then return 0; % Wn
  1339. if numberp u then <<r:=float u; goto x>>;
  1340. if not domainp u or not memq(car u,'(!:rd!: !:gi!: !:cr!:))
  1341. then return nil;
  1342. if evalgreaterp(plotrepart u, fl2rd plotmax!*) then
  1343. return plotoverflow plotmax!* else
  1344. if evalgreaterp(fl2rd (-plotmax!*),plotrepart u) then
  1345. return plotoverflow (-plotmax!*);
  1346. r:=errorset({'rdwrap!-dm,mkquote u},nil,nil);
  1347. if errorp r or(r:=car r) eq 'failed then return nil;
  1348. x: return if mn then -r else r;
  1349. end;
  1350. symbolic procedure plotoverflow u;
  1351. <<if not !*plotoverflow then
  1352. lprim "plot number range exceeded";
  1353. !*plotoverflow := t;
  1354. 'overflow . u
  1355. >> where !*protfg = nil;
  1356. symbolic procedure plotevalform0(f,a);
  1357. (if ploterrorp u
  1358. then typerr(f,"expression for plot") else car u)
  1359. where u=
  1360. errorset({'plotevalform1,mkquote f,mkquote a},nil,nil);
  1361. %symbolic procedure plotevalform1(f,a);
  1362. % begin scalar x,w;
  1363. % if numberp f then return float f;
  1364. % if (x:=assoc(f,a)) then return plotevalform1(cdr x,a);
  1365. % if not atom f and flagp(car f,'plotevallisp) then
  1366. % return eval
  1367. % (car f . for each y in cdr f collect plotevalform1(y,a));
  1368. % if not atom f then f :=
  1369. % car f . for each y in cdr f collect prepf plotevalform2(y,a);
  1370. % w:=simp f;
  1371. % if denr w neq 1 or not domainp numr w then goto err;
  1372. % return rdwrap!* numr w;
  1373. % err:
  1374. % plotsynerr!*:=t;
  1375. % typerr(prepsq w,"numeric value");
  1376. %end;
  1377. symbolic procedure plotevalform1(f,a);
  1378. begin scalar x;
  1379. if numberp f then return float f;
  1380. if (x:=assoc(f,a)) then return plotevalform1(cdr x,a);
  1381. if atom f then go to err;
  1382. return if cddr f then
  1383. idapply(car f,{plotevalform1(cadr f,a),plotevalform1(caddr f,a)})
  1384. else
  1385. idapply(car f,{plotevalform1(cadr f,a)});
  1386. err:
  1387. plotsynerr!*:=t;
  1388. typerr(prepsq f,"numeric value");
  1389. end;
  1390. %symbolic procedure plotevalform2(f,a);
  1391. % begin scalar x,w;
  1392. % if fixp f then return f;
  1393. % if floatp f then return rdunwrap f;
  1394. % if (x:=assoc(f,a)) then return plotevalform2(cdr x,a);
  1395. % if not atom f and flagp(car f,'plotevallisp) then
  1396. % return rdunwrap eval
  1397. % (car f . for each y in cdr f collect plotevalform1(y,a));
  1398. % if not atom f then f :=
  1399. % car f . for each y in cdr f collect prepf plotevalform2(y,a);
  1400. % w:=simp f;
  1401. % if denr w neq 1 or not domainp numr w then goto err;
  1402. % return numr w;
  1403. % err:
  1404. % plotsynerr!*:=t;
  1405. % typerr(prepsq w,"numeric value");
  1406. %end;
  1407. symbolic procedure ploterrorp u;
  1408. if u member !*plotinterrupts
  1409. then rederr prin2 "***** plot killed"
  1410. else atom u or cdr u;
  1411. endmodule;
  1412. module parray; % multidimensional arrays.
  1413. symbolic procedure mk!-p!-array3(nx,ny,nz);
  1414. <<for i:=0:nx do iputv(w,i,mk!-p!-array2(ny,nz)); w>>
  1415. where w=mkvect(nx#+1);
  1416. symbolic procedure mk!-p!-array2(ny,nz);
  1417. <<for i:=0:ny do iputv(w,i,mkvect(nz#+1)); w>>
  1418. where w=mkvect(ny#+1);
  1419. symbolic procedure p!-get3(v,i,j,k);
  1420. igetv(igetv(igetv(v,i),j),k);
  1421. symbolic procedure p!-put3(v,i,j,k,w);
  1422. iputv(igetv(igetv(v,i),j),k,w);
  1423. endmodule;
  1424. module xvect; % Support for vectors with adaptive length.
  1425. % Author: Herbert Melenk, ZIB-Berlin.
  1426. symbolic procedure mkxvect(); {mkvect(128)};
  1427. symbolic procedure xputv(v,n,w);
  1428. begin scalar i,j;
  1429. i:=iquotient(n,128); j:=iremainder(n,128);
  1430. while(i>0) do
  1431. <<if null cdr v then cdr v:= mkxvect();
  1432. v:=cdr v; i:=i #- 1>>;
  1433. iputv(car v,j,w);
  1434. return w;
  1435. end;
  1436. symbolic procedure xgetv(v,n);
  1437. begin scalar i,j,w;
  1438. i:=iquotient(n,128); j:=iremainder(n,128);
  1439. while(i>0 and v) do
  1440. <<v:=cdr v; i:=i #- 1>>;
  1441. w:=if v then igetv(car v,j);
  1442. return w
  1443. end;
  1444. endmodule;
  1445. end;
  1446. //E*O*F plot/plot.red//
  1447. exit 0