package gve.calc;
import java.awt.*;
import gve.calc.formula.*;

public class PlotCanvas extends Canvas
{
	public static final byte DOTS = 0;
	public static final byte CONNECTDOTS = 1;
	public static final byte INTERVALS = 2;
	private byte plotMode;
	private Formula [] funcs;
	private double xmin = -10, xmax = 10, ymin = -10, ymax = 10;
	private Color [] defaultColors = { Color.black, Color.green,Color.blue };
	private Layer userlayer;
	
Animation threads can use isPlotting() to check when the picture has been updated
private boolean plotting = false; private boolean dbuffer = false; private Image offscreen; public PlotCanvas() { setBackground(Color.white); setForeground(Color.black); plotMode = CONNECTDOTS; } public PlotCanvas(Formula f) { this(); setFunction(f); } public void addFunction(Formula f) { Formula [] newfuncs; if (funcs == null) newfuncs = new Formula[1]; else newfuncs = new Formula[funcs.length+1]; System.arraycopy(funcs,0,newfuncs,0,funcs.length); newfuncs[funcs.length] = f; funcs = newfuncs; } public void setFunction(Formula f) { funcs = new Formula[1]; funcs[0] = f; repaint(); } public void setDbuffer(boolean b) { dbuffer = b; } public void setLayer(Layer l) { userlayer = l; } public void removeFunctions() { funcs = null; repaint(); } public void setPlotMode(byte mode) { plotMode = mode; repaint(); } public void setXmin(double d) { xmin = d; repaint(); } public void setXmax(double d) { xmax = d; repaint(); } public void setYmin(double d) { ymin = d; repaint(); } public void setYmax(double d) { ymax = d; repaint(); } public void setXrange(double min,double max) { xmin = min; xmax = max; repaint(); } public void setYrange(double min,double max) { ymin = min; ymax = max; repaint(); } public void setRanges(double xmin,double xmax,double ymin,double ymax) { this.xmin = xmin; this.xmax = xmax; this.ymin = ymin; this.ymax = ymax; repaint(); } public double getXmin() { return xmin; } public double getXmax() { return xmax; } public double getYmin() { return ymin; } public double getYmax() { return ymax; } public boolean isPlotting() { return plotting; }
Zoom in on a detail. (factor < 1) or zoom out to show more (zoom > 1)
public void zoom(double factor) { double width = xmax-xmin; double height = ymax-ymin; xmin = xmin + width/2 - width*factor/2; xmax = xmin + width*factor; ymin = ymin + height/2 - height*factor/2; ymax = ymin + height*factor; repaint(); }
This is basically a stripped down version of paintConnectDots()
private void paintDots(Graphics g,Formula func) { Dimension bound = getSize(); double step = (xmax-xmin) / bound.width; Evaluator ev = new MultiEvaluator(); StandardFunctions.registerFunctions(ev); double x; int screenX = 0; Real dv = new Real(0.0); ev.defineVariable("x",dv); for (x=xmin; x<=xmax; x+=step,screenX++) { dv.doubleValue = x; Part res = func.evaluate(ev); if (res instanceof Real) { double y = ((Real)res).doubleValue; if (y<ymin || y>ymax) continue; int screenY = (int)((ymax-y)/(ymax-ymin)*bound.height); g.drawLine(screenX,screenY,screenX,screenY); } } } private void paintConnectDots(Graphics g,Formula func) { Dimension bound = getSize(); double step = (xmax-xmin) / bound.width; Evaluator ev = new MultiEvaluator(); StandardFunctions.registerFunctions(ev); // initialization of prevY is not necessary, but else // the compiler complains int prevY = 0; boolean previous = false; double x; int screenX = 0; Real dv = new Real(0.0); ev.defineVariable("x",dv); for (x=xmin; x<=xmax; x+=step,screenX++) { dv.doubleValue = x; Part res = func.evaluate(ev); if (res instanceof Real) { double y = ((Real)res).doubleValue; if (y<ymin || y>ymax) { previous = false; continue; } int screenY = (int)((ymax-y)/(ymax-ymin)*bound.height); if (previous) { g.drawLine(screenX-1,prevY,screenX,screenY); } else { previous = true; // silly, but plots a pixel g.drawLine(screenX,screenY,screenX,screenY); } prevY = screenY; } else previous = false; } } private void paintIntervals(Graphics g,Formula func) { Dimension bound = getSize(); double step = (xmax-xmin) / bound.width; int height = bound.height; Evaluator ev = new MultiEvaluator(); StandardFunctions.registerFunctions(ev); double x; int screenX = 0; Interval interv = new Interval(0,1,false,true); ev.defineVariable("x",interv); for (x=xmin; x<=xmax; x+=step,screenX++) { interv.low = x; interv.high = x + step; //System.out.print(interv); Part res = func.evaluate(ev); paintInterval(res,g,screenX,height); } }
Helper function for paintIntervals()
private void paintInterval(Part obj,Graphics g,int screenX,int height) { //System.out.println("\t->"+obj); if (obj instanceof Interval) { Interval interv = (Interval)obj; int screenL; if (interv.low < ymin) screenL = height; else if (interv.low > ymax) return; else screenL = (int)((ymax-interv.low)/(ymax-ymin)*height); int screenH; if (interv.high < ymin) return; else if (interv.high > ymax) screenH = 0; else screenH = (int)((ymax-interv.high)/(ymax-ymin)*height); //System.out.println("->>> plot pixels "+screenL+" --- "+screenH); g.drawLine(screenX,screenL,screenX,screenH); } else if (obj instanceof OperatorUnion) { OperatorUnion op = (OperatorUnion)obj; paintInterval(op.left,g,screenX,height); paintInterval(op.right,g,screenX,height); } } public int xToPix(double x) { return (int)((x-xmin)/(xmax-xmin)*getSize().width); } public int yToPix(double y) { return (int)((ymax-y)/(ymax-ymin)*getSize().height); } public void invalidate() { super.invalidate(); offscreen = null; } public void update(Graphics g) { if (dbuffer) paint(g); else super.update(g); } public void paint(Graphics g) { if (funcs == null) return; plotting = true; Graphics oldg = null; Dimension siz = getSize(); if (dbuffer) { if (offscreen == null) offscreen = createImage(siz.width,siz.height); oldg = g; g = offscreen.getGraphics(); g.setClip(0,0,siz.width,siz.height); g.setColor(getBackground()); g.fillRect(0,0,siz.width,siz.height); g.setColor(Color.black); } setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); if (userlayer != null) { userlayer.paintLayer(g,siz.width,siz.height); } for (int i = funcs.length-1; i>=0; i--) { Formula f = funcs[i]; if (f == null) continue; if (i < defaultColors.length) g.setColor(defaultColors[i]); else g.setColor(Color.black); switch (plotMode) { case DOTS: paintDots(g,f); break; case CONNECTDOTS: paintConnectDots(g,f); break; case INTERVALS: paintIntervals(g,f); break; } } if (dbuffer) { oldg.drawImage(offscreen,0,0,null); g.dispose(); } setCursor(Cursor.getDefaultCursor()); plotting = false; } }