xref: /inferno-os/appl/math/gr.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsythimplement GR;
2*37da2899SCharles.Forsyth
3*37da2899SCharles.Forsythinclude "sys.m";
4*37da2899SCharles.Forsyth	sys: Sys;
5*37da2899SCharles.Forsyth	print, sprint: import sys;
6*37da2899SCharles.Forsythinclude "math.m";
7*37da2899SCharles.Forsyth	math: Math;
8*37da2899SCharles.Forsyth	ceil, fabs, floor, Infinity, log10, pow10, sqrt: import math;
9*37da2899SCharles.Forsythinclude "draw.m";
10*37da2899SCharles.Forsyth	screen: ref Draw->Screen;
11*37da2899SCharles.Forsythinclude "tk.m";
12*37da2899SCharles.Forsyth	tk: Tk;
13*37da2899SCharles.Forsyth	Toplevel: import tk;
14*37da2899SCharles.Forsythinclude "tkclient.m";
15*37da2899SCharles.Forsyth	tkclient: Tkclient;
16*37da2899SCharles.Forsythinclude "gr.m";
17*37da2899SCharles.Forsyth
18*37da2899SCharles.Forsythgr_cfg := array[] of {
19*37da2899SCharles.Forsyth	"frame .fc",
20*37da2899SCharles.Forsyth	"frame .fc.b",
21*37da2899SCharles.Forsyth	"label .fc.b.xy -text {0 0} -anchor e",
22*37da2899SCharles.Forsyth	"pack .fc.b.xy -fill x",
23*37da2899SCharles.Forsyth	"pack .fc.b -fill both -expand 1",
24*37da2899SCharles.Forsyth	"canvas .fc.c -relief sunken -bd 2 -width 600 -height 480 -bg white"+
25*37da2899SCharles.Forsyth		" -font /fonts/lucidasans/unicode.8.font",
26*37da2899SCharles.Forsyth	"pack .fc.c -fill both -expand 1",
27*37da2899SCharles.Forsyth	"pack .Wm_t -fill x",
28*37da2899SCharles.Forsyth	"pack .fc -fill both -expand 1",
29*37da2899SCharles.Forsyth	"pack propagate . 0",
30*37da2899SCharles.Forsyth	"bind .fc.c <ButtonPress-1> {send grcmd down1,%x,%y}",
31*37da2899SCharles.Forsyth};
32*37da2899SCharles.Forsyth
33*37da2899SCharles.ForsythTkCmd(t: ref Toplevel, arg: string): string
34*37da2899SCharles.Forsyth{
35*37da2899SCharles.Forsyth	rv := tk->cmd(t,arg);
36*37da2899SCharles.Forsyth	if(rv!=nil && rv[0]=='!')
37*37da2899SCharles.Forsyth		print("tk->cmd(%s): %s\n",arg,rv);
38*37da2899SCharles.Forsyth	return rv;
39*37da2899SCharles.Forsyth}
40*37da2899SCharles.Forsyth
41*37da2899SCharles.Forsyth
42*37da2899SCharles.Forsythopen(ctxt: ref Draw->Context, title: string): ref Plot
43*37da2899SCharles.Forsyth{
44*37da2899SCharles.Forsyth	if(sys==nil){
45*37da2899SCharles.Forsyth		sys = load Sys Sys->PATH;
46*37da2899SCharles.Forsyth		math = load Math Math->PATH;
47*37da2899SCharles.Forsyth		tk = load Tk Tk->PATH;
48*37da2899SCharles.Forsyth		tkclient = load Tkclient Tkclient->PATH;
49*37da2899SCharles.Forsyth		tkclient->init();
50*37da2899SCharles.Forsyth	}
51*37da2899SCharles.Forsyth	textsize := 8.;	# textsize is in points, if no user transform
52*37da2899SCharles.Forsyth	(t, tb) := tkclient->toplevel(ctxt, "", title, Tkclient->Appl);
53*37da2899SCharles.Forsyth	cc := chan of string;
54*37da2899SCharles.Forsyth	tk->namechan(t, cc, "grcmd");
55*37da2899SCharles.Forsyth	p := ref Plot(nil, Infinity,-Infinity,Infinity,-Infinity, textsize, t, tb, cc);
56*37da2899SCharles.Forsyth	for (i:=0; i<len gr_cfg; i++)
57*37da2899SCharles.Forsyth		tk->cmd(p.t,gr_cfg[i]);
58*37da2899SCharles.Forsyth	tkclient->onscreen(p.t, nil);
59*37da2899SCharles.Forsyth	tkclient->startinput(p.t, "kbd"::"ptr"::nil);
60*37da2899SCharles.Forsyth	return p;
61*37da2899SCharles.Forsyth}
62*37da2899SCharles.Forsyth
63*37da2899SCharles.ForsythPlot.bye(p: self ref Plot)
64*37da2899SCharles.Forsyth{
65*37da2899SCharles.Forsyth	cmdloop: for(;;) alt {
66*37da2899SCharles.Forsyth	s := <-p.t.ctxt.kbd =>
67*37da2899SCharles.Forsyth		tk->keyboard(p.t, s);
68*37da2899SCharles.Forsyth	s := <-p.t.ctxt.ptr =>
69*37da2899SCharles.Forsyth		tk->pointer(p.t, *s);
70*37da2899SCharles.Forsyth	s := <-p.t.ctxt.ctl or
71*37da2899SCharles.Forsyth	s = <-p.t.wreq or
72*37da2899SCharles.Forsyth	s = <-p.titlechan =>
73*37da2899SCharles.Forsyth		if(s == "exit")
74*37da2899SCharles.Forsyth			break cmdloop;
75*37da2899SCharles.Forsyth		tkclient->wmctl(p.t, s);
76*37da2899SCharles.Forsyth		case s{
77*37da2899SCharles.Forsyth		"size" =>
78*37da2899SCharles.Forsyth			canvw := int TkCmd(p.t, ".fc.c cget -width");
79*37da2899SCharles.Forsyth			canvh := int TkCmd(p.t, ".fc.c cget -height");
80*37da2899SCharles.Forsyth			TkCmd(p.t,".fc.b.xy configure -text {"+sprint("%d %d",canvw,canvh)+"}");
81*37da2899SCharles.Forsyth		}
82*37da2899SCharles.Forsyth	press := <-p.canvaschan =>
83*37da2899SCharles.Forsyth		(nil,cmds) := sys->tokenize(press,",");
84*37da2899SCharles.Forsyth		if(cmds==nil) continue;
85*37da2899SCharles.Forsyth		case hd cmds {
86*37da2899SCharles.Forsyth		"down1" =>
87*37da2899SCharles.Forsyth			xpos := real(hd tl cmds);
88*37da2899SCharles.Forsyth			ypos := real(hd tl tl cmds);
89*37da2899SCharles.Forsyth			x := (xpos-bx)/ax;
90*37da2899SCharles.Forsyth			y := -(ypos-tky+by)/ay;
91*37da2899SCharles.Forsyth			TkCmd(p.t,".fc.b.xy configure -text {"+sprint("%.3g %.3g",x,y)+"}");
92*37da2899SCharles.Forsyth		}
93*37da2899SCharles.Forsyth	}
94*37da2899SCharles.Forsyth	TkCmd(p.t,"destroy .;update");
95*37da2899SCharles.Forsyth	p.t = nil;
96*37da2899SCharles.Forsyth}
97*37da2899SCharles.Forsyth
98*37da2899SCharles.ForsythPlot.equalxy(p: self ref Plot)
99*37da2899SCharles.Forsyth{
100*37da2899SCharles.Forsyth	r := 0.;
101*37da2899SCharles.Forsyth	if( r < p.xmax - p.xmin ) r = p.xmax - p.xmin;
102*37da2899SCharles.Forsyth	if( r < p.ymax - p.ymin ) r = p.ymax - p.ymin;
103*37da2899SCharles.Forsyth	m := (p.xmax + p.xmin)/2.;
104*37da2899SCharles.Forsyth	p.xmax = m + r/2.;
105*37da2899SCharles.Forsyth	p.xmin = m - r/2.;
106*37da2899SCharles.Forsyth	m = (p.ymax + p.ymin)/2.;
107*37da2899SCharles.Forsyth	p.ymax = m + r/2.;
108*37da2899SCharles.Forsyth	p.ymin = m - r/2.;
109*37da2899SCharles.Forsyth}
110*37da2899SCharles.Forsyth
111*37da2899SCharles.ForsythPlot.graph(p: self ref Plot, x, y: array of real)
112*37da2899SCharles.Forsyth{
113*37da2899SCharles.Forsyth	n := len x;
114*37da2899SCharles.Forsyth	op := OP(GR->GRAPH, n, array[n] of real, array[n] of real, nil);
115*37da2899SCharles.Forsyth	while(n--){
116*37da2899SCharles.Forsyth		t := x[n];
117*37da2899SCharles.Forsyth		op.x[n] = t;
118*37da2899SCharles.Forsyth		if(t < p.xmin)
119*37da2899SCharles.Forsyth			p.xmin = t;
120*37da2899SCharles.Forsyth		if(t > p.xmax)
121*37da2899SCharles.Forsyth			p.xmax = t;
122*37da2899SCharles.Forsyth		t = y[n];
123*37da2899SCharles.Forsyth		op.y[n] = t;
124*37da2899SCharles.Forsyth		if(t < p.ymin)
125*37da2899SCharles.Forsyth			p.ymin = t;
126*37da2899SCharles.Forsyth		if(t > p.ymax)
127*37da2899SCharles.Forsyth			p.ymax = t;
128*37da2899SCharles.Forsyth	}
129*37da2899SCharles.Forsyth	p.op = op :: p.op;
130*37da2899SCharles.Forsyth}
131*37da2899SCharles.Forsyth
132*37da2899SCharles.ForsythPlot.text(p: self ref Plot, justify: int, s: string, x, y: real)
133*37da2899SCharles.Forsyth{
134*37da2899SCharles.Forsyth	op := OP(GR->TEXT, justify, array[1] of real, array[1] of real, s);
135*37da2899SCharles.Forsyth	op.x[0] = x;
136*37da2899SCharles.Forsyth	op.y[0] = y;
137*37da2899SCharles.Forsyth	p.op = op :: p.op;
138*37da2899SCharles.Forsyth}
139*37da2899SCharles.Forsyth
140*37da2899SCharles.ForsythPlot.pen(p: self ref Plot, nib: int)
141*37da2899SCharles.Forsyth{
142*37da2899SCharles.Forsyth	p.op = OP(GR->PEN, nib, nil, nil, nil) :: p.op;
143*37da2899SCharles.Forsyth}
144*37da2899SCharles.Forsyth
145*37da2899SCharles.Forsyth
146*37da2899SCharles.Forsyth#---------------------------------------------------------
147*37da2899SCharles.Forsyth# The rest of this file is concerned with sending the "display list"
148*37da2899SCharles.Forsyth# to Tk.  The only interesting parts of the problem are picking axes
149*37da2899SCharles.Forsyth# and drawing dashed lines properly.
150*37da2899SCharles.Forsyth
151*37da2899SCharles.Forsythax, bx, ay, by: real;			# transform user to pixels
152*37da2899SCharles.Forsythtky: con 630.;				# Tk_y = tky - y
153*37da2899SCharles.Forsythnseg: int;				# how many segments in current stroke path
154*37da2899SCharles.Forsythpendown: int;				# is pen currently drawing?
155*37da2899SCharles.Forsythxoff := array[] of{"w","","e"};	# LJUST, CENTER, RJUST
156*37da2899SCharles.Forsythyoff := array[] of{"n","","s","s"};	# HIGH, MED, BASE, LOW
157*37da2899SCharles.Forsythlinewidth: real;
158*37da2899SCharles.Forsythtoplevel: ref Toplevel;			# p.t
159*37da2899SCharles.Forsythtkcmd: string;
160*37da2899SCharles.Forsyth
161*37da2899SCharles.Forsythmv(x, y: real)
162*37da2899SCharles.Forsyth{
163*37da2899SCharles.Forsyth	tkcmd = sprint(".fc.c create line %.1f %.1f", ax*x+bx, tky-(ay*y+by));
164*37da2899SCharles.Forsyth}
165*37da2899SCharles.Forsyth
166*37da2899SCharles.Forsythstroke()
167*37da2899SCharles.Forsyth{
168*37da2899SCharles.Forsyth	if(pendown){
169*37da2899SCharles.Forsyth		tkcmd += " -width 3";   # -capstyle round -joinstyle round
170*37da2899SCharles.Forsyth		TkCmd(toplevel,tkcmd);
171*37da2899SCharles.Forsyth		tkcmd = nil;
172*37da2899SCharles.Forsyth		pendown = 0;
173*37da2899SCharles.Forsyth		nseg = 0;
174*37da2899SCharles.Forsyth	}
175*37da2899SCharles.Forsyth}
176*37da2899SCharles.Forsyth
177*37da2899SCharles.Forsythvec(x, y: real)
178*37da2899SCharles.Forsyth{
179*37da2899SCharles.Forsyth	tkcmd += sprint(" %.1f %.1f", ax*x+bx, tky-(ay*y+by));
180*37da2899SCharles.Forsyth	pendown = 1;
181*37da2899SCharles.Forsyth	nseg++;
182*37da2899SCharles.Forsyth	if(nseg>1000){
183*37da2899SCharles.Forsyth		stroke();
184*37da2899SCharles.Forsyth		mv(x,y);
185*37da2899SCharles.Forsyth	}
186*37da2899SCharles.Forsyth}
187*37da2899SCharles.Forsyth
188*37da2899SCharles.Forsythcircle(u, v, radius: real)
189*37da2899SCharles.Forsyth{
190*37da2899SCharles.Forsyth	x := ax*u+bx;
191*37da2899SCharles.Forsyth	y := tky-(ay*v+by);
192*37da2899SCharles.Forsyth	r := radius*(ax+ay)/2.;
193*37da2899SCharles.Forsyth	tkcmd = sprint(".fc.c create oval %.1f %.1f %.1f %.1f -width 3",
194*37da2899SCharles.Forsyth		x-r, y-r, x+r, y+r);
195*37da2899SCharles.Forsyth	TkCmd(toplevel,tkcmd);
196*37da2899SCharles.Forsyth	tkcmd = nil;
197*37da2899SCharles.Forsyth}
198*37da2899SCharles.Forsyth
199*37da2899SCharles.Forsythtext(s: string, x, y: real, xoff, yoff: string)
200*37da2899SCharles.Forsyth{
201*37da2899SCharles.Forsyth	# rot = rotation in degrees.  90 is used for y-axis
202*37da2899SCharles.Forsyth	# x,y are in PostScript coordinate system, not user
203*37da2899SCharles.Forsyth	anchor := yoff + xoff;
204*37da2899SCharles.Forsyth	if(anchor!="")
205*37da2899SCharles.Forsyth		anchor = "-anchor " + anchor + " ";
206*37da2899SCharles.Forsyth	tkcmd = sprint(".fc.c create text %.1f %.1f %s-text '%s",
207*37da2899SCharles.Forsyth		ax*x+bx,
208*37da2899SCharles.Forsyth		tky-(ay*y+by), anchor, s);
209*37da2899SCharles.Forsyth	TkCmd(toplevel,tkcmd);
210*37da2899SCharles.Forsyth	tkcmd = nil;
211*37da2899SCharles.Forsyth}
212*37da2899SCharles.Forsyth
213*37da2899SCharles.Forsythdatarange(xmin, xmax, margin: real): (real,real)
214*37da2899SCharles.Forsyth{
215*37da2899SCharles.Forsyth	r := 1.e-30;
216*37da2899SCharles.Forsyth	if( r < 0.001*fabs(xmin) )
217*37da2899SCharles.Forsyth		r = 0.001*fabs(xmin);
218*37da2899SCharles.Forsyth	if( r < 0.001*fabs(xmax) )
219*37da2899SCharles.Forsyth		r = 0.001*fabs(xmax);
220*37da2899SCharles.Forsyth	if( r < xmax-xmin )
221*37da2899SCharles.Forsyth		r = xmax-xmin;
222*37da2899SCharles.Forsyth	r *= 1.+2.*margin;
223*37da2899SCharles.Forsyth	x0 :=(xmin+xmax)/2. - r/2.;
224*37da2899SCharles.Forsyth	return ( x0, x0 + r);
225*37da2899SCharles.Forsyth}
226*37da2899SCharles.Forsyth
227*37da2899SCharles.Forsythdashed(ndash: int, x, y: array of real)
228*37da2899SCharles.Forsyth{
229*37da2899SCharles.Forsyth	cx, cy: real;	# current position
230*37da2899SCharles.Forsyth	d: real;	# length undone in p[i],p[i+1]
231*37da2899SCharles.Forsyth	t: real;	# length undone in current dash
232*37da2899SCharles.Forsyth	n := len x;
233*37da2899SCharles.Forsyth	if(n!=len y || n<=0)
234*37da2899SCharles.Forsyth		return;
235*37da2899SCharles.Forsyth
236*37da2899SCharles.Forsyth	# choose precise dashlen
237*37da2899SCharles.Forsyth	s := 0.;
238*37da2899SCharles.Forsyth	for(i := 0; i < n - 1; i += 1){
239*37da2899SCharles.Forsyth		u := x[i+1] - x[i];
240*37da2899SCharles.Forsyth		v := y[i+1] - y[i];
241*37da2899SCharles.Forsyth		s += sqrt(u*u + v*v);
242*37da2899SCharles.Forsyth	}
243*37da2899SCharles.Forsyth	i = int floor(real ndash * s);
244*37da2899SCharles.Forsyth	if(i < 2)
245*37da2899SCharles.Forsyth		i = 2;
246*37da2899SCharles.Forsyth	dashlen := s / real(2 * i - 1);
247*37da2899SCharles.Forsyth
248*37da2899SCharles.Forsyth	t = dashlen;
249*37da2899SCharles.Forsyth	ink := 1;
250*37da2899SCharles.Forsyth	mv(x[0], y[0]);
251*37da2899SCharles.Forsyth	cx = x[0];
252*37da2899SCharles.Forsyth	cy = y[0];
253*37da2899SCharles.Forsyth	for(i = 0; i < n - 1; i += 1){
254*37da2899SCharles.Forsyth		u := x[i+1] - x[i];
255*37da2899SCharles.Forsyth		v := y[i+1] - y[i];
256*37da2899SCharles.Forsyth		d = sqrt(u * u + v * v);
257*37da2899SCharles.Forsyth		if(d > 0.){
258*37da2899SCharles.Forsyth			u /= d;
259*37da2899SCharles.Forsyth			v /= d;
260*37da2899SCharles.Forsyth			while(t <= d){
261*37da2899SCharles.Forsyth				cx += t * u;
262*37da2899SCharles.Forsyth				cy += t * v;
263*37da2899SCharles.Forsyth				if(ink){
264*37da2899SCharles.Forsyth					vec(cx, cy);
265*37da2899SCharles.Forsyth					stroke();
266*37da2899SCharles.Forsyth				}else{
267*37da2899SCharles.Forsyth					mv(cx, cy);
268*37da2899SCharles.Forsyth				}
269*37da2899SCharles.Forsyth				d -= t;
270*37da2899SCharles.Forsyth				t = dashlen;
271*37da2899SCharles.Forsyth				ink = 1 - ink;
272*37da2899SCharles.Forsyth			}
273*37da2899SCharles.Forsyth			cx = x[i+1];
274*37da2899SCharles.Forsyth			cy = y[i+1];
275*37da2899SCharles.Forsyth			if(ink){
276*37da2899SCharles.Forsyth				vec(cx, cy);
277*37da2899SCharles.Forsyth			}else{
278*37da2899SCharles.Forsyth				mv(cx, cy);
279*37da2899SCharles.Forsyth			}
280*37da2899SCharles.Forsyth			t -= d;
281*37da2899SCharles.Forsyth		}
282*37da2899SCharles.Forsyth	}
283*37da2899SCharles.Forsyth	stroke();
284*37da2899SCharles.Forsyth}
285*37da2899SCharles.Forsyth
286*37da2899SCharles.Forsythlabfmt(x:real): string
287*37da2899SCharles.Forsyth{
288*37da2899SCharles.Forsyth	lab := sprint("%.6g",x);
289*37da2899SCharles.Forsyth	if(len lab>2){
290*37da2899SCharles.Forsyth		if(lab[0]=='0' && lab[1]=='.')
291*37da2899SCharles.Forsyth			lab = lab[1:];
292*37da2899SCharles.Forsyth		else if(lab[0]=='-' && len lab>3 && lab[1]=='0' && lab[2]=='.')
293*37da2899SCharles.Forsyth			lab = "-"+lab[2:];
294*37da2899SCharles.Forsyth	}
295*37da2899SCharles.Forsyth	return lab;
296*37da2899SCharles.Forsyth}
297*37da2899SCharles.Forsyth
298*37da2899SCharles.ForsythPlot.paint(p: self ref Plot, xlabel, xunit, ylabel, yunit: string)
299*37da2899SCharles.Forsyth{
300*37da2899SCharles.Forsyth	oplist: list of OP;
301*37da2899SCharles.Forsyth
302*37da2899SCharles.Forsyth	# tunable parameters for dimensions of graph (fraction of box side)
303*37da2899SCharles.Forsyth	margin: con 0.075;		# separation of data from box boundary
304*37da2899SCharles.Forsyth	ticksize := 0.02;
305*37da2899SCharles.Forsyth	sep := ticksize;		# separation of text from box boundary
306*37da2899SCharles.Forsyth
307*37da2899SCharles.Forsyth	# derived coordinates of various feature points...
308*37da2899SCharles.Forsyth	x0, x1, y0, y1: real;		# box corners, in original coord
309*37da2899SCharles.Forsyth	# radius := 0.2*p.textsize;	# radius for circle marker
310*37da2899SCharles.Forsyth	radius := 0.8*p.textsize;	# radius for circle marker
311*37da2899SCharles.Forsyth
312*37da2899SCharles.Forsyth	Pen := SOLID;
313*37da2899SCharles.Forsyth	width := SOLID;
314*37da2899SCharles.Forsyth	linewidth = 2.;
315*37da2899SCharles.Forsyth	nseg = 0;
316*37da2899SCharles.Forsyth	pendown = 0;
317*37da2899SCharles.Forsyth
318*37da2899SCharles.Forsyth	if(xunit=="") xunit = nil;
319*37da2899SCharles.Forsyth	if(yunit=="") yunit = nil;
320*37da2899SCharles.Forsyth
321*37da2899SCharles.Forsyth	(x0,x1) = datarange(p.xmin,p.xmax,margin);
322*37da2899SCharles.Forsyth	ax = (400.-2.*p.textsize)/((x1-x0)*(1.+2.*sep));
323*37da2899SCharles.Forsyth	bx = 506.-ax*x1;
324*37da2899SCharles.Forsyth	(y0,y1) = datarange(p.ymin,p.ymax,margin);
325*37da2899SCharles.Forsyth	ay = (400.-2.*p.textsize)/((y1-y0)*(1.+2.*sep));
326*37da2899SCharles.Forsyth	by = 596.-ay*y1;
327*37da2899SCharles.Forsyth	# PostScript version
328*37da2899SCharles.Forsyth	# magic numbers here come from BoundingBox: 106 196 506 596
329*37da2899SCharles.Forsyth	# (x0,x1) = datarange(p.xmin,p.xmax,margin);
330*37da2899SCharles.Forsyth	# ax = (400.-2.*p.textsize)/((x1-x0)*(1.+2.*sep));
331*37da2899SCharles.Forsyth	# bx = 506.-ax*x1;
332*37da2899SCharles.Forsyth	# (y0,y1) = datarange(p.ymin,p.ymax,margin);
333*37da2899SCharles.Forsyth	# ay = (400.-2.*p.textsize)/((y1-y0)*(1.+2.*sep));
334*37da2899SCharles.Forsyth	# by = 596.-ay*y1;
335*37da2899SCharles.Forsyth
336*37da2899SCharles.Forsyth	# convert from fraction of box to PostScript units
337*37da2899SCharles.Forsyth	ticksize *= ax*(x1-x0);
338*37da2899SCharles.Forsyth	sep *= ax*(x1-x0);
339*37da2899SCharles.Forsyth
340*37da2899SCharles.Forsyth	# revert to original drawing order
341*37da2899SCharles.Forsyth	log := p.op;
342*37da2899SCharles.Forsyth	oplist = nil;
343*37da2899SCharles.Forsyth	while(log!=nil){
344*37da2899SCharles.Forsyth		oplist = hd log :: oplist;
345*37da2899SCharles.Forsyth		log = tl log;
346*37da2899SCharles.Forsyth	}
347*37da2899SCharles.Forsyth	p.op = oplist;
348*37da2899SCharles.Forsyth
349*37da2899SCharles.Forsyth	toplevel = p.t;
350*37da2899SCharles.Forsyth	#------------send display list to Tk-----------------
351*37da2899SCharles.Forsyth	while(oplist!=nil){
352*37da2899SCharles.Forsyth		op := hd oplist;
353*37da2899SCharles.Forsyth		n := op.n;
354*37da2899SCharles.Forsyth		case op.code{
355*37da2899SCharles.Forsyth		GRAPH =>
356*37da2899SCharles.Forsyth			if(Pen == DASHED){
357*37da2899SCharles.Forsyth				dashed(17, op.x, op.y);
358*37da2899SCharles.Forsyth			}else if(Pen == DOTTED){
359*37da2899SCharles.Forsyth				dashed(85, op.x, op.y);
360*37da2899SCharles.Forsyth			}else{
361*37da2899SCharles.Forsyth				for(i:=0; i<n; i++){
362*37da2899SCharles.Forsyth					xx := op.x[i];
363*37da2899SCharles.Forsyth					yy := op.y[i];
364*37da2899SCharles.Forsyth					if(Pen == CIRCLE){
365*37da2899SCharles.Forsyth						circle(xx, yy, radius/(ax+ay));
366*37da2899SCharles.Forsyth					}else if(Pen == CROSS){
367*37da2899SCharles.Forsyth						mv(xx-radius/ax, yy);
368*37da2899SCharles.Forsyth						vec(xx+radius/ax, yy);
369*37da2899SCharles.Forsyth						stroke();
370*37da2899SCharles.Forsyth						mv(xx, yy-radius/ay);
371*37da2899SCharles.Forsyth						vec(xx, yy+radius/ay);
372*37da2899SCharles.Forsyth						stroke();
373*37da2899SCharles.Forsyth					}else if(Pen == INVIS){
374*37da2899SCharles.Forsyth					}else{
375*37da2899SCharles.Forsyth						if(i==0){
376*37da2899SCharles.Forsyth							mv(xx, yy);
377*37da2899SCharles.Forsyth						}else{
378*37da2899SCharles.Forsyth							vec(xx, yy);
379*37da2899SCharles.Forsyth						}
380*37da2899SCharles.Forsyth					}
381*37da2899SCharles.Forsyth				}
382*37da2899SCharles.Forsyth				stroke();
383*37da2899SCharles.Forsyth			}
384*37da2899SCharles.Forsyth		TEXT =>
385*37da2899SCharles.Forsyth			angle := 0.;
386*37da2899SCharles.Forsyth			if(op.n&UP) angle = 90.;
387*37da2899SCharles.Forsyth			text(op.t,op.x[0],op.y[0],xoff[n&7],yoff[(n>>3)&7]);
388*37da2899SCharles.Forsyth		PEN =>
389*37da2899SCharles.Forsyth			Pen = n;
390*37da2899SCharles.Forsyth			if( Pen==SOLID && width!=SOLID ){
391*37da2899SCharles.Forsyth				linewidth = 2.;
392*37da2899SCharles.Forsyth				width=SOLID;
393*37da2899SCharles.Forsyth			}else if( Pen==REFERENCE && width!=REFERENCE ){
394*37da2899SCharles.Forsyth				linewidth = 0.8;
395*37da2899SCharles.Forsyth				width=REFERENCE;
396*37da2899SCharles.Forsyth			}
397*37da2899SCharles.Forsyth		}
398*37da2899SCharles.Forsyth		oplist = tl oplist;
399*37da2899SCharles.Forsyth	}
400*37da2899SCharles.Forsyth
401*37da2899SCharles.Forsyth	#--------------------now add axes-----------------------
402*37da2899SCharles.Forsyth	mv(x0,y0);
403*37da2899SCharles.Forsyth	vec(x1,y0);
404*37da2899SCharles.Forsyth	vec(x1,y1);
405*37da2899SCharles.Forsyth	vec(x0,y1);
406*37da2899SCharles.Forsyth	vec(x0,y0);
407*37da2899SCharles.Forsyth	stroke();
408*37da2899SCharles.Forsyth
409*37da2899SCharles.Forsyth	# x ticks
410*37da2899SCharles.Forsyth	(lab1,labn,labinc,k,u,s) := mytic(x0,x1);
411*37da2899SCharles.Forsyth	for (i := lab1; i <= labn; i += labinc){
412*37da2899SCharles.Forsyth		r := real i*s*u;
413*37da2899SCharles.Forsyth		mv(r,y0);
414*37da2899SCharles.Forsyth		vec(r,y0+ticksize/ay);
415*37da2899SCharles.Forsyth		stroke();
416*37da2899SCharles.Forsyth		mv(r,y1);
417*37da2899SCharles.Forsyth		vec(r,y1-ticksize/ay);
418*37da2899SCharles.Forsyth		stroke();
419*37da2899SCharles.Forsyth		text(labfmt(real i*s),r,y0-sep/ay,"","n");
420*37da2899SCharles.Forsyth	}
421*37da2899SCharles.Forsyth	yy := y0-(2.*sep+p.textsize)/ay;
422*37da2899SCharles.Forsyth	labelstr := "";
423*37da2899SCharles.Forsyth	if(xlabel!=nil)
424*37da2899SCharles.Forsyth		labelstr = xlabel;
425*37da2899SCharles.Forsyth	if(k!=0||xunit!=nil)
426*37da2899SCharles.Forsyth		labelstr += " /";
427*37da2899SCharles.Forsyth	if(k!=0)
428*37da2899SCharles.Forsyth		labelstr += " ₁₀"+ string k;
429*37da2899SCharles.Forsyth	if(xunit!=nil)
430*37da2899SCharles.Forsyth		labelstr += " " + xunit;
431*37da2899SCharles.Forsyth	text(labelstr,(x0+x1)/2.,yy,"","n");
432*37da2899SCharles.Forsyth
433*37da2899SCharles.Forsyth	# y ticks
434*37da2899SCharles.Forsyth	(lab1,labn,labinc,k,u,s) = mytic(y0,y1);
435*37da2899SCharles.Forsyth	for (i = lab1; i <= labn; i += labinc){
436*37da2899SCharles.Forsyth		r := real i*s*u;
437*37da2899SCharles.Forsyth		mv(x0,r);
438*37da2899SCharles.Forsyth		vec(x0+ticksize/ax,r);
439*37da2899SCharles.Forsyth		stroke();
440*37da2899SCharles.Forsyth		mv(x1,r);
441*37da2899SCharles.Forsyth		vec(x1-ticksize/ax,r);
442*37da2899SCharles.Forsyth		stroke();
443*37da2899SCharles.Forsyth		text(labfmt(real i*s),x0-sep/ax,r,"e","");
444*37da2899SCharles.Forsyth	}
445*37da2899SCharles.Forsyth	xx := x0-(4.*sep+p.textsize)/ax;
446*37da2899SCharles.Forsyth	labelstr = "";
447*37da2899SCharles.Forsyth	if(ylabel!=nil)
448*37da2899SCharles.Forsyth		labelstr = ylabel;
449*37da2899SCharles.Forsyth	if(k!=0||yunit!=nil)
450*37da2899SCharles.Forsyth		labelstr += " /";
451*37da2899SCharles.Forsyth	if(k!=0)
452*37da2899SCharles.Forsyth		labelstr += " ₁₀"+ string k;
453*37da2899SCharles.Forsyth	if(yunit!=nil)
454*37da2899SCharles.Forsyth		labelstr += " " + yunit;
455*37da2899SCharles.Forsyth	text(labelstr,xx,(y0+y1)/2.,"e","");
456*37da2899SCharles.Forsyth
457*37da2899SCharles.Forsyth	TkCmd(p.t, "update");
458*37da2899SCharles.Forsyth}
459*37da2899SCharles.Forsyth
460*37da2899SCharles.Forsyth
461*37da2899SCharles.Forsyth
462*37da2899SCharles.Forsyth# automatic tic choice                      Eric Grosse  9 Dec 84
463*37da2899SCharles.Forsyth# Input: low and high endpoints of expanded data range
464*37da2899SCharles.Forsyth# Output: lab1, labn, labinc, k, u, s   where the tics are
465*37da2899SCharles.Forsyth#   (lab1*s, (lab1+labinc)*s, ..., labn*s) * 10^k
466*37da2899SCharles.Forsyth# and u = 10^k.  k is metric, i.e. k=0 mod 3.
467*37da2899SCharles.Forsyth
468*37da2899SCharles.Forsythmax3(a, b, c: real): real
469*37da2899SCharles.Forsyth{
470*37da2899SCharles.Forsyth	if(a<b) a=b;
471*37da2899SCharles.Forsyth	if(a<c) a=c;
472*37da2899SCharles.Forsyth	return(a);
473*37da2899SCharles.Forsyth}
474*37da2899SCharles.Forsyth
475*37da2899SCharles.Forsythmy_mod(i, n: int): int
476*37da2899SCharles.Forsyth{
477*37da2899SCharles.Forsyth	while(i< 0) i+=n;
478*37da2899SCharles.Forsyth	while(i>=n) i-=n;
479*37da2899SCharles.Forsyth	return(i);
480*37da2899SCharles.Forsyth}
481*37da2899SCharles.Forsyth
482*37da2899SCharles.Forsythmytic(l, h: real): (int,int,int,int,real,real)
483*37da2899SCharles.Forsyth{
484*37da2899SCharles.Forsyth	lab1, labn, labinc, k, nlab, j, ndig, t1, tn: int;
485*37da2899SCharles.Forsyth	u, s: real;
486*37da2899SCharles.Forsyth	eps := .0001;
487*37da2899SCharles.Forsyth	k = int floor( log10((h-l)/(3.+eps)) );
488*37da2899SCharles.Forsyth	u = pow10(k);
489*37da2899SCharles.Forsyth	t1 = int ceil(l/u-eps);
490*37da2899SCharles.Forsyth	tn = int floor(h/u+eps);
491*37da2899SCharles.Forsyth	lab1 = t1;
492*37da2899SCharles.Forsyth	labn = tn;
493*37da2899SCharles.Forsyth	labinc = 1;
494*37da2899SCharles.Forsyth	nlab = labn - lab1 + 1;
495*37da2899SCharles.Forsyth	if( nlab>5 ){
496*37da2899SCharles.Forsyth		lab1 = t1 + my_mod(-t1,2);
497*37da2899SCharles.Forsyth		labn = tn - my_mod( tn,2);
498*37da2899SCharles.Forsyth		labinc = 2;
499*37da2899SCharles.Forsyth		nlab = (labn-lab1)/labinc + 1;
500*37da2899SCharles.Forsyth		if( nlab>5 ){
501*37da2899SCharles.Forsyth			lab1 = t1 + my_mod(-t1,5);
502*37da2899SCharles.Forsyth			labn = tn - my_mod( tn,5);
503*37da2899SCharles.Forsyth			labinc = 5;
504*37da2899SCharles.Forsyth			nlab = (labn-lab1)/labinc + 1;
505*37da2899SCharles.Forsyth			if( nlab>5 ){
506*37da2899SCharles.Forsyth				u *= 10.;
507*37da2899SCharles.Forsyth				k++;
508*37da2899SCharles.Forsyth				lab1 = int ceil(l/u-eps);
509*37da2899SCharles.Forsyth				labn = int floor(h/u+eps);
510*37da2899SCharles.Forsyth				nlab = labn - lab1 + 1;
511*37da2899SCharles.Forsyth				labinc = 1;
512*37da2899SCharles.Forsyth			} else if( nlab<3 ){
513*37da2899SCharles.Forsyth				lab1 = t1 + my_mod(-t1,4);
514*37da2899SCharles.Forsyth				labn = tn - my_mod( tn,4);
515*37da2899SCharles.Forsyth				labinc = 4;
516*37da2899SCharles.Forsyth				nlab = (labn-lab1)/labinc + 1;
517*37da2899SCharles.Forsyth			}
518*37da2899SCharles.Forsyth		}
519*37da2899SCharles.Forsyth	}
520*37da2899SCharles.Forsyth	ndig = int(1.+floor(log10(max3(fabs(real lab1),fabs(real labn),1.e-30))));
521*37da2899SCharles.Forsyth	if( ((k<=0)&&(k>=-ndig))   # no zeros have to be added
522*37da2899SCharles.Forsyth	    || ((k<0)&&(k>=-3))
523*37da2899SCharles.Forsyth	    || ((k>0)&&(ndig+k<=4)) ){   # even with zeros, label is small
524*37da2899SCharles.Forsyth		s = u;
525*37da2899SCharles.Forsyth		k = 0;
526*37da2899SCharles.Forsyth		u = 1.;
527*37da2899SCharles.Forsyth	}else if(k>0){
528*37da2899SCharles.Forsyth		s = 1.;
529*37da2899SCharles.Forsyth		j = ndig;
530*37da2899SCharles.Forsyth		while(k%3!=0){
531*37da2899SCharles.Forsyth			k--;
532*37da2899SCharles.Forsyth			u/=10.;
533*37da2899SCharles.Forsyth			s*=10.;
534*37da2899SCharles.Forsyth			j++;
535*37da2899SCharles.Forsyth		}
536*37da2899SCharles.Forsyth		if(j-3>0){
537*37da2899SCharles.Forsyth			k+=3;
538*37da2899SCharles.Forsyth			u*=1000.;
539*37da2899SCharles.Forsyth			s/=1000.;
540*37da2899SCharles.Forsyth		}
541*37da2899SCharles.Forsyth	}else{ # k<0
542*37da2899SCharles.Forsyth		s = 1.;
543*37da2899SCharles.Forsyth		j = ndig;
544*37da2899SCharles.Forsyth		while(k%3!=0){
545*37da2899SCharles.Forsyth			k++;
546*37da2899SCharles.Forsyth			u*=10.;
547*37da2899SCharles.Forsyth			s/=10.;
548*37da2899SCharles.Forsyth			j--;
549*37da2899SCharles.Forsyth		}
550*37da2899SCharles.Forsyth		if(j<0){
551*37da2899SCharles.Forsyth			k-=3;
552*37da2899SCharles.Forsyth			u/=1000.;
553*37da2899SCharles.Forsyth			s*=1000.;
554*37da2899SCharles.Forsyth		}
555*37da2899SCharles.Forsyth	}
556*37da2899SCharles.Forsyth	return (lab1, labn, labinc, k, u, s);
557*37da2899SCharles.Forsyth}
558