/* =========================================================== * JFreeChart : a free chart library for the Java(tm) platform * =========================================================== * * (C) Copyright 2000-2011, by Object Refinery Limited and Contributors. * * Project Info: http://www.jfree.org/jfreechart/index.html * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners.] * * -------------------------- * DefaultContourDataset.java * -------------------------- * (C) Copyright 2002-2008, by David M. O'Donnell and Contributors. * * Original Author: David M. O'Donnell; * Contributor(s): David Gilbert (for Object Refinery Limited); * * Changes (from 23-Jan-2003) * -------------------------- * 23-Jan-2003 : Added standard header (DG); * 20-May-2003 : removed member vars numX and numY, which were never used (TM); * 06-May-2004 : Now extends AbstractXYZDataset (DG); * 15-Jul-2004 : Switched getX() with getXValue(), getY() with getYValue() and * getZ() with getZValue() methods (DG); * ------------- JFREECHART 1.0.x -------------------------------------------- * 31-Jan-2007 : Deprecated (DG); * */ package org.jfree.data.contour; import java.util.Arrays; import java.util.Date; import java.util.Vector; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYBlockRenderer; import org.jfree.data.Range; import org.jfree.data.xy.AbstractXYZDataset; import org.jfree.data.xy.XYDataset; /** * A convenience class that provides a default implementation of the * {@link ContourDataset} interface. * * @deprecated This class is no longer supported (as of version 1.0.4). If * you are creating contour plots, please try to use {@link XYPlot} and * {@link XYBlockRenderer}. */ public class DefaultContourDataset extends AbstractXYZDataset implements ContourDataset { /** The series name (this dataset supports only one series). */ protected Comparable seriesKey = null; /** Storage for the x values. */ protected Number[] xValues = null; /** Storage for the y values. */ protected Number[] yValues = null; /** Storage for the z values. */ protected Number[] zValues = null; /** The index for the start of each column in the data. */ protected int[] xIndex = null; /** Flags that track whether x, y and z are dates. */ boolean[] dateAxis = new boolean[3]; /** * Creates a new dataset, initially empty. */ public DefaultContourDataset() { super(); } /** * Constructs a new dataset with the given data. * * @param seriesKey the series key. * @param xData the x values. * @param yData the y values. * @param zData the z values. */ public DefaultContourDataset(Comparable seriesKey, Object[] xData, Object[] yData, Object[] zData) { this.seriesKey = seriesKey; initialize(xData, yData, zData); } /** * Initialises the dataset. * * @param xData the x values. * @param yData the y values. * @param zData the z values. */ public void initialize(Object[] xData, Object[] yData, Object[] zData) { this.xValues = new Double[xData.length]; this.yValues = new Double[yData.length]; this.zValues = new Double[zData.length]; // We organise the data with the following assumption: // 1) the data are sorted by x then y // 2) that the data will be represented by a rectangle formed by // using x[i+1], x, y[j+1], and y. // 3) we march along the y-axis at the same value of x until a new // value x is found at which point we will flag the index // where x[i+1]<>x[i] Vector tmpVector = new Vector(); //create a temporary vector double x = 1.123452e31; // set x to some arbitary value (used below) for (int k = 0; k < this.xValues.length; k++) { if (xData[k] != null) { Number xNumber; if (xData[k] instanceof Number) { xNumber = (Number) xData[k]; } else if (xData[k] instanceof Date) { this.dateAxis[0] = true; Date xDate = (Date) xData[k]; xNumber = new Long(xDate.getTime()); //store data as Long } else { xNumber = new Integer(0); } this.xValues[k] = new Double(xNumber.doubleValue()); // store Number as Double // check if starting new column if (x != this.xValues[k].doubleValue()) { tmpVector.add(new Integer(k)); //store index where new //column starts x = this.xValues[k].doubleValue(); // set x to most recent value } } } Object[] inttmp = tmpVector.toArray(); this.xIndex = new int[inttmp.length]; // create array xIndex to hold // new column indices for (int i = 0; i < inttmp.length; i++) { this.xIndex[i] = ((Integer) inttmp[i]).intValue(); } for (int k = 0; k < this.yValues.length; k++) { // store y and z axes // as Doubles this.yValues[k] = (Double) yData[k]; if (zData[k] != null) { this.zValues[k] = (Double) zData[k]; } } } /** * Creates an object array from an array of doubles. * * @param data the data. * * @return An array of <code>Double</code> objects. */ public static Object[][] formObjectArray(double[][] data) { Object[][] object = new Double[data.length][data[0].length]; for (int i = 0; i < object.length; i++) { for (int j = 0; j < object[i].length; j++) { object[i][j] = new Double(data[i][j]); } } return object; } /** * Creates an object array from an array of doubles. * * @param data the data. * * @return An array of <code>Double</code> objects. */ public static Object[] formObjectArray(double[] data) { Object[] object = new Double[data.length]; for (int i = 0; i < object.length; i++) { object[i] = new Double(data[i]); } return object; } /** * Returns the number of items in the specified series. This method * is provided to satisfy the {@link XYDataset} interface implementation. * * @param series must be zero, as this dataset only supports one series. * * @return The item count. */ public int getItemCount(int series) { if (series > 0) { throw new IllegalArgumentException("Only one series for contour"); } return this.zValues.length; } /** * Returns the maximum z-value. * * @return The maximum z-value. */ public double getMaxZValue() { double zMax = -1.e20; for (int k = 0; k < this.zValues.length; k++) { if (this.zValues[k] != null) { zMax = Math.max(zMax, this.zValues[k].doubleValue()); } } return zMax; } /** * Returns the minimum z-value. * * @return The minimum z-value. */ public double getMinZValue() { double zMin = 1.e20; for (int k = 0; k < this.zValues.length; k++) { if (this.zValues[k] != null) { zMin = Math.min(zMin, this.zValues[k].doubleValue()); } } return zMin; } /** * Returns the maximum z-value within visible region of plot. * * @param x the x range. * @param y the y range. * * @return The z range. */ public Range getZValueRange(Range x, Range y) { double minX = x.getLowerBound(); double minY = y.getLowerBound(); double maxX = x.getUpperBound(); double maxY = y.getUpperBound(); double zMin = 1.e20; double zMax = -1.e20; for (int k = 0; k < this.zValues.length; k++) { if (this.xValues[k].doubleValue() >= minX && this.xValues[k].doubleValue() <= maxX && this.yValues[k].doubleValue() >= minY && this.yValues[k].doubleValue() <= maxY) { if (this.zValues[k] != null) { zMin = Math.min(zMin, this.zValues[k].doubleValue()); zMax = Math.max(zMax, this.zValues[k].doubleValue()); } } } return new Range(zMin, zMax); } /** * Returns the minimum z-value. * * @param minX the minimum x value. * @param minY the minimum y value. * @param maxX the maximum x value. * @param maxY the maximum y value. * * @return The minimum z-value. */ public double getMinZValue(double minX, double minY, double maxX, double maxY) { double zMin = 1.e20; for (int k = 0; k < this.zValues.length; k++) { if (this.zValues[k] != null) { zMin = Math.min(zMin, this.zValues[k].doubleValue()); } } return zMin; } /** * Returns the number of series. * <P> * Required by XYDataset interface (this will always return 1) * * @return 1. */ public int getSeriesCount() { return 1; } /** * Returns the name of the specified series. * * Method provided to satisfy the XYDataset interface implementation * * @param series must be zero. * * @return The series name. */ public Comparable getSeriesKey(int series) { if (series > 0) { throw new IllegalArgumentException("Only one series for contour"); } return this.seriesKey; } /** * Returns the index of the xvalues. * * @return The x values. */ public int[] getXIndices() { return this.xIndex; } /** * Returns the x values. * * @return The x values. */ public Number[] getXValues() { return this.xValues; } /** * Returns the x value for the specified series and index (zero-based * indices). Required by the {@link XYDataset}. * * @param series must be zero; * @param item the item index (zero-based). * * @return The x value. */ public Number getX(int series, int item) { if (series > 0) { throw new IllegalArgumentException("Only one series for contour"); } return this.xValues[item]; } /** * Returns an x value. * * @param item the item index (zero-based). * * @return The X value. */ public Number getXValue(int item) { return this.xValues[item]; } /** * Returns a Number array containing all y values. * * @return The Y values. */ public Number[] getYValues() { return this.yValues; } /** * Returns the y value for the specified series and index (zero-based * indices). Required by the {@link XYDataset}. * * @param series the series index (must be zero for this dataset). * @param item the item index (zero-based). * * @return The Y value. */ public Number getY(int series, int item) { if (series > 0) { throw new IllegalArgumentException("Only one series for contour"); } return this.yValues[item]; } /** * Returns a Number array containing all z values. * * @return The Z values. */ public Number[] getZValues() { return this.zValues; } /** * Returns the z value for the specified series and index (zero-based * indices). Required by the {@link XYDataset} * * @param series the series index (must be zero for this dataset). * @param item the item index (zero-based). * * @return The Z value. */ public Number getZ(int series, int item) { if (series > 0) { throw new IllegalArgumentException("Only one series for contour"); } return this.zValues[item]; } /** * Returns an int array contain the index into the x values. * * @return The X values. */ public int[] indexX() { int[] index = new int[this.xValues.length]; for (int k = 0; k < index.length; k++) { index[k] = indexX(k); } return index; } /** * Given index k, returns the column index containing k. * * @param k index of interest. * * @return The column index. */ public int indexX(int k) { int i = Arrays.binarySearch(this.xIndex, k); if (i >= 0) { return i; } else { return -1 * i - 2; } } /** * Given index k, return the row index containing k. * * @param k index of interest. * * @return The row index. */ public int indexY(int k) { // this may be obsolete (not used anywhere) return (k / this.xValues.length); } /** * Given column and row indices, returns the k index. * * @param i index of along x-axis. * @param j index of along y-axis. * * @return The Z index. */ public int indexZ(int i, int j) { return this.xValues.length * j + i; } /** * Returns true if axis are dates. * * @param axisNumber The axis where 0-x, 1-y, and 2-z. * * @return A boolean. */ public boolean isDateAxis(int axisNumber) { if (axisNumber < 0 || axisNumber > 2) { return false; // bad axisNumber } return this.dateAxis[axisNumber]; } /** * Sets the names of the series in the data source. * * @param seriesKeys the keys of the series in the data source. */ public void setSeriesKeys(Comparable[] seriesKeys) { if (seriesKeys.length > 1) { throw new IllegalArgumentException( "Contours only support one series"); } this.seriesKey = seriesKeys[0]; fireDatasetChanged(); } }