Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java @ 1077:3067e700fc13
Minor cosmetics and docs.
flys-artifacts/trunk@2574 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Felix Wolfsteller <felix.wolfsteller@intevation.de> |
---|---|
date | Thu, 25 Aug 2011 10:34:20 +0000 |
parents | bd3683453928 |
children | 111794adf285 |
line wrap: on
line source
package de.intevation.flys.artifacts.charts; import java.math.MathContext; import java.awt.Dimension; import java.awt.BorderLayout; import java.awt.FlowLayout; import javax.swing.JPanel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JTextField; import javax.swing.DefaultComboBoxModel; import java.awt.event.ItemListener; import java.awt.event.ItemEvent; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.geom.Point2D; import java.awt.geom.Line2D; import java.util.ArrayList; import java.util.List; import java.util.Comparator; import java.util.Collections; import java.util.Iterator; import java.io.File; import java.io.IOException; import java.io.FileWriter; import java.io.PrintWriter; import org.jfree.ui.ApplicationFrame; import org.jfree.ui.RefineryUtilities; import org.jfree.chart.ChartFactory; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.ChartUtilities; import org.jfree.chart.JFreeChart; import org.jfree.chart.ChartPanel; import org.jfree.chart.axis.NumberAxis; import org.jfree.data.xy.XYDataset; import org.jfree.data.xy.DefaultXYDataset; import de.intevation.flys.model.CrossSection; import de.intevation.flys.model.CrossSectionLine; import de.intevation.flys.model.CrossSectionPoint; import de.intevation.flys.geom.Lines; import de.intevation.flys.backend.SessionFactoryProvider; import org.hibernate.Session; import org.hibernate.Query; import gnu.trove.TDoubleArrayList; public class CrossSectionApp extends ApplicationFrame { public static final String RIVER = System.getProperty("river", "Mosel"); public static final double EPSILON = 1e-4; public static final double TOO_SMALL = 0.2; public static final double TOO_BIG = 500; public static final Comparator<CrossSectionPoint> COL_POS_CMP = new Comparator<CrossSectionPoint>() { @Override public int compare(CrossSectionPoint a, CrossSectionPoint b) { double xa = a.getX().doubleValue(); double xb = b.getX().doubleValue(); double d = xa - xb; if (d < -EPSILON) return -1; if (d > +EPSILON) return +1; int diff = a.getColPos() - b.getColPos(); return diff < 0 ? -1 : diff > 0 ? +1 : 0; } }; public static final boolean isValid(double x) { x = Math.abs(x); return x > TOO_SMALL && x < TOO_BIG; } protected Session session; protected JComboBox crossSectionsCB; protected JComboBox crossSectionLinesCB; protected JTextField waterlevelTF; protected ChartPanel chartPanel; protected Double lastWaterLevel; public static class CrossSectionItem { CrossSection crossSection; public CrossSectionItem(CrossSection crossSection) { this.crossSection = crossSection; } public String toString() { return crossSection.getDescription(); } } // CrossSectionItem public static class CrossSectionLineItem { CrossSectionLine line; public CrossSectionLineItem(CrossSectionLine line) { this.line = line; } public String toString() { double v = line.getKm().doubleValue(); return String.valueOf(Math.round(v * 1000.0)/1000d); } } // CrossSectionLineItem public CrossSectionApp(String title) { super(title); session = SessionFactoryProvider .createSessionFactory() .openSession(); JPanel content = createContent(); content.setPreferredSize(new Dimension(640, 480)); setContentPane(content); } public List<CrossSection> crossSections(String river) { Query query = session.createQuery( "from CrossSection where river.name = :river"); query.setParameter("river", river); return query.list(); } public JPanel createContent() { JPanel panel = new JPanel(new BorderLayout()); JPanel nav = new JPanel(new FlowLayout()); Object [] csis = createCrossSectionItems(); crossSectionsCB = new JComboBox(csis); DefaultComboBoxModel dcbm; if (csis.length > 0) { Object [] cslis = createCrossSectionLineItems( ((CrossSectionItem)csis[0]).crossSection); dcbm = new DefaultComboBoxModel(cslis); if (cslis.length > 0) { dcbm.setSelectedItem(cslis[0]); } } else { dcbm = new DefaultComboBoxModel(new Object[0]); } crossSectionLinesCB = new JComboBox(dcbm); nav.add(crossSectionsCB); nav.add(crossSectionLinesCB); crossSectionsCB.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ie) { if (ie.getStateChange() == ItemEvent.SELECTED) { updateCrossSection( ((CrossSectionItem)ie.getItem()).crossSection); } } }); crossSectionLinesCB.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ie) { if (ie.getStateChange() == ItemEvent.SELECTED) { updateChart(); } } }); waterlevelTF = new JTextField(5); waterlevelTF.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { waterLevelChanged(); } }); nav.add(waterlevelTF); JButton dump = new JButton("dump"); dump.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { dumpData(); } }); nav.add(dump); panel.add(nav, BorderLayout.SOUTH); chartPanel = createChartPanel(); panel.add(chartPanel, BorderLayout.CENTER); return panel; } protected void waterLevelChanged() { String value = waterlevelTF.getText(); try { lastWaterLevel = Double.parseDouble(value); } catch (NumberFormatException nfe) { waterlevelTF.setText( lastWaterLevel != null ? lastWaterLevel.toString() : ""); return; } updateChart(); } protected void updateChart() { CrossSectionLineItem csli = (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); JFreeChart chart = createChart(csli == null ? new DefaultXYDataset() : generateDataset(csli.line, lastWaterLevel)); chartPanel.setChart(chart); } protected ChartPanel createChartPanel() { CrossSectionLineItem csli = (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); JFreeChart chart = createChart(csli == null ? new DefaultXYDataset() : generateDataset(csli.line, lastWaterLevel)); return new ChartPanel(chart); } protected void dumpData() { CrossSectionLineItem csli = (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); if (csli == null) { return; } CrossSectionLine line = csli.line; double km = Math.round(line.getKm().doubleValue() * 1000d)/1000d; String kmS = String.valueOf(km).replace(".", "-"); int i = 1; File file = new File("cross-section-" + kmS + ".txt"); while (file.exists()) { file = new File("cross-section-" + kmS + "[" + (i++) + "].txt"); } System.err.println("dump points to file '" + file + "'"); List<CrossSectionPoint> points = line.getPoints(); PrintWriter out = null; MathContext mc = new MathContext(3); try { out = new PrintWriter( new FileWriter(file)); for (CrossSectionPoint point: points) { out.println( point.getX().round(mc) + " " + point.getY().round(mc)); } out.flush(); } catch (IOException ioe) { ioe.printStackTrace(); } finally { if (out != null) { out.close(); } } } protected XYDataset generateDataset( CrossSectionLine line, Double waterlevel ) { DefaultXYDataset dataset = new DefaultXYDataset(); List<CrossSectionPoint> ps = line.getPoints(); if (ps.isEmpty()) { return dataset; } Collections.sort(ps, COL_POS_CMP); List<Point2D> points = new ArrayList<Point2D>(ps.size()); for (CrossSectionPoint p: ps) { double x = p.getX().doubleValue(); double y = p.getY().doubleValue(); if (isValid(x) && isValid(y)) { points.add(new Point2D.Double(x, y)); } } if (points.isEmpty()) { return dataset; } double [] xs = new double[points.size()]; double [] ys = new double[xs.length]; xs[0] = points.get(0).getX(); ys[0] = points.get(0).getY(); for (int i = 1; i < xs.length; ++i) { Point2D p = points.get(i); double x = p.getX(); double y = p.getY(); if (x <= xs[i-1]) { x = xs[i-1] + EPSILON; } xs[i] = x; ys[i] = y; } if (waterlevel != null) { double [][] data = createWaterLines(points, waterlevel); dataset.addSeries(String.valueOf(waterlevel), data); } CrossSection cs = line.getCrossSection(); String legend = (cs != null ? cs.getDescription() : "???") + " " + Math.round(line.getKm().doubleValue() * 1000d)/1000d; dataset.addSeries(legend, new double [][] { xs, ys }); return dataset; } protected static double [][] createWaterLines( List<Point2D> points, double waterlevel ) { List<Line2D> lines = Lines.fillWater(points, waterlevel); TDoubleArrayList lxs = new TDoubleArrayList(); TDoubleArrayList lys = new TDoubleArrayList(); for (Iterator<Line2D> iter = lines.iterator(); iter.hasNext();) { Line2D l = iter.next(); Point2D p1 = l.getP1(); Point2D p2 = l.getP2(); lxs.add(p1.getX()); lys.add(p1.getY()); lxs.add(p2.getX()); lys.add(p2.getY()); if (iter.hasNext()) { lxs.add(Double.NaN); lys.add(Double.NaN); } } return new double [][] { lxs.toNativeArray(), lys.toNativeArray() }; } protected void updateCrossSection(CrossSection crossSection) { Object [] cslis = createCrossSectionLineItems(crossSection); DefaultComboBoxModel dcbm = new DefaultComboBoxModel(cslis); if (cslis.length > 0) { dcbm.setSelectedItem(cslis[0]); } crossSectionLinesCB.setModel(dcbm); if (cslis.length > 0) { CrossSectionLine line = ((CrossSectionLineItem)cslis[0]).line; } updateChart(); } protected Object [] createCrossSectionLineItems(CrossSection cs) { List<CrossSectionLine> lines = cs.getLines(); Object [] result = new Object[lines.size()]; for (int i = 0; i < result.length; ++i) { result[i] = new CrossSectionLineItem(lines.get(i)); } return result; } protected Object [] createCrossSectionItems() { List<CrossSection> crossSections = crossSections(RIVER); Object [] result = new Object[crossSections.size()]; for (int i = 0; i < result.length; ++i) { result[i] = new CrossSectionItem(crossSections.get(i)); } return result; } public static JFreeChart createChart(XYDataset dataset) { JFreeChart chart = ChartFactory.createXYLineChart( null, "Abstand [m]", "H\u00f6he [m]", dataset, PlotOrientation.VERTICAL, true, true, false); XYPlot plot = chart.getXYPlot(); NumberAxis yAxis = (NumberAxis)plot.getRangeAxis(); yAxis.setAutoRangeIncludesZero(false); ChartUtilities.applyCurrentTheme(chart); return chart; } public static void main(String [] args) { CrossSectionApp csa = new CrossSectionApp("Querprofile"); csa.pack(); RefineryUtilities.centerFrameOnScreen(csa); csa.setVisible(true); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :