001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/processing/raster/interpolation/InverseDistanceToPower.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2006 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     ---------------------------------------------------------------------------*/
043    package org.deegree.processing.raster.interpolation;
044    
045    import java.util.ArrayList;
046    import java.util.Collections;
047    import java.util.List;
048    
049    import org.deegree.datatypes.values.Interval;
050    import org.deegree.datatypes.values.Values;
051    import org.deegree.io.quadtree.IndexException;
052    import org.deegree.io.quadtree.Quadtree;
053    import org.deegree.model.spatialschema.Envelope;
054    import org.deegree.model.spatialschema.GeometryFactory;
055    
056    /**
057     * Class for interpolating a set of data tuples (x, y, value) onto
058     * a grid using Inverse Distance to Power algorithm
059     * 
060     *
061     * @version $Revision: 6259 $
062     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
063     * @author last edited by: $Author: bezema $
064     *
065     * @version 1.0. $Revision: 6259 $, $Date: 2007-03-20 10:15:15 +0100 (Di, 20 Mär 2007) $
066     *
067     * @since 2.0
068     */
069    public class InverseDistanceToPower extends Interpolation {
070    
071        private double power = 2;
072    
073        /**
074         * 
075         * @param data
076         * @param power
077         */
078        public InverseDistanceToPower( Quadtree data, double power ) {
079            super( data );
080            this.power = power;
081        }
082    
083        /**
084         * 
085         * @param data
086         * @param ignoreValues
087         * @param power
088         */
089        public InverseDistanceToPower( Quadtree data, Values ignoreValues, double power ) {
090            super( data, ignoreValues );
091            this.power = power;
092        }
093    
094        /**
095         * 
096         * @param data
097         * @param ignoreValues
098         * @param searchRadius1
099         * @param searchRadius2
100         * @param searchRadiusAngle
101         * @param minData
102         * @param maxData
103         * @param noValue
104         * @param autoincreaseSearchRadius1 
105         * @param autoincreaseSearchRadius2 
106         * @param power
107         */
108        public InverseDistanceToPower( Quadtree data, Values ignoreValues, double searchRadius1,
109                                      double searchRadius2, double searchRadiusAngle, int minData,
110                                      int maxData, double noValue, double autoincreaseSearchRadius1,
111                                      double autoincreaseSearchRadius2, double power ) {
112            super( data, ignoreValues, searchRadius1, searchRadius2, searchRadiusAngle, minData,
113                   maxData, noValue, autoincreaseSearchRadius1, autoincreaseSearchRadius2 );
114            this.power = power;
115        }
116    
117        /**
118         * calculates the interpolated value for a position defined by x and y
119         * 
120         * @param x 
121         * @param y 
122         * @return the interpolated value
123         * @throws InterpolationException
124         */
125        @Override
126        public double calcInterpolatedValue( double x, double y, double searchRadius1, double searchRadius2 )
127                                throws InterpolationException {
128            double tmpSR1 = searchRadius1;
129            double tmpSR2 = searchRadius2;
130            
131            try {
132                Envelope searchRadius = GeometryFactory.createEnvelope( x - tmpSR1, y - tmpSR2,
133                                                                        x + tmpSR1, y + tmpSR2, 
134                                                                        null );
135                List foundValues = data.query( searchRadius );
136    
137                List<DataTuple> values = new ArrayList<DataTuple>();
138                for ( Object obj : foundValues ) {
139                    DataTuple tuple = (DataTuple) obj;
140    
141                    boolean ignore = false;
142    
143                    if ( ignoreValues != null && ignoreValues.getInterval().length > 0 ) {
144                        for ( Interval interval : ignoreValues.getInterval() ) {
145                            double min = Double.parseDouble( interval.getMin().getValue() );
146                            double max = Double.parseDouble( interval.getMax().getValue() );
147                            if ( tuple.value > min && tuple.value < max ) {
148                                ignore = true;
149                            }
150                        }
151                    }
152    
153                    if ( !ignore ) {
154                        double dx = Math.abs( tuple.x - x );
155                        double dy = Math.abs( tuple.y - y );
156                        /*
157                        if ( dx == 0 && dy == 0 ) {
158                            //                    System.out.println( "Call with already existing value!" );
159                            return tuple.value;
160                        }
161                        */
162                        double dist = Math.sqrt( dx * dx + dy * dy );
163                        double weight = Math.pow( dist, power );
164                        values.add( new DataTuple( dist, tuple.value, weight ) );
165                    }
166                }
167    
168                if ( values.size() < minData ) {
169                    if ( autoincreaseSearchRadius1 == 0 && autoincreaseSearchRadius2 == 0 ) {
170                        return noValue;
171                    }
172    
173                    tmpSR1 += autoincreaseSearchRadius1;
174                    tmpSR2 += autoincreaseSearchRadius2;
175                    //System.out.print( " Increasing the search radius to " + tmpSR1 + " and " + tmpSR2 +"\r" );
176                    return calcInterpolatedValue( x, y, tmpSR1, tmpSR2 );
177                }
178    
179                if ( values.size() > maxData ) {
180                    Collections.sort( values );
181                    values = values.subList( 0, maxData );
182                }
183    
184                double valueSum = 0;
185    
186                double weightSum = 0;
187    
188                for ( Object obj : values ) {
189                    // in the data tuple, x is interpreted as the distance, y is the value and
190                    // "value" is the weight
191                    DataTuple tuple = (DataTuple) obj;
192                    valueSum += ( tuple.y / tuple.value );
193                    weightSum += ( 1 / tuple.value );
194                }
195    
196                double result = ( valueSum / weightSum );
197    
198                if ( Double.isInfinite( result ) ) {
199                    return noValue;
200                }
201    
202                if ( Double.isNaN( result ) ) {
203                    return noValue;
204                }
205    
206                return result;
207            } catch ( IndexException e ) {
208                throw new InterpolationException( e );
209            }
210        }
211    }
212    
213    /* ********************************************************************
214     Changes to this class. What the people have been up to:
215     $Log$
216     Revision 1.7  2007/01/11 20:32:43  poth
217     code enhancement
218    
219     Revision 1.6  2006/11/17 13:59:47  schmitz
220     Fixed distance calculation.
221    
222     Revision 1.5  2006/11/16 21:03:44  poth
223     *** empty log message ***
224    
225     Revision 1.4  2006/11/16 17:11:17  poth
226     bug fix - calculation of weight
227    
228     Revision 1.3  2006/10/25 11:59:04  schmitz
229     Text2Tiff is unfinished due to problems with geotiff format.
230     The rest of the interpolation/Text2Tiff should work fine now.
231    
232     Revision 1.2  2006/10/20 14:57:08  schmitz
233     Added a memory point quadtree implementation.
234     Used the quadtree for interpolation.
235     Updated the text2tiff tool to use quadtree and interpolation.
236    
237     Revision 1.1  2006/10/12 15:44:57  poth
238     initial checkin
239    
240    
241     ********************************************************************** */