diff flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java @ 938:bd3683453928

Debugged the water fill algorithm. flys-artifacts/trunk@2330 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Thu, 14 Jul 2011 14:11:29 +0000
parents d0f3fea20f01
children a7def20539fb
line wrap: on
line diff
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java	Thu Jul 14 11:27:01 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java	Thu Jul 14 14:11:29 2011 +0000
@@ -1,16 +1,19 @@
-package de.intevation.flys.geom.Lines;
+package de.intevation.flys.geom;
 
 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;
 
+import org.apache.log4j.Logger;
+
 public class Lines
 {
+    private static Logger log = Logger.getLogger(Lines.class);
+
     public static final double EPSILON = 1e-4;
 
     public static enum Mode { UNDEF, WET, DRY };
@@ -18,28 +21,14 @@
     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 static List<Line2D> fillWater(List<Point2D> points, double waterLevel) {
 
-        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;
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            log.debug("fillWater");
+            log.debug("----------------------------");
         }
-    } // class StableIndex
-
-    public static List<Line2D> fillWater(List<Point2D> points, double waterLevel) {
 
         List<Line2D> result = new ArrayList();
 
@@ -67,10 +56,7 @@
 
         // 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);
+        for (Point2D p: points) {
             double x = p.getX(), y = p.getY();
             if (x < minX) minX = x;
             if (x > maxX) maxX = x;
@@ -79,32 +65,43 @@
         }
 
         if (minY > waterLevel) { // profile completely over water level
+            log.debug("complete over water");
             return result;
         }
 
         if (waterLevel > maxY) { // water floods profile
+            log.debug("complete under water");
             result.add(new Line2D.Double(minX, waterLevel, maxX, waterLevel));
             return result;
         }
 
-        Arrays.sort(ps);
-
         Mode mode = Mode.UNDEF;
 
-        double  startX   = minX;
+        double startX = minX;
 
         for (int i = 1; i < N; ++i) {
-            Point2D p1 = ps[i-1].point;
-            Point2D p2 = ps[i  ].point;
+            Point2D p1 = points.get(i-1);
+            Point2D p2 = points.get(i);
 
-            if (p1.getX() < waterLevel && p2.getX() < waterLevel) {
+            if (p1.getY() < waterLevel && p2.getY() < waterLevel) {
                 // completely under water
+                if (debug) {
+                    log.debug("under water: " + p1 + " " + p2);
+                }
+                if (mode != Mode.WET) {
+                    startX = p1.getX();
+                    mode = Mode.WET;
+                }
                 continue;
             }
 
-            if (p1.getX() > waterLevel && p2.getX() > waterLevel) {
+            if (p1.getY() > waterLevel && p2.getY() > waterLevel) {
+                if (debug) {
+                    log.debug("over water: " + p1 + " " + p2);
+                }
                 // completely over water
                 if (mode == Mode.WET) {
+                    log.debug("over/wet");
                     result.add(new Line2D.Double(
                         startX, waterLevel,
                         p1.getX(), waterLevel));
@@ -117,16 +114,19 @@
                 // vertical line
                 switch (mode) {
                     case WET:
+                        log.debug("vertical/wet");
                         mode = Mode.DRY;
                         result.add(new Line2D.Double(
                             startX, waterLevel,
                             p1.getX(), waterLevel));
                         break;
                     case DRY:
+                        log.debug("vertical/dry");
                         mode = Mode.WET;
                         startX = p2.getX();
                         break;
                     default: // UNDEF
+                        log.debug("vertical/undef");
                         if (p2.getY() < waterLevel) {
                             mode = Mode.WET;
                             startX = p2.getX();
@@ -138,14 +138,79 @@
                 continue;
             }
 
+            // check if waterlevel directly hits the vertices;
+
+            boolean p1W = Math.abs(waterLevel - p1.getY()) < EPSILON;
+            boolean p2W = Math.abs(waterLevel - p2.getY()) < EPSILON;
+
+            if (p1W || p2W) {
+                if (debug) {
+                    log.debug("water hits vertex: " + p1 + " " + p2 + " " + mode);
+                }
+                if (p1W && p2W) { // parallel to water -> dry
+                    log.debug("water hits both vertices");
+                    if (mode == Mode.WET) {
+                        result.add(new Line2D.Double(
+                            startX, waterLevel,
+                            p1.getX(), waterLevel));
+                    }
+                    mode = Mode.DRY;
+                }
+                else if (p1W) { // p1 == waterlevel
+                    log.debug("water hits first vertex");
+                    if (p2.getY() > waterLevel) { // --> dry
+                        if (mode == Mode.WET) {
+                            result.add(new Line2D.Double(
+                                startX, waterLevel,
+                                p1.getX(), waterLevel));
+                        }
+                        mode = Mode.DRY;
+                    }
+                    else { // --> wet
+                        if (mode != Mode.WET) {
+                            startX = p1.getX();
+                            mode = Mode.WET;
+                        }
+                    }
+                }
+                else { // p2 == waterlevel
+                    log.debug("water hits second vertex");
+                    if (p1.getY() > waterLevel) { // --> wet
+                        if (mode != Mode.WET) {
+                            startX = p2.getX();
+                            mode = Mode.WET;
+                        }
+                    }
+                    else { // --> dry
+                        if (mode == Mode.WET) {
+                            result.add(new Line2D.Double(
+                                startX, waterLevel,
+                                p2.getX(), waterLevel));
+                        }
+                        mode = Mode.DRY;
+                    }
+                }
+                if (debug) {
+                    log.debug("mode is now: " + mode);
+                }
+                continue;
+            }
+
             // intersection case
             double x = Linear.linear(
                 waterLevel,
-                p1.getY(), p1.getX(),
-                p2.getY(), p2.getX());
+                p1.getY(), p2.getY(),
+                p1.getX(), p2.getX());
+
+            if (debug) {
+                log.debug("intersection p1:" + p1);
+                log.debug("intersection p2:" + p2);
+                log.debug("intersection at x: " + x);
+            }
 
             switch (mode) {
                 case WET:
+                    log.debug("intersect/wet");
                     mode = Mode.DRY;
                     result.add(new Line2D.Double(
                         startX, waterLevel,
@@ -153,12 +218,15 @@
                     break;
 
                 case DRY:
+                    log.debug("intersect/dry");
                     mode   = Mode.WET;
                     startX = x;
                     break;
 
                 default: // UNDEF
+                    log.debug("intersect/undef");
                     if (p2.getY() > waterLevel) {
+                        log.debug("intersect/undef/over");
                         mode = Mode.DRY;
                         result.add(new Line2D.Double(
                             p1.getX(), waterLevel,

http://dive4elements.wald.intevation.org