Mercurial > dive4elements > river
comparison 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 |
comparison
equal
deleted
inserted
replaced
937:9e813e9137a5 | 938:bd3683453928 |
---|---|
1 package de.intevation.flys.geom.Lines; | 1 package de.intevation.flys.geom; |
2 | 2 |
3 import java.util.List; | 3 import java.util.List; |
4 import java.util.ArrayList; | 4 import java.util.ArrayList; |
5 import java.util.Arrays; | |
6 | 5 |
7 import java.awt.geom.Point2D; | 6 import java.awt.geom.Point2D; |
8 import java.awt.geom.Line2D; | 7 import java.awt.geom.Line2D; |
9 | 8 |
10 import de.intevation.flys.artifacts.math.Linear; | 9 import de.intevation.flys.artifacts.math.Linear; |
11 | 10 |
11 import org.apache.log4j.Logger; | |
12 | |
12 public class Lines | 13 public class Lines |
13 { | 14 { |
15 private static Logger log = Logger.getLogger(Lines.class); | |
16 | |
14 public static final double EPSILON = 1e-4; | 17 public static final double EPSILON = 1e-4; |
15 | 18 |
16 public static enum Mode { UNDEF, WET, DRY }; | 19 public static enum Mode { UNDEF, WET, DRY }; |
17 | 20 |
18 protected Lines() { | 21 protected Lines() { |
19 } | 22 } |
20 | 23 |
21 public static final class StableIndex | |
22 implements Comparable<StableIndex> | |
23 { | |
24 protected Point2D point; | |
25 protected int index; | |
26 | |
27 public StableIndex(Point2D point, int index) { | |
28 this.point = point; | |
29 this.index = index; | |
30 } | |
31 | |
32 public int compareTo(StableIndex other) { | |
33 double diff = point.getX() - other.point.getX(); | |
34 if (diff < -EPSILON ) return -1; | |
35 if (diff > +EPSILON ) return +1; | |
36 if (index < other.index) return -1; | |
37 if (index > other.index) return +1; | |
38 return 0; | |
39 } | |
40 } // class StableIndex | |
41 | |
42 public static List<Line2D> fillWater(List<Point2D> points, double waterLevel) { | 24 public static List<Line2D> fillWater(List<Point2D> points, double waterLevel) { |
25 | |
26 boolean debug = log.isDebugEnabled(); | |
27 | |
28 if (debug) { | |
29 log.debug("fillWater"); | |
30 log.debug("----------------------------"); | |
31 } | |
43 | 32 |
44 List<Line2D> result = new ArrayList(); | 33 List<Line2D> result = new ArrayList(); |
45 | 34 |
46 int N = points.size(); | 35 int N = points.size(); |
47 | 36 |
65 double maxX = -Double.MAX_VALUE; | 54 double maxX = -Double.MAX_VALUE; |
66 double maxY = -Double.MAX_VALUE; | 55 double maxY = -Double.MAX_VALUE; |
67 | 56 |
68 // To ensure for sequences of equals x's that | 57 // To ensure for sequences of equals x's that |
69 // the original index order is preserved. | 58 // the original index order is preserved. |
70 StableIndex [] ps = new StableIndex[N]; | 59 for (Point2D p: points) { |
71 for (int i = 0; i < N; ++i) { | |
72 Point2D p = points.get(i); | |
73 ps[i] = new StableIndex(p, i); | |
74 double x = p.getX(), y = p.getY(); | 60 double x = p.getX(), y = p.getY(); |
75 if (x < minX) minX = x; | 61 if (x < minX) minX = x; |
76 if (x > maxX) maxX = x; | 62 if (x > maxX) maxX = x; |
77 if (y < minY) minY = y; | 63 if (y < minY) minY = y; |
78 if (y > maxY) maxY = y; | 64 if (y > maxY) maxY = y; |
79 } | 65 } |
80 | 66 |
81 if (minY > waterLevel) { // profile completely over water level | 67 if (minY > waterLevel) { // profile completely over water level |
68 log.debug("complete over water"); | |
82 return result; | 69 return result; |
83 } | 70 } |
84 | 71 |
85 if (waterLevel > maxY) { // water floods profile | 72 if (waterLevel > maxY) { // water floods profile |
73 log.debug("complete under water"); | |
86 result.add(new Line2D.Double(minX, waterLevel, maxX, waterLevel)); | 74 result.add(new Line2D.Double(minX, waterLevel, maxX, waterLevel)); |
87 return result; | 75 return result; |
88 } | 76 } |
89 | 77 |
90 Arrays.sort(ps); | |
91 | |
92 Mode mode = Mode.UNDEF; | 78 Mode mode = Mode.UNDEF; |
93 | 79 |
94 double startX = minX; | 80 double startX = minX; |
95 | 81 |
96 for (int i = 1; i < N; ++i) { | 82 for (int i = 1; i < N; ++i) { |
97 Point2D p1 = ps[i-1].point; | 83 Point2D p1 = points.get(i-1); |
98 Point2D p2 = ps[i ].point; | 84 Point2D p2 = points.get(i); |
99 | 85 |
100 if (p1.getX() < waterLevel && p2.getX() < waterLevel) { | 86 if (p1.getY() < waterLevel && p2.getY() < waterLevel) { |
101 // completely under water | 87 // completely under water |
102 continue; | 88 if (debug) { |
103 } | 89 log.debug("under water: " + p1 + " " + p2); |
104 | 90 } |
105 if (p1.getX() > waterLevel && p2.getX() > waterLevel) { | 91 if (mode != Mode.WET) { |
92 startX = p1.getX(); | |
93 mode = Mode.WET; | |
94 } | |
95 continue; | |
96 } | |
97 | |
98 if (p1.getY() > waterLevel && p2.getY() > waterLevel) { | |
99 if (debug) { | |
100 log.debug("over water: " + p1 + " " + p2); | |
101 } | |
106 // completely over water | 102 // completely over water |
107 if (mode == Mode.WET) { | 103 if (mode == Mode.WET) { |
104 log.debug("over/wet"); | |
108 result.add(new Line2D.Double( | 105 result.add(new Line2D.Double( |
109 startX, waterLevel, | 106 startX, waterLevel, |
110 p1.getX(), waterLevel)); | 107 p1.getX(), waterLevel)); |
111 } | 108 } |
112 mode = Mode.DRY; | 109 mode = Mode.DRY; |
115 | 112 |
116 if (Math.abs(p1.getX() - p2.getX()) < EPSILON) { | 113 if (Math.abs(p1.getX() - p2.getX()) < EPSILON) { |
117 // vertical line | 114 // vertical line |
118 switch (mode) { | 115 switch (mode) { |
119 case WET: | 116 case WET: |
117 log.debug("vertical/wet"); | |
120 mode = Mode.DRY; | 118 mode = Mode.DRY; |
121 result.add(new Line2D.Double( | 119 result.add(new Line2D.Double( |
122 startX, waterLevel, | 120 startX, waterLevel, |
123 p1.getX(), waterLevel)); | 121 p1.getX(), waterLevel)); |
124 break; | 122 break; |
125 case DRY: | 123 case DRY: |
124 log.debug("vertical/dry"); | |
126 mode = Mode.WET; | 125 mode = Mode.WET; |
127 startX = p2.getX(); | 126 startX = p2.getX(); |
128 break; | 127 break; |
129 default: // UNDEF | 128 default: // UNDEF |
129 log.debug("vertical/undef"); | |
130 if (p2.getY() < waterLevel) { | 130 if (p2.getY() < waterLevel) { |
131 mode = Mode.WET; | 131 mode = Mode.WET; |
132 startX = p2.getX(); | 132 startX = p2.getX(); |
133 } | 133 } |
134 else { | 134 else { |
136 } | 136 } |
137 } | 137 } |
138 continue; | 138 continue; |
139 } | 139 } |
140 | 140 |
141 // check if waterlevel directly hits the vertices; | |
142 | |
143 boolean p1W = Math.abs(waterLevel - p1.getY()) < EPSILON; | |
144 boolean p2W = Math.abs(waterLevel - p2.getY()) < EPSILON; | |
145 | |
146 if (p1W || p2W) { | |
147 if (debug) { | |
148 log.debug("water hits vertex: " + p1 + " " + p2 + " " + mode); | |
149 } | |
150 if (p1W && p2W) { // parallel to water -> dry | |
151 log.debug("water hits both vertices"); | |
152 if (mode == Mode.WET) { | |
153 result.add(new Line2D.Double( | |
154 startX, waterLevel, | |
155 p1.getX(), waterLevel)); | |
156 } | |
157 mode = Mode.DRY; | |
158 } | |
159 else if (p1W) { // p1 == waterlevel | |
160 log.debug("water hits first vertex"); | |
161 if (p2.getY() > waterLevel) { // --> dry | |
162 if (mode == Mode.WET) { | |
163 result.add(new Line2D.Double( | |
164 startX, waterLevel, | |
165 p1.getX(), waterLevel)); | |
166 } | |
167 mode = Mode.DRY; | |
168 } | |
169 else { // --> wet | |
170 if (mode != Mode.WET) { | |
171 startX = p1.getX(); | |
172 mode = Mode.WET; | |
173 } | |
174 } | |
175 } | |
176 else { // p2 == waterlevel | |
177 log.debug("water hits second vertex"); | |
178 if (p1.getY() > waterLevel) { // --> wet | |
179 if (mode != Mode.WET) { | |
180 startX = p2.getX(); | |
181 mode = Mode.WET; | |
182 } | |
183 } | |
184 else { // --> dry | |
185 if (mode == Mode.WET) { | |
186 result.add(new Line2D.Double( | |
187 startX, waterLevel, | |
188 p2.getX(), waterLevel)); | |
189 } | |
190 mode = Mode.DRY; | |
191 } | |
192 } | |
193 if (debug) { | |
194 log.debug("mode is now: " + mode); | |
195 } | |
196 continue; | |
197 } | |
198 | |
141 // intersection case | 199 // intersection case |
142 double x = Linear.linear( | 200 double x = Linear.linear( |
143 waterLevel, | 201 waterLevel, |
144 p1.getY(), p1.getX(), | 202 p1.getY(), p2.getY(), |
145 p2.getY(), p2.getX()); | 203 p1.getX(), p2.getX()); |
204 | |
205 if (debug) { | |
206 log.debug("intersection p1:" + p1); | |
207 log.debug("intersection p2:" + p2); | |
208 log.debug("intersection at x: " + x); | |
209 } | |
146 | 210 |
147 switch (mode) { | 211 switch (mode) { |
148 case WET: | 212 case WET: |
213 log.debug("intersect/wet"); | |
149 mode = Mode.DRY; | 214 mode = Mode.DRY; |
150 result.add(new Line2D.Double( | 215 result.add(new Line2D.Double( |
151 startX, waterLevel, | 216 startX, waterLevel, |
152 x, waterLevel)); | 217 x, waterLevel)); |
153 break; | 218 break; |
154 | 219 |
155 case DRY: | 220 case DRY: |
221 log.debug("intersect/dry"); | |
156 mode = Mode.WET; | 222 mode = Mode.WET; |
157 startX = x; | 223 startX = x; |
158 break; | 224 break; |
159 | 225 |
160 default: // UNDEF | 226 default: // UNDEF |
227 log.debug("intersect/undef"); | |
161 if (p2.getY() > waterLevel) { | 228 if (p2.getY() > waterLevel) { |
229 log.debug("intersect/undef/over"); | |
162 mode = Mode.DRY; | 230 mode = Mode.DRY; |
163 result.add(new Line2D.Double( | 231 result.add(new Line2D.Double( |
164 p1.getX(), waterLevel, | 232 p1.getX(), waterLevel, |
165 x, waterLevel)); | 233 x, waterLevel)); |
166 } | 234 } |