Source for org.jfree.data.contour.NonGridContourDataset

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   6:  *
   7:  * Project Info:  http://www.jfree.org/jfreechart/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  *
  27:  * --------------------------
  28:  * NonGridContourDataset.java
  29:  * --------------------------
  30:  * (C) Copyright 2002-2005, by David M. O'Donnell.
  31:  *
  32:  * Original Author:  David M. O'Donnell;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *
  35:  * $Id: NonGridContourDataset.java,v 1.3.2.1 2005/10/25 21:30:20 mungady Exp $
  36:  *
  37:  * Changes (from 24-Jul-2003)
  38:  * --------------------------
  39:  * 24-Jul-2003 : Added standard header (DG);
  40:  *
  41:  */
  42: 
  43: package org.jfree.data.contour;
  44: 
  45: import org.jfree.data.Range;
  46: 
  47: /**
  48:  * A convenience class that extends the {@link DefaultContourDataset} to 
  49:  * accommodate non-grid data.
  50:  */
  51: public class NonGridContourDataset extends DefaultContourDataset {
  52: 
  53:     /** Default number of x values. */
  54:     static final int DEFAULT_NUM_X = 50;
  55:     
  56:     /** Default number of y values. */
  57:     static final int DEFAULT_NUM_Y = 50;
  58:     
  59:     /** Default power. */
  60:     static final int DEFAULT_POWER = 4;
  61: 
  62:     /**
  63:      * Default constructor.
  64:      */
  65:     public NonGridContourDataset() {
  66:         super();
  67:     }
  68: 
  69:     /**
  70:      * Constructor for NonGridContourDataset.  Uses default values for grid 
  71:      * dimensions and weighting.
  72:      * 
  73:      * @param seriesName  the series name.
  74:      * @param xData  the x values.
  75:      * @param yData  the y values.
  76:      * @param zData  the z values.
  77:      */
  78:     public NonGridContourDataset(String seriesName,
  79:                                  Object[] xData, Object[] yData, 
  80:                                  Object[] zData) {
  81:         super(seriesName, xData, yData, zData);
  82:         buildGrid(DEFAULT_NUM_X, DEFAULT_NUM_Y, DEFAULT_POWER);
  83:     }
  84: 
  85:     /**
  86:      * Constructor for NonGridContourDataset.
  87:      * 
  88:      * @param seriesName  the series name.
  89:      * @param xData  the x values.
  90:      * @param yData  the y values.
  91:      * @param zData  the z values.
  92:      * @param numX  number grid cells in along the x-axis
  93:      * @param numY  number grid cells in along the y-axis
  94:      * @param power  exponent for inverse distance weighting
  95:      */
  96:     public NonGridContourDataset(String seriesName, 
  97:                                  Object[] xData, Object[] yData, 
  98:                                  Object[] zData,
  99:                                  int numX, int numY, int power) {
 100:         super(seriesName, xData, yData, zData);
 101:         buildGrid(numX, numY, power);
 102:     }
 103: 
 104:     /**
 105:      * Builds a regular grid.  Maps the non-grid data into the regular grid 
 106:      * using an inverse distance between grid and non-grid points.  Weighting 
 107:      * of distance can be controlled by setting through the power parameter 
 108:      * that controls the exponent used on the distance weighting 
 109:      * (e.g., distance^power).
 110:      * 
 111:      * @param numX  number grid points in along the x-axis
 112:      * @param numY  number grid points in along the y-axis
 113:      * @param power  exponent for inverse distance weighting
 114:      */
 115:     protected void buildGrid(int numX, int numY, int power) {
 116: 
 117:         int numValues = numX * numY;
 118:         double[] xGrid = new double[numValues];
 119:         double[] yGrid = new double [numValues];
 120:         double[] zGrid = new double [numValues];
 121: 
 122:         // Find min, max for the x and y axes
 123:         double xMin = 1.e20;
 124:         for (int k = 0; k < this.xValues.length; k++) {
 125:             xMin = Math.min(xMin, this.xValues[k].doubleValue());
 126:         }
 127: 
 128:         double xMax = -1.e20;
 129:         for (int k = 0; k < this.xValues.length; k++) {
 130:             xMax = Math.max(xMax, this.xValues[k].doubleValue());
 131:         }
 132: 
 133:         double yMin = 1.e20;
 134:         for (int k = 0; k < this.yValues.length; k++) {
 135:             yMin = Math.min(yMin, this.yValues[k].doubleValue());
 136:         }
 137: 
 138:         double yMax = -1.e20;
 139:         for (int k = 0; k < this.yValues.length; k++) {
 140:             yMax = Math.max(yMax, this.yValues[k].doubleValue());
 141:         }
 142: 
 143:         Range xRange = new Range(xMin, xMax);
 144:         Range yRange = new Range(yMin, yMax);
 145: 
 146:         xRange.getLength();
 147:         yRange.getLength();
 148: 
 149:         // Determine the cell size
 150:         double dxGrid = xRange.getLength() / (numX - 1);
 151:         double dyGrid = yRange.getLength() / (numY - 1);
 152: 
 153:         // Generate the grid
 154:         double x = 0.0;
 155:         for (int i = 0; i < numX; i++) {
 156:             if (i == 0) {
 157:                 x = xMin;
 158:             }
 159:             else {
 160:                 x += dxGrid;
 161:             }
 162:             double y = 0.0;
 163:             for (int j = 0; j < numY; j++) {
 164:                 int k = numY * i + j;
 165:                 xGrid[k] = x;
 166:                 if (j == 0) {
 167:                     y = yMin;
 168:                 }
 169:                 else {
 170:                     y += dyGrid;
 171:                 }
 172:                 yGrid[k] = y;
 173:             }
 174:         }
 175: 
 176:         // Map the nongrid data into the new regular grid
 177:         for (int kGrid = 0; kGrid < xGrid.length; kGrid++) {
 178:             double dTotal = 0.0;
 179:             zGrid[kGrid] = 0.0;
 180:             for (int k = 0; k < this.xValues.length; k++) {
 181:                 double xPt = this.xValues[k].doubleValue();
 182:                 double yPt = this.yValues[k].doubleValue();
 183:                 double d = distance(xPt, yPt, xGrid[kGrid], yGrid[kGrid]);
 184:                 if (power != 1) {
 185:                     d = Math.pow(d, power);
 186:                 }
 187:                 d = Math.sqrt(d);
 188:                 if (d > 0.0) {
 189:                     d = 1.0 / d;
 190:                 }
 191:                 else { // if d is real small set the inverse to a large number 
 192:                        // to avoid INF
 193:                     d = 1.e20;
 194:                 }
 195:                 if (this.zValues[k] != null) {
 196:                     // scale by the inverse of distance^power
 197:                     zGrid[kGrid] += this.zValues[k].doubleValue() * d; 
 198:                 }
 199:                 dTotal += d;
 200:             }
 201:             zGrid[kGrid] = zGrid[kGrid] / dTotal;  //remove distance of the sum
 202:         }
 203: 
 204:         //initalize xValues, yValues, and zValues arrays.
 205:         initialize(
 206:             formObjectArray(xGrid), formObjectArray(yGrid), 
 207:             formObjectArray(zGrid)
 208:         );
 209: 
 210:     }
 211: 
 212:     /**
 213:      * Calculates the distance between two points.
 214:      * 
 215:      * @param xDataPt  the x coordinate.
 216:      * @param yDataPt  the y coordinate.
 217:      * @param xGrdPt  the x grid coordinate.
 218:      * @param yGrdPt  the y grid coordinate.
 219:      * 
 220:      * @return The distance between two points.
 221:      */
 222:     protected double distance(double xDataPt, 
 223:                               double yDataPt, 
 224:                               double xGrdPt, 
 225:                               double yGrdPt) {
 226:         double dx = xDataPt - xGrdPt;
 227:         double dy = yDataPt - yGrdPt;
 228:         return Math.sqrt(dx * dx + dy * dy);
 229:     }
 230: 
 231: }