Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java @ 934:d0f3fea20f01
Fixed corner case.
flys-artifacts/trunk@2320 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 12 Jul 2011 08:05:54 +0000 |
parents | 34136924661b |
children | bd3683453928 |
line wrap: on
line source
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<StableIndex> { 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<Line2D> fillWater(List<Point2D> points, double waterLevel) { List<Line2D> 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( p.getX(), waterLevel, p.getX(), waterLevel)); } 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 } // for all points p[i] and p[i-1] 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 :