Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/geom/Lines.java @ 3818:dc18457b1cef
merged flys-artifacts/pre2.7-2012-03-16
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:59 +0200 |
parents | a7def20539fb |
children | a6fa128e4654 |
comparison
equal
deleted
inserted
replaced
2456:60ab1054069d | 3818:dc18457b1cef |
---|---|
1 package de.intevation.flys.geom; | |
2 | |
3 import java.util.ArrayList; | |
4 import java.util.List; | |
5 import java.util.Iterator; | |
6 | |
7 import java.awt.geom.Point2D; | |
8 import java.awt.geom.Line2D; | |
9 | |
10 import de.intevation.flys.artifacts.math.Linear; | |
11 | |
12 import org.apache.log4j.Logger; | |
13 | |
14 import gnu.trove.TDoubleArrayList; | |
15 | |
16 public class Lines | |
17 { | |
18 private static Logger log = Logger.getLogger(Lines.class); | |
19 | |
20 public static final double EPSILON = 1e-4; | |
21 | |
22 public static enum Mode { UNDEF, WET, DRY }; | |
23 | |
24 protected Lines() { | |
25 } | |
26 | |
27 public static List<Line2D> fillWater(List<Point2D> points, double waterLevel) { | |
28 | |
29 boolean debug = log.isDebugEnabled(); | |
30 | |
31 if (debug) { | |
32 log.debug("fillWater"); | |
33 log.debug("----------------------------"); | |
34 } | |
35 | |
36 List<Line2D> result = new ArrayList(); | |
37 | |
38 int N = points.size(); | |
39 | |
40 if (N == 0) { | |
41 return result; | |
42 } | |
43 | |
44 if (N == 1) { | |
45 Point2D p = points.get(0); | |
46 // Only generate point if over water | |
47 if (waterLevel > p.getY()) { | |
48 result.add(new Line2D.Double( | |
49 p.getX(), waterLevel, | |
50 p.getX(), waterLevel)); | |
51 } | |
52 return result; | |
53 } | |
54 | |
55 double minX = Double.MAX_VALUE; | |
56 double minY = Double.MAX_VALUE; | |
57 double maxX = -Double.MAX_VALUE; | |
58 double maxY = -Double.MAX_VALUE; | |
59 | |
60 // To ensure for sequences of equals x's that | |
61 // the original index order is preserved. | |
62 for (Point2D p: points) { | |
63 double x = p.getX(), y = p.getY(); | |
64 if (x < minX) minX = x; | |
65 if (x > maxX) maxX = x; | |
66 if (y < minY) minY = y; | |
67 if (y > maxY) maxY = y; | |
68 } | |
69 | |
70 if (minY > waterLevel) { // profile completely over water level | |
71 log.debug("complete over water"); | |
72 return result; | |
73 } | |
74 | |
75 if (waterLevel > maxY) { // water floods profile | |
76 log.debug("complete under water"); | |
77 result.add(new Line2D.Double(minX, waterLevel, maxX, waterLevel)); | |
78 return result; | |
79 } | |
80 | |
81 Mode mode = Mode.UNDEF; | |
82 | |
83 double startX = minX; | |
84 | |
85 for (int i = 1; i < N; ++i) { | |
86 Point2D p1 = points.get(i-1); | |
87 Point2D p2 = points.get(i); | |
88 | |
89 if (p1.getY() < waterLevel && p2.getY() < waterLevel) { | |
90 // completely under water | |
91 if (debug) { | |
92 log.debug("under water: " + p1 + " " + p2); | |
93 } | |
94 if (mode != Mode.WET) { | |
95 startX = p1.getX(); | |
96 mode = Mode.WET; | |
97 } | |
98 continue; | |
99 } | |
100 | |
101 if (p1.getY() > waterLevel && p2.getY() > waterLevel) { | |
102 if (debug) { | |
103 log.debug("over water: " + p1 + " " + p2); | |
104 } | |
105 // completely over water | |
106 if (mode == Mode.WET) { | |
107 log.debug("over/wet"); | |
108 result.add(new Line2D.Double( | |
109 startX, waterLevel, | |
110 p1.getX(), waterLevel)); | |
111 } | |
112 mode = Mode.DRY; | |
113 continue; | |
114 } | |
115 | |
116 if (Math.abs(p1.getX() - p2.getX()) < EPSILON) { | |
117 // vertical line | |
118 switch (mode) { | |
119 case WET: | |
120 log.debug("vertical/wet"); | |
121 mode = Mode.DRY; | |
122 result.add(new Line2D.Double( | |
123 startX, waterLevel, | |
124 p1.getX(), waterLevel)); | |
125 break; | |
126 case DRY: | |
127 log.debug("vertical/dry"); | |
128 mode = Mode.WET; | |
129 startX = p2.getX(); | |
130 break; | |
131 default: // UNDEF | |
132 log.debug("vertical/undef"); | |
133 if (p2.getY() < waterLevel) { | |
134 mode = Mode.WET; | |
135 startX = p2.getX(); | |
136 } | |
137 else { | |
138 mode = Mode.DRY; | |
139 } | |
140 } | |
141 continue; | |
142 } | |
143 | |
144 // check if waterlevel directly hits the vertices; | |
145 | |
146 boolean p1W = Math.abs(waterLevel - p1.getY()) < EPSILON; | |
147 boolean p2W = Math.abs(waterLevel - p2.getY()) < EPSILON; | |
148 | |
149 if (p1W || p2W) { | |
150 if (debug) { | |
151 log.debug("water hits vertex: " + p1 + " " + p2 + " " + mode); | |
152 } | |
153 if (p1W && p2W) { // parallel to water -> dry | |
154 log.debug("water hits both vertices"); | |
155 if (mode == Mode.WET) { | |
156 result.add(new Line2D.Double( | |
157 startX, waterLevel, | |
158 p1.getX(), waterLevel)); | |
159 } | |
160 mode = Mode.DRY; | |
161 } | |
162 else if (p1W) { // p1 == waterlevel | |
163 log.debug("water hits first vertex"); | |
164 if (p2.getY() > waterLevel) { // --> dry | |
165 if (mode == Mode.WET) { | |
166 result.add(new Line2D.Double( | |
167 startX, waterLevel, | |
168 p1.getX(), waterLevel)); | |
169 } | |
170 mode = Mode.DRY; | |
171 } | |
172 else { // --> wet | |
173 if (mode != Mode.WET) { | |
174 startX = p1.getX(); | |
175 mode = Mode.WET; | |
176 } | |
177 } | |
178 } | |
179 else { // p2 == waterlevel | |
180 log.debug("water hits second vertex"); | |
181 if (p1.getY() > waterLevel) { // --> wet | |
182 if (mode != Mode.WET) { | |
183 startX = p2.getX(); | |
184 mode = Mode.WET; | |
185 } | |
186 } | |
187 else { // --> dry | |
188 if (mode == Mode.WET) { | |
189 result.add(new Line2D.Double( | |
190 startX, waterLevel, | |
191 p2.getX(), waterLevel)); | |
192 } | |
193 mode = Mode.DRY; | |
194 } | |
195 } | |
196 if (debug) { | |
197 log.debug("mode is now: " + mode); | |
198 } | |
199 continue; | |
200 } | |
201 | |
202 // intersection case | |
203 double x = Linear.linear( | |
204 waterLevel, | |
205 p1.getY(), p2.getY(), | |
206 p1.getX(), p2.getX()); | |
207 | |
208 if (debug) { | |
209 log.debug("intersection p1:" + p1); | |
210 log.debug("intersection p2:" + p2); | |
211 log.debug("intersection at x: " + x); | |
212 } | |
213 | |
214 switch (mode) { | |
215 case WET: | |
216 log.debug("intersect/wet"); | |
217 mode = Mode.DRY; | |
218 result.add(new Line2D.Double( | |
219 startX, waterLevel, | |
220 x, waterLevel)); | |
221 break; | |
222 | |
223 case DRY: | |
224 log.debug("intersect/dry"); | |
225 mode = Mode.WET; | |
226 startX = x; | |
227 break; | |
228 | |
229 default: // UNDEF | |
230 log.debug("intersect/undef"); | |
231 if (p2.getY() > waterLevel) { | |
232 log.debug("intersect/undef/over"); | |
233 mode = Mode.DRY; | |
234 result.add(new Line2D.Double( | |
235 p1.getX(), waterLevel, | |
236 x, waterLevel)); | |
237 } | |
238 else { | |
239 mode = Mode.WET; | |
240 startX = x; | |
241 } | |
242 } // switch mode | |
243 } // for all points p[i] and p[i-1] | |
244 | |
245 if (mode == Mode.WET) { | |
246 result.add(new Line2D.Double( | |
247 startX, waterLevel, | |
248 maxX, waterLevel)); | |
249 } | |
250 | |
251 return result; | |
252 } | |
253 | |
254 public static double [][] createWaterLines( | |
255 List<Point2D> points, | |
256 double waterlevel | |
257 ) { | |
258 List<Line2D> lines = fillWater(points, waterlevel); | |
259 | |
260 TDoubleArrayList lxs = new TDoubleArrayList(); | |
261 TDoubleArrayList lys = new TDoubleArrayList(); | |
262 | |
263 for (Iterator<Line2D> iter = lines.iterator(); iter.hasNext();) { | |
264 Line2D l = iter.next(); | |
265 Point2D p1 = l.getP1(); | |
266 Point2D p2 = l.getP2(); | |
267 lxs.add(p1.getX()); | |
268 lys.add(p1.getY()); | |
269 lxs.add(p2.getX()); | |
270 lys.add(p2.getY()); | |
271 if (iter.hasNext()) { | |
272 lxs.add(Double.NaN); | |
273 lys.add(Double.NaN); | |
274 } | |
275 } | |
276 | |
277 return new double [][] { lxs.toNativeArray(), lys.toNativeArray() }; | |
278 } | |
279 } | |
280 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |