001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * -------------------------- 028 * NonGridContourDataset.java 029 * -------------------------- 030 * (C) Copyright 2002-2005, by David M. O'Donnell. 031 * 032 * Original Author: David M. O'Donnell; 033 * Contributor(s): David Gilbert (for Object Refinery Limited); 034 * 035 * $Id: NonGridContourDataset.java,v 1.3.2.1 2005/10/25 21:30:20 mungady Exp $ 036 * 037 * Changes (from 24-Jul-2003) 038 * -------------------------- 039 * 24-Jul-2003 : Added standard header (DG); 040 * 041 */ 042 043 package org.jfree.data.contour; 044 045 import org.jfree.data.Range; 046 047 /** 048 * A convenience class that extends the {@link DefaultContourDataset} to 049 * accommodate non-grid data. 050 */ 051 public class NonGridContourDataset extends DefaultContourDataset { 052 053 /** Default number of x values. */ 054 static final int DEFAULT_NUM_X = 50; 055 056 /** Default number of y values. */ 057 static final int DEFAULT_NUM_Y = 50; 058 059 /** Default power. */ 060 static final int DEFAULT_POWER = 4; 061 062 /** 063 * Default constructor. 064 */ 065 public NonGridContourDataset() { 066 super(); 067 } 068 069 /** 070 * Constructor for NonGridContourDataset. Uses default values for grid 071 * dimensions and weighting. 072 * 073 * @param seriesName the series name. 074 * @param xData the x values. 075 * @param yData the y values. 076 * @param zData the z values. 077 */ 078 public NonGridContourDataset(String seriesName, 079 Object[] xData, Object[] yData, 080 Object[] zData) { 081 super(seriesName, xData, yData, zData); 082 buildGrid(DEFAULT_NUM_X, DEFAULT_NUM_Y, DEFAULT_POWER); 083 } 084 085 /** 086 * Constructor for NonGridContourDataset. 087 * 088 * @param seriesName the series name. 089 * @param xData the x values. 090 * @param yData the y values. 091 * @param zData the z values. 092 * @param numX number grid cells in along the x-axis 093 * @param numY number grid cells in along the y-axis 094 * @param power exponent for inverse distance weighting 095 */ 096 public NonGridContourDataset(String seriesName, 097 Object[] xData, Object[] yData, 098 Object[] zData, 099 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 }