package graph; import java.awt.*; import java.applet.*; import java.util.*; import java.lang.*; import java.io.StreamTokenizer; import java.io.InputStream; import java.io.IOException; import java.net.URL; /* ************************************************************************** ** ** Class graph.Graph2D ** ************************************************************************** ** Modified from Leigh Brookshaw's graph classes by Michael Cross ** Copyright (C) 1995, 1996 Leigh Brookshaw ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ************************************************************************** ** ** class Graph2D extends Canvas ** ** The main entry point and interface for the 2D graphing package. ** This class keeps track of the DataSets and the Axes. ** It has the main drawing engine that positions axis etc. ** *************************************************************************/ /** * This is the main plotting class. It partitions the canvas to contain the * specified axes with the remaining space taken with the plotting region. * Axes are packed against the walls of the canvas. The paint and * update methods of this class handle all the drawing operations of the * graph. This means that independent components like Axis and DataSets must be * registered with this class to be incorporated into the plot. * * @version LB1.12 MCC 3/19/97 * @author Leigh Brookshaw modified by Michael Cross */ public class Graph2D extends Canvas { /* ** Default Background Color */ private Color DefaultBackground = null; /* ********************* ** ** Protected Variables ** *********************/ /** * A vector list of All the axes attached * @see Graph2d#attachAxis() */ protected Vector axis = new Vector(4); /** * A vector list of All the DataSets attached * @see Graph2d#attachDataSet() * @see DataSet */ protected Vector dataset = new Vector(10); /** * The markers that may have been loaded * @see Graph2D#setMarkers() */ protected Markers markers = null; /** * The blinking "data loading" thread * @see Graph2D#startedloading() */ protected LoadMessage load_thread = null; /** * The background color for the data window */ protected Color DataBackground = null; /************************************** ** ** Protected Variables added by MCC ** **************************************/ /* ** The offscreen graphics */ protected Graphics lg = null; protected Image offScreenImage; protected Graphics offScreenGraphics=null; /* ** Size of graphics region */ protected Rectangle r_save=null; /* ** Size of graphics region clipped by axes etc */ protected Rectangle r_g=null; /* ** True if new graphics region */ protected boolean newRectangle = false; /* ********************** ** ** Public Variables ** *********************/ /** * If this is greater than zero it means that * data loading threads are active so the message "loading data" * is flashed on the plot canvas. When it is back to zero the plot * progresses normally */ public int loadingData = 0; /** * The width of the border at the top of the canvas. This allows * slopover from axis labels, legends etc. */ public int borderTop = 20; /** * The width of the border at the bottom of the canvas. This allows * slopover from axis labels, legends etc. */ public int borderBottom = 20; /** * The width of the border at the left of the canvas. This allows * slopover from axis labels, legends etc. */ public int borderLeft = 20; /** * The width of the border at the right of the canvas. This allows * slopover from axis labels, legends etc. */ public int borderRight = 20; /** * If set true a frame will be drawn around the data window. * Any axes will overlay this frame. */ public boolean frame = true; /** * The color of the frame to be drawn */ public Color framecolor; /** * If set true (the default) a grid will be drawn over the data window. * The grid will align with the major tic marks of the Innermost axes. */ public boolean drawgrid = true; /** * The color of the grid to be drawn */ public Color gridcolor = Color.pink; /** * If set true (the default) a grid line will be drawn * across the data window * at the zeros of the innermost axes. */ public boolean drawzero = true; /** * The color of the zero grid lines. */ public Color zerocolor = Color.orange; /** * The rectangle that the data will be plotted within. This is an output * variable only. */ public Rectangle datarect = new Rectangle(); /** * If set true (the default) the canvas will be set to the background * color (erasing the plot) when the update method is called. * This would only be changed for special effects. */ public boolean clearAll = true; /** * If set true (the default) everything associated with the plot * will be drawn when the update method or paint method are called. * Normally * only modified for special effects */ public boolean paintAll = true; /** * Modify the position of the axis and the range of the axis so that * the aspect ratio of the major tick marks are 1 and the plot is square * on the screen */ public boolean square = false; /** * Text to be painted Last onto the Graph Canvas. */ public TextLine lastText = null; /* ******************* ** ** Public Methods ** *******************/ /** * Load and Attach a DataSet from a File. * The method loads the data into a DataSet class * and attaches the class to the graph for plotting. * * The data is assumed to consist * (at this stage) 2 ASCII columns of numbers x, y. As always blank lines * are ignored and everything following # is ignored as a comment. * * @param file The URL of the data file to read. * @return The DataSet constructed containing the data read. */ public DataSet loadFile( URL file) { byte b[] = new byte[50]; int nbytes = 0; int max = 100; int inc = 100; int n = 0; double data[] = new double[max]; InputStream is = null; boolean comment = false; int c; try { is = file.openStream(); while( (c=is.read()) > -1 ) { switch (c) { case '#': comment = true; break; case '\r': case '\n': comment = false; case ' ': case '\t': if( nbytes > 0 ) { String s = new String(b,0,0,nbytes); data[n] = Double.valueOf(s).doubleValue(); n++; if( n >= max ) { max += inc; double d[] = new double[max]; System.arraycopy(data, 0, d, 0, n); data = d; } nbytes = 0; } break; default: if( !comment ) { b[nbytes] = (byte)c; nbytes++; } break; } } if (is != null) is.close(); } catch(Exception e) { System.out.println("Failed to load Data set from file "); e.printStackTrace(); if (is != null) try { is.close(); } catch (Exception ev) { } return null; } return loadDataSet(data,n/2); } /** * Load and Attach a DataSet from an array. * The method loads the data into a DataSet class * and attaches the class to the graph for plotting. * * The data is assumed to be stored * in the form x,y,x,y,x,y.... A local copy of the data is made. * * @param data The data to be loaded in the form x,y,x,y,... * @param n The number of (x,y) data points. This means that the * minimum length of the data array is 2*n. * @return The DataSet constructed containing the data read. */ public DataSet loadDataSet( double data[], int n ) { DataSet d; try { d = new DataSet(data, n); dataset.addElement( d ); d.g2d = this; } catch (Exception e) { System.out.println("Failed to load Data set "); e.printStackTrace(); return null; } return d; } /** * Attach a DataSet to the graph. By attaching the data set the class * can draw the data through its paint method. */ public void attachDataSet( DataSet d ) { if( d != null) { dataset.addElement( d ); d.g2d = this; } } /** * Detach the DataSet from the class. Data associated with the DataSet * will nolonger be plotted. * * @param d The DataSet to detach. */ public void detachDataSet( DataSet d ) { if(d != null) { if(d.xaxis != null) d.xaxis.detachDataSet(d); if(d.yaxis != null) d.yaxis.detachDataSet(d); dataset.removeElement(d); } } /** * Detach All the DataSets from the class. */ public void detachDataSets() { DataSet d; int i; if(dataset == null | dataset.isEmpty() ) return; for (i=0; i datarect (MCC 6/2/97) if( !dataset.isEmpty() ) { for (i=0; i 0) return; if(load_thread != null) load_thread.end(); load_thread = null; } /** * Change the message to be flashed on the canvas * @param s String contining the new message. * @see Graph2D#startedloading() * @see Graph2D#finishedloading() * @see LoadMessage */ public void loadmessage(String s) { if(load_thread == null) load_thread = new LoadMessage(this); load_thread.setMessage(s); } /* ******************* ** ** Protected Methods ** *******************/ /** * Check to see if any of axes range has changed. (MCC 3/19/97) */ protected boolean axesChanged() { boolean changed = false; Axis a; for (int i=0; i yrange ) range = xrange; else range = yrange; for (int i=0; i dr.height) { x += (dr.width-dr.height)/2.0; width -= dr.width-dr.height; } else { y += (dr.height-dr.width)/2.0; height -= dr.height-dr.width; } return new Rectangle(x,y,width,height); } /** * Calculate the rectangle occupied by the data */ protected Rectangle getDataRectangle(Graphics g, Rectangle r) { Axis a; int waxis; int x = r.x; int y = r.y; int width = r.width; int height = r.height; for (int i=0; i