diff gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation3D.java @ 657:af3f56758f59

merged gnv-artifacts/0.5
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:13:53 +0200
parents 44415ae01ddb
children 9a828e5a2390
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/Interpolation3D.java	Fri Sep 28 12:13:53 2012 +0200
@@ -0,0 +1,241 @@
+package de.intevation.gnv.math;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+
+import com.vividsolutions.jts.index.strtree.STRtree;
+
+import java.awt.Dimension;
+
+import java.io.Serializable;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author Sascha L. Teichmann (sascha.teichmann@intevation.de)
+ */
+public class Interpolation3D
+implements   Serializable
+{
+    private static Logger log = Logger.getLogger(Interpolation3D.class);
+
+    public static final int DEFAULT_WIDTH  = 1024;
+    public static final int DEFAULT_HEIGHT =  768;
+
+    public static final double EPS = 1e-6d;
+
+    protected int width;
+    protected int height;
+
+    protected double cellWidth;
+    protected double cellHeight;
+
+    protected double [] raster;
+    protected double [] depths;
+
+    public Interpolation3D() {
+        this(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    }
+
+    public Interpolation3D(Dimension size) {
+        this(size.width, size.height);
+    }
+
+    public Interpolation3D(int width, int height) {
+        this.width  = width;
+        this.height = height;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    public double getCellWidth() {
+        return cellWidth;
+    }
+
+    public double getCellHeight() {
+        return cellHeight;
+    }
+
+    public double [] getRaster() {
+        return raster;
+    }
+
+    public double [] getDepths() {
+        return depths;
+    }
+
+    public double getMaxDepth() {
+        double maxDepth = Double.MAX_VALUE;
+        for (int i = depths!=null?depths.length-1:0; i >= 0; --i) {
+            double d = depths[i];
+            if (!Double.isNaN(d) && d < maxDepth) {
+                maxDepth = d;
+            }
+        }
+        return maxDepth;
+    }
+
+    public boolean interpolate(
+        List<? extends Coordinate> path,
+        List<? extends XYColumn>   points,
+        double                     from,
+        double                     to,
+        Metrics                    metrics,
+        XYDepth                    xyDepth
+    ) {
+        boolean debug = log.isDebugEnabled();
+
+        int N = path.size();
+        int M = points.size();
+
+        if (debug) {
+            log.debug("Size of path: " + N);
+            log.debug("Size of points: " + M);
+        }
+
+        if (M < 1 || N < 2) { // nothing to do
+            return false;
+        }
+
+        List<GridCell> cells = GridCell.pointsToGridCells(
+            points, Interpolation2D.relevantArea(path, points));
+
+        if (cells.isEmpty()) {
+            log.warn("no cells found");
+            return false;
+        }
+
+        // put into spatial index to speed up finding neighbors.
+        STRtree spatialIndex = new STRtree();
+
+        for (GridCell cell: cells) {
+            spatialIndex.insert(cell.getEnvelope(), cell);
+        }
+
+        LinearToMap linearToMap = new LinearToMap(
+            path, from, to, metrics);
+
+        double [] depths = new double[width];
+        Arrays.fill(depths, Double.NaN);
+
+        double cellWidth = (to - from)/width;
+
+        double maxDepth = Double.MAX_VALUE;
+
+        int i = 0;
+        Coordinate center = new Coordinate();
+        for (double p = cellWidth*0.5; i < depths.length; ++i, p += cellWidth) {
+            if (linearToMap.locate(p, center)) {
+                double depth = xyDepth.depth(center);
+                depths[i] = depth;
+                if (depth < maxDepth) {
+                    maxDepth = depth;
+                }
+            }
+        }
+
+        if (maxDepth == Double.MAX_VALUE) {
+            log.warn("no depth found -> no interpolation");
+            return false;
+        }
+
+        double cellHeight = Math.abs(maxDepth)/height;
+
+        if (debug) {
+            log.debug("max depth found: " + maxDepth);
+            log.debug("cell size: " + cellWidth + " x " + cellHeight);
+        }
+
+        double [] raster = new double[width*height];
+        Arrays.fill(raster, Double.NaN);
+
+        Envelope            queryBuffer  = new Envelope();
+        GridCell.CellFinder finder       = new GridCell.CellFinder();
+
+        i = 0;
+        for (double p = cellWidth*0.5; i < depths.length; ++i, p += cellWidth) {
+            double depth = depths[i];
+            if (Double.isNaN(depth) || depth >= 0d) {
+                continue;
+            }
+            linearToMap.locate(p, center);
+
+            queryBuffer.init(
+                center.x - EPS, center.x + EPS, 
+                center.y - EPS, center.y + EPS);
+
+            finder.prepare(center);
+            spatialIndex.query(queryBuffer, finder);
+
+            GridCell found = finder.found;
+
+            if (found == null) {
+                continue;
+            }
+
+            XYColumn n0 = (XYColumn)found.p1;
+            XYColumn n1 = (XYColumn)found.p2;
+            XYColumn n2 = (XYColumn)found.p3;
+            XYColumn n3 = (XYColumn)found.p4;
+
+            if (n0.prepare(xyDepth)
+            &&  n1.prepare(xyDepth)
+            &&  n2.prepare(xyDepth)
+            &&  n3.prepare(xyDepth)
+            ) {
+                double y1 = Interpolation2D.interpolate(
+                    n0.x, n0.y,
+                    n1.x, n1.y,
+                    center.x);
+                double y2 = Interpolation2D.interpolate(
+                    n2.x, n2.y,
+                    n3.x, n3.y,
+                    center.x);
+                double z = -cellHeight*0.5;
+                for (int j = i;
+                    j < raster.length && z >= depth;
+                    z -= cellHeight, j += width) {
+
+                    double v0 = n0.value(z);
+                    double v1 = n1.value(z);
+                    double v2 = n2.value(z);
+                    double v3 = n3.value(z);
+
+                    double z1 = Interpolation2D.interpolate(
+                        n0.x, v0,
+                        n1.x, v1,
+                        center.x);
+                    double z2 = Interpolation2D.interpolate(
+                        n2.x, v2,
+                        n3.x, v3,
+                        center.x);
+                    double value = Interpolation2D.interpolate(
+                        y1, z1,
+                        y2, z2,
+                        center.y);
+                    raster[j] = value;
+                }
+                // XXX: Adjusted depth to create no gap 
+                // between last value and ground.
+                depths[i] = z+0.5d*cellHeight; 
+            } // down the x/y column
+        } // all along the track
+
+        this.depths     = depths;
+        this.raster     = raster;
+        this.cellWidth  = cellWidth;
+        this.cellHeight = cellHeight;
+
+        return true;
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8:

http://dive4elements.wald.intevation.org