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