    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    }