001: /* ===========================================================
002: * JFreeChart : a free chart library for the Java(tm) platform
003: * ===========================================================
004: *
005: * (C) Copyright 2000-2007, 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: * DefaultContourDataset.java
029: * --------------------------
030: * (C) Copyright 2002-2005, by David M. O'Donnell and Contributors.
031: *
032: * Original Author: David M. O'Donnell;
033: * Contributor(s): David Gilbert (for Object Refinery Limited);
034: *
035: * $Id: DefaultContourDataset.java,v 1.6.2.4 2007/04/04 09:08:21 mungady Exp $
036: *
037: * Changes (from 23-Jan-2003)
038: * --------------------------
039: * 23-Jan-2003 : Added standard header (DG);
040: * 20-May-2003 : removed member vars numX and numY, which were never used (TM);
041: * 06-May-2004 : Now extends AbstractXYZDataset (DG);
042: * 15-Jul-2004 : Switched getX() with getXValue(), getY() with getYValue() and
043: * getZ() with getZValue() methods (DG);
044: * ------------- JFREECHART 1.0.x --------------------------------------------
045: * 31-Jan-2007 : Deprecated (DG);
046: *
047: */
048:
049: package org.jfree.data.contour;
050:
051: import java.util.Arrays;
052: import java.util.Date;
053: import java.util.Vector;
054:
055: import org.jfree.chart.plot.XYPlot;
056: import org.jfree.chart.renderer.xy.XYBlockRenderer;
057: import org.jfree.data.Range;
058: import org.jfree.data.xy.AbstractXYZDataset;
059: import org.jfree.data.xy.XYDataset;
060:
061: /**
062: * A convenience class that provides a default implementation of the
063: * {@link ContourDataset} interface.
064: *
065: * @deprecated This class is no longer supported (as of version 1.0.4). If
066: * you are creating contour plots, please try to use {@link XYPlot} and
067: * {@link XYBlockRenderer}.
068: */
069: public class DefaultContourDataset extends AbstractXYZDataset implements
070: ContourDataset {
071:
072: /** The series name (this dataset supports only one series). */
073: protected Comparable seriesKey = null;
074:
075: /** Storage for the x values. */
076: protected Number[] xValues = null;
077:
078: /** Storage for the y values. */
079: protected Number[] yValues = null;
080:
081: /** Storage for the z values. */
082: protected Number[] zValues = null;
083:
084: /** The index for the start of each column in the data. */
085: protected int[] xIndex = null;
086:
087: /** Flags that track whether x, y and z are dates. */
088: boolean[] dateAxis = new boolean[3];
089:
090: /**
091: * Creates a new dataset, initially empty.
092: */
093: public DefaultContourDataset() {
094: super ();
095: }
096:
097: /**
098: * Constructs a new dataset with the given data.
099: *
100: * @param seriesKey the series key.
101: * @param xData the x values.
102: * @param yData the y values.
103: * @param zData the z values.
104: */
105: public DefaultContourDataset(Comparable seriesKey, Object[] xData,
106: Object[] yData, Object[] zData) {
107:
108: this .seriesKey = seriesKey;
109: initialize(xData, yData, zData);
110: }
111:
112: /**
113: * Initialises the dataset.
114: *
115: * @param xData the x values.
116: * @param yData the y values.
117: * @param zData the z values.
118: */
119: public void initialize(Object[] xData, Object[] yData,
120: Object[] zData) {
121:
122: this .xValues = new Double[xData.length];
123: this .yValues = new Double[yData.length];
124: this .zValues = new Double[zData.length];
125:
126: // We organise the data with the following assumption:
127: // 1) the data are sorted by x then y
128: // 2) that the data will be represented by a rectangle formed by
129: // using x[i+1], x, y[j+1], and y.
130: // 3) we march along the y-axis at the same value of x until a new
131: // value x is found at which point we will flag the index
132: // where x[i+1]<>x[i]
133:
134: Vector tmpVector = new Vector(); //create a temporary vector
135: double x = 1.123452e31; // set x to some arbitary value (used below)
136: for (int k = 0; k < this .xValues.length; k++) {
137: if (xData[k] != null) {
138: Number xNumber;
139: if (xData[k] instanceof Number) {
140: xNumber = (Number) xData[k];
141: } else if (xData[k] instanceof Date) {
142: this .dateAxis[0] = true;
143: Date xDate = (Date) xData[k];
144: xNumber = new Long(xDate.getTime()); //store data as Long
145: } else {
146: xNumber = new Integer(0);
147: }
148: this .xValues[k] = new Double(xNumber.doubleValue());
149: // store Number as Double
150:
151: // check if starting new column
152: if (x != this .xValues[k].doubleValue()) {
153: tmpVector.add(new Integer(k)); //store index where new
154: //column starts
155: x = this .xValues[k].doubleValue();
156: // set x to most recent value
157: }
158: }
159: }
160:
161: Object[] inttmp = tmpVector.toArray();
162: this .xIndex = new int[inttmp.length]; // create array xIndex to hold
163: // new column indices
164:
165: for (int i = 0; i < inttmp.length; i++) {
166: this .xIndex[i] = ((Integer) inttmp[i]).intValue();
167: }
168: for (int k = 0; k < this .yValues.length; k++) { // store y and z axes
169: // as Doubles
170: this .yValues[k] = (Double) yData[k];
171: if (zData[k] != null) {
172: this .zValues[k] = (Double) zData[k];
173: }
174: }
175: }
176:
177: /**
178: * Creates an object array from an array of doubles.
179: *
180: * @param data the data.
181: *
182: * @return An array of <code>Double</code> objects.
183: */
184: public static Object[][] formObjectArray(double[][] data) {
185: Object[][] object = new Double[data.length][data[0].length];
186:
187: for (int i = 0; i < object.length; i++) {
188: for (int j = 0; j < object[i].length; j++) {
189: object[i][j] = new Double(data[i][j]);
190: }
191: }
192: return object;
193: }
194:
195: /**
196: * Creates an object array from an array of doubles.
197: *
198: * @param data the data.
199: *
200: * @return An array of <code>Double</code> objects.
201: */
202: public static Object[] formObjectArray(double[] data) {
203: Object[] object = new Double[data.length];
204: for (int i = 0; i < object.length; i++) {
205: object[i] = new Double(data[i]);
206: }
207: return object;
208: }
209:
210: /**
211: * Returns the number of items in the specified series. This method
212: * is provided to satisfy the {@link XYDataset} interface implementation.
213: *
214: * @param series must be zero, as this dataset only supports one series.
215: *
216: * @return The item count.
217: */
218: public int getItemCount(int series) {
219: if (series > 0) {
220: throw new IllegalArgumentException(
221: "Only one series for contour");
222: }
223: return this .zValues.length;
224: }
225:
226: /**
227: * Returns the maximum z-value.
228: *
229: * @return The maximum z-value.
230: */
231: public double getMaxZValue() {
232: double zMax = -1.e20;
233: for (int k = 0; k < this .zValues.length; k++) {
234: if (this .zValues[k] != null) {
235: zMax = Math.max(zMax, this .zValues[k].doubleValue());
236: }
237: }
238: return zMax;
239: }
240:
241: /**
242: * Returns the minimum z-value.
243: *
244: * @return The minimum z-value.
245: */
246: public double getMinZValue() {
247: double zMin = 1.e20;
248: for (int k = 0; k < this .zValues.length; k++) {
249: if (this .zValues[k] != null) {
250: zMin = Math.min(zMin, this .zValues[k].doubleValue());
251: }
252: }
253: return zMin;
254: }
255:
256: /**
257: * Returns the maximum z-value within visible region of plot.
258: *
259: * @param x the x range.
260: * @param y the y range.
261: *
262: * @return The z range.
263: */
264: public Range getZValueRange(Range x, Range y) {
265:
266: double minX = x.getLowerBound();
267: double minY = y.getLowerBound();
268: double maxX = x.getUpperBound();
269: double maxY = y.getUpperBound();
270:
271: double zMin = 1.e20;
272: double zMax = -1.e20;
273: for (int k = 0; k < this .zValues.length; k++) {
274: if (this .xValues[k].doubleValue() >= minX
275: && this .xValues[k].doubleValue() <= maxX
276: && this .yValues[k].doubleValue() >= minY
277: && this .yValues[k].doubleValue() <= maxY) {
278: if (this .zValues[k] != null) {
279: zMin = Math
280: .min(zMin, this .zValues[k].doubleValue());
281: zMax = Math
282: .max(zMax, this .zValues[k].doubleValue());
283: }
284: }
285: }
286:
287: return new Range(zMin, zMax);
288: }
289:
290: /**
291: * Returns the minimum z-value.
292: *
293: * @param minX the minimum x value.
294: * @param minY the minimum y value.
295: * @param maxX the maximum x value.
296: * @param maxY the maximum y value.
297: *
298: * @return The minimum z-value.
299: */
300: public double getMinZValue(double minX, double minY, double maxX,
301: double maxY) {
302:
303: double zMin = 1.e20;
304: for (int k = 0; k < this .zValues.length; k++) {
305: if (this .zValues[k] != null) {
306: zMin = Math.min(zMin, this .zValues[k].doubleValue());
307: }
308: }
309: return zMin;
310:
311: }
312:
313: /**
314: * Returns the number of series.
315: * <P>
316: * Required by XYDataset interface (this will always return 1)
317: *
318: * @return 1.
319: */
320: public int getSeriesCount() {
321: return 1;
322: }
323:
324: /**
325: * Returns the name of the specified series.
326: *
327: * Method provided to satisfy the XYDataset interface implementation
328: *
329: * @param series must be zero.
330: *
331: * @return The series name.
332: */
333: public Comparable getSeriesKey(int series) {
334: if (series > 0) {
335: throw new IllegalArgumentException(
336: "Only one series for contour");
337: }
338: return this .seriesKey;
339: }
340:
341: /**
342: * Returns the index of the xvalues.
343: *
344: * @return The x values.
345: */
346: public int[] getXIndices() {
347: return this .xIndex;
348: }
349:
350: /**
351: * Returns the x values.
352: *
353: * @return The x values.
354: */
355: public Number[] getXValues() {
356: return this .xValues;
357: }
358:
359: /**
360: * Returns the x value for the specified series and index (zero-based
361: * indices). Required by the {@link XYDataset}.
362: *
363: * @param series must be zero;
364: * @param item the item index (zero-based).
365: *
366: * @return The x value.
367: */
368: public Number getX(int series, int item) {
369: if (series > 0) {
370: throw new IllegalArgumentException(
371: "Only one series for contour");
372: }
373: return this .xValues[item];
374: }
375:
376: /**
377: * Returns an x value.
378: *
379: * @param item the item index (zero-based).
380: *
381: * @return The X value.
382: */
383: public Number getXValue(int item) {
384: return this .xValues[item];
385: }
386:
387: /**
388: * Returns a Number array containing all y values.
389: *
390: * @return The Y values.
391: */
392: public Number[] getYValues() {
393: return this .yValues;
394: }
395:
396: /**
397: * Returns the y value for the specified series and index (zero-based
398: * indices). Required by the {@link XYDataset}.
399: *
400: * @param series the series index (must be zero for this dataset).
401: * @param item the item index (zero-based).
402: *
403: * @return The Y value.
404: */
405: public Number getY(int series, int item) {
406: if (series > 0) {
407: throw new IllegalArgumentException(
408: "Only one series for contour");
409: }
410: return this .yValues[item];
411: }
412:
413: /**
414: * Returns a Number array containing all z values.
415: *
416: * @return The Z values.
417: */
418: public Number[] getZValues() {
419: return this .zValues;
420: }
421:
422: /**
423: * Returns the z value for the specified series and index (zero-based
424: * indices). Required by the {@link XYDataset}
425: *
426: * @param series the series index (must be zero for this dataset).
427: * @param item the item index (zero-based).
428: *
429: * @return The Z value.
430: */
431: public Number getZ(int series, int item) {
432: if (series > 0) {
433: throw new IllegalArgumentException(
434: "Only one series for contour");
435: }
436: return this .zValues[item];
437: }
438:
439: /**
440: * Returns an int array contain the index into the x values.
441: *
442: * @return The X values.
443: */
444: public int[] indexX() {
445: int[] index = new int[this .xValues.length];
446: for (int k = 0; k < index.length; k++) {
447: index[k] = indexX(k);
448: }
449: return index;
450: }
451:
452: /**
453: * Given index k, returns the column index containing k.
454: *
455: * @param k index of interest.
456: *
457: * @return The column index.
458: */
459: public int indexX(int k) {
460: int i = Arrays.binarySearch(this .xIndex, k);
461: if (i >= 0) {
462: return i;
463: } else {
464: return -1 * i - 2;
465: }
466: }
467:
468: /**
469: * Given index k, return the row index containing k.
470: *
471: * @param k index of interest.
472: *
473: * @return The row index.
474: */
475: public int indexY(int k) { // this may be obsolete (not used anywhere)
476: return (k / this .xValues.length);
477: }
478:
479: /**
480: * Given column and row indices, returns the k index.
481: *
482: * @param i index of along x-axis.
483: * @param j index of along y-axis.
484: *
485: * @return The Z index.
486: */
487: public int indexZ(int i, int j) {
488: return this .xValues.length * j + i;
489: }
490:
491: /**
492: * Returns true if axis are dates.
493: *
494: * @param axisNumber The axis where 0-x, 1-y, and 2-z.
495: *
496: * @return A boolean.
497: */
498: public boolean isDateAxis(int axisNumber) {
499: if (axisNumber < 0 || axisNumber > 2) {
500: return false; // bad axisNumber
501: }
502: return this .dateAxis[axisNumber];
503: }
504:
505: /**
506: * Sets the names of the series in the data source.
507: *
508: * @param seriesKeys the keys of the series in the data source.
509: */
510: public void setSeriesKeys(Comparable[] seriesKeys) {
511: if (seriesKeys.length > 1) {
512: throw new IllegalArgumentException(
513: "Contours only support one series");
514: }
515: this .seriesKey = seriesKeys[0];
516: fireDatasetChanged();
517: }
518:
519: }
|