Mercurial > dive4elements > river
comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java @ 936:759808931a2e
Add Swing standalone app to test/develope cross sections directly from database.
flys-artifacts/trunk@2328 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Wed, 13 Jul 2011 17:33:15 +0000 |
parents | |
children | bd3683453928 |
comparison
equal
deleted
inserted
replaced
935:353ddfa231a7 | 936:759808931a2e |
---|---|
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.DefaultComboBoxModel; | |
13 | |
14 import java.awt.event.ItemListener; | |
15 import java.awt.event.ItemEvent; | |
16 import java.awt.event.ActionListener; | |
17 import java.awt.event.ActionEvent; | |
18 | |
19 import java.util.ArrayList; | |
20 import java.util.List; | |
21 import java.util.Comparator; | |
22 import java.util.Collections; | |
23 | |
24 import java.io.File; | |
25 import java.io.IOException; | |
26 import java.io.FileWriter; | |
27 import java.io.PrintWriter; | |
28 | |
29 import org.jfree.ui.ApplicationFrame; | |
30 import org.jfree.ui.RefineryUtilities; | |
31 | |
32 import org.jfree.chart.ChartFactory; | |
33 | |
34 import org.jfree.chart.plot.PlotOrientation; | |
35 | |
36 import org.jfree.chart.ChartUtilities; | |
37 import org.jfree.chart.JFreeChart; | |
38 import org.jfree.chart.ChartPanel; | |
39 | |
40 import org.jfree.data.xy.XYDataset; | |
41 import org.jfree.data.xy.DefaultXYDataset; | |
42 | |
43 import de.intevation.flys.model.CrossSection; | |
44 import de.intevation.flys.model.CrossSectionLine; | |
45 import de.intevation.flys.model.CrossSectionPoint; | |
46 | |
47 import de.intevation.flys.backend.SessionFactoryProvider; | |
48 | |
49 import org.hibernate.Session; | |
50 import org.hibernate.Query; | |
51 | |
52 | |
53 public class CrossSectionApp | |
54 extends ApplicationFrame | |
55 { | |
56 public static final String RIVER = System.getProperty("river", "Mosel"); | |
57 | |
58 public static final double EPSILON = 1e-4; | |
59 | |
60 public static final double TOO_SMALL = 0.2; | |
61 public static final double TOO_BIG = 4000; | |
62 | |
63 public static final Comparator<CrossSectionPoint> COL_POS_CMP = | |
64 new Comparator<CrossSectionPoint>() { | |
65 @Override | |
66 public int compare(CrossSectionPoint a, CrossSectionPoint b) { | |
67 double xa = a.getX().doubleValue(); | |
68 double xb = b.getX().doubleValue(); | |
69 double d = xa - xb; | |
70 if (d < -EPSILON) return -1; | |
71 if (d > +EPSILON) return +1; | |
72 int diff = a.getColPos() - b.getColPos(); | |
73 return diff < 0 ? -1 : diff > 0 ? +1 : 0; | |
74 } | |
75 }; | |
76 | |
77 public static final boolean isValid(double x) { | |
78 x = Math.abs(x); | |
79 return x > TOO_SMALL && x < TOO_BIG; | |
80 } | |
81 | |
82 protected Session session; | |
83 | |
84 protected JComboBox crossSectionsCB; | |
85 protected JComboBox crossSectionLinesCB; | |
86 | |
87 protected ChartPanel chartPanel; | |
88 | |
89 | |
90 public static class CrossSectionItem { | |
91 | |
92 CrossSection crossSection; | |
93 | |
94 public CrossSectionItem(CrossSection crossSection) { | |
95 this.crossSection = crossSection; | |
96 } | |
97 | |
98 public String toString() { | |
99 return crossSection.getDescription(); | |
100 } | |
101 } // CrossSectionItem | |
102 | |
103 public static class CrossSectionLineItem { | |
104 | |
105 CrossSectionLine line; | |
106 | |
107 public CrossSectionLineItem(CrossSectionLine line) { | |
108 this.line = line; | |
109 } | |
110 | |
111 public String toString() { | |
112 double v = line.getKm().doubleValue(); | |
113 return String.valueOf(Math.round(v * 1000.0)/1000d); | |
114 } | |
115 } // CrossSectionLineItem | |
116 | |
117 public CrossSectionApp(String title) { | |
118 super(title); | |
119 | |
120 session = SessionFactoryProvider | |
121 .createSessionFactory() | |
122 .openSession(); | |
123 | |
124 JPanel content = createContent(); | |
125 content.setPreferredSize(new Dimension(640, 480)); | |
126 setContentPane(content); | |
127 | |
128 } | |
129 | |
130 public List<CrossSection> crossSections(String river) { | |
131 Query query = session.createQuery( | |
132 "from CrossSection where river.name = :river"); | |
133 query.setParameter("river", river); | |
134 return query.list(); | |
135 } | |
136 | |
137 public JPanel createContent() { | |
138 JPanel panel = new JPanel(new BorderLayout()); | |
139 | |
140 | |
141 JPanel nav = new JPanel(new FlowLayout()); | |
142 | |
143 Object [] csis = createCrossSectionItems(); | |
144 crossSectionsCB = new JComboBox(csis); | |
145 | |
146 DefaultComboBoxModel dcbm; | |
147 | |
148 if (csis.length > 0) { | |
149 Object [] cslis = | |
150 createCrossSectionLineItems( | |
151 ((CrossSectionItem)csis[0]).crossSection); | |
152 dcbm = new DefaultComboBoxModel(cslis); | |
153 if (cslis.length > 0) { | |
154 dcbm.setSelectedItem(cslis[0]); | |
155 } | |
156 } | |
157 else { | |
158 dcbm = new DefaultComboBoxModel(new Object[0]); | |
159 } | |
160 | |
161 crossSectionLinesCB = new JComboBox(dcbm); | |
162 | |
163 nav.add(crossSectionsCB); | |
164 nav.add(crossSectionLinesCB); | |
165 | |
166 crossSectionsCB.addItemListener(new ItemListener() { | |
167 public void itemStateChanged(ItemEvent ie) { | |
168 if (ie.getStateChange() == ItemEvent.SELECTED) { | |
169 updateCrossSection( | |
170 ((CrossSectionItem)ie.getItem()).crossSection); | |
171 } | |
172 } | |
173 }); | |
174 | |
175 crossSectionLinesCB.addItemListener(new ItemListener() { | |
176 public void itemStateChanged(ItemEvent ie) { | |
177 if (ie.getStateChange() == ItemEvent.SELECTED) { | |
178 updateCrossSectionLine(((CrossSectionLineItem)ie.getItem()).line); | |
179 } | |
180 } | |
181 }); | |
182 | |
183 panel.add(nav, BorderLayout.SOUTH); | |
184 | |
185 chartPanel = createChartPanel(); | |
186 | |
187 panel.add(chartPanel, BorderLayout.CENTER); | |
188 | |
189 JButton dump = new JButton("dump"); | |
190 | |
191 dump.addActionListener(new ActionListener() { | |
192 public void actionPerformed(ActionEvent ae) { | |
193 dumpData(); | |
194 } | |
195 }); | |
196 | |
197 nav.add(dump); | |
198 | |
199 return panel; | |
200 } | |
201 | |
202 protected ChartPanel createChartPanel() { | |
203 CrossSectionLineItem csli = | |
204 (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); | |
205 | |
206 if (csli == null) { | |
207 return new ChartPanel(null); | |
208 } | |
209 | |
210 XYDataset dataset = crossSectionPoints(csli.line); | |
211 | |
212 JFreeChart chart = createChart(dataset); | |
213 | |
214 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 } | |
222 | |
223 protected void dumpData() { | |
224 | |
225 CrossSectionLineItem csli = | |
226 (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); | |
227 | |
228 if (csli == null) { | |
229 return; | |
230 } | |
231 | |
232 CrossSectionLine line = csli.line; | |
233 | |
234 double km = Math.round(line.getKm().doubleValue() * 1000d)/1000d; | |
235 | |
236 String kmS = String.valueOf(km).replace(".", "-"); | |
237 | |
238 int i = 1; | |
239 File file = new File("cross-section-" + kmS + ".txt"); | |
240 while (file.exists()) { | |
241 file = new File("cross-section-" + kmS + "[" + (i++) + "].txt"); | |
242 } | |
243 | |
244 System.err.println("dump points to file '" + file + "'"); | |
245 | |
246 List<CrossSectionPoint> points = line.getPoints(); | |
247 | |
248 PrintWriter out = null; | |
249 | |
250 MathContext mc = new MathContext(3); | |
251 | |
252 try { | |
253 out = | |
254 new PrintWriter( | |
255 new FileWriter(file)); | |
256 | |
257 for (CrossSectionPoint point: points) { | |
258 out.println( | |
259 point.getX().round(mc) + " " + | |
260 point.getY().round(mc)); | |
261 } | |
262 | |
263 out.flush(); | |
264 } | |
265 catch (IOException ioe) { | |
266 ioe.printStackTrace(); | |
267 } | |
268 finally { | |
269 if (out != null) { | |
270 out.close(); | |
271 } | |
272 } | |
273 } | |
274 | |
275 protected XYDataset crossSectionPoints(CrossSectionLine line) { | |
276 DefaultXYDataset dataset = new DefaultXYDataset(); | |
277 | |
278 List<CrossSectionPoint> ps = line.getPoints(); | |
279 | |
280 List<CrossSectionPoint> points = | |
281 new ArrayList<CrossSectionPoint>(ps.size()); | |
282 | |
283 for (CrossSectionPoint p: ps) { | |
284 if (isValid(p.getX().doubleValue()) | |
285 && isValid(p.getY().doubleValue())) { | |
286 points.add(p); | |
287 } | |
288 } | |
289 | |
290 if (points.isEmpty()) { | |
291 return dataset; | |
292 } | |
293 | |
294 Collections.sort(points, COL_POS_CMP); | |
295 | |
296 double [] xs = new double[points.size()]; | |
297 double [] ys = new double[xs.length]; | |
298 | |
299 double x = points.get(0).getX().doubleValue(); | |
300 double y = points.get(0).getY().doubleValue(); | |
301 | |
302 xs[0] = x; | |
303 ys[0] = y; | |
304 | |
305 for (int i = 1; i < xs.length; ++i) { | |
306 CrossSectionPoint p = points.get(i); | |
307 x = p.getX().doubleValue(); | |
308 y = p.getY().doubleValue(); | |
309 | |
310 if (x <= xs[i-1]) { | |
311 x = xs[i-1] + EPSILON; | |
312 } | |
313 xs[i] = x; | |
314 ys[i] = y; | |
315 } | |
316 | |
317 CrossSection cs = line.getCrossSection(); | |
318 | |
319 String legend = (cs != null ? cs.getDescription() : "???") | |
320 + " " + Math.round(line.getKm().doubleValue() * 1000d)/1000d; | |
321 | |
322 dataset.addSeries(legend, new double [][] { xs, ys }); | |
323 | |
324 return dataset; | |
325 } | |
326 | |
327 protected void updateCrossSection(CrossSection crossSection) { | |
328 Object [] cslis = createCrossSectionLineItems(crossSection); | |
329 DefaultComboBoxModel dcbm = new DefaultComboBoxModel(cslis); | |
330 if (cslis.length > 0) { | |
331 dcbm.setSelectedItem(cslis[0]); | |
332 } | |
333 crossSectionLinesCB.setModel(dcbm); | |
334 if (cslis.length > 0) { | |
335 CrossSectionLine line = | |
336 ((CrossSectionLineItem)cslis[0]).line; | |
337 updateCrossSectionLine(line); | |
338 } | |
339 } | |
340 | |
341 protected Object [] createCrossSectionLineItems(CrossSection cs) { | |
342 List<CrossSectionLine> lines = cs.getLines(); | |
343 Object [] result = new Object[lines.size()]; | |
344 for (int i = 0; i < result.length; ++i) { | |
345 result[i] = new CrossSectionLineItem(lines.get(i)); | |
346 } | |
347 return result; | |
348 } | |
349 | |
350 | |
351 protected Object [] createCrossSectionItems() { | |
352 List<CrossSection> crossSections = crossSections(RIVER); | |
353 Object [] result = new Object[crossSections.size()]; | |
354 for (int i = 0; i < result.length; ++i) { | |
355 result[i] = new CrossSectionItem(crossSections.get(i)); | |
356 } | |
357 return result; | |
358 } | |
359 | |
360 public static JFreeChart createChart(XYDataset dataset) { | |
361 JFreeChart chart = ChartFactory.createXYLineChart( | |
362 null, | |
363 "Abstand [m]", | |
364 "H\u00f6he [m]", | |
365 dataset, | |
366 PlotOrientation.VERTICAL, | |
367 true, | |
368 true, | |
369 false); | |
370 ChartUtilities.applyCurrentTheme(chart); | |
371 return chart; | |
372 } | |
373 | |
374 public static void main(String [] args) { | |
375 CrossSectionApp csa = new CrossSectionApp("Querprofile"); | |
376 csa.pack(); | |
377 RefineryUtilities.centerFrameOnScreen(csa); | |
378 csa.setVisible(true); | |
379 } | |
380 } | |
381 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |