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     * NonGridContourDataset.java
029     * --------------------------
030     * (C) Copyright 2002-2007, 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.2 2007/01/31 15:56:19 mungady Exp $
036     *
037     * Changes (from 24-Jul-2003)
038     * --------------------------
039     * 24-Jul-2003 : Added standard header (DG);
040     * ------------- JFREECHART 1.0.x ---------------------------------------------
041     * 31-Jan-2007 : Deprecated (DG);
042     *
043     */
044    
045    package org.jfree.data.contour;
046    
047    import org.jfree.chart.plot.XYPlot;
048    import org.jfree.chart.renderer.xy.XYBlockRenderer;
049    import org.jfree.data.Range;
050    
051    /**
052     * A convenience class that extends the {@link DefaultContourDataset} to 
053     * accommodate non-grid data.
054     * 
055     * @deprecated This class is no longer supported.  If you are creating
056     *     contour plots, please try to use {@link XYPlot} and 
057     *     {@link XYBlockRenderer}.
058     */
059    public class NonGridContourDataset extends DefaultContourDataset {
060    
061        /** Default number of x values. */
062        static final int DEFAULT_NUM_X = 50;
063        
064        /** Default number of y values. */
065        static final int DEFAULT_NUM_Y = 50;
066        
067        /** Default power. */
068        static final int DEFAULT_POWER = 4;
069    
070        /**
071         * Default constructor.
072         */
073        public NonGridContourDataset() {
074            super();
075        }
076    
077        /**
078         * Constructor for NonGridContourDataset.  Uses default values for grid 
079         * dimensions and weighting.
080         * 
081         * @param seriesName  the series name.
082         * @param xData  the x values.
083         * @param yData  the y values.
084         * @param zData  the z values.
085         */
086        public NonGridContourDataset(String seriesName,
087                                     Object[] xData, Object[] yData, 
088                                     Object[] zData) {
089            super(seriesName, xData, yData, zData);
090            buildGrid(DEFAULT_NUM_X, DEFAULT_NUM_Y, DEFAULT_POWER);
091        }
092    
093        /**
094         * Constructor for NonGridContourDataset.
095         * 
096         * @param seriesName  the series name.
097         * @param xData  the x values.
098         * @param yData  the y values.
099         * @param zData  the z values.
100         * @param numX  number grid cells in along the x-axis
101         * @param numY  number grid cells in along the y-axis
102         * @param power  exponent for inverse distance weighting
103         */
104        public NonGridContourDataset(String seriesName, 
105                                     Object[] xData, Object[] yData, 
106                                     Object[] zData,
107                                     int numX, int numY, int power) {
108            super(seriesName, xData, yData, zData);
109            buildGrid(numX, numY, power);
110        }
111    
112        /**
113         * Builds a regular grid.  Maps the non-grid data into the regular grid 
114         * using an inverse distance between grid and non-grid points.  Weighting 
115         * of distance can be controlled by setting through the power parameter 
116         * that controls the exponent used on the distance weighting 
117         * (e.g., distance^power).
118         * 
119         * @param numX  number grid points in along the x-axis
120         * @param numY  number grid points in along the y-axis
121         * @param power  exponent for inverse distance weighting
122         */
123        protected void buildGrid(int numX, int numY, int power) {
124    
125            int numValues = numX * numY;
126            double[] xGrid = new double[numValues];
127            double[] yGrid = new double [numValues];
128            double[] zGrid = new double [numValues];
129    
130            // Find min, max for the x and y axes
131            double xMin = 1.e20;
132            for (int k = 0; k < this.xValues.length; k++) {
133                xMin = Math.min(xMin, this.xValues[k].doubleValue());
134            }
135    
136            double xMax = -1.e20;
137            for (int k = 0; k < this.xValues.length; k++) {
138                xMax = Math.max(xMax, this.xValues[k].doubleValue());
139            }
140    
141            double yMin = 1.e20;
142            for (int k = 0; k < this.yValues.length; k++) {
143                yMin = Math.min(yMin, this.yValues[k].doubleValue());
144            }
145    
146            double yMax = -1.e20;
147            for (int k = 0; k < this.yValues.length; k++) {
148                yMax = Math.max(yMax, this.yValues[k].doubleValue());
149            }
150    
151            Range xRange = new Range(xMin, xMax);
152            Range yRange = new Range(yMin, yMax);
153    
154            xRange.getLength();
155            yRange.getLength();
156    
157            // Determine the cell size
158            double dxGrid = xRange.getLength() / (numX - 1);
159            double dyGrid = yRange.getLength() / (numY - 1);
160    
161            // Generate the grid
162            double x = 0.0;
163            for (int i = 0; i < numX; i++) {
164                if (i == 0) {
165                    x = xMin;
166                }
167                else {
168                    x += dxGrid;
169                }
170                double y = 0.0;
171                for (int j = 0; j < numY; j++) {
172                    int k = numY * i + j;
173                    xGrid[k] = x;
174                    if (j == 0) {
175                        y = yMin;
176                    }
177                    else {
178                        y += dyGrid;
179                    }
180                    yGrid[k] = y;
181                }
182            }
183    
184            // Map the nongrid data into the new regular grid
185            for (int kGrid = 0; kGrid < xGrid.length; kGrid++) {
186                double dTotal = 0.0;
187                zGrid[kGrid] = 0.0;
188                for (int k = 0; k < this.xValues.length; k++) {
189                    double xPt = this.xValues[k].doubleValue();
190                    double yPt = this.yValues[k].doubleValue();
191                    double d = distance(xPt, yPt, xGrid[kGrid], yGrid[kGrid]);
192                    if (power != 1) {
193                        d = Math.pow(d, power);
194                    }
195                    d = Math.sqrt(d);
196                    if (d > 0.0) {
197                        d = 1.0 / d;
198                    }
199                    else { // if d is real small set the inverse to a large number 
200                           // to avoid INF
201                        d = 1.e20;
202                    }
203                    if (this.zValues[k] != null) {
204                        // scale by the inverse of distance^power
205                        zGrid[kGrid] += this.zValues[k].doubleValue() * d; 
206                    }
207                    dTotal += d;
208                }
209                zGrid[kGrid] = zGrid[kGrid] / dTotal;  //remove distance of the sum
210            }
211    
212            //initalize xValues, yValues, and zValues arrays.
213            initialize(
214                formObjectArray(xGrid), formObjectArray(yGrid), 
215                formObjectArray(zGrid)
216            );
217    
218        }
219    
220        /**
221         * Calculates the distance between two points.
222         * 
223         * @param xDataPt  the x coordinate.
224         * @param yDataPt  the y coordinate.
225         * @param xGrdPt  the x grid coordinate.
226         * @param yGrdPt  the y grid coordinate.
227         * 
228         * @return The distance between two points.
229         */
230        protected double distance(double xDataPt, 
231                                  double yDataPt, 
232                                  double xGrdPt, 
233                                  double yGrdPt) {
234            double dx = xDataPt - xGrdPt;
235            double dy = yDataPt - yGrdPt;
236            return Math.sqrt(dx * dx + dy * dy);
237        }
238    
239    }