import ifi.plot.*; import java.awt.*; import java.util.Vector; /* * The PlotArea class is used to create plots of discrete functions. * An arbitrary number of functions may be plotted. * * This initial plot area will have zero size. The * size should preferably be controlled by a layout manager that provides * dynamical resizeing of its components. It is also possible to * use the setSize, setPreferedSize and setMinimumSize methods in * Component. * */ class PlotArea extends DoubleBufferedCanvas{ // Store the functions in a vector. Vector functions = new Vector(); // If user supplies the bounding box or calls calculateBounds, // we store the bounding box here. If bounds==null, then // updateCanvas should recalculate a bounding box each time // it is called (autoscale of axis). BoundingBox bounds; // Can be used when calling the getSample function in PlotableFunction. // Efficiency only. We avoid allocating many small arrays. static double p[] = new double[2]; /* * Add a function to the collection of functions to be plotted. */ public void addFunction(PlotableFunction f){ functions.addElement(f); updatePlot(); } /* * Remove a function from the collection of functions to be plotted. * If this is the last function in the set, the bounding box * information will be deleted. */ public void removeFunction(PlotableFunction f){ functions.removeElement(f); if(functions.size() == 0) bounds = null; updatePlot(); } /* * Empty the collection of functions to be plotted. * The bounding box information will be deleted. */ public void removeAllFunctions(){ functions.removeAllElements(); bounds = null; updatePlot(); } /* * Calculate and store the extent of all functions currently * in the collection of functions to be plotted. The bounding * box defined by this extent will be used when plotting the * functions. Functions added after caling this method will * not influence the bounding box used when plotting. */ public void calculateBounds(){ bounds = new BoundingBox(); updateBounds(bounds); } /* * Use a fixed bounding box. The extent of the functions * in the collection of functions is ignored. */ public void setBoundingBox(BoundingBox b){ bounds = b; updatePlot(); } /* * Update the provided bounding box so that all functions * in the collection of plottable functions fits whitin * the bounding box. */ protected void updateBounds(BoundingBox bb){ for(int i = 0; i < functions.size(); i++) bb.update((PlotableFunction) functions.elementAt(i)); } /* * This functions can be used to force an update of the canvas. * It is called automaticly when the number of functions changes, or * if the bounding box is changed. */ public void updatePlot(){ updateCanvas(); } /* * Draw all functions and the coordinate system. Put a 10 pixel * margin around the coordinate system. */ synchronized protected void updateCanvas(Graphics g){ // Find size and position of canvas Dimension d = getSize(); // Calculate coordinates of drawing area. // The margin area is for labels. int margin = 50; int canvas_width = d.width - 2 * margin; int canvas_height = d.height - 2 * margin; int canvas_left = margin; int canvas_right = canvas_left + canvas_width; int canvas_top = margin; int canvas_bottom = canvas_top + canvas_height; // Calculate scaling and translations // We must first find the bounding box of the data. // The bounding box is either given or must be calculated. if(bounds==null) bounds = new BoundingBox(); updateBounds(bounds); double sx = canvas_width / bounds.getWidth(); double sy = - canvas_height / bounds.getHeight(); double tx = canvas_left - bounds.getMinX() / bounds.getWidth() * canvas_width; double ty = canvas_bottom + bounds.getMinY() / bounds.getHeight() * canvas_height; // Clear old image g.clearRect(0, 0, d.width, d.height); g.setColor(Color.black); // Draw coordinate system and put labels on the axis if(functions.size() > 0){ g.drawLine(canvas_left, canvas_bottom, canvas_left, canvas_top); g.drawLine(canvas_left, canvas_bottom, canvas_right, canvas_bottom); g.drawString(String.valueOf(bounds.getMinX()), canvas_left, canvas_bottom + margin / 2); g.drawString(String.valueOf(bounds.getMaxX()), canvas_right, canvas_bottom + margin / 2); g.drawString(String.valueOf(bounds.getMinY()), margin / 4, canvas_bottom); g.drawString(String.valueOf(bounds.getMaxY()), margin / 4, canvas_top); } // Set clip area for function data (not needed!) // g.clipRect(canvas_left-1, canvas_top-1, canvas_width+2, canvas_height+2); // Loop through functions and draw lines between the samples. for(int i = 0; i < functions.size(); i++){ PlotableFunction f = (PlotableFunction) functions.elementAt(i); g.setColor(f.getColor()); int n = f.numSamplingPoints(); f.getSample(0, p); int start_x = (int)(sx * p[0] + tx); int start_y = (int)(sy * p[1] + ty); for(int j = 1; j < n; j++){ f.getSample(j, p); int stop_x = (int)(sx * p[0] + tx); int stop_y = (int)(sy * p[1] + ty); g.drawLine(start_x, start_y, stop_x, stop_y); start_x = stop_x; start_y = stop_y; } } } }