import java.awt.*; public class QuadCanvas extends Canvas { private Quads[] CanvasQuads; /* Holds the array of functions to be plotted when necessary. */ private int NumberOfQuads=0; // Size of the array. Set by the constructor. public double globalYmin,globalYmax,globalXmin,globalXmax; /* These are the values for the global coordinate system for the plot. */ public int xSize=420; // The horizontal size for the drawing canvas int ySize=420; // The vertical size for the drawing canvas public boolean DrawAxes; // True if axes are to be drawn public boolean DrawGrid; // True if grid lines are to be drawn. public int NumberOfGridLines; /* Current number of grid lines (20 by default, set by the constructor. */ private boolean ClearIt; /* When true, causes the plotted area to be redrawn blank. This is temporary. As soon as any event causes a redraw, ClearIt will already have been set false and the redraw will occur. */ public boolean Clicked; /* Set true if the mouse is clicked on the drawing region. */ public int ClickX; /* Set to the x coordinate of the last point where a click occured on the drawing region. */ /* Constructor - sets values for the variables for this drawing area. Notice that it expects an array of Quads at construction time. These are the quads it uses for drawing. */ QuadCanvas(Quads [] InputCanvasQuads, int InputNumberOfQuads) { NumberOfQuads=InputNumberOfQuads; CanvasQuads=new Quads[InputNumberOfQuads]; for(int i=0;i=0) && (x<=xSize)) { ClickX=x; Clicked=true; } return true; } // Clears the drawing area temporarily. public void Clear(boolean InClear) { ClearIt=InClear; repaint(); } /* Called by the paint function to clear the screen before a plot of all the functions begins. */ public void QuadCanvasClear(Graphics g) { g.setColor(Color.white); g.fillRect(0,0,xSize,ySize); } // drawFunction draws the single function represented by Quads Function. private void drawFunction(Graphics g,Quads Function) { g.setColor(Function.QuadColor); double Height=globalYmax-globalYmin; double Width=globalXmax-globalXmin; double Integral=0.0; int newx=0; int newy=0; int oldyd=0; int oldyi=0; int newyi=0; int newyd=0; int ZeroSpot=ySize - (int) (-globalYmin/Height*ySize); double x=Function.Xmin; double y; double yd=0.0; double yi=0.0; if(Function.XminglobalXmax) EndX=globalXmax; double dx=Width/((double) xSize); if(Function.PlotIntegral) { /* Compute the approximate integral to the left endpoint so that we always compute the integral from 0 to x. */ double IntegralX=x; yi=0.0; if(IntegralX<0.0) { while(IntegralX<=0.0) { yi=yi-Function.Evaluate(IntegralX); IntegralX=IntegralX+dx; } yi=yi*dx; } else { IntegralX=0.0; while(IntegralX<=x) { yi=yi+Function.Evaluate(IntegralX); IntegralX=IntegralX+dx; } yi=yi*dx; } oldyi=ySize-(int) (ySize*(yi-globalYmin)/Height); newyi=oldyi; } if (!Function.Linear) { // Do a dot plot if(dx>0.0) { while(x<=EndX) { y=Function.Evaluate(x); if(!Function.EvaluationError) { newx=(int) ((x-globalXmin)/Width*xSize); newy=ySize-(int) (ySize*(y-globalYmin)/Height); if((newy<=10*ySize) && (newy>=-10*ySize)) { if (Function.IntegrateIt && (x>=Function.LeftLimit) && (x<=Function.RightLimit)){ // Here is where the integration region gets // drawn. g.setColor(Color.yellow); if(DrawAxes) // Don't cover up the axes. if(newy>ZeroSpot) g.drawLine(newx,ZeroSpot+1,newx,newy); else g.drawLine(newx,ZeroSpot-1,newx,newy); else g.drawLine(newx,ZeroSpot,newx,newy); g.setColor(Function.QuadColor); } g.fillRect(newx-1,newy-1,2,2); if(Function.PlotDerivative) { yd=2.0*(Function.Evaluate(x+dx/2.0)-y)/dx; if(!Function.EvaluationError) { newy=ySize- (int) (ySize*(yd-globalYmin)/Height); if((newy<=10*ySize) && (newy>=-10*ySize)) { g.setColor(Color.orange); g.fillRect(newx,newy,2,2); g.setColor(Function.QuadColor); } } } if(Function.PlotIntegral) { yi=yi+y*dx; newyi=ySize-(int) (ySize*(yi-globalYmin)/Height); if((newyi<=10*ySize) && (newyi>=-10*ySize)) { g.setColor(Color.green); g.fillRect(newx,newyi,2,2); g.setColor(Function.QuadColor); } } } } x=x+dx; } } y=Function.Evaluate(EndX); // Sometimes we 'miss' the last point. if(!Function.EvaluationError) g.fillRect((int) ((EndX-globalXmin)/Width*xSize), ySize-(int) (ySize*(y-globalYmin)/Height),2,2); } else { // A plot that draws line segments between adjacent points. if(dx>0.0) { int oldx=0; int oldy=0; int i; boolean LastOK=false; /* LastOK false means that the previous x value caused a function evaluation error, so it is necessary to avoid drawing a line between that point and the next point. We start with LastOK false because the first point has nothing to connect to. */ boolean LastOKd=false; /* LastOKd works just like LastOK when plotting the derivative. */ while(x<=EndX) { y=Function.Evaluate(x); if(Function.EvaluationError) { LastOK=false; LastOKd=false; } else { newx=(int) ((x-globalXmin)/Width*xSize); newy=ySize-(int) (ySize*(y-globalYmin)/Height); if((newy>10*ySize) || (newy<-10*ySize)) LastOK=false; if(LastOK) { if(Function.IntegrateIt && (x>=Function.LeftLimit) && (x<=Function.RightLimit)) { // Draw Integration region g.setColor(Color.yellow); if(DrawAxes) // Don't cover up the axes. if(newy>ZeroSpot) g.drawLine(newx,ZeroSpot+1,newx,newy); else g.drawLine(newx,ZeroSpot-1,newx,newy); else g.drawLine(newx,ZeroSpot,newx,newy); g.setColor(Function.QuadColor); } // draw the line between the previous point // (oldx,oldy) and this one (newx,newy). g.drawLine(oldx,oldy,newx,newy); g.drawLine(oldx-1,oldy,newx-1,newy); g.drawLine(oldx,oldy-1,newx,newy-1); g.drawLine(oldx+1,oldy,newx+1,newy); g.drawLine(oldx,oldy+1,newx,newy+1); } else LastOK=true; if(Function.PlotDerivative) { yd=2.0*(Function.Evaluate(x+dx/2.0)-y)/dx; if(Function.EvaluationError) LastOKd=false; else { newyd=ySize-(int) (ySize*(yd-globalYmin)/Height); if(LastOKd) { g.setColor(Color.orange); g.drawLine(oldx,oldyd,newx,newyd); g.drawLine(oldx-1,oldyd,newx-1,newyd); g.drawLine(oldx,oldyd-1,newx,newyd-1); g.drawLine(oldx+1,oldyd,newx+1,newyd); g.drawLine(oldx,oldyd+1,newx,newyd+1); g.setColor(Function.QuadColor); } else LastOKd=true; oldyd=newyd; } } if(Function.PlotIntegral) { yi=yi+y*dx; newyi=ySize-(int) (ySize*(yi-globalYmin)/Height); if((newyi<10*ySize) && (newyi>-10*ySize)) { g.setColor(Color.green); g.drawLine(oldx,oldyi,newx,newyi); g.drawLine(oldx-1,oldyi,newx-1,newyi); g.drawLine(oldx,oldyi-1,newx,newyi-1); g.drawLine(oldx+1,oldyi,newx+1,newyi); g.drawLine(oldx,oldyi+1,newx,newyi+1); g.setColor(Function.QuadColor); } } // This point becomes the old point next time through. oldx=newx; oldy=newy; oldyi=newyi; } x=x+dx; } y=Function.Evaluate(EndX); // Do that last point that might get missed. if(!Function.EvaluationError && LastOK) { newx=(int) ((EndX-globalXmin)/Width*xSize); newy=ySize-(int) (ySize*(y-globalYmin)/Height); g.drawLine(oldx,oldy,newx,newy); g.drawLine(oldx-1,oldy,newx-1,newy); g.drawLine(oldx,oldy-1,newx,newy-1); g.drawLine(oldx+1,oldy,newx+1,newy); g.drawLine(oldx,oldy+1,newx,newy+1); } } } // After drawing the integration region, make sure it disappears at // the next plot. Function.IntegrateIt=false; } /* As usual, paint is called by repaint either directly (as in drawFunctions above), or as a result of a necessary redraw when the drawing region becomes exposed after being hidden, or whatever. In any case, our paint checks several things. It first clears the drawing area (with QuadCanvasClear), then checks to see if DrawGrid is true and the NumberOfGridLines>0. If so, it draws the grid array. It then checks to see if DrawAxes is true. If so, it draws the axes. It then goes through the entire array of functions and if any of them are active, it calls drawFunction to plot that function. */ public void paint(Graphics g) { int i,Value; double Size,gridValue; QuadCanvasClear(g); // clear canvas if(!ClearIt) { // plot grid if(DrawGrid & (NumberOfGridLines>0)) { g.setColor(Color.lightGray); double Width=globalXmax-globalXmin; double Height=globalYmax-globalYmin; Size=Math.max(Width,Height)/NumberOfGridLines; if (((globalXmin<=0.0) && (globalXmax>=0.0)) || ((globalYmin<=0.0) && (globalYmax>=0.0))) { // Plot vertical grid lines from 0 to the right i=0; while((i*Size)<=globalXmax) { Value=(int)((i*Size-globalXmin)/Width*xSize); g.drawLine(Value,0,Value,ySize); i++; } // Plot vertical grid lines from 0 to the left i=-1; while((i*Size)>=globalXmin) { Value=(int)((i*Size-globalXmin)/Width*xSize); g.drawLine(Value,0,Value,ySize); i--; } // Plot horizontal grid lines from 0 to the top i=0; while((i*Size)<=globalYmax) { Value=ySize-(int) ((i*Size-globalYmin)/ Height*ySize); g.drawLine(0,Value,xSize,Value); i++; } // Plot horizontal grid lines from 0 to the top i=-1; while((i*Size)>=globalYmin) { Value=ySize-(int) ((i*Size-globalYmin)/ Height*ySize); g.drawLine(0,Value,xSize,Value); i--; } } else { /* Neither axis is on the grid, so we simply put up gridlines from left side and bottom to right and top at equal spacing */ gridValue=Size+globalXmin; while(gridValue=0.0)) for(i=-1;i<2;i++) { Value=(int) (-globalXmin/ (globalXmax-globalXmin)* xSize); g.drawLine(Value+i,0,Value+i,ySize); } if ((globalYmin<=0.0) & (globalYmax>=0.0)) for(i=-1;i<2;i++) { Value=ySize-(int) (-globalYmin/ (globalYmax-globalYmin)* ySize); g.drawLine(0,Value+i,xSize,Value+i); } } for(i=0;i