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