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 License
  20. * along with this library; if not, write to the Free Software Foundation,
  21. * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  22. *
  23. * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  24. * in the United States and other countries.]
  25. *
  26. * --------------------------
  27. * NonGridContourDataset.java
  28. * --------------------------
  29. * (C) Copyright 2002-2005, by David M. O'Donnell.
  30. *
  31. * Original Author: David M. O'Donnell;
  32. * Contributor(s): David Gilbert (for Object Refinery Limited);
  33. *
  34. * $Id: NonGridContourDataset.java,v 1.3 2005/02/24 10:11:25 mungady Exp $
  35. *
  36. * Changes (from 24-Jul-2003)
  37. * --------------------------
  38. * 24-Jul-2003 : Added standard header (DG);
  39. *
  40. */
  41. package org.jfree.data.contour;
  42. import org.jfree.data.Range;
  43. /**
  44. * A convenience class that extends the {@link DefaultContourDataset} to
  45. * accommodate non-grid data.
  46. */
  47. public class NonGridContourDataset extends DefaultContourDataset {
  48. /** Default number of x values. */
  49. static final int DEFAULT_NUM_X = 50;
  50. /** Default number of y values. */
  51. static final int DEFAULT_NUM_Y = 50;
  52. /** Default power. */
  53. static final int DEFAULT_POWER = 4;
  54. /**
  55. * Default constructor.
  56. */
  57. public NonGridContourDataset() {
  58. super();
  59. }
  60. /**
  61. * Constructor for NonGridContourDataset. Uses default values for grid
  62. * dimensions and weighting.
  63. *
  64. * @param seriesName the series name.
  65. * @param xData the x values.
  66. * @param yData the y values.
  67. * @param zData the z values.
  68. */
  69. public NonGridContourDataset(String seriesName,
  70. Object[] xData, Object[] yData,
  71. Object[] zData) {
  72. super(seriesName, xData, yData, zData);
  73. buildGrid(DEFAULT_NUM_X, DEFAULT_NUM_Y, DEFAULT_POWER);
  74. }
  75. /**
  76. * Constructor for NonGridContourDataset.
  77. *
  78. * @param seriesName the series name.
  79. * @param xData the x values.
  80. * @param yData the y values.
  81. * @param zData the z values.
  82. * @param numX number grid cells in along the x-axis
  83. * @param numY number grid cells in along the y-axis
  84. * @param power exponent for inverse distance weighting
  85. */
  86. public NonGridContourDataset(String seriesName,
  87. Object[] xData, Object[] yData,
  88. Object[] zData,
  89. int numX, int numY, int power) {
  90. super(seriesName, xData, yData, zData);
  91. buildGrid(numX, numY, power);
  92. }
  93. /**
  94. * Builds a regular grid. Maps the non-grid data into the regular grid
  95. * using an inverse distance between grid and non-grid points. Weighting
  96. * of distance can be controlled by setting through the power parameter
  97. * that controls the exponent used on the distance weighting
  98. * (e.g., distance^power).
  99. *
  100. * @param numX number grid points in along the x-axis
  101. * @param numY number grid points in along the y-axis
  102. * @param power exponent for inverse distance weighting
  103. */
  104. protected void buildGrid(int numX, int numY, int power) {
  105. int numValues = numX * numY;
  106. double[] xGrid = new double[numValues];
  107. double[] yGrid = new double [numValues];
  108. double[] zGrid = new double [numValues];
  109. // Find min, max for the x and y axes
  110. double xMin = 1.e20;
  111. for (int k = 0; k < this.xValues.length; k++) {
  112. xMin = Math.min(xMin, this.xValues[k].doubleValue());
  113. }
  114. double xMax = -1.e20;
  115. for (int k = 0; k < this.xValues.length; k++) {
  116. xMax = Math.max(xMax, this.xValues[k].doubleValue());
  117. }
  118. double yMin = 1.e20;
  119. for (int k = 0; k < this.yValues.length; k++) {
  120. yMin = Math.min(yMin, this.yValues[k].doubleValue());
  121. }
  122. double yMax = -1.e20;
  123. for (int k = 0; k < this.yValues.length; k++) {
  124. yMax = Math.max(yMax, this.yValues[k].doubleValue());
  125. }
  126. Range xRange = new Range(xMin, xMax);
  127. Range yRange = new Range(yMin, yMax);
  128. xRange.getLength();
  129. yRange.getLength();
  130. // Determine the cell size
  131. double dxGrid = xRange.getLength() / (numX - 1);
  132. double dyGrid = yRange.getLength() / (numY - 1);
  133. // Generate the grid
  134. double x = 0.0;
  135. for (int i = 0; i < numX; i++) {
  136. if (i == 0) {
  137. x = xMin;
  138. }
  139. else {
  140. x += dxGrid;
  141. }
  142. double y = 0.0;
  143. for (int j = 0; j < numY; j++) {
  144. int k = numY * i + j;
  145. xGrid[k] = x;
  146. if (j == 0) {
  147. y = yMin;
  148. }
  149. else {
  150. y += dyGrid;
  151. }
  152. yGrid[k] = y;
  153. }
  154. }
  155. // Map the nongrid data into the new regular grid
  156. for (int kGrid = 0; kGrid < xGrid.length; kGrid++) {
  157. double dTotal = 0.0;
  158. zGrid[kGrid] = 0.0;
  159. for (int k = 0; k < this.xValues.length; k++) {
  160. double xPt = this.xValues[k].doubleValue();
  161. double yPt = this.yValues[k].doubleValue();
  162. double d = distance(xPt, yPt, xGrid[kGrid], yGrid[kGrid]);
  163. if (power != 1) {
  164. d = Math.pow(d, power);
  165. }
  166. d = Math.sqrt(d);
  167. if (d > 0.0) {
  168. d = 1.0 / d;
  169. }
  170. else { // if d is real small set the inverse to a large number
  171. // to avoid INF
  172. d = 1.e20;
  173. }
  174. if (this.zValues[k] != null) {
  175. // scale by the inverse of distance^power
  176. zGrid[kGrid] += this.zValues[k].doubleValue() * d;
  177. }
  178. dTotal += d;
  179. }
  180. zGrid[kGrid] = zGrid[kGrid] / dTotal; //remove distance of the sum
  181. }
  182. //initalize xValues, yValues, and zValues arrays.
  183. initialize(
  184. formObjectArray(xGrid), formObjectArray(yGrid),
  185. formObjectArray(zGrid)
  186. );
  187. }
  188. /**
  189. * Calculates the distance between two points.
  190. *
  191. * @param xDataPt the x coordinate.
  192. * @param yDataPt the y coordinate.
  193. * @param xGrdPt the x grid coordinate.
  194. * @param yGrdPt the y grid coordinate.
  195. *
  196. * @return The distance between two points.
  197. */
  198. protected double distance(double xDataPt,
  199. double yDataPt,
  200. double xGrdPt,
  201. double yGrdPt) {
  202. double dx = xDataPt - xGrdPt;
  203. double dy = yDataPt - yGrdPt;
  204. return Math.sqrt(dx * dx + dy * dy);
  205. }
  206. }