Mercurial > dive4elements > gnv-client
diff gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation2D.java @ 519:4e347624ee7c
Last part to fix gnv/issue153. Now 'Profilschnitte', 'Horizontalschnitte' and 'horizontale Schnittprofile'
all use the same x/y interpolation code.
gnv-artifacts/trunk@613 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Sat, 23 Jan 2010 21:16:45 +0000 |
parents | d9d933e06875 |
children | 44415ae01ddb |
line wrap: on
line diff
--- a/gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation2D.java Sat Jan 23 18:10:34 2010 +0000 +++ b/gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation2D.java Sat Jan 23 21:16:45 2010 +0000 @@ -3,18 +3,10 @@ import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.index.quadtree.Quadtree; - -import gnu.trove.TDoubleArrayList; +import com.vividsolutions.jts.index.strtree.STRtree; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.List; -import org.apache.commons.math.stat.descriptive.moment.Mean; -import org.apache.commons.math.stat.descriptive.moment.StandardDeviation; - import org.apache.log4j.Logger; /** @@ -24,6 +16,11 @@ { private static Logger log = Logger.getLogger(Interpolation2D.class); + public static final int CULL_POINT_THRESHOLD = Integer.getInteger( + "gnv.interpolation2d.cull.point.threshold", 1000); + + public static final double EPS = 1e-6d; + public interface Consumer { void interpolated(Coordinate point, boolean success); } // interface Consumer @@ -31,164 +28,22 @@ private Interpolation2D() { } - private static final double dist(double a, double b) { - a -= b; - return Math.sqrt(a*a); - } - - private static final double OUTLIER_EPS = 0.4d; - - public static final double [] calculateBufferRemoveOutlier( - List <? extends Point2d> points + public static Envelope pathBoundingBox( + List<? extends Coordinate> path, + double extra ) { - HashMap<Integer, ArrayList<Point2d>> iMap = - new HashMap<Integer, ArrayList<Point2d>>(); - - HashMap<Integer, ArrayList<Point2d>> jMap = - new HashMap<Integer, ArrayList<Point2d>>(); - - for (int k = points.size()-1; k >= 0; --k) { - Point2d p = points.get(k); - - ArrayList<Point2d> jList = jMap.get(p.j); - ArrayList<Point2d> iList = iMap.get(p.i); - - if (jList == null) { - jMap.put(p.j, jList = new ArrayList<Point2d>()); - } - jList.add(p); + int N = path.size(); + Envelope area = new Envelope(path.get(N-1)); - if (iList == null) { - iMap.put(p.i, iList = new ArrayList<Point2d>()); - } - iList.add(p); - } - - TDoubleArrayList deltas = new TDoubleArrayList(); - - Mean mean = new Mean(); - StandardDeviation sd = new StandardDeviation(); - - for (ArrayList<Point2d> v: jMap.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); - double dy = v.get(i).distance(v.get(i-1)); - deltas.add(dy); - mean.increment(dy); - sd .increment(dy); - } - } - - deltas.sort(); - - double m = mean.getResult(); - double s = sd .getResult(); - double eps = OUTLIER_EPS*s; - - int yi = deltas.size() - 1; - while (yi > 0 && dist(deltas.get(yi), m) > eps) { - --yi; - } - - double dyMax = deltas.get(yi) + 1e-5d; - - if (log.isDebugEnabled()) { - log.debug("mean y: " + m); - log.debug("sigma y: " + s); + for (int i = N-2; i >= 0; --i) { + area.expandToInclude(path.get(i)); } - deltas.reset(); - mean.clear(); - sd .clear(); - - for (ArrayList<Point2d> v: iMap.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); - double dx = v.get(i).distance(v.get(i-1)); - deltas.add(dx); - mean.increment(dx); - sd .increment(dx); - } - } - - deltas.sort(); - - m = mean.getResult(); - s = sd .getResult(); - eps = OUTLIER_EPS*s; - - int xi = deltas.size() - 1; - - while (xi > 0 && dist(deltas.get(xi), m) > eps) { - --xi; - } - - double dxMax = deltas.get(xi) + 1e-5d; - - if (log.isDebugEnabled()) { - log.debug("mean y: " + m); - log.debug("sigma y: " + s); - } - - return new double [] { dxMax, dyMax }; - } - - public static final double [] calculateBuffer( - List <? extends Point2d> points - ) { - HashMap<Integer, ArrayList<Point2d>> iMap = - new HashMap<Integer, ArrayList<Point2d>>(); + area.expandBy( + extra*area.getWidth(), + extra*area.getHeight()); - HashMap<Integer, ArrayList<Point2d>> jMap = - new HashMap<Integer, ArrayList<Point2d>>(); - - for (int k = points.size()-1; k >= 0; --k) { - Point2d p = points.get(k); - - ArrayList<Point2d> jList = jMap.get(p.j); - ArrayList<Point2d> iList = iMap.get(p.i); - - if (jList == null) { - jMap.put(p.j, jList = new ArrayList<Point2d>()); - } - jList.add(p); - - if (iList == null) { - iMap.put(p.i, iList = new ArrayList<Point2d>()); - } - iList.add(p); - } - - double dxMax = -Double.MAX_VALUE; - double dyMax = -Double.MAX_VALUE; - - for (ArrayList<Point2d> v: jMap.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 += 1e-5d; - - for (ArrayList<Point2d> v: iMap.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 += 1e-5d; - - return new double [] { dxMax, dyMax }; + return area; } public static void interpolate( @@ -214,20 +69,23 @@ return; } - double [] buffer = calculateBuffer(points); - double dxMax = buffer[0]; - double dyMax = buffer[1]; + Envelope relevantArea = M > CULL_POINT_THRESHOLD + ? pathBoundingBox(path, 0.05d) + : null; + + List<GridCell> cells = GridCell.pointsToGridCells( + points, relevantArea); - if (debug) { - log.debug("buffer size: " + dxMax + " / " + dyMax); + if (cells.isEmpty()) { + log.warn("no cells found"); + return; } // put into spatial index to speed up finding neighbors. - Quadtree spatialIndex = new Quadtree(); + STRtree spatialIndex = new STRtree(); - for (int i = 0; i < M; ++i) { - Point2d p = points.get(i); - spatialIndex.insert(p.envelope(), p); + for (GridCell cell: cells) { + spatialIndex.insert(cell.getEnvelope(), cell); } LinearToMap linearToMap = new LinearToMap( @@ -235,85 +93,59 @@ double dP = (to - from)/steps; - Coordinate center = new Coordinate(); - - Envelope queryBuffer = new Envelope(); - - Point2d [] neighbors = new Point2d[4]; + Coordinate center = new Coordinate(); + Envelope queryBuffer = new Envelope(); + GridCell.CellFinder finder = new GridCell.CellFinder(); int missedInterpolations = 0; - int interpolations = 0; - - L1Comparator invL1 = new L1Comparator(center); + 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); - - Collections.sort(potential, invL1); - - neighbors[0] = neighbors[1] = - neighbors[2] = neighbors[3] = null; + center.x - EPS, center.x + EPS, + center.y - EPS, center.y + EPS); - /* bit code of neighbors - 0---1 - | x | - 2---3 - */ + finder.prepare(center); + spatialIndex.query(queryBuffer, finder); - 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; + GridCell found = finder.found; + + if (found == null) { + consumer.interpolated(center, false); + ++missedInterpolations; + continue; } - int numNeighbors = Integer.bitCount(mask); + Point2d n0 = found.p1; + Point2d n1 = found.p2; + Point2d n2 = found.p3; + Point2d n3 = found.p4; - // 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, true); - ++interpolations; - } - else { - consumer.interpolated(center, false); - ++missedInterpolations; - } + double z1 = interpolate( + n0.x, n0.z, + n1.x, n1.z, + center.x); + double z2 = interpolate( + n2.x, n2.z, + n3.x, n3.z, + center.x); + double y1 = interpolate( + n0.x, n0.y, + n1.x, n1.y, + center.x); + double y2 = interpolate( + n2.x, n2.y, + n3.x, n3.y, + center.x); + center.z = interpolate( + y1, z1, + y2, z2, + center.y); + consumer.interpolated(center, true); + ++interpolations; } if (debug) {