comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.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 111794adf285
children a7def20539fb
comparison
equal deleted inserted replaced
917:b48c36076e17 1190:f514894ec2fd
1 package de.intevation.flys.artifacts.charts;
2
3 import java.math.MathContext;
4
5 import java.awt.Dimension;
6 import java.awt.BorderLayout;
7 import java.awt.FlowLayout;
8
9 import javax.swing.JPanel;
10 import javax.swing.JButton;
11 import javax.swing.JComboBox;
12 import javax.swing.JTextField;
13 import javax.swing.DefaultComboBoxModel;
14
15 import java.awt.event.ItemListener;
16 import java.awt.event.ItemEvent;
17 import java.awt.event.ActionListener;
18 import java.awt.event.ActionEvent;
19
20 import java.awt.geom.Point2D;
21 import java.awt.geom.Line2D;
22
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Comparator;
26 import java.util.Collections;
27 import java.util.Iterator;
28
29 import java.io.File;
30 import java.io.IOException;
31 import java.io.FileWriter;
32 import java.io.PrintWriter;
33
34 import org.jfree.ui.ApplicationFrame;
35 import org.jfree.ui.RefineryUtilities;
36
37 import org.jfree.chart.ChartFactory;
38
39 import org.jfree.chart.plot.PlotOrientation;
40 import org.jfree.chart.plot.XYPlot;
41
42 import org.jfree.chart.ChartUtilities;
43 import org.jfree.chart.JFreeChart;
44 import org.jfree.chart.ChartPanel;
45
46 import org.jfree.chart.axis.NumberAxis;
47
48 import org.jfree.data.xy.XYDataset;
49 import org.jfree.data.xy.DefaultXYDataset;
50
51 import de.intevation.flys.model.CrossSection;
52 import de.intevation.flys.model.CrossSectionLine;
53 import de.intevation.flys.model.CrossSectionPoint;
54
55 import de.intevation.flys.geom.Lines;
56
57 import de.intevation.flys.backend.SessionFactoryProvider;
58
59 import org.hibernate.Session;
60 import org.hibernate.Query;
61
62 import gnu.trove.TDoubleArrayList;
63
64 public class CrossSectionApp
65 extends ApplicationFrame
66 {
67 public static final String RIVER = System.getProperty("river", "Saar");
68
69 public static final double EPSILON = 1e-4;
70
71 public static final double TOO_SMALL = 0.2;
72 public static final double TOO_BIG = 500;
73
74 public static final Comparator<CrossSectionPoint> COL_POS_CMP =
75 new Comparator<CrossSectionPoint>() {
76 @Override
77 public int compare(CrossSectionPoint a, CrossSectionPoint b) {
78 // TODO evaluate: isnt it enough to
79 // return (|d| > |EPS|) ? d : diff
80 double xa = a.getX().doubleValue();
81 double xb = b.getX().doubleValue();
82 double d = xa - xb;
83 if (d < -EPSILON) return -1;
84 if (d > +EPSILON) return +1;
85 int diff = a.getColPos() - b.getColPos();
86 return diff < 0 ? -1 : diff > 0 ? +1 : 0;
87 }
88 };
89
90 public static final boolean isValid(double x) {
91 x = Math.abs(x);
92 return x > TOO_SMALL && x < TOO_BIG;
93 }
94
95 protected Session session;
96
97 protected JComboBox crossSectionsCB;
98 protected JComboBox crossSectionLinesCB;
99 protected JTextField waterlevelTF;
100
101 protected ChartPanel chartPanel;
102
103 protected Double lastWaterLevel;
104
105
106 public static class CrossSectionItem {
107
108 CrossSection crossSection;
109
110 public CrossSectionItem(CrossSection crossSection) {
111 this.crossSection = crossSection;
112 }
113
114 public String toString() {
115 return crossSection.getDescription();
116 }
117 } // CrossSectionItem
118
119 public static class CrossSectionLineItem {
120
121 CrossSectionLine line;
122
123 public CrossSectionLineItem(CrossSectionLine line) {
124 this.line = line;
125 }
126
127 public String toString() {
128 double v = line.getKm().doubleValue();
129 return String.valueOf(Math.round(v * 1000.0)/1000d);
130 }
131 } // CrossSectionLineItem
132
133 public CrossSectionApp(String title) {
134 super(title);
135
136 session = SessionFactoryProvider
137 .createSessionFactory()
138 .openSession();
139
140 JPanel content = createContent();
141 content.setPreferredSize(new Dimension(640, 480));
142 setContentPane(content);
143
144 }
145
146 public List<CrossSection> crossSections(String river) {
147 Query query = session.createQuery(
148 "from CrossSection where river.name = :river");
149 query.setParameter("river", river);
150 return query.list();
151 }
152
153 public JPanel createContent() {
154 JPanel panel = new JPanel(new BorderLayout());
155
156
157 JPanel nav = new JPanel(new FlowLayout());
158
159 Object [] csis = createCrossSectionItems();
160 crossSectionsCB = new JComboBox(csis);
161
162 DefaultComboBoxModel dcbm;
163
164 if (csis.length > 0) {
165 Object [] cslis =
166 createCrossSectionLineItems(
167 ((CrossSectionItem)csis[0]).crossSection);
168 dcbm = new DefaultComboBoxModel(cslis);
169 if (cslis.length > 0) {
170 dcbm.setSelectedItem(cslis[0]);
171 }
172 }
173 else {
174 dcbm = new DefaultComboBoxModel(new Object[0]);
175 }
176
177 crossSectionLinesCB = new JComboBox(dcbm);
178
179 nav.add(crossSectionsCB);
180 nav.add(crossSectionLinesCB);
181
182 crossSectionsCB.addItemListener(new ItemListener() {
183 public void itemStateChanged(ItemEvent ie) {
184 if (ie.getStateChange() == ItemEvent.SELECTED) {
185 updateCrossSection(
186 ((CrossSectionItem)ie.getItem()).crossSection);
187 }
188 }
189 });
190
191 crossSectionLinesCB.addItemListener(new ItemListener() {
192 public void itemStateChanged(ItemEvent ie) {
193 if (ie.getStateChange() == ItemEvent.SELECTED) {
194 updateChart();
195 }
196 }
197 });
198
199
200 waterlevelTF = new JTextField(5);
201
202 waterlevelTF.addActionListener(new ActionListener() {
203 public void actionPerformed(ActionEvent ae) {
204 waterLevelChanged();
205 }
206 });
207
208 nav.add(waterlevelTF);
209
210 JButton dump = new JButton("dump");
211
212 dump.addActionListener(new ActionListener() {
213 public void actionPerformed(ActionEvent ae) {
214 dumpData();
215 }
216 });
217
218 nav.add(dump);
219
220 panel.add(nav, BorderLayout.SOUTH);
221
222 chartPanel = createChartPanel();
223
224 panel.add(chartPanel, BorderLayout.CENTER);
225
226 return panel;
227 }
228
229 protected void waterLevelChanged() {
230 String value = waterlevelTF.getText();
231 try {
232 lastWaterLevel = Double.parseDouble(value);
233 }
234 catch (NumberFormatException nfe) {
235 waterlevelTF.setText(
236 lastWaterLevel != null ? lastWaterLevel.toString() : "");
237 return;
238 }
239 updateChart();
240 }
241
242 protected void updateChart() {
243
244 CrossSectionLineItem csli =
245 (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem();
246
247 JFreeChart chart = createChart(csli == null
248 ? new DefaultXYDataset()
249 : generateDataset(csli.line, lastWaterLevel));
250
251 chartPanel.setChart(chart);
252 }
253
254 protected ChartPanel createChartPanel() {
255 CrossSectionLineItem csli =
256 (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem();
257
258 JFreeChart chart = createChart(csli == null
259 ? new DefaultXYDataset()
260 : generateDataset(csli.line, lastWaterLevel));
261
262 return new ChartPanel(chart);
263 }
264
265 protected void dumpData() {
266
267 CrossSectionLineItem csli =
268 (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem();
269
270 if (csli == null) {
271 return;
272 }
273
274 CrossSectionLine line = csli.line;
275
276 double km = Math.round(line.getKm().doubleValue() * 1000d)/1000d;
277
278 String kmS = String.valueOf(km).replace(".", "-");
279
280 int i = 1;
281 File file = new File("cross-section-" + kmS + ".txt");
282 while (file.exists()) {
283 file = new File("cross-section-" + kmS + "[" + (i++) + "].txt");
284 }
285
286 System.err.println("dump points to file '" + file + "'");
287
288 List<CrossSectionPoint> points = line.getPoints();
289
290 PrintWriter out = null;
291
292 MathContext mc = new MathContext(3);
293
294 try {
295 out =
296 new PrintWriter(
297 new FileWriter(file));
298
299 for (CrossSectionPoint point: points) {
300 out.println(
301 point.getX().round(mc) + " " +
302 point.getY().round(mc));
303 }
304
305 out.flush();
306 }
307 catch (IOException ioe) {
308 ioe.printStackTrace();
309 }
310 finally {
311 if (out != null) {
312 out.close();
313 }
314 }
315 }
316
317 public static XYDataset generateDataset(
318 CrossSectionLine line,
319 Double waterlevel
320 ) {
321 DefaultXYDataset dataset = new DefaultXYDataset();
322
323 List<CrossSectionPoint> ps = line.getPoints();
324
325 if (ps.isEmpty()) {
326 return dataset;
327 }
328
329 Collections.sort(ps, COL_POS_CMP);
330
331 List<Point2D> points = new ArrayList<Point2D>(ps.size());
332
333 for (CrossSectionPoint p: ps) {
334 double x = p.getX().doubleValue();
335 double y = p.getY().doubleValue();
336 if (isValid(x) && isValid(y)) {
337 points.add(new Point2D.Double(x, y));
338 }
339 }
340
341 if (points.isEmpty()) {
342 return dataset;
343 }
344
345 double [] xs = new double[points.size()];
346 double [] ys = new double[xs.length];
347
348 xs[0] = points.get(0).getX();
349 ys[0] = points.get(0).getY();
350
351 for (int i = 1; i < xs.length; ++i) {
352 Point2D p = points.get(i);
353 double x = p.getX();
354 double y = p.getY();
355
356 if (x <= xs[i-1]) {
357 x = xs[i-1] + EPSILON;
358 }
359 xs[i] = x;
360 ys[i] = y;
361 }
362
363 if (waterlevel != null) {
364 double [][] data = createWaterLines(points, waterlevel);
365 dataset.addSeries(String.valueOf(waterlevel), data);
366 }
367
368 CrossSection cs = line.getCrossSection();
369
370 String legend = (cs != null ? cs.getDescription() : "???")
371 + " " + Math.round(line.getKm().doubleValue() * 1000d)/1000d;
372
373 dataset.addSeries(legend, new double [][] { xs, ys });
374
375 return dataset;
376 }
377
378 public static double [][] createWaterLines(
379 List<Point2D> points,
380 double waterlevel
381 ) {
382 List<Line2D> lines = Lines.fillWater(points, waterlevel);
383
384 TDoubleArrayList lxs = new TDoubleArrayList();
385 TDoubleArrayList lys = new TDoubleArrayList();
386
387 for (Iterator<Line2D> iter = lines.iterator(); iter.hasNext();) {
388 Line2D l = iter.next();
389 Point2D p1 = l.getP1();
390 Point2D p2 = l.getP2();
391 lxs.add(p1.getX());
392 lys.add(p1.getY());
393 lxs.add(p2.getX());
394 lys.add(p2.getY());
395 if (iter.hasNext()) {
396 lxs.add(Double.NaN);
397 lys.add(Double.NaN);
398 }
399 }
400
401 return new double [][] { lxs.toNativeArray(), lys.toNativeArray() };
402 }
403
404 protected void updateCrossSection(CrossSection crossSection) {
405 Object [] cslis = createCrossSectionLineItems(crossSection);
406 DefaultComboBoxModel dcbm = new DefaultComboBoxModel(cslis);
407 if (cslis.length > 0) {
408 dcbm.setSelectedItem(cslis[0]);
409 }
410 crossSectionLinesCB.setModel(dcbm);
411 if (cslis.length > 0) {
412 CrossSectionLine line =
413 ((CrossSectionLineItem)cslis[0]).line;
414 }
415 updateChart();
416 }
417
418 protected Object [] createCrossSectionLineItems(CrossSection cs) {
419 List<CrossSectionLine> lines = cs.getLines();
420 Object [] result = new Object[lines.size()];
421 for (int i = 0; i < result.length; ++i) {
422 result[i] = new CrossSectionLineItem(lines.get(i));
423 }
424 return result;
425 }
426
427
428 protected Object [] createCrossSectionItems() {
429 List<CrossSection> crossSections = crossSections(RIVER);
430 Object [] result = new Object[crossSections.size()];
431 for (int i = 0; i < result.length; ++i) {
432 result[i] = new CrossSectionItem(crossSections.get(i));
433 }
434 return result;
435 }
436
437 public static JFreeChart createChart(XYDataset dataset) {
438 JFreeChart chart = ChartFactory.createXYLineChart(
439 null,
440 "Abstand [m]",
441 "H\u00f6he [m]",
442 dataset,
443 PlotOrientation.VERTICAL,
444 true,
445 true,
446 false);
447
448 XYPlot plot = chart.getXYPlot();
449 NumberAxis yAxis = (NumberAxis)plot.getRangeAxis();
450 yAxis.setAutoRangeIncludesZero(false);
451
452 ChartUtilities.applyCurrentTheme(chart);
453 return chart;
454 }
455
456 public static void main(String [] args) {
457 CrossSectionApp csa = new CrossSectionApp("Querprofile");
458 csa.pack();
459 RefineryUtilities.centerFrameOnScreen(csa);
460 csa.setVisible(true);
461 }
462 }
463 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org