001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_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    }