Mercurial > dive4elements > gnv-client
diff gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation2D.java @ 376:d8f3ef441bf2
merged gnv-artifacts/0.3
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:13:47 +0200 |
parents | 086e3af38b96 |
children | 04a242c67fe6 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation2D.java Fri Sep 28 12:13:47 2012 +0200 @@ -0,0 +1,214 @@ +package de.intevation.gnv.math; + +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Collections; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; + +import com.vividsolutions.jts.index.quadtree.Quadtree; + +import org.apache.log4j.Logger; + +/** + * @author Sascha L. Teichmann + */ +public final class Interpolation2D +{ + private static Logger log = Logger.getLogger(Interpolation2D.class); + + public interface Consumer { + void interpolated(Coordinate point); + } // interface Consumer + + private Interpolation2D() { + } + + public static void interpolate( + List<? extends Coordinate> path, + List<? extends Point2d> points, + double from, + double to, + int steps, + Metrics metrics, + Consumer consumer + ) { + int N = path.size(); + int M = points.size(); + + log.debug("Size of path: " + N); + log.debug("Size of points: " + M); + + if (M < 1 || N < 2) { // nothing to do + return; + } + + HashMap<Integer, ArrayList<Point2d>> map = new HashMap<Integer, ArrayList<Point2d>>(); + + for (int k = M-1; k >= 0; --k) { + Point2d p = points.get(k); + + ArrayList<Point2d> list = map.get(p.j); + + if (list == null) { + map.put(p.j, list = new ArrayList<Point2d>()); + } + list.add(p); + } + + double dxMax = -Double.MAX_VALUE; + + for (ArrayList<Point2d> v: map.values()) { + Collections.sort(v, Point2d.X_COMPARATOR); + for (int i = 1, L = v.size(); i < L; ++i) { + double dx = Math.abs(v.get(i).x - v.get(i-1).x); + if (dx > dxMax) { + dxMax = dx; + } + } + } + + dxMax = dxMax + 1e-5d; + + map.clear(); + + for (int k = M-1; k >= 0; --k) { + Point2d p = points.get(k); + + ArrayList<Point2d> list = map.get(p.i); + + if (list == null) { + map.put(p.i, list = new ArrayList<Point2d>()); + } + list.add(p); + } + + double dyMax = -Double.MAX_VALUE; + + for (ArrayList<Point2d> v: map.values()) { + Collections.sort(v, Point2d.Y_COMPARATOR); + for (int i = 1, L = v.size(); i < L; ++i) { + double dy = Math.abs(v.get(i).y - v.get(i-1).y); + if (dy > dyMax) { + dyMax = dy; + } + } + } + + dyMax = dyMax + 1e-5d; + + map = null; + + log.debug("buffer size: " + dxMax + " / " + dyMax); + + // put into spatial index to speed up finding neighbors. + Quadtree spatialIndex = new Quadtree(); + + for (int i = 0; i < M; ++i) { + Point2d p = points.get(i); + spatialIndex.insert(p.envelope(), p); + } + + LinearToMap linearToMap = new LinearToMap( + path, from, to, metrics); + + double dP = (to - from)/steps; + + Coordinate center = new Coordinate(); + + Envelope queryBuffer = new Envelope(); + + Point2d [] neighbors = new Point2d[4]; + + int missedInterpolations = 0; + int interpolations = 0; + + for (double p = from; p <= to; p += dP) { + if (!linearToMap.locate(p, center)) { + continue; + } + queryBuffer.init( + center.x - dxMax, center.x + dxMax, + center.y - dyMax, center.y + dyMax); + + List potential = spatialIndex.query(queryBuffer); + + L1Comparator invL1 = new L1Comparator(center); + Collections.sort(potential, invL1); + + neighbors[0] = neighbors[1] = + neighbors[2] = neighbors[3] = null; + + /* bit code of neighbors + 0---1 + | x | + 2---3 + */ + + int mask = 0; + // reversed order is essential here! + for (int i = potential.size()-1; i >= 0; --i) { + Point2d n = (Point2d)potential.get(i); + int code = n.x > center.x ? 1 : 0; + if (n.y > center.y) code |= 2; + neighbors[code] = n; + mask |= 1 << code; + } + + int numNeighbors = Integer.bitCount(mask); + + // only interpolate if we have all four neighbors + // and we do not have any gaps. + if (numNeighbors == 4 + && !neighbors[0].hasIGap(neighbors[1]) + && !neighbors[1].hasJGap(neighbors[3]) + && !neighbors[3].hasIGap(neighbors[2]) + && !neighbors[2].hasJGap(neighbors[0]) + ) { + double z1 = interpolate( + neighbors[0].x, neighbors[0].z, + neighbors[1].x, neighbors[1].z, + center.x); + double z2 = interpolate( + neighbors[2].x, neighbors[2].z, + neighbors[3].x, neighbors[3].z, + center.x); + double y1 = interpolate( + neighbors[0].x, neighbors[0].y, + neighbors[1].x, neighbors[1].y, + center.x); + double y2 = interpolate( + neighbors[2].x, neighbors[2].y, + neighbors[3].x, neighbors[3].y, + center.x); + center.z = interpolate( + y1, z1, + y2, z2, + center.y); + consumer.interpolated(center); + ++interpolations; + } + else { + ++missedInterpolations; + } + } + + log.debug("interpolations: " + interpolations + " / " + missedInterpolations); + } + + public static final double interpolate( + double x1, double y1, + double x2, double y2, + double x + ) { + if (x2 == x1) { + return (y1 + y2)*0.5d; + } + double m = (y2-y1)/(x2-x1); + double b = y1 - m*x1; + return m*x + b; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: