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