package graph; import java.awt.*; import java.applet.*; import java.util.*; import java.lang.*; /* ************************************************************************** ** ** Class VectorSet ** ************************************************************************** ** Copyright (C) 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. ************************************************************************** ** ** This class extends the DataSet class to vectors ** *************************************************************************/ /** * This class is designed to hold vectors to be plotted. It extends the * DataSet class. * The vectors are defined as (x,y,dx,dy) where (x,y) is the position * of the vector tail and (dx,dy) is the relative position of the head. * It is to be used in conjunction with the Graph2D class and Axis * class for plotting 2D graphs. * * @version $Revision: 1.3 $, $Date: 1996/10/23 03:30:22 $ * @author Leigh Brookshaw */ public class VectorSet extends DataSet { /** * The Default stride of the Vector class */ private final static int VECTOR_STRIDE = 4; /** * Boolean set if legend is to be drawn */ private boolean drawlegend = false; /* *************************** ** Public Static Values **************************/ /** * A constant value flag used to specify if the mean magnitude of the * vectors is going to be used as the scaling variable */ public final static int MEAN = 1; /** * A constant value flag used to specify if the minimum magnitude of the * vectors is going to be used as the scaling variable */ public final static int MINIMUM = 2; /** * A constant value flag used to specify if the max magnitude of the * vectors is going to be used as the scaling variable */ public final static int MAXIMUM = 3; /* *********************** ** Public Variables **********************/ /** * This is the scaling to be used when drawing vectors. The scaling is the * fraction of the axis the mean vector magnitude will be scaled to. */ public double scale = 0.1; /* ********************* ** Protected Variables **********************/ /** * This is the stride of the data in the data array. For a vector set * it will be 4. */ protected int stride = VECTOR_STRIDE; /** * The flag specifying which scaling variable to use */ protected int scalingType = 1; /* ********************* ** Private Variables *********************/ /** * The mean magnitude squared of the vectors */ private double vmean; /** * The minimum magnitude squared of the vectors */ private double vmin; /** * The maximum magnitude squared of the vectors */ private double vmax; /* ********************* ** Constructors ********************/ /** * Instantiate an empty data set. * @exception Exception * A Generic exception if it fails to instantiate the * the class with the correct stride. */ public VectorSet ( ) throws Exception { super(VECTOR_STRIDE); stride = VECTOR_STRIDE; }; /** * Instantiate a DataSet with the parsed data. * The double array contains the data. * The data is stored in the array in the sequence *
* x,y,dx,dy,x,y,dx,dy,... ** Where (x,y) is the position of the tail and (dx,dy) is the relative * position of the head. * This means that the length of the data * array is 4*n. * @param d Array containing the (x,y,dy,dx) vectors. * @param n Number of (x,y) data pairs in the array. * @exception Exception * A Generic exception if it fails to load the * parsed array into the class. */ public VectorSet ( double d[], int n ) throws Exception { super(d,n,VECTOR_STRIDE); this.stride = VECTOR_STRIDE; } /** * Instantiate an empty data set. * @param s The scaling to use when plotting the vectors. * @exception Exception * A Generic exception if it fails to instantiate the * the class with the correct stride. */ public VectorSet (double scale) throws Exception{ super(VECTOR_STRIDE); this.scale = scale; } /** * Instantiate a DataSet with the parsed data. * @param d Array containing the (x,y,dy,dx) vectors. * @param n Number of (x,y,dx,dy) vectors in the array. * @exception Exception * A Generic exception if it fails to load the * parsed array into the class. */ public VectorSet ( double d[], int n, double scale ) throws Exception { this(d,n); this.scale = scale; } /* ******************* ** Public Methods ******************/ /** * Set the scaling to use when drawing vectors * @param scale The scaling to employ */ public void setScale(double scale) { this.scale = scale; } /** * Set the scaling type to use when drawing vectors * @param type Either MEAN, MAXIMUM or MINIMUM. */ public void setScalingType(int type) { if(type == MEAN || type == MAXIMUM || type == MINIMUM) scalingType = type; } /** * return the current scaling factor. That is the calculated scaling * using the axis range the mean/max/min magnitude and the percentage * scale. */ public double getScaleFactor() { double f; if( xrange > yrange ) f = scale*yrange; else f = scale*xrange; if(vmean <= 0.0) return 1.0; if( scalingType == MEAN ) return f/vmean; if( scalingType == MINIMUM ) return f/vmin; if( scalingType == MAXIMUM ) return f/vmax; return 1.0; } /** * Draw a Vector legend in the graph window. The legend will be placed * above the data window in the center */ public void legend() { super.legend(-1,-1,null); drawlegend = true; } /** * Define a Vector legend in the graph window. The legend will be placed * above the data window in the center * @param text text to display in the legend */ public void legend(String text) { super.legend(-1,-1,text); drawlegend = true; } /** * Define a Vector legend in the graph window * @param x pixel position of the legend. * @param y pixel position of the legend. * @param text text to display in the legend */ public void legend(int x, int y, String text) { super.legend(x,y,text); drawlegend = true; } /** * Define a Vector legend in the graph window * @param x data position of the legend. * @param y data position of the legend. * @param text text to display in the legend */ public void legend(double x, double y, String text) { super.legend(x,y,text); drawlegend = true; } /** * Draw the vectors at the data points. * If this data has been attached to an Axis then scale the data * based on the axis maximum/minimum otherwise scale using * the data's maximum/minimum * @param g Graphics state * @param bounds The data window to draw into */ public void draw_data(Graphics g, Rectangle bounds) { Color c; if ( xaxis != null ) { xmax = xaxis.maximum; xmin = xaxis.minimum; } if ( yaxis != null ) { ymax = yaxis.maximum; ymin = yaxis.minimum; } xrange = xmax - xmin; yrange = ymax - ymin; /* ** draw the legend before we clip the data window */ draw_legend(g,bounds); /* ** Clip the data window */ if(clipping) g.clipRect(bounds.x, bounds.y, bounds.width, bounds.height); c = g.getColor(); if ( linecolor != null) g.setColor(linecolor); else g.setColor(c); drawVectors(g,bounds); g.setColor(c); } /** * Draw a legend for this Vector set * @param g Graphics context * @param w Data Window */ protected void draw_legend(Graphics g, Rectangle w) { Color c = g.getColor(); TextLine value = new TextLine(); double dx; int ix,iy; int length; if(!drawlegend) return; /* ** Calculate the vector magnitude of a line legend_length ** pixels long. This will be our standard vector */ dx = xrange*((double)legend_length)/((double)w.width) /getScaleFactor(); value.parseDouble(dx,3); /* ** Calculate the length of the legend */ length = legend_length+value.getWidth(g)+value.charWidth(g,' '); /* ** Calculate the position of the legend if needed. */ if( legend_ix == 0 && legend_iy == 0 ) { legend_ix = (int)(w.x + ((legend_dx-xmin)/xrange)*w.width); legend_iy = (int)(w.y + (1.0 - (legend_dy-ymin)/yrange)*w.height); } else if( legend_ix == -1 && legend_iy == -1 ) { legend_ix = w.x + w.width/2 - length/2; legend_iy = w.y - value.getAscent(g)/2 ; } /* ** In what follows the vector tail is the zero point. It is on ** the right - the vector points to the left */ if ( linecolor != null) g.setColor(linecolor); /* ** Draw the standard vector */ g.drawLine(legend_ix,legend_iy,legend_ix+legend_length,legend_iy); ix = legend_ix + (int)(0.25*(double)legend_length+0.5); iy = legend_iy - (int)(0.25*(double)legend_length+0.5); g.drawLine(legend_ix,legend_iy,ix,iy); ix = legend_ix + (int)(0.25*(double)legend_length+0.5); iy = legend_iy + (int)(0.25*(double)legend_length+0.5); g.drawLine(legend_ix,legend_iy,ix,iy); /* ** Add the value of the standard vector. To the right of the vector */ value.draw(g, legend_ix+legend_length+value.charWidth(g,' '), iy, TextLine.LEFT); /* ** Add any legend text (above the vector) that might have been ** defined. */ g.setColor(c); if( legend_text != null && !legend_text.isNull() ) { legend_text.draw( g,legend_ix + length/2, iy-value.getAscent(g) -legend_text.getDescent(g)-legend_text.getLeading(g) , TextLine.CENTER); } } /* ********************* ** Protected Methods *********************/ protected void drawVectors(Graphics g, Rectangle w) { int ix0,iy0; int ix1,iy1; double x0,y0,x1,y1,dx,dy; // Is there any data to draw? Sometimes the draw command will // will be called before any data has been placed in the class. if( data == null || data.length < stride ) return; // Lets draw the vectors for(int i=0; i