/* * GeoTools - OpenSource mapping toolkit * http://geotools.org * (C) 2002-2006, GeoTools Project Managment Committee (PMC) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.referencing.operation.builder; import java.awt.geom.Point2D; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.geotools.geometry.DirectPosition2D; import org.geotools.referencing.operation.transform.IdentityTransform; import org.opengis.parameter.ParameterValueGroup; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; import org.opengis.spatialschema.geometry.Envelope; /** * Implementation grid builder based on inverse distance weighted (IDW) interpolation. * * @see <A HREF="http://en.wikipedia.org/wiki/Inverse_distance_weighting">IDW at Wikipedia</A> * * @author jezekjan * */ public class IDWGridBuilder extends WarpGridBuilder { /** * Constructs IDWGridBuilder from set of parameters. * * @param vectors known shift vectors * @param dx width of gird cell * @param dy height of grid cells * @param env Envelope of generated grid * @throws TransformException */ public IDWGridBuilder(List vectors, double dx, double dy, Envelope env) throws TransformException { super(vectors, dx, dy, env, IdentityTransform.create(2)); } /** * Constructs IDWGridBuilder from set of parameters. The Warp Grid values are * calculated in transformed coordinate system. * @param vectors known shift vectors * @param dx width of gird cell * @param dy height of grid cells * @param envelope Envelope of generated grid * @param realToGrid Transformation from real to grid coordinates (when working with images) * @throws TransformException */ public IDWGridBuilder(List vectors, double dx, double dy, Envelope envelope, MathTransform realToGrid) throws TransformException { super(vectors, dx, dy, envelope, realToGrid); } protected float[] computeWarpGrid(ParameterValueGroup WarpParams) { float[] warpPositions = (float[]) WarpParams.parameter("warpPositions").getValue(); for (int i = 0; i <= WarpParams.parameter("yNumCells").intValue(); i++) { for (int j = 0; j <= WarpParams.parameter("xNumCells").intValue(); j++) { Point2D shiftVector = calculateShift(new DirectPosition2D(WarpParams.parameter( "xStart").intValue() + (j * WarpParams.parameter("xStep").intValue()), WarpParams.parameter("yStart").intValue() + (i * WarpParams.parameter("yStep").intValue()))); double x = shiftVector.getX() + (j * WarpParams.parameter("xStep").intValue()) + WarpParams.parameter("xStart").intValue(); double y = shiftVector.getY() + (i * WarpParams.parameter("yStep").intValue()) + WarpParams.parameter("yStart").intValue(); warpPositions[(i * ((1 + WarpParams.parameter("xNumCells").intValue()) * 2)) + (2 * j)] = (float) x; warpPositions[(i * ((1 + WarpParams.parameter("xNumCells").intValue()) * 2)) + (2 * j) + 1] = (float) y; } } return warpPositions; } /** * Calculates the real point shift from the iregular pairs of MappedPositions using * Inverse distance weighting interpolation. The distance is cartesian. * @param p position where we requaired the shift to be calculated * @return x and y shifts as Point2D */ private Point2D calculateShift(Point2D p) { double maxdist = 500000; HashMap nearest = getNearestMappedPositions(p, maxdist); double dx; double sumdx = 0; double dy = 0; double sumdy = 0; double sumweight = 0; for (Iterator i = nearest.keySet().iterator(); i.hasNext();) { MappedPosition mp = (MappedPosition) i.next(); double distance = ((Double) nearest.get(mp)).doubleValue(); double weight = (1 / Math.pow(distance, 2)); if (distance > 0.005) { sumdx = sumdx + ((mp.getTarget().getCoordinates()[0] - mp.getSource().getCoordinates()[0]) * weight); sumdy = sumdy + ((mp.getTarget().getCoordinates()[1] - mp.getSource().getCoordinates()[1]) * weight); sumweight = sumweight + weight; } else { dx = (mp.getTarget().getCoordinates()[0] - mp.getSource().getCoordinates()[0]); dy = (mp.getTarget().getCoordinates()[1] - mp.getSource().getCoordinates()[1]); return (new DirectPosition2D(dx, dy)); } } dx = sumdx / sumweight; dy = sumdy / sumweight; return (new DirectPosition2D(dx, dy)); } /** * Computes nearest points. * @param p * @param maxdistance * @param number * @return * * @todo consider some indexing mechanism for finding the nearest positions */ private HashMap getNearestMappedPositions(Point2D p, double maxdistance) { HashMap nearest = new HashMap(); MappedPosition mp = null; for (Iterator i = this.getGridMappedPositions().iterator(); i.hasNext();) { mp = (MappedPosition) i.next(); double dist = p.distance((Point2D) mp.getSource()); if ((dist < maxdistance)) { nearest.put(mp, new Double(dist)); } } return nearest; } }