# HG changeset patch # User Sascha L. Teichmann # Date 1310400510 0 # Node ID 34136924661be460cfb79d7651eaf42a2072a56c # Parent 9ff7e06bcb771820a619c6f04527e5cf6383ef24 Generate water level lines for given cross section. flys-artifacts/trunk@2319 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r 9ff7e06bcb77 -r 34136924661b flys-artifacts/ChangeLog --- a/flys-artifacts/ChangeLog Fri Jul 08 08:26:18 2011 +0000 +++ b/flys-artifacts/ChangeLog Mon Jul 11 16:08:30 2011 +0000 @@ -1,3 +1,8 @@ +2011-07-11 Sascha L. Teichmann + + * src/main/java/de/intevation/flys/artifacts/geom/Lines.java: New. + fillWater() generates a list of wet lines for a given profile and a + given water level. 2011-07-08 Ingo Weinzierl * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: The diff -r 9ff7e06bcb77 -r 34136924661b flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java Mon Jul 11 16:08:30 2011 +0000 @@ -0,0 +1,182 @@ +package de.intevation.flys.geom.Lines; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import java.awt.geom.Point2D; +import java.awt.geom.Line2D; + +import de.intevation.flys.artifacts.math.Linear; + +public class Lines +{ + public static final double EPSILON = 1e-4; + + public static enum Mode { UNDEF, WET, DRY }; + + protected Lines() { + } + + public static final class StableIndex + implements Comparable + { + protected Point2D point; + protected int index; + + public StableIndex(Point2D point, int index) { + this.point = point; + this.index = index; + } + + public int compareTo(StableIndex other) { + double diff = point.getX() - other.point.getX(); + if (diff < -EPSILON ) return -1; + if (diff > +EPSILON ) return +1; + if (index < other.index) return -1; + if (index > other.index) return +1; + return 0; + } + } // class StableIndex + + public static List fillWater(List points, double waterLevel) { + + List result = new ArrayList(); + + int N = points.size(); + + if (N == 0) { + return result; + } + + if (N == 1) { + Point2D p = points.get(0); + // Only generate point if over water + if (waterLevel > p.getY()) { + result.add(new Line2D.Double( + waterLevel, p.getY(), waterLevel, p.getY())); + } + return result; + } + + double minX = Double.MAX_VALUE; + double minY = Double.MAX_VALUE; + double maxX = -Double.MAX_VALUE; + double maxY = -Double.MAX_VALUE; + + // To ensure for sequences of equals x's that + // the original index order is preserved. + StableIndex [] ps = new StableIndex[N]; + for (int i = 0; i < N; ++i) { + Point2D p = points.get(i); + ps[i] = new StableIndex(p, i); + double x = p.getX(), y = p.getY(); + if (x < minX) minX = x; + if (x > maxX) maxX = x; + if (y < minY) minY = y; + if (y > maxY) maxY = y; + } + + if (minY > waterLevel) { // profile completely over water level + return result; + } + + if (waterLevel > maxY) { // water floods profile + result.add(new Line2D.Double(minX, waterLevel, maxX, waterLevel)); + return result; + } + + Arrays.sort(ps); + + Mode mode = Mode.UNDEF; + + double startX = minX; + + for (int i = 1; i < N; ++i) { + Point2D p1 = ps[i-1].point; + Point2D p2 = ps[i ].point; + + if (p1.getX() < waterLevel && p2.getX() < waterLevel) { + // completely under water + continue; + } + + if (p1.getX() > waterLevel && p2.getX() > waterLevel) { + // completely over water + if (mode == Mode.WET) { + result.add(new Line2D.Double( + startX, waterLevel, + p1.getX(), waterLevel)); + } + mode = Mode.DRY; + continue; + } + + if (Math.abs(p1.getX() - p2.getX()) < EPSILON) { + // vertical line + switch (mode) { + case WET: + mode = Mode.DRY; + result.add(new Line2D.Double( + startX, waterLevel, + p1.getX(), waterLevel)); + break; + case DRY: + mode = Mode.WET; + startX = p2.getX(); + break; + default: // UNDEF + if (p2.getY() < waterLevel) { + mode = Mode.WET; + startX = p2.getX(); + } + else { + mode = Mode.DRY; + } + } + continue; + } + + // intersection case + double x = Linear.linear( + waterLevel, + p1.getY(), p1.getX(), + p2.getY(), p2.getX()); + + switch (mode) { + case WET: + mode = Mode.DRY; + result.add(new Line2D.Double( + startX, waterLevel, + x, waterLevel)); + break; + + case DRY: + mode = Mode.WET; + startX = x; + break; + + default: // UNDEF + if (p2.getY() > waterLevel) { + mode = Mode.DRY; + result.add(new Line2D.Double( + p1.getX(), waterLevel, + x, waterLevel)); + } + else { + mode = Mode.WET; + startX = x; + } + } // switch mode + } + + if (mode == Mode.WET) { + result.add(new Line2D.Double( + startX, waterLevel, + maxX, waterLevel)); + } + + return result; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :