package graph; import java.awt.*; import java.applet.*; import java.net.URL; import java.util.*; import java.io.InputStream; /* ************************************************************************** ** ** Class Contour ** ************************************************************************** ** 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 interactive graphics class to incorporate ** contours. ** *************************************************************************/ /** * This class extends the interactive graphics class G2Dint to incorporate * contouring. * * @version $Revision: 1.11 $, $Date: 1996/08/12 23:37:08 $. * @author Leigh Brookshaw */ public class Contour extends G2Dint { /* ************** ** ** Constants ** *************/ /* ** The minimum length of a curve before it gets a label */ static final int MINCELLS = 30; /* ** Default number of contour levels */ static final int NLEVELS = 12; /********************** ** ** Protected Variables ** ***********************/ /** * Dimension of the contour grid in the X direction */ protected int nx; /** * Dimension of the contour grid in the Y direction */ protected int ny; /** * Vector array containing the Contour curves. * Each index in the array contains curves at a given * contour level */ protected Vector curves[]; /** * If set the class calculates the contour levels based on * the data minimum and maximum. Default value true. */ protected boolean autoLevels; /* * If true the contour levels are calculated in * logarithmic intervals */ protected boolean logLevels; /* * If true the limits of the plot are the limits of the * data grid not the limits of the contours! */ protected boolean gridLimits; /* * The array of contour levels */ protected double levels[]; /** * The label for each contour level */ protected TextLine labels[]; /** * Font to use in drawing Labels */ protected Font labelfont; /** * Color to use in drawing Labels */ protected Color labelcolor; /** * Style to use in drawing Labels. TextLine.SCIENTIFIC or * TextLine.ALGEBRAIC. */ protected int labelStyle; /** * Precision to use in drawing Labels. */ protected int labelPrecision; /** * Number of Significant figures to use in drawing Labels. */ protected int labelSignificant; /** * Which levels will get labels. If it is equal to 1 every level * gets a label, equal to 2 every second level etc. If it is equal to 0 * no labels are displayed. */ protected int labelLevels; /** * If false labels are not drawn */ protected boolean drawlabels; /** * If true the labels will be calculated for each * contour level. These might not look all that hot. */ protected boolean autoLabels; /** * Color to draw non labelled contour line */ protected Color contourColor; /** * Color to draw labelled contour line */ protected Color labelledColor; /** * The data grid, a 2D array stored in linear form. * It is assumed that [0,0] is the bottom left corner * and the data is ordered by row. */ protected double grid[]; /** * The X minimum limit of the data grid */ protected double xmin; /** * The X maximum limit of the data grid */ protected double xmax; /** * The Y minimum limit of the data grid */ protected double ymin; /** * The Y maximum limit of the data grid */ protected double ymax; /** * The minimum value of the grid values */ protected double zmin; /** * The maximum value of the grid values */ protected double zmax; /** * Boolean value if true Contours will not be calculated */ public boolean noContours = false; /* ***************** ** ** Constructors ** ****************/ /** * Instantaite the class */ public Contour() { grid = null; xmin = 0.0; xmax = 0.0; ymin = 0.0; ymax = 0.0; zmin = 0.0; zmax = 0.0; nx = 0; ny = 0; levels = new double[NLEVELS]; labels = new TextLine[NLEVELS]; autoLevels = true; logLevels = false; gridLimits = false; autoLabels = true; labelfont = new Font("Helvetica",Font.PLAIN,12); labelcolor = Color.blue; labelLevels = 1; labelStyle = TextLine.ALGEBRAIC; labelPrecision = 2; labelSignificant = 3; drawlabels = true; contourColor = null; labelledColor = null; curves = null; } /* ************ ** ** Methods ** ***********/ /** * Load the grid to contour from a URL. There are 2 formats for the data * optionally the limits of the grid can be parsed.
*
   *  The expected format of the data 
   *           1st Number:   nx
   *           2nd Number:   ny
   *           nx*ny numbers following
   *
   *  Optionally
   *           1st Number:   nx
   *           2nd Number:   ny
   *           3rd Number:   xmin
   *           4th Number:   xmax
   *           5th Number:   ymin
   *           6th Number:   ymax
   *           nx*ny numbers following
   *  

* If xmin, xmax, ymin, ymax are not specified they are assumed * to be [1.0,nx,1.0,ny] * * @param file URL of the file to load * @return true of the load was successful. * */ public boolean loadGrid( 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 Grid from file "); e.printStackTrace(); if (is != null) try { is.close(); } catch (Exception ev) { } return false; } if(n < 1 ) { System.out.println("Failed to load Grid from file "); return false; } nx = (int)(data[0] + 0.5); ny = (int)(data[1] + 0.5); if( n == nx*ny+6 ) { xmin = data[2]; xmax = data[3]; ymin = data[4]; ymax = data[5]; grid = new double[nx*ny]; System.arraycopy(data, 6, grid, 0, nx*ny); } else if( n == nx*ny+2 ) { xmin = 1.0; xmax = (double)(nx); ymin = 1.0; ymax = (double)(ny); grid = new double[nx*ny]; System.arraycopy(data, 2, grid, 0, nx*ny); } else { System.out.println("Error loading grid, Wrong number of points "); grid = null; return false; } zrange(); calcLevels(); detachCurves(); curves = null; return true; } /** * Set the range of the grid * @param xmin Minimum X value * @param xmax Maximum X value * @param ymin Minimum Y value * @param ymax Maximum Y value */ public void setRange(double xmin,double xmax,double ymin,double ymax) { if( xmin >= xmax || ymin >= ymax ) return; this.xmin = xmin; this.xmax = xmax; this.ymin = ymin; this.ymax = ymax; } /** * Return the range of the grid * @return An array contining xmin,xmax,ymin,ymax. */ public double[] getRange() { double d[] = new double[4]; d[0] = xmin; d[1] = xmax; d[2] = ymin; d[3] = ymax; return d; } /** * return the dimensions of the grid * @return An array containing the number of columns, number of rows. */ public int[] getDim() { int i[] = new int[2]; i[0] = nx; i[1] = ny; return i; } /** * Return the grid * @return An array of size nx by ny contining the data grid. */ public double[] getGrid() { return grid; } /** * Manually set the contour levels. * @param levels An array containing the contour levels * @param nl The number of contour levels in the arrray */ public void setLevels(double levels[], int nl) { int i; if( levels == null || nl <= 0 ) return; detachCurves(); curves = null; autoLevels = false; this.levels = new double[nl]; System.arraycopy(levels,0,this.levels,0,nl); labels = new TextLine[nl]; for(i=0; i * if 0 no labels are drawn * if 1 every level gets a label * If 2 every 2nd level gets a label * etc. * */ public void setLabelLevels(int i) { if(i<=0) labelLevels = 0; else labelLevels = i; } /** * If true contour levels are calculated on a log scale. * @param b boolean */ public void setLogLevels(boolean b) { logLevels = b; if( zmin <= 0.0 || zmax <= 0.0 ) logLevels = false; } /** * Set the number of contour levels. * @@param l Number of contour levels */ public void setNLevels(int l) { if(l <= 0) return; levels = new double[l]; calcLevels(); detachCurves(); curves = null; } /** * If true contour levels are calculated automatically. * @param b boolean */ public void setAutoLevels(boolean b) { autoLevels = b; } /** * If true contour levels are not labeled. * @param b boolean */ public void setDrawLabels(boolean b) { drawlabels = b; } /** * Set the label style, either TextLine.SCIENTIFIC or * TextLine.ALGEBRAIC. * @param s Style */ public void setLabelStyle(int s) { labelStyle = s; calcLabels(); } /** * Get the label style, either TextLine.SCIENTIFIC or * TextLine.ALGEBRAIC. * @return style */ public int getLabelStyle() { return labelStyle; } /** * Set the label precision. * @param s Precision */ public void setLabelPrecision(int p) { labelPrecision = p; calcLabels(); } /** * Get the label precision. * @return precision */ public int getLabelPrecision() { return labelPrecision; } /** * Set the label significant figures. * @param s number of significant figures */ public void setLabelSignificance(int s) { labelSignificant = s; calcLabels(); } /** * Get the number of significant figures for labels. * @return number of significant figures */ public int getLabelSignificance() { return labelSignificant; } /** * Add extra events to the G2Dint event handler. * * If 'l' is pressed repaint without the labels * If 'L' is pressed repaint with the labels. */ public boolean keyDown(Event e, int key) { if(xaxis==null || yaxis==null) return false; if( super.keyDown(e,key) ) return true; switch ( key ) { case 'l': drawlabels = false; repaint(); return true; case 'L': drawlabels = true; repaint(); return true; } return false; } /* ******************** ** ** Private Methods ** *******************/ /* ** calcLevels() ** Calculate the contour levels */ private void calcLevels() { int i; int l; if(!autoLevels) return; if(levels == null) levels = new double[NLEVELS]; labels = new TextLine[levels.length]; // Nice label steps not implemented yet //levelStep(); if( logLevels ) { double inc = Math.log(zmax-zmin)/ (double)(levels.length+1); try { for(i=0; i xmin ) xaxis.minimum = xmin; if(xaxis.maximum < xmax ) xaxis.maximum = xmax; } if( yaxis != null ) { if(yaxis.minimum > ymin ) yaxis.minimum = ymin; if(yaxis.maximum < ymax ) yaxis.maximum = ymax; } } else if( dataset.isEmpty() ) { if( xaxis != null ) { xaxis.minimum = xmin; xaxis.maximum = xmax; } if( yaxis != null ) { yaxis.minimum = ymin; yaxis.maximum = ymax; } } } /** * Set the colors for the contour lines */ private void setContourColors() { int i; int j; Vector v; if(curves == null || (contourColor==null && labelledColor==null) ) return; for(i=0; i MINCELLS ) { point = ds.getPoint(index); x = xaxis.getInteger(point[0]); y = yaxis.getInteger(point[1]); r.width = labels[i].getWidth(g); r.height = labels[i].getAscent(g); r.x = x - r.width/2; r.y = y - r.height/2; g.setColor(DataBackground); g.fillRect(r.x, r.y, r.width, r.height); g.setColor(current); labels[i].draw(g, r.x, r.y+r.height, TextLine.LEFT); points -= MINCELLS; index += MINCELLS; } } } } super.paintLast(g,rect); } /* ** calculateCurves() ** Calculate the contours and attach them to the graph and axes. */ protected void calculateCurves() { int i; int j; double data[]; double xscale = (xmax-xmin)/(double)(nx-1); double yscale = (ymax-ymin)/(double)(ny-1); IsoCurve isocurve; isocurve = new IsoCurve(grid,nx,ny); if( curves != null) { detachCurves(); curves = null; } if( zmin == zmax ) return; curves = new Vector[levels.length]; for(i=0; i