sascha@933: package de.intevation.flys.geom.Lines; sascha@933: sascha@933: import java.util.List; sascha@933: import java.util.ArrayList; sascha@933: import java.util.Arrays; sascha@933: sascha@933: import java.awt.geom.Point2D; sascha@933: import java.awt.geom.Line2D; sascha@933: sascha@933: import de.intevation.flys.artifacts.math.Linear; sascha@933: sascha@933: public class Lines sascha@933: { sascha@933: public static final double EPSILON = 1e-4; sascha@933: sascha@933: public static enum Mode { UNDEF, WET, DRY }; sascha@933: sascha@933: protected Lines() { sascha@933: } sascha@933: sascha@933: public static final class StableIndex sascha@933: implements Comparable sascha@933: { sascha@933: protected Point2D point; sascha@933: protected int index; sascha@933: sascha@933: public StableIndex(Point2D point, int index) { sascha@933: this.point = point; sascha@933: this.index = index; sascha@933: } sascha@933: sascha@933: public int compareTo(StableIndex other) { sascha@933: double diff = point.getX() - other.point.getX(); sascha@933: if (diff < -EPSILON ) return -1; sascha@933: if (diff > +EPSILON ) return +1; sascha@933: if (index < other.index) return -1; sascha@933: if (index > other.index) return +1; sascha@933: return 0; sascha@933: } sascha@933: } // class StableIndex sascha@933: sascha@933: public static List fillWater(List points, double waterLevel) { sascha@933: sascha@933: List result = new ArrayList(); sascha@933: sascha@933: int N = points.size(); sascha@933: sascha@933: if (N == 0) { sascha@933: return result; sascha@933: } sascha@933: sascha@933: if (N == 1) { sascha@933: Point2D p = points.get(0); sascha@933: // Only generate point if over water sascha@933: if (waterLevel > p.getY()) { sascha@933: result.add(new Line2D.Double( sascha@933: waterLevel, p.getY(), waterLevel, p.getY())); sascha@933: } sascha@933: return result; sascha@933: } sascha@933: sascha@933: double minX = Double.MAX_VALUE; sascha@933: double minY = Double.MAX_VALUE; sascha@933: double maxX = -Double.MAX_VALUE; sascha@933: double maxY = -Double.MAX_VALUE; sascha@933: sascha@933: // To ensure for sequences of equals x's that sascha@933: // the original index order is preserved. sascha@933: StableIndex [] ps = new StableIndex[N]; sascha@933: for (int i = 0; i < N; ++i) { sascha@933: Point2D p = points.get(i); sascha@933: ps[i] = new StableIndex(p, i); sascha@933: double x = p.getX(), y = p.getY(); sascha@933: if (x < minX) minX = x; sascha@933: if (x > maxX) maxX = x; sascha@933: if (y < minY) minY = y; sascha@933: if (y > maxY) maxY = y; sascha@933: } sascha@933: sascha@933: if (minY > waterLevel) { // profile completely over water level sascha@933: return result; sascha@933: } sascha@933: sascha@933: if (waterLevel > maxY) { // water floods profile sascha@933: result.add(new Line2D.Double(minX, waterLevel, maxX, waterLevel)); sascha@933: return result; sascha@933: } sascha@933: sascha@933: Arrays.sort(ps); sascha@933: sascha@933: Mode mode = Mode.UNDEF; sascha@933: sascha@933: double startX = minX; sascha@933: sascha@933: for (int i = 1; i < N; ++i) { sascha@933: Point2D p1 = ps[i-1].point; sascha@933: Point2D p2 = ps[i ].point; sascha@933: sascha@933: if (p1.getX() < waterLevel && p2.getX() < waterLevel) { sascha@933: // completely under water sascha@933: continue; sascha@933: } sascha@933: sascha@933: if (p1.getX() > waterLevel && p2.getX() > waterLevel) { sascha@933: // completely over water sascha@933: if (mode == Mode.WET) { sascha@933: result.add(new Line2D.Double( sascha@933: startX, waterLevel, sascha@933: p1.getX(), waterLevel)); sascha@933: } sascha@933: mode = Mode.DRY; sascha@933: continue; sascha@933: } sascha@933: sascha@933: if (Math.abs(p1.getX() - p2.getX()) < EPSILON) { sascha@933: // vertical line sascha@933: switch (mode) { sascha@933: case WET: sascha@933: mode = Mode.DRY; sascha@933: result.add(new Line2D.Double( sascha@933: startX, waterLevel, sascha@933: p1.getX(), waterLevel)); sascha@933: break; sascha@933: case DRY: sascha@933: mode = Mode.WET; sascha@933: startX = p2.getX(); sascha@933: break; sascha@933: default: // UNDEF sascha@933: if (p2.getY() < waterLevel) { sascha@933: mode = Mode.WET; sascha@933: startX = p2.getX(); sascha@933: } sascha@933: else { sascha@933: mode = Mode.DRY; sascha@933: } sascha@933: } sascha@933: continue; sascha@933: } sascha@933: sascha@933: // intersection case sascha@933: double x = Linear.linear( sascha@933: waterLevel, sascha@933: p1.getY(), p1.getX(), sascha@933: p2.getY(), p2.getX()); sascha@933: sascha@933: switch (mode) { sascha@933: case WET: sascha@933: mode = Mode.DRY; sascha@933: result.add(new Line2D.Double( sascha@933: startX, waterLevel, sascha@933: x, waterLevel)); sascha@933: break; sascha@933: sascha@933: case DRY: sascha@933: mode = Mode.WET; sascha@933: startX = x; sascha@933: break; sascha@933: sascha@933: default: // UNDEF sascha@933: if (p2.getY() > waterLevel) { sascha@933: mode = Mode.DRY; sascha@933: result.add(new Line2D.Double( sascha@933: p1.getX(), waterLevel, sascha@933: x, waterLevel)); sascha@933: } sascha@933: else { sascha@933: mode = Mode.WET; sascha@933: startX = x; sascha@933: } sascha@933: } // switch mode sascha@933: } sascha@933: sascha@933: if (mode == Mode.WET) { sascha@933: result.add(new Line2D.Double( sascha@933: startX, waterLevel, sascha@933: maxX, waterLevel)); sascha@933: } sascha@933: sascha@933: return result; sascha@933: } sascha@933: } sascha@933: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :