    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/processing/raster/interpolation/InverseDistanceToPower.java $
    002    /*----------------------------------------------------------------------------
    003     This file is part of deegree, http://deegree.org/
    004     Copyright (C) 2001-2009 by:
    005       Department of Geography, University of Bonn
    006     and
    007       lat/lon GmbH
    008
    009     This library is free software; you can redistribute it and/or modify it under
    010     the terms of the GNU Lesser General Public License as published by the Free
    011     Software Foundation; either version 2.1 of the License, or (at your option)
    012     any later version.
    013     This library is distributed in the hope that it will be useful, but WITHOUT
    014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    016     details.
    017     You should have received a copy of the GNU Lesser General Public License
    018     along with this library; if not, write to the Free Software Foundation, Inc.,
    019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    020
    021     Contact information:
    022
    023     lat/lon GmbH
    024     Aennchenstr. 19, 53177 Bonn
    025     Germany
    026     http://lat-lon.de/
    027
    028     Department of Geography, University of Bonn
    029     Prof. Dr. Klaus Greve
    030     Postfach 1147, 53001 Bonn
    031     Germany
    032     http://www.geographie.uni-bonn.de/deegree/
    033
    034     e-mail: info@deegree.org
    035    ----------------------------------------------------------------------------*/
    036    package org.deegree.processing.raster.interpolation;
    037
    038    import java.util.ArrayList;
    039    import java.util.Collections;
    040    import java.util.List;
    041
    042    import org.deegree.datatypes.values.Interval;
    043    import org.deegree.datatypes.values.Values;
    044    import org.deegree.io.quadtree.IndexException;
    045    import org.deegree.io.quadtree.Quadtree;
    046    import org.deegree.model.spatialschema.Envelope;
    047    import org.deegree.model.spatialschema.GeometryFactory;
    048
    049    /**
    050     * Class for interpolating a set of data tuples (x, y, value) onto a grid using Inverse Distance to
    051     * Power algorithm
    052     *
    053     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
    054     * @author last edited by: $Author: mschneider $
    055     *
    056     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
    057     */
    058    public class InverseDistanceToPower extends Interpolation {
    059
    060        private double power = 2;
    061
    062        /**
    063         *
    064         * @param data
    065         * @param power
    066         */
    067        public InverseDistanceToPower( Quadtree<?> data, double power ) {
    068            super( data );
    069            this.power = power;
    070        }
    071
    072        /**
    073         *
    074         * @param data
    075         * @param ignoreValues
    076         * @param power
    077         */
    078        public InverseDistanceToPower( Quadtree<?> data, Values ignoreValues, double power ) {
    079            super( data, ignoreValues );
    080            this.power = power;
    081        }
    082
    083        /**
    084         *
    085         * @param data
    086         * @param ignoreValues
    087         * @param searchRadius1
    088         * @param searchRadius2
    089         * @param searchRadiusAngle
    090         * @param minData
    091         * @param maxData
    092         * @param noValue
    093         * @param autoincreaseSearchRadius1
    094         * @param autoincreaseSearchRadius2
    095         * @param power
    096         */
    097        public InverseDistanceToPower( Quadtree<?> data, Values ignoreValues, double searchRadius1, double searchRadius2,
    098                                       double searchRadiusAngle, int minData, int maxData, double noValue,
    099                                       double autoincreaseSearchRadius1, double autoincreaseSearchRadius2, double power ) {
    100            super( data, ignoreValues, searchRadius1, searchRadius2, searchRadiusAngle, minData, maxData, noValue,
    101                   autoincreaseSearchRadius1, autoincreaseSearchRadius2 );
    102            this.power = power;
    103        }
    104
    105        /**
    106         * calculates the interpolated value for a position defined by x and y
    107         *
    108         * @param x
    109         * @param y
    110         * @return the interpolated value
    111         * @throws InterpolationException
    112         */
    113        @Override
    114        public double calcInterpolatedValue( double x, double y, double searchRadius1, double searchRadius2 )
    115                                throws InterpolationException {
    116            double tmpSR1 = searchRadius1;
    117            double tmpSR2 = searchRadius2;
    118
    119            try {
    120                Envelope searchRadius = GeometryFactory.createEnvelope( x - tmpSR1, y - tmpSR2, x + tmpSR1, y + tmpSR2,
    121                                                                        null );
    122                List<?> foundValues = data.query( searchRadius );
    123
    124                List<DataTuple> values = new ArrayList<DataTuple>();
    125                for ( Object obj : foundValues ) {
    126                    DataTuple tuple = (DataTuple) obj;
    127
    128                    boolean ignore = false;
    129
    130                    if ( ignoreValues != null && ignoreValues.getInterval().length > 0 ) {
    131                        for ( Interval interval : ignoreValues.getInterval() ) {
    132                            double min = Double.parseDouble( interval.getMin().getValue() );
    133                            double max = Double.parseDouble( interval.getMax().getValue() );
    134                            if ( tuple.value > min && tuple.value < max ) {
    135                                ignore = true;
    136                            }
    137                        }
    138                    }
    139
    140                    if ( !ignore ) {
    141                        double dx = Math.abs( tuple.x - x );
    142                        double dy = Math.abs( tuple.y - y );
    143                        /*
    144                         * if ( dx == 0 && dy == 0 ) { // System.out.println( "Call with already
    145                         * existing value!" ); return tuple.value; }
    146                         */
    147                        double dist = Math.sqrt( dx * dx + dy * dy );
    148                        double weight = Math.pow( dist, power );
    149                        values.add( new DataTuple( dist, tuple.value, weight ) );
    150                    }
    151                }
    152
    153                if ( values.size() < minData ) {
    154                    if ( autoincreaseSearchRadius1 == 0 && autoincreaseSearchRadius2 == 0 ) {
    155                        return noValue;
    156                    }
    157
    158                    tmpSR1 += autoincreaseSearchRadius1;
    159                    tmpSR2 += autoincreaseSearchRadius2;
    160                    // System.out.print( " Increasing the search radius to " + tmpSR1 + " and " + tmpSR2
    161                    // +"\r" );
    162                    return calcInterpolatedValue( x, y, tmpSR1, tmpSR2 );
    163                }
    164
    165                if ( values.size() > maxData ) {
    166                    Collections.sort( values );
    167                    values = values.subList( 0, maxData );
    168                }
    169
    170                double valueSum = 0;
    171
    172                double weightSum = 0;
    173
    174                for ( Object obj : values ) {
    175                    // in the data tuple, x is interpreted as the distance, y is the value and
    176                    // "value" is the weight
    177                    DataTuple tuple = (DataTuple) obj;
    178                    valueSum += ( tuple.y / tuple.value );
    179                    weightSum += ( 1 / tuple.value );
    180                }
    181
    182                double result = ( valueSum / weightSum );
    183
    184                if ( Double.isInfinite( result ) ) {
    185                    return noValue;
    186                }
    187
    188                if ( Double.isNaN( result ) ) {
    189                    return noValue;
    190                }
    191
    192                return result;
    193            } catch ( IndexException e ) {
    194                throw new InterpolationException( e );
    195            }
    196        }
    197    }