view gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation3D.java @ 605:e8ebdbc7f1e3

First step of removing the cache blob. The static part of the describe document will be created by using the input data stored at each state. Some TODOs left (see ChangeLog). gnv-artifacts/trunk@671 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Tue, 09 Feb 2010 14:27:55 +0000
parents 44415ae01ddb
children 9a828e5a2390
line wrap: on
line source
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