comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java @ 1190:f514894ec2fd

merged flys-artifacts/2.5
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:17 +0200
parents bd3683453928
children a7def20539fb
comparison
equal deleted inserted replaced
917:b48c36076e17 1190:f514894ec2fd
1 package de.intevation.flys.geom;
2
3 import java.util.List;
4 import java.util.ArrayList;
5
6 import java.awt.geom.Point2D;
7 import java.awt.geom.Line2D;
8
9 import de.intevation.flys.artifacts.math.Linear;
10
11 import org.apache.log4j.Logger;
12
13 public class Lines
14 {
15 private static Logger log = Logger.getLogger(Lines.class);
16
17 public static final double EPSILON = 1e-4;
18
19 public static enum Mode { UNDEF, WET, DRY };
20
21 protected Lines() {
22 }
23
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 }
32
33 List<Line2D> result = new ArrayList();
34
35 int N = points.size();
36
37 if (N == 0) {
38 return result;
39 }
40
41 if (N == 1) {
42 Point2D p = points.get(0);
43 // Only generate point if over water
44 if (waterLevel > p.getY()) {
45 result.add(new Line2D.Double(
46 p.getX(), waterLevel,
47 p.getX(), waterLevel));
48 }
49 return result;
50 }
51
52 double minX = Double.MAX_VALUE;
53 double minY = Double.MAX_VALUE;
54 double maxX = -Double.MAX_VALUE;
55 double maxY = -Double.MAX_VALUE;
56
57 // To ensure for sequences of equals x's that
58 // the original index order is preserved.
59 for (Point2D p: points) {
60 double x = p.getX(), y = p.getY();
61 if (x < minX) minX = x;
62 if (x > maxX) maxX = x;
63 if (y < minY) minY = y;
64 if (y > maxY) maxY = y;
65 }
66
67 if (minY > waterLevel) { // profile completely over water level
68 log.debug("complete over water");
69 return result;
70 }
71
72 if (waterLevel > maxY) { // water floods profile
73 log.debug("complete under water");
74 result.add(new Line2D.Double(minX, waterLevel, maxX, waterLevel));
75 return result;
76 }
77
78 Mode mode = Mode.UNDEF;
79
80 double startX = minX;
81
82 for (int i = 1; i < N; ++i) {
83 Point2D p1 = points.get(i-1);
84 Point2D p2 = points.get(i);
85
86 if (p1.getY() < waterLevel && p2.getY() < waterLevel) {
87 // completely under water
88 if (debug) {
89 log.debug("under water: " + p1 + " " + p2);
90 }
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 }
102 // completely over water
103 if (mode == Mode.WET) {
104 log.debug("over/wet");
105 result.add(new Line2D.Double(
106 startX, waterLevel,
107 p1.getX(), waterLevel));
108 }
109 mode = Mode.DRY;
110 continue;
111 }
112
113 if (Math.abs(p1.getX() - p2.getX()) < EPSILON) {
114 // vertical line
115 switch (mode) {
116 case WET:
117 log.debug("vertical/wet");
118 mode = Mode.DRY;
119 result.add(new Line2D.Double(
120 startX, waterLevel,
121 p1.getX(), waterLevel));
122 break;
123 case DRY:
124 log.debug("vertical/dry");
125 mode = Mode.WET;
126 startX = p2.getX();
127 break;
128 default: // UNDEF
129 log.debug("vertical/undef");
130 if (p2.getY() < waterLevel) {
131 mode = Mode.WET;
132 startX = p2.getX();
133 }
134 else {
135 mode = Mode.DRY;
136 }
137 }
138 continue;
139 }
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
199 // intersection case
200 double x = Linear.linear(
201 waterLevel,
202 p1.getY(), p2.getY(),
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 }
210
211 switch (mode) {
212 case WET:
213 log.debug("intersect/wet");
214 mode = Mode.DRY;
215 result.add(new Line2D.Double(
216 startX, waterLevel,
217 x, waterLevel));
218 break;
219
220 case DRY:
221 log.debug("intersect/dry");
222 mode = Mode.WET;
223 startX = x;
224 break;
225
226 default: // UNDEF
227 log.debug("intersect/undef");
228 if (p2.getY() > waterLevel) {
229 log.debug("intersect/undef/over");
230 mode = Mode.DRY;
231 result.add(new Line2D.Double(
232 p1.getX(), waterLevel,
233 x, waterLevel));
234 }
235 else {
236 mode = Mode.WET;
237 startX = x;
238 }
239 } // switch mode
240 } // for all points p[i] and p[i-1]
241
242 if (mode == Mode.WET) {
243 result.add(new Line2D.Double(
244 startX, waterLevel,
245 maxX, waterLevel));
246 }
247
248 return result;
249 }
250 }
251 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org