sascha@361: package de.intevation.gnv.math; sascha@361: sascha@361: import java.util.List; sascha@361: import java.util.Collections; sascha@361: sascha@361: import com.vividsolutions.jts.geom.Coordinate; sascha@361: import com.vividsolutions.jts.geom.Envelope; sascha@361: sascha@361: import com.vividsolutions.jts.index.quadtree.Quadtree; sascha@361: sascha@361: /** sascha@361: * @author Sascha L. Teichmann sascha@361: */ sascha@361: public final class Interpolation2D sascha@361: { sascha@361: public interface Consumer { sascha@361: void interpolated(Coordinate point); sascha@361: } // interface Consumer sascha@361: sascha@361: private Interpolation2D() { sascha@361: } sascha@361: sascha@361: public static void interpolate( sascha@361: List path, sascha@361: List points, sascha@361: double from, sascha@361: double to, sascha@361: int steps, sascha@361: Metrics metrics, sascha@361: Consumer consumer sascha@361: ) { sascha@361: int N = path.size(); sascha@361: int M = points.size(); sascha@361: sascha@361: if (M < 1 || N < 2) { // nothing to do sascha@361: return; sascha@361: } sascha@361: // figure out max delta(p[i].x, p[i-1].x) sascha@361: Collections.sort(points, Point2d.X_COMPARATOR); sascha@361: double dxMax = -Double.MAX_VALUE; sascha@361: for (int i = 1; i < M; ++i) { sascha@361: double dx = Math.abs(path.get(i).x - path.get(i-1).x); sascha@361: if (dx > dxMax) { sascha@361: dxMax = dx; sascha@361: } sascha@361: } sascha@361: sascha@361: dxMax = dxMax*0.5d + 1e-5d; sascha@361: sascha@361: // figure out max delta(p[i].y, p[i-1].y) sascha@361: Collections.sort(path, Point2d.X_COMPARATOR); sascha@361: double dyMax = -Double.MAX_VALUE; sascha@361: for (int i = 1; i < M; ++i) { sascha@361: double dy = Math.abs(path.get(i).y - path.get(i-1).y); sascha@361: if (dy > dyMax) { sascha@361: dyMax = dy; sascha@361: } sascha@361: } sascha@361: sascha@361: dyMax = dyMax*0.5d + 1e-5d; sascha@361: sascha@361: // put into spatial index to speed up finding neighbors. sascha@361: Quadtree spatialIndex = new Quadtree(); sascha@361: sascha@361: for (int i = 0; i < M; ++i) { sascha@361: Point2d p = points.get(i); sascha@361: spatialIndex.insert(p.envelope(), p); sascha@361: } sascha@361: sascha@361: LinearToMap linearToMap = new LinearToMap( sascha@361: path, from, to, metrics); sascha@361: sascha@361: double dP = (to - from)/steps; sascha@361: sascha@361: Coordinate center = new Coordinate(); sascha@361: sascha@361: Envelope queryBuffer = new Envelope(); sascha@361: sascha@361: Point2d [] neighbors = new Point2d[4]; sascha@361: sascha@361: for (double p = to; p <= from; p += dP) { sascha@361: if (!linearToMap.locate(p, center)) { sascha@361: continue; sascha@361: } sascha@361: queryBuffer.init( sascha@361: center.x - dxMax, center.x + dxMax, sascha@361: center.y - dyMax, center.y + dyMax); sascha@361: sascha@361: List potential = spatialIndex.query(queryBuffer); sascha@361: sascha@361: L1Comparator invL1 = new L1Comparator(center); sascha@361: Collections.sort(potential, invL1); sascha@361: sascha@361: neighbors[0] = neighbors[1] = sascha@361: neighbors[2] = neighbors[3] = null; sascha@361: sascha@361: /* bit code of neighbors sascha@361: 0---1 sascha@361: | x | sascha@361: 2---3 sascha@361: */ sascha@361: sascha@361: int mask = 0; sascha@361: // reversed order is essential here! sascha@361: for (int i = potential.size()-1; i >= 0; --i) { sascha@361: Point2d n = (Point2d)potential.get(i); sascha@361: int code = n.x > center.x ? 1 : 0; sascha@361: if (n.y > center.y) code |= 2; sascha@361: neighbors[code] = n; sascha@361: mask |= 1 << code; sascha@361: } sascha@361: sascha@361: int numNeighbors = Integer.bitCount(mask); sascha@361: sascha@361: // only interpolate if we have all four neighbors sascha@361: // and we do not have any gaps. sascha@361: if (numNeighbors == 4 sascha@361: && !neighbors[0].hasIGap(neighbors[0]) sascha@361: && !neighbors[1].hasJGap(neighbors[3]) sascha@361: && !neighbors[3].hasIGap(neighbors[2]) sascha@361: && !neighbors[2].hasJGap(neighbors[0]) sascha@361: ) { sascha@361: double z1 = interpolate( sascha@361: neighbors[0].x, neighbors[0].z, sascha@361: neighbors[1].x, neighbors[1].z, sascha@361: center.x); sascha@361: double z2 = interpolate( sascha@361: neighbors[2].x, neighbors[2].z, sascha@361: neighbors[3].x, neighbors[3].z, sascha@361: center.x); sascha@361: double y1 = interpolate( sascha@361: neighbors[0].x, neighbors[0].y, sascha@361: neighbors[1].x, neighbors[1].y, sascha@361: center.x); sascha@361: double y2 = interpolate( sascha@361: neighbors[2].x, neighbors[2].y, sascha@361: neighbors[3].x, neighbors[3].y, sascha@361: center.x); sascha@361: center.z = interpolate( sascha@361: y1, z1, sascha@361: y2, z2, sascha@361: center.y); sascha@361: consumer.interpolated(center); sascha@361: } sascha@361: } sascha@361: } sascha@361: sascha@361: public static final double interpolate( sascha@361: double x1, double y1, sascha@361: double x2, double y2, sascha@361: double x sascha@361: ) { sascha@361: if (x2 == x1) { sascha@361: return (y1 + y2)*0.5d; sascha@361: } sascha@361: double m = (y2-y1)/(x2-x1); sascha@361: double b = y1 - m*x1; sascha@361: return m*x + b; sascha@361: } sascha@361: } sascha@361: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: