Mercurial > dive4elements > gnv-client
view gnv-artifacts/src/main/java/de/intevation/gnv/math/Interpolation3D.java @ 484:823e4f808418
Generate JTS geometries (multi polygons and multi linestrings) from
interpolation with external palette indices.
gnv-artifacts/trunk@559 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Mon, 18 Jan 2010 11:25:52 +0000 |
parents | 537e663d6c0c |
children | 234d9892e497 |
line wrap: on
line source
package de.intevation.gnv.math; import java.util.List; import java.util.Arrays; import java.util.Collections; import java.io.Serializable; import java.awt.Dimension; 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 (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; protected int width; protected int height; 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 [] 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; } double [] buffer = Interpolation2D.calculateBuffer(points); double dxMax = buffer[0]; double dyMax = buffer[1]; if (debug) { 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 [] 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(); XYColumn [] neighbors = new XYColumn[4]; i = 0; for (double p = cellWidth*0.5; i < depths.length; ++i, p += cellWidth) { double depth = depths[i]; if (Double.isNaN(depth)) { continue; } linearToMap.locate(p, center); 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 j = potential.size()-1; j >= 0; --j) { XYColumn n = (XYColumn)potential.get(j); 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]) && neighbors[0].prepare(xyDepth) && neighbors[1].prepare(xyDepth) && neighbors[2].prepare(xyDepth) && neighbors[3].prepare(xyDepth) ) { double y1 = Interpolation2D.interpolate( neighbors[0].x, neighbors[0].y, neighbors[1].x, neighbors[1].y, center.x); double y2 = Interpolation2D.interpolate( neighbors[2].x, neighbors[2].y, neighbors[3].x, neighbors[3].y, center.x); int j = i; for (double z = -cellHeight*0.5; j < raster.length && z >= depth; z -= cellHeight, j += width) { double v0 = neighbors[0].value(z); double v1 = neighbors[1].value(z); double v2 = neighbors[2].value(z); double v3 = neighbors[3].value(z); double z1 = Interpolation2D.interpolate( neighbors[0].x, v0, neighbors[1].x, v1, center.x); double z2 = Interpolation2D.interpolate( neighbors[2].x, v2, neighbors[3].x, v3, center.x); double value = Interpolation2D.interpolate( y1, z1, y2, z2, center.y); raster[j] = value; } } // down the x/y column } // all along the track this.depths = depths; this.raster = raster; return true; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: