(* * plotlib - graphics graph plotting package * *) (* ------------------------------------------------------------------- *) {translate logical x location into physical pixel location} function get_phys_x(vx: real): integer; var x: real; begin if (vx > maxx) then vx := maxx; if (vx < minx) then vx := minx; x := (phys_maxx - phys_minx) * (vx - minx) / (maxx - minx) + phys_minx; get_phys_x := trunc(x); end; {translate logical y location into physical pixel location} function get_phys_y(vy: real): integer; var y: real; begin if (vy > maxy) then vy := maxy; if (vy < miny) then vy := miny; y := (phys_maxy - phys_miny) * (vy - miny) / (maxy - miny) + phys_miny; get_phys_y := trunc(y); end; (* ------------------------------------------------------------------- *) procedure draw(x1,y1,x2,y2,color: integer); begin SetColor(color); Line(x1,y1,x2,y2); end; procedure plot(x1,y1,color: integer); begin SetColor(color); PutPixel(x1,y1,$FFFF); end; (* ------------------------------------------------------------------- *) {connect two logical points with a line} procedure connect(x1,y1,x2,y2: real); var px1,py1,px2,py2: integer; begin px1 := get_phys_x(x1); if x2 <> x1 then px2 := get_phys_x(x2) else px2 := px1; py1 := get_phys_y(y1); if y2 <> y1 then py2 := get_phys_y(y2) else py2 := py1; if (px1 <> px2) or (py1 <> py2) then draw(px1,py1,px2,py2,color) else plot(px1,py1,color); end; {place a tick mark on a point} procedure tick(x1,y1: real); begin plot(get_phys_x(x1),get_phys_y(y1),color); end; (* ------------------------------------------------------------------- *) {determine a nice looking scale} procedure determinescale (var world_min: real; var world_max: real; var stepsz: real; var stepcnt: integer; maxstep: integer); var new_min: real; new_max: real; damper: integer; pct: real; range: real; curstep: integer; w: real; const limit = 32000; {maximum number of iterations to determine the new scale boundries} (* return next higher stepsize multiplier *) function nextstep: real; begin case curstep of 1: nextstep := 2; {2} 2: nextstep := 2.5; {5} 3: nextstep := 2; {10} end; curstep := curstep + 1; if curstep > 3 then curstep := 1; end; (* return number of steps with current stepsz *) function nsteps: integer; var n: real; begin if stepsz = 0.0 then n := 0.0 else n := (new_max - new_min)/ stepsz + 1.5; if n < 0.0 then n := 0.0; if n >= maxint then n := maxint-1.0; nsteps := trunc (n); end; begin {determine proper step size} (* find best step size *) new_min := world_min; new_max := world_max; curstep := 1; stepsz := 1; while (nsteps < maxstep) and (nsteps > 0) do stepsz := stepsz / 10.0; while (nsteps > maxstep) and (nsteps > 0) do stepsz := stepsz * nextstep; (* * note - this process will take forever if you have a very narrow * range that is sitting on a huge offset. the damper variable * will cause this routine to give up after limit iterations * if it has not found the endpoints *) damper := 0; repeat new_min := 0.0; {determine even endpoints based on stepsz} new_max := 0.0; if stepsz <> 0.0 then begin while (new_min <= world_min) and (damper < limit) do begin damper := damper + 1; new_min := new_min + abs(stepsz)*200.0; end; w := world_min; while (new_min > w) and (damper < limit) do begin damper := damper + 1; new_min := new_min - abs(stepsz); end; new_max := new_min; while (new_max >= world_max) and (damper < limit) do begin damper := damper + 1; new_max := new_max - abs(stepsz); end; w := world_max; while (new_max < w) and (damper < limit) do begin damper := damper + 1; new_max := new_max + abs(stepsz); end; end; (* if new min/max causes extra steps, then go to a larger step size and try again *) stepcnt := nsteps; if stepcnt > maxstep then stepsz := stepsz * nextstep; until stepcnt <= maxstep; world_min := new_min; {assign final return values} world_max := new_max; end; {PLOT_set_scale} (* ------------------------------------------------------------------- *) {place a marker at a logical point} procedure marker(x,y: real; style: integer); begin case style of 1: begin {place an X on the point} draw(get_phys_x(x)-mark_x,get_phys_y(y)-mark_y, get_phys_x(x)+mark_x,get_phys_y(y)+mark_y,yellow); draw(get_phys_x(x)-mark_x,get_phys_y(y)+mark_y, get_phys_x(x)+mark_x,get_phys_y(y)-mark_y,yellow); end; 2: begin {place an box around the point} draw(get_phys_x(x)-mark_x,get_phys_y(y)-mark_y, get_phys_x(x)-mark_x,get_phys_y(y)+mark_y,yellow); draw(get_phys_x(x)+mark_x,get_phys_y(y)-mark_y, get_phys_x(x)+mark_x,get_phys_y(y)+mark_y,yellow); draw(get_phys_x(x)-mark_x,get_phys_y(y)+mark_y, get_phys_x(x)+mark_x,get_phys_y(y)+mark_y,yellow); draw(get_phys_x(x)-mark_x,get_phys_y(y)-mark_y, get_phys_x(x)+mark_x,get_phys_y(y)-mark_y,yellow); end; 3: begin {place a triangle on the point} draw(get_phys_x(x)-mark_x,get_phys_y(y)+mark_y, get_phys_x(x) ,get_phys_y(y)-mark_y,yellow); draw(get_phys_x(x)+mark_x,get_phys_y(y)+mark_y, get_phys_x(x) ,get_phys_y(y)-mark_y,yellow); draw(get_phys_x(x)+mark_x,get_phys_y(y)+mark_y, get_phys_x(x)-mark_x,get_phys_y(y)+mark_y,yellow); end; 4: begin {place an inverted triangle on the point} draw(get_phys_x(x)-mark_x,get_phys_y(y)-mark_y, get_phys_x(x) ,get_phys_y(y)+mark_y,yellow); draw(get_phys_x(x)+mark_x,get_phys_y(y)-mark_y, get_phys_x(x) ,get_phys_y(y)+mark_y,yellow); draw(get_phys_x(x)+mark_x,get_phys_y(y)-mark_y, get_phys_x(x)-mark_x,get_phys_y(y)-mark_y,yellow); end; end; end; (* ------------------------------------------------------------------- *) {place a label on the y axis} procedure labely(y: real); var s: string; begin MoveTo(1,get_phys_y(y)); str(y:12:2,s); OutText(s); end; (* ------------------------------------------------------------------- *) {place a tick mark on the y axis} procedure ticky(y: real); begin draw(trunc(phys_minx-mark_x),get_phys_y(y), trunc(phys_minx), get_phys_y(y),color); end; (* ------------------------------------------------------------------- *) {place a label on the x axis} procedure labelx(x: real); var s: string; begin MoveTo(get_phys_x(x),trunc(phys_miny)+10); str(x:0:2,s); OutText(s); end; (* ------------------------------------------------------------------- *) {place a tick mark on the x axis} procedure tickx(x: real); begin draw(get_phys_x(x),trunc(phys_miny-mark_y), get_phys_x(x),trunc(phys_miny),color); end; (* ------------------------------------------------------------------- *) {output the x axis scales} procedure putxscale; var i,j: integer; y: real; x: real; px,py: integer; begin x := minx; for i := 1 to nxsteps do begin labelx(x); px := get_phys_x(x); y := miny; for j := 1 to numtics*nysteps do begin py := get_phys_y(y); draw(px,py,px,py,color); y := y + ystep/numtics; end; for j := 1 to numtics do begin tickx(x); x := x + xstep/numtics; end; end; end; (* ------------------------------------------------------------------- *) {output the y axis scales} procedure putyscale; var i,j: integer; y: real; begin y := miny; for i := 1 to nysteps do begin labely(y); connect(minx,y,maxx,y); for j := 1 to numtics do begin ticky(y); y := y + ystep / numtics; end; end; end; (* ------------------------------------------------------------------- *) {output the border and scales for the graph} procedure border; begin determinescale(minx,maxx,xstep,nxsteps,6); determinescale(miny,maxy,ystep,nysteps,6); color := green; putxscale; putyscale; color := red; end; (* ------------------------------------------------------------------- *) procedure plot_data(variable_number: integer; x: integer; y: real); begin tick(int(x),y); if (x mod 40) = 0 then marker(int(x),y,variable_number); end; (* ------------------------------------------------------------------- *) procedure event(x: integer; note: string); begin connect(int(x),miny,int(x),maxy); {writeln(note);} end; (* ------------------------------------------------------------------- *) procedure open_graph; begin Text_Mode := LastMode; Graph_Driver := detect; InitGraph(Graph_Driver,Graph_Mode,Driver_Path); phys_maxx := GetMaxX; phys_minx := trunc(int(GetMaxX)/6.2); phys_miny := trunc(int(GetMaxY)*154.0/200.0); phys_maxy := phys_miny div 5; end; (* ------------------------------------------------------------------- *) procedure close_graph; begin CloseGraph; TextMode(Text_Mode); window(1,1,80,25); end;