Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/artifacts/charts/CrossSectionApp.java @ 3807:d73c43798a99 pre2.6-2011-11-04
merged flys-backend/pre2.6-2011-11-04
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:51 +0200 |
parents | d562772a418e |
children | 94871b7ce9e9 |
line wrap: on
line source
package de.intevation.flys.artifacts.charts; import de.intevation.flys.backend.SessionFactoryProvider; import de.intevation.flys.geom.Lines; import de.intevation.flys.model.CrossSection; import de.intevation.flys.model.CrossSectionLine; import de.intevation.flys.model.CrossSectionPoint; import de.intevation.flys.utils.Pair; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.geom.Point2D; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.math.MathContext; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.TreeMap; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.AbstractTableModel; import org.hibernate.Query; import org.hibernate.Session; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.ChartUtilities; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.jfree.ui.ApplicationFrame; import org.jfree.ui.RefineryUtilities; public class CrossSectionApp extends ApplicationFrame { public static final String RIVER = System.getProperty("river", "Saar"); public static final double EPSILON = 1e-4; protected Session session; protected JComboBox crossSectionLinesCB; protected JTextField waterlevelTF; protected ChartPanel chartPanel; protected Double lastWaterLevel; protected List<CrossSection> crossSections; protected boolean [] drawCrossSection; protected boolean [] drawWaterLevel; protected boolean [] drawGround; protected Map<Double, List<Pair<CrossSection, CrossSectionLine>>> km2lines; public class CrossSectionTableModel extends AbstractTableModel { @Override public String getColumnName(int col) { switch (col) { case 0: return "Peilungsname"; case 1: return "Peilung"; case 2: return "Wasserstand"; case 3: return "Boden"; } return ""; } @Override public int getColumnCount() { return 4; } @Override public int getRowCount() { return crossSections != null ? crossSections.size() : 0; } @Override public Object getValueAt(int row, int col) { if (crossSections == null) return null; switch (col) { case 0: return crossSections.get(row).getDescription(); case 1: return drawCrossSection[row]; case 2: return drawWaterLevel[row]; case 3: return drawGround[row]; } return null; } @Override public void setValueAt(Object value, int row, int col) { switch (col) { case 1: if (change(drawCrossSection, row, (Boolean)value)) { fireTableCellUpdated(row, col); } break; case 2: if (change(drawWaterLevel, row, (Boolean)value)) { fireTableCellUpdated(row, col); } break; case 3: if (change(drawGround, row, (Boolean)value)) { fireTableCellUpdated(row, col); } break; } } @Override public Class<?> getColumnClass(int columnIndex) { switch (columnIndex) { case 0: return String.class; case 1: return Boolean.class; case 2: return Boolean.class; case 3: return Boolean.class; } return null; } @Override public boolean isCellEditable( int rowIndex, int columnIndex ) { return columnIndex >= 1 && columnIndex <= 3; } } // class CrossSectionTableModel private static boolean change( boolean [] values, int index, boolean value ) { if (values[index] != value) { values[index] = value; return true; } return false; } public static class CrossSectionLineItem { Double km; List<Pair<CrossSection, CrossSectionLine>> lines; public CrossSectionLineItem( Double km, List<Pair<CrossSection, CrossSectionLine>> lines ) { this.km = km; this.lines = lines; } public String toString() { return String.valueOf(km); } } // CrossSectionLineItem public CrossSectionApp(String title) { super(title); session = SessionFactoryProvider .createSessionFactory() .openSession(); JPanel content = createContent(); content.setPreferredSize(new Dimension(800, 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(); } protected Map<Double, List<Pair<CrossSection, CrossSectionLine>>> loadAllLines( List<CrossSection> crossSections ) { Map<Double, List<Pair<CrossSection, CrossSectionLine>>> km2lines = new TreeMap<Double, List<Pair<CrossSection, CrossSectionLine>>>(); for (CrossSection cs: crossSections) { List<CrossSectionLine> lines = cs.getLines(); for (CrossSectionLine csl: lines) { Double km = Math.round(csl.getKm().doubleValue() * 1000d)/1000d; List<Pair<CrossSection, CrossSectionLine>> ls = km2lines.get(km); if (ls == null) { ls = new ArrayList<Pair<CrossSection, CrossSectionLine>>(2); km2lines.put(km, ls); } ls.add(new Pair<CrossSection, CrossSectionLine>(cs, csl)); } } return km2lines; } public JPanel createContent() { JPanel panel = new JPanel(new BorderLayout()); JPanel nav = new JPanel(new FlowLayout()); crossSections = crossSections(RIVER); km2lines = loadAllLines(crossSections); drawCrossSection = new boolean[crossSections.size()]; Arrays.fill(drawCrossSection, true); drawWaterLevel = new boolean[crossSections.size()]; drawGround = new boolean[crossSections.size()]; Object [] clis = createCrossSectionLineItems(km2lines); DefaultComboBoxModel dcbm = new DefaultComboBoxModel(clis); crossSectionLinesCB = new JComboBox(dcbm); nav.add(crossSectionLinesCB); crossSectionLinesCB.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent ie) { if (ie.getStateChange() == ItemEvent.SELECTED) { updateChart(); } } }); waterlevelTF = new JTextField(5); waterlevelTF.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { waterLevelChanged(); } }); nav.add(waterlevelTF); JButton dump = new JButton("dump"); dump.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { dumpData(); } }); nav.add(dump); chartPanel = createChartPanel(); panel.add(chartPanel, BorderLayout.CENTER); CrossSectionTableModel cstm = new CrossSectionTableModel(); cstm.addTableModelListener(new TableModelListener() { @Override public void tableChanged(TableModelEvent e) { updateChart(); } }); JTable crossTable = new JTable(cstm); JPanel west = new JPanel(new BorderLayout()); JScrollPane scrollPane = new JScrollPane(crossTable); west.add(scrollPane); west.add(nav, BorderLayout.SOUTH); panel.add(west, BorderLayout.WEST); 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 XYSeriesCollection() : generateDataset()); chartPanel.setChart(chart); } protected ChartPanel createChartPanel() { CrossSectionLineItem csli = (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); JFreeChart chart = createChart(csli == null ? new XYSeriesCollection() : generateDataset()); return new ChartPanel(chart); } protected void dumpData() { CrossSectionLineItem csli = (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); if (csli == null) { return; } double km = Math.round(csli.km.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 + "'"); PrintWriter out = null; MathContext mc = new MathContext(3); try { out = new PrintWriter( new FileWriter(file)); for (Pair<CrossSection, CrossSectionLine> pair: csli.lines) { out.println("# " + pair.getA().getDescription()); for (CrossSectionPoint point: pair.getB().getPoints()) { out.println( point.getX().round(mc) + " " + point.getY().round(mc)); } } out.flush(); } catch (IOException ioe) { ioe.printStackTrace(); } finally { if (out != null) { out.close(); } } } public void generateWaterLevels( List<Point2D> points, XYSeriesCollection collection ) { if (points == null || points.isEmpty()) { return; } if (lastWaterLevel != null) { double [][] data = Lines.createWaterLines(points, lastWaterLevel); XYSeries series = new XYSeries(String.valueOf(lastWaterLevel), false); double [] x = data[0]; double [] y = data[1]; for (int i = 0; i < x.length; ++i) { series.add(x[i], y[i], false); } collection.addSeries(series); } } public void generateProfile( List<Point2D> points, String legend, XYSeriesCollection collection ) { if (points == null || points.isEmpty()) { return; } double [][] values = CrossSectionLine.fetchCrossSectionProfile(points); XYSeries series = new XYSeries(legend, false); double [] x = values[0]; double [] y = values[1]; for (int i = 0; i < x.length; ++i) { series.add(x[i], y[i], false); } collection.addSeries(series); } public XYSeriesCollection generateDataset() { XYSeriesCollection collection = new XYSeriesCollection(); CrossSectionLineItem csli = (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); for (int i = 0; i < drawCrossSection.length; ++i) { List<Point2D> points = null; if (drawCrossSection[i]) { CrossSection cs = crossSections.get(i); for (Pair<CrossSection, CrossSectionLine> csl: csli.lines) { if (csl.getA() == cs) { points = csl.getB().fetchCrossSectionLinesPoints(); generateProfile( points, cs.getDescription(), collection); break; } } } if (drawWaterLevel[i]) { CrossSection cs = crossSections.get(i); for (Pair<CrossSection, CrossSectionLine> csl: csli.lines) { if (csl.getA() == cs) { if (points != null) { points = csl.getB().fetchCrossSectionLinesPoints(); } generateWaterLevels( points, collection); break; } } } } return collection; } protected Object [] createCrossSectionLineItems( Map<Double, List<Pair<CrossSection, CrossSectionLine>>> km2lines ) { Object [] result = new Object[km2lines.size()]; int i = 0; for (Map.Entry<Double, List<Pair<CrossSection, CrossSectionLine>>> entry: km2lines.entrySet()) { result[i++] = new CrossSectionLineItem( entry.getKey(), entry.getValue()); } return result; } public static JFreeChart createChart(XYSeriesCollection collection) { JFreeChart chart = ChartFactory.createXYLineChart( null, "Abstand [m]", "H\u00f6he [m]", collection, 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 :