Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.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 | 759808931a2e |
children | 111794adf285 |
comparison
equal
deleted
inserted
replaced
937:9e813e9137a5 | 938:bd3683453928 |
---|---|
7 import java.awt.FlowLayout; | 7 import java.awt.FlowLayout; |
8 | 8 |
9 import javax.swing.JPanel; | 9 import javax.swing.JPanel; |
10 import javax.swing.JButton; | 10 import javax.swing.JButton; |
11 import javax.swing.JComboBox; | 11 import javax.swing.JComboBox; |
12 import javax.swing.JTextField; | |
12 import javax.swing.DefaultComboBoxModel; | 13 import javax.swing.DefaultComboBoxModel; |
13 | 14 |
14 import java.awt.event.ItemListener; | 15 import java.awt.event.ItemListener; |
15 import java.awt.event.ItemEvent; | 16 import java.awt.event.ItemEvent; |
16 import java.awt.event.ActionListener; | 17 import java.awt.event.ActionListener; |
17 import java.awt.event.ActionEvent; | 18 import java.awt.event.ActionEvent; |
18 | 19 |
20 import java.awt.geom.Point2D; | |
21 import java.awt.geom.Line2D; | |
22 | |
19 import java.util.ArrayList; | 23 import java.util.ArrayList; |
20 import java.util.List; | 24 import java.util.List; |
21 import java.util.Comparator; | 25 import java.util.Comparator; |
22 import java.util.Collections; | 26 import java.util.Collections; |
27 import java.util.Iterator; | |
23 | 28 |
24 import java.io.File; | 29 import java.io.File; |
25 import java.io.IOException; | 30 import java.io.IOException; |
26 import java.io.FileWriter; | 31 import java.io.FileWriter; |
27 import java.io.PrintWriter; | 32 import java.io.PrintWriter; |
30 import org.jfree.ui.RefineryUtilities; | 35 import org.jfree.ui.RefineryUtilities; |
31 | 36 |
32 import org.jfree.chart.ChartFactory; | 37 import org.jfree.chart.ChartFactory; |
33 | 38 |
34 import org.jfree.chart.plot.PlotOrientation; | 39 import org.jfree.chart.plot.PlotOrientation; |
40 import org.jfree.chart.plot.XYPlot; | |
35 | 41 |
36 import org.jfree.chart.ChartUtilities; | 42 import org.jfree.chart.ChartUtilities; |
37 import org.jfree.chart.JFreeChart; | 43 import org.jfree.chart.JFreeChart; |
38 import org.jfree.chart.ChartPanel; | 44 import org.jfree.chart.ChartPanel; |
39 | 45 |
46 import org.jfree.chart.axis.NumberAxis; | |
47 | |
40 import org.jfree.data.xy.XYDataset; | 48 import org.jfree.data.xy.XYDataset; |
41 import org.jfree.data.xy.DefaultXYDataset; | 49 import org.jfree.data.xy.DefaultXYDataset; |
42 | 50 |
43 import de.intevation.flys.model.CrossSection; | 51 import de.intevation.flys.model.CrossSection; |
44 import de.intevation.flys.model.CrossSectionLine; | 52 import de.intevation.flys.model.CrossSectionLine; |
45 import de.intevation.flys.model.CrossSectionPoint; | 53 import de.intevation.flys.model.CrossSectionPoint; |
46 | 54 |
55 import de.intevation.flys.geom.Lines; | |
56 | |
47 import de.intevation.flys.backend.SessionFactoryProvider; | 57 import de.intevation.flys.backend.SessionFactoryProvider; |
48 | 58 |
49 import org.hibernate.Session; | 59 import org.hibernate.Session; |
50 import org.hibernate.Query; | 60 import org.hibernate.Query; |
51 | 61 |
62 import gnu.trove.TDoubleArrayList; | |
52 | 63 |
53 public class CrossSectionApp | 64 public class CrossSectionApp |
54 extends ApplicationFrame | 65 extends ApplicationFrame |
55 { | 66 { |
56 public static final String RIVER = System.getProperty("river", "Mosel"); | 67 public static final String RIVER = System.getProperty("river", "Mosel"); |
57 | 68 |
58 public static final double EPSILON = 1e-4; | 69 public static final double EPSILON = 1e-4; |
59 | 70 |
60 public static final double TOO_SMALL = 0.2; | 71 public static final double TOO_SMALL = 0.2; |
61 public static final double TOO_BIG = 4000; | 72 public static final double TOO_BIG = 500; |
62 | 73 |
63 public static final Comparator<CrossSectionPoint> COL_POS_CMP = | 74 public static final Comparator<CrossSectionPoint> COL_POS_CMP = |
64 new Comparator<CrossSectionPoint>() { | 75 new Comparator<CrossSectionPoint>() { |
65 @Override | 76 @Override |
66 public int compare(CrossSectionPoint a, CrossSectionPoint b) { | 77 public int compare(CrossSectionPoint a, CrossSectionPoint b) { |
81 | 92 |
82 protected Session session; | 93 protected Session session; |
83 | 94 |
84 protected JComboBox crossSectionsCB; | 95 protected JComboBox crossSectionsCB; |
85 protected JComboBox crossSectionLinesCB; | 96 protected JComboBox crossSectionLinesCB; |
97 protected JTextField waterlevelTF; | |
86 | 98 |
87 protected ChartPanel chartPanel; | 99 protected ChartPanel chartPanel; |
100 | |
101 protected Double lastWaterLevel; | |
88 | 102 |
89 | 103 |
90 public static class CrossSectionItem { | 104 public static class CrossSectionItem { |
91 | 105 |
92 CrossSection crossSection; | 106 CrossSection crossSection; |
173 }); | 187 }); |
174 | 188 |
175 crossSectionLinesCB.addItemListener(new ItemListener() { | 189 crossSectionLinesCB.addItemListener(new ItemListener() { |
176 public void itemStateChanged(ItemEvent ie) { | 190 public void itemStateChanged(ItemEvent ie) { |
177 if (ie.getStateChange() == ItemEvent.SELECTED) { | 191 if (ie.getStateChange() == ItemEvent.SELECTED) { |
178 updateCrossSectionLine(((CrossSectionLineItem)ie.getItem()).line); | 192 updateChart(); |
179 } | 193 } |
180 } | 194 } |
181 }); | 195 }); |
182 | 196 |
183 panel.add(nav, BorderLayout.SOUTH); | 197 |
184 | 198 waterlevelTF = new JTextField(5); |
185 chartPanel = createChartPanel(); | 199 |
186 | 200 waterlevelTF.addActionListener(new ActionListener() { |
187 panel.add(chartPanel, BorderLayout.CENTER); | 201 public void actionPerformed(ActionEvent ae) { |
202 waterLevelChanged(); | |
203 } | |
204 }); | |
205 | |
206 nav.add(waterlevelTF); | |
188 | 207 |
189 JButton dump = new JButton("dump"); | 208 JButton dump = new JButton("dump"); |
190 | 209 |
191 dump.addActionListener(new ActionListener() { | 210 dump.addActionListener(new ActionListener() { |
192 public void actionPerformed(ActionEvent ae) { | 211 public void actionPerformed(ActionEvent ae) { |
194 } | 213 } |
195 }); | 214 }); |
196 | 215 |
197 nav.add(dump); | 216 nav.add(dump); |
198 | 217 |
218 panel.add(nav, BorderLayout.SOUTH); | |
219 | |
220 chartPanel = createChartPanel(); | |
221 | |
222 panel.add(chartPanel, BorderLayout.CENTER); | |
223 | |
199 return panel; | 224 return panel; |
225 } | |
226 | |
227 protected void waterLevelChanged() { | |
228 String value = waterlevelTF.getText(); | |
229 try { | |
230 lastWaterLevel = Double.parseDouble(value); | |
231 } | |
232 catch (NumberFormatException nfe) { | |
233 waterlevelTF.setText( | |
234 lastWaterLevel != null ? lastWaterLevel.toString() : ""); | |
235 return; | |
236 } | |
237 updateChart(); | |
238 } | |
239 | |
240 protected void updateChart() { | |
241 | |
242 CrossSectionLineItem csli = | |
243 (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); | |
244 | |
245 JFreeChart chart = createChart(csli == null | |
246 ? new DefaultXYDataset() | |
247 : generateDataset(csli.line, lastWaterLevel)); | |
248 | |
249 chartPanel.setChart(chart); | |
200 } | 250 } |
201 | 251 |
202 protected ChartPanel createChartPanel() { | 252 protected ChartPanel createChartPanel() { |
203 CrossSectionLineItem csli = | 253 CrossSectionLineItem csli = |
204 (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); | 254 (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); |
205 | 255 |
206 if (csli == null) { | 256 JFreeChart chart = createChart(csli == null |
207 return new ChartPanel(null); | 257 ? new DefaultXYDataset() |
208 } | 258 : generateDataset(csli.line, lastWaterLevel)); |
209 | |
210 XYDataset dataset = crossSectionPoints(csli.line); | |
211 | |
212 JFreeChart chart = createChart(dataset); | |
213 | 259 |
214 return new ChartPanel(chart); | 260 return new ChartPanel(chart); |
215 } | |
216 | |
217 protected void updateCrossSectionLine(CrossSectionLine line) { | |
218 XYDataset dataset = crossSectionPoints(line); | |
219 JFreeChart chart = createChart(dataset); | |
220 chartPanel.setChart(chart); | |
221 } | 261 } |
222 | 262 |
223 protected void dumpData() { | 263 protected void dumpData() { |
224 | 264 |
225 CrossSectionLineItem csli = | 265 CrossSectionLineItem csli = |
270 out.close(); | 310 out.close(); |
271 } | 311 } |
272 } | 312 } |
273 } | 313 } |
274 | 314 |
275 protected XYDataset crossSectionPoints(CrossSectionLine line) { | 315 protected XYDataset generateDataset( |
316 CrossSectionLine line, | |
317 Double waterlevel | |
318 ) { | |
276 DefaultXYDataset dataset = new DefaultXYDataset(); | 319 DefaultXYDataset dataset = new DefaultXYDataset(); |
277 | 320 |
278 List<CrossSectionPoint> ps = line.getPoints(); | 321 List<CrossSectionPoint> ps = line.getPoints(); |
279 | 322 |
280 List<CrossSectionPoint> points = | 323 if (ps.isEmpty()) { |
281 new ArrayList<CrossSectionPoint>(ps.size()); | 324 return dataset; |
325 } | |
326 | |
327 Collections.sort(ps, COL_POS_CMP); | |
328 | |
329 List<Point2D> points = new ArrayList<Point2D>(ps.size()); | |
282 | 330 |
283 for (CrossSectionPoint p: ps) { | 331 for (CrossSectionPoint p: ps) { |
284 if (isValid(p.getX().doubleValue()) | 332 double x = p.getX().doubleValue(); |
285 && isValid(p.getY().doubleValue())) { | 333 double y = p.getY().doubleValue(); |
286 points.add(p); | 334 if (isValid(x) && isValid(y)) { |
335 points.add(new Point2D.Double(x, y)); | |
287 } | 336 } |
288 } | 337 } |
289 | 338 |
290 if (points.isEmpty()) { | 339 if (points.isEmpty()) { |
291 return dataset; | 340 return dataset; |
292 } | 341 } |
293 | 342 |
294 Collections.sort(points, COL_POS_CMP); | |
295 | |
296 double [] xs = new double[points.size()]; | 343 double [] xs = new double[points.size()]; |
297 double [] ys = new double[xs.length]; | 344 double [] ys = new double[xs.length]; |
298 | 345 |
299 double x = points.get(0).getX().doubleValue(); | 346 xs[0] = points.get(0).getX(); |
300 double y = points.get(0).getY().doubleValue(); | 347 ys[0] = points.get(0).getY(); |
301 | |
302 xs[0] = x; | |
303 ys[0] = y; | |
304 | 348 |
305 for (int i = 1; i < xs.length; ++i) { | 349 for (int i = 1; i < xs.length; ++i) { |
306 CrossSectionPoint p = points.get(i); | 350 Point2D p = points.get(i); |
307 x = p.getX().doubleValue(); | 351 double x = p.getX(); |
308 y = p.getY().doubleValue(); | 352 double y = p.getY(); |
309 | 353 |
310 if (x <= xs[i-1]) { | 354 if (x <= xs[i-1]) { |
311 x = xs[i-1] + EPSILON; | 355 x = xs[i-1] + EPSILON; |
312 } | 356 } |
313 xs[i] = x; | 357 xs[i] = x; |
314 ys[i] = y; | 358 ys[i] = y; |
315 } | 359 } |
316 | 360 |
361 if (waterlevel != null) { | |
362 double [][] data = createWaterLines(points, waterlevel); | |
363 dataset.addSeries(String.valueOf(waterlevel), data); | |
364 } | |
365 | |
317 CrossSection cs = line.getCrossSection(); | 366 CrossSection cs = line.getCrossSection(); |
318 | 367 |
319 String legend = (cs != null ? cs.getDescription() : "???") | 368 String legend = (cs != null ? cs.getDescription() : "???") |
320 + " " + Math.round(line.getKm().doubleValue() * 1000d)/1000d; | 369 + " " + Math.round(line.getKm().doubleValue() * 1000d)/1000d; |
321 | 370 |
322 dataset.addSeries(legend, new double [][] { xs, ys }); | 371 dataset.addSeries(legend, new double [][] { xs, ys }); |
323 | 372 |
324 return dataset; | 373 return dataset; |
374 } | |
375 | |
376 protected static double [][] createWaterLines( | |
377 List<Point2D> points, | |
378 double waterlevel | |
379 ) { | |
380 List<Line2D> lines = Lines.fillWater(points, waterlevel); | |
381 | |
382 TDoubleArrayList lxs = new TDoubleArrayList(); | |
383 TDoubleArrayList lys = new TDoubleArrayList(); | |
384 | |
385 for (Iterator<Line2D> iter = lines.iterator(); iter.hasNext();) { | |
386 Line2D l = iter.next(); | |
387 Point2D p1 = l.getP1(); | |
388 Point2D p2 = l.getP2(); | |
389 lxs.add(p1.getX()); | |
390 lys.add(p1.getY()); | |
391 lxs.add(p2.getX()); | |
392 lys.add(p2.getY()); | |
393 if (iter.hasNext()) { | |
394 lxs.add(Double.NaN); | |
395 lys.add(Double.NaN); | |
396 } | |
397 } | |
398 | |
399 return new double [][] { lxs.toNativeArray(), lys.toNativeArray() }; | |
325 } | 400 } |
326 | 401 |
327 protected void updateCrossSection(CrossSection crossSection) { | 402 protected void updateCrossSection(CrossSection crossSection) { |
328 Object [] cslis = createCrossSectionLineItems(crossSection); | 403 Object [] cslis = createCrossSectionLineItems(crossSection); |
329 DefaultComboBoxModel dcbm = new DefaultComboBoxModel(cslis); | 404 DefaultComboBoxModel dcbm = new DefaultComboBoxModel(cslis); |
332 } | 407 } |
333 crossSectionLinesCB.setModel(dcbm); | 408 crossSectionLinesCB.setModel(dcbm); |
334 if (cslis.length > 0) { | 409 if (cslis.length > 0) { |
335 CrossSectionLine line = | 410 CrossSectionLine line = |
336 ((CrossSectionLineItem)cslis[0]).line; | 411 ((CrossSectionLineItem)cslis[0]).line; |
337 updateCrossSectionLine(line); | 412 } |
338 } | 413 updateChart(); |
339 } | 414 } |
340 | 415 |
341 protected Object [] createCrossSectionLineItems(CrossSection cs) { | 416 protected Object [] createCrossSectionLineItems(CrossSection cs) { |
342 List<CrossSectionLine> lines = cs.getLines(); | 417 List<CrossSectionLine> lines = cs.getLines(); |
343 Object [] result = new Object[lines.size()]; | 418 Object [] result = new Object[lines.size()]; |
365 dataset, | 440 dataset, |
366 PlotOrientation.VERTICAL, | 441 PlotOrientation.VERTICAL, |
367 true, | 442 true, |
368 true, | 443 true, |
369 false); | 444 false); |
445 | |
446 XYPlot plot = chart.getXYPlot(); | |
447 NumberAxis yAxis = (NumberAxis)plot.getRangeAxis(); | |
448 yAxis.setAutoRangeIncludesZero(false); | |
449 | |
370 ChartUtilities.applyCurrentTheme(chart); | 450 ChartUtilities.applyCurrentTheme(chart); |
371 return chart; | 451 return chart; |
372 } | 452 } |
373 | 453 |
374 public static void main(String [] args) { | 454 public static void main(String [] args) { |