sascha@936: package de.intevation.flys.artifacts.charts; sascha@936: sascha@1817: import de.intevation.flys.backend.SessionFactoryProvider; sascha@936: sascha@1817: import de.intevation.flys.geom.Lines; sascha@936: sascha@936: import de.intevation.flys.model.CrossSection; sascha@936: import de.intevation.flys.model.CrossSectionLine; sascha@936: import de.intevation.flys.model.CrossSectionPoint; sascha@936: sascha@1817: import de.intevation.flys.utils.Pair; sascha@938: sascha@1817: import java.awt.BorderLayout; sascha@1817: import java.awt.Dimension; sascha@1817: import java.awt.FlowLayout; sascha@936: sascha@1817: import java.awt.event.ActionEvent; sascha@1817: import java.awt.event.ActionListener; sascha@1817: import java.awt.event.ItemEvent; sascha@1817: import java.awt.event.ItemListener; sascha@1817: sascha@1817: import java.awt.geom.Point2D; sascha@1817: sascha@1817: import java.io.File; sascha@1817: import java.io.FileWriter; sascha@1817: import java.io.IOException; sascha@1817: import java.io.PrintWriter; sascha@1817: sascha@1817: import java.math.MathContext; sascha@1817: sascha@1817: import java.util.ArrayList; sascha@1817: import java.util.Arrays; sascha@1817: import java.util.List; sascha@1817: import java.util.Map; sascha@1817: import java.util.TreeMap; sascha@1817: sascha@1817: import javax.swing.DefaultComboBoxModel; sascha@1817: import javax.swing.JButton; sascha@1817: import javax.swing.JComboBox; sascha@1817: import javax.swing.JPanel; sascha@1817: import javax.swing.JScrollPane; sascha@1817: import javax.swing.JTable; sascha@1817: import javax.swing.JTextField; sascha@1817: sascha@1817: import javax.swing.event.TableModelEvent; sascha@1817: import javax.swing.event.TableModelListener; sascha@1817: sascha@1817: import javax.swing.table.AbstractTableModel; sascha@1817: sascha@1817: import org.hibernate.Query; sascha@936: import org.hibernate.Session; sascha@1817: sascha@1817: import org.jfree.chart.ChartFactory; sascha@1817: import org.jfree.chart.ChartPanel; sascha@1817: import org.jfree.chart.ChartUtilities; sascha@1817: import org.jfree.chart.JFreeChart; sascha@1817: sascha@1817: import org.jfree.chart.axis.NumberAxis; sascha@1817: sascha@1817: import org.jfree.chart.plot.PlotOrientation; sascha@1817: import org.jfree.chart.plot.XYPlot; sascha@1817: sascha@1817: import org.jfree.data.xy.XYSeries; sascha@1817: import org.jfree.data.xy.XYSeriesCollection; sascha@1817: sascha@1817: import org.jfree.ui.ApplicationFrame; sascha@1817: import org.jfree.ui.RefineryUtilities; sascha@936: sascha@936: public class CrossSectionApp sascha@936: extends ApplicationFrame sascha@936: { felix@1122: public static final String RIVER = System.getProperty("river", "Saar"); sascha@936: sascha@936: public static final double EPSILON = 1e-4; sascha@936: sascha@936: protected Session session; sascha@936: sascha@936: protected JComboBox crossSectionLinesCB; sascha@938: protected JTextField waterlevelTF; sascha@936: sascha@936: protected ChartPanel chartPanel; sascha@936: sascha@938: protected Double lastWaterLevel; sascha@938: sascha@1817: protected List crossSections; sascha@1817: protected boolean [] drawCrossSection; sascha@1817: protected boolean [] drawWaterLevel; sascha@1817: protected boolean [] drawGround; sascha@936: sascha@1817: protected Map>> km2lines; sascha@936: sascha@1817: public class CrossSectionTableModel extends AbstractTableModel { sascha@1817: sascha@1817: @Override sascha@1817: public String getColumnName(int col) { sascha@1817: switch (col) { sascha@1817: case 0: return "Peilungsname"; sascha@1817: case 1: return "Peilung"; sascha@1817: case 2: return "Wasserstand"; sascha@1817: case 3: return "Boden"; sascha@1817: } sascha@1817: return ""; sascha@1817: } sascha@1817: sascha@1817: @Override sascha@1817: public int getColumnCount() { sascha@1817: return 4; sascha@1817: } sascha@1817: sascha@1817: @Override sascha@1817: public int getRowCount() { sascha@1817: return crossSections != null ? crossSections.size() : 0; sascha@1817: } sascha@1817: sascha@1817: @Override sascha@1817: public Object getValueAt(int row, int col) { sascha@1817: if (crossSections == null) return null; sascha@1817: switch (col) { sascha@1817: case 0: return crossSections.get(row).getDescription(); sascha@1817: case 1: return drawCrossSection[row]; sascha@1817: case 2: return drawWaterLevel[row]; sascha@1817: case 3: return drawGround[row]; sascha@1817: } sascha@1817: return null; sascha@1817: } sascha@1817: sascha@1817: @Override sascha@1817: public void setValueAt(Object value, int row, int col) { sascha@1817: switch (col) { sascha@1817: case 1: sascha@1817: if (change(drawCrossSection, row, (Boolean)value)) { sascha@1817: fireTableCellUpdated(row, col); sascha@1817: } sascha@1817: break; sascha@1817: case 2: sascha@1817: if (change(drawWaterLevel, row, (Boolean)value)) { sascha@1817: fireTableCellUpdated(row, col); sascha@1817: } sascha@1817: break; sascha@1817: case 3: sascha@1817: if (change(drawGround, row, (Boolean)value)) { sascha@1817: fireTableCellUpdated(row, col); sascha@1817: } sascha@1817: break; sascha@1817: } sascha@1817: } sascha@1817: sascha@1817: @Override sascha@1817: public Class getColumnClass(int columnIndex) { sascha@1817: switch (columnIndex) { sascha@1817: case 0: return String.class; sascha@1817: case 1: return Boolean.class; sascha@1817: case 2: return Boolean.class; sascha@1817: case 3: return Boolean.class; sascha@1817: } sascha@1817: return null; sascha@1817: } sascha@1817: sascha@1817: @Override sascha@1817: public boolean isCellEditable( sascha@1817: int rowIndex, sascha@1817: int columnIndex sascha@1817: ) { sascha@1817: return columnIndex >= 1 && columnIndex <= 3; sascha@1817: } sascha@1817: } // class CrossSectionTableModel sascha@1817: sascha@1817: private static boolean change( sascha@1817: boolean [] values, sascha@1817: int index, sascha@1817: boolean value sascha@1817: ) { sascha@1817: if (values[index] != value) { sascha@1817: values[index] = value; sascha@1817: return true; sascha@1817: } sascha@1817: return false; sascha@1817: } sascha@1817: sascha@1817: public static class CrossSectionLineItem { sascha@1817: sascha@1817: Double km; sascha@1817: List> lines; sascha@1817: sascha@1817: public CrossSectionLineItem( sascha@1817: Double km, sascha@1817: List> lines sascha@1817: ) { sascha@1817: this.km = km; sascha@1817: this.lines = lines; sascha@936: } sascha@936: sascha@936: public String toString() { sascha@1817: return String.valueOf(km); sascha@936: } sascha@936: } // CrossSectionLineItem sascha@936: sascha@936: public CrossSectionApp(String title) { sascha@936: super(title); sascha@936: sascha@936: session = SessionFactoryProvider sascha@936: .createSessionFactory() sascha@936: .openSession(); sascha@936: sascha@936: JPanel content = createContent(); sascha@1817: content.setPreferredSize(new Dimension(800, 480)); sascha@936: setContentPane(content); sascha@936: sascha@936: } sascha@936: sascha@936: public List crossSections(String river) { sascha@936: Query query = session.createQuery( sascha@936: "from CrossSection where river.name = :river"); sascha@936: query.setParameter("river", river); sascha@936: return query.list(); sascha@936: } sascha@936: sascha@1817: protected Map>> loadAllLines( sascha@1817: List crossSections sascha@1817: ) { sascha@1817: Map>> km2lines = sascha@1817: new TreeMap>>(); sascha@1817: for (CrossSection cs: crossSections) { sascha@1817: List lines = cs.getLines(); sascha@1817: for (CrossSectionLine csl: lines) { sascha@1817: Double km = Math.round(csl.getKm().doubleValue() * 1000d)/1000d; sascha@1817: List> ls = km2lines.get(km); sascha@1817: if (ls == null) { sascha@1817: ls = new ArrayList>(2); sascha@1817: km2lines.put(km, ls); sascha@1817: } sascha@1817: ls.add(new Pair(cs, csl)); sascha@1817: } sascha@1817: } sascha@1817: return km2lines; sascha@1817: } sascha@1817: sascha@936: public JPanel createContent() { sascha@936: JPanel panel = new JPanel(new BorderLayout()); sascha@936: sascha@936: sascha@936: JPanel nav = new JPanel(new FlowLayout()); sascha@936: sascha@1817: crossSections = crossSections(RIVER); sascha@1817: km2lines = loadAllLines(crossSections); sascha@1817: drawCrossSection = new boolean[crossSections.size()]; sascha@1817: Arrays.fill(drawCrossSection, true); sascha@936: sascha@1817: drawWaterLevel = new boolean[crossSections.size()]; sascha@1817: drawGround = new boolean[crossSections.size()]; sascha@1817: sascha@1817: Object [] clis = createCrossSectionLineItems(km2lines); sascha@1817: sascha@1817: DefaultComboBoxModel dcbm = new DefaultComboBoxModel(clis); sascha@936: sascha@936: crossSectionLinesCB = new JComboBox(dcbm); sascha@936: sascha@936: nav.add(crossSectionLinesCB); sascha@936: sascha@936: crossSectionLinesCB.addItemListener(new ItemListener() { sascha@1817: @Override sascha@936: public void itemStateChanged(ItemEvent ie) { sascha@936: if (ie.getStateChange() == ItemEvent.SELECTED) { sascha@938: updateChart(); sascha@936: } sascha@936: } sascha@936: }); sascha@936: sascha@938: waterlevelTF = new JTextField(5); sascha@936: sascha@938: waterlevelTF.addActionListener(new ActionListener() { sascha@1817: @Override sascha@938: public void actionPerformed(ActionEvent ae) { sascha@938: waterLevelChanged(); sascha@938: } sascha@938: }); sascha@938: sascha@938: nav.add(waterlevelTF); sascha@936: sascha@936: JButton dump = new JButton("dump"); sascha@936: sascha@936: dump.addActionListener(new ActionListener() { sascha@1817: @Override sascha@936: public void actionPerformed(ActionEvent ae) { sascha@936: dumpData(); sascha@936: } sascha@936: }); sascha@936: sascha@936: nav.add(dump); sascha@936: sascha@938: sascha@938: chartPanel = createChartPanel(); sascha@938: sascha@938: panel.add(chartPanel, BorderLayout.CENTER); sascha@938: sascha@1817: sascha@1817: CrossSectionTableModel cstm = new CrossSectionTableModel(); sascha@1817: sascha@1817: cstm.addTableModelListener(new TableModelListener() { sascha@1817: @Override sascha@1817: public void tableChanged(TableModelEvent e) { sascha@1817: updateChart(); sascha@1817: } sascha@1817: }); sascha@1817: sascha@1817: JTable crossTable = new JTable(cstm); sascha@1817: sascha@1817: JPanel west = new JPanel(new BorderLayout()); sascha@1817: JScrollPane scrollPane = new JScrollPane(crossTable); sascha@1817: west.add(scrollPane); sascha@1817: sascha@1817: west.add(nav, BorderLayout.SOUTH); sascha@1817: sascha@1817: panel.add(west, BorderLayout.WEST); sascha@1817: sascha@936: return panel; sascha@936: } sascha@936: sascha@938: protected void waterLevelChanged() { sascha@938: String value = waterlevelTF.getText(); sascha@938: try { sascha@938: lastWaterLevel = Double.parseDouble(value); sascha@938: } sascha@938: catch (NumberFormatException nfe) { sascha@938: waterlevelTF.setText( sascha@938: lastWaterLevel != null ? lastWaterLevel.toString() : ""); sascha@938: return; sascha@938: } sascha@938: updateChart(); sascha@938: } sascha@938: sascha@938: protected void updateChart() { sascha@938: sascha@938: CrossSectionLineItem csli = sascha@938: (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); sascha@938: sascha@938: JFreeChart chart = createChart(csli == null sascha@1817: ? new XYSeriesCollection() sascha@1817: : generateDataset()); sascha@938: sascha@938: chartPanel.setChart(chart); sascha@938: } sascha@938: sascha@936: protected ChartPanel createChartPanel() { sascha@936: CrossSectionLineItem csli = sascha@936: (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); sascha@936: sascha@938: JFreeChart chart = createChart(csli == null sascha@1817: ? new XYSeriesCollection() sascha@1817: : generateDataset()); sascha@936: sascha@936: return new ChartPanel(chart); sascha@936: } sascha@936: sascha@936: protected void dumpData() { sascha@936: sascha@936: CrossSectionLineItem csli = sascha@936: (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); sascha@936: sascha@936: if (csli == null) { sascha@936: return; sascha@936: } sascha@936: sascha@936: sascha@1820: double km = Math.round(csli.km.doubleValue() * 1000d)/1000d; sascha@936: sascha@936: String kmS = String.valueOf(km).replace(".", "-"); sascha@936: sascha@936: int i = 1; sascha@936: File file = new File("cross-section-" + kmS + ".txt"); sascha@936: while (file.exists()) { sascha@936: file = new File("cross-section-" + kmS + "[" + (i++) + "].txt"); sascha@936: } sascha@936: sascha@936: System.err.println("dump points to file '" + file + "'"); sascha@936: sascha@936: PrintWriter out = null; sascha@936: sascha@936: MathContext mc = new MathContext(3); sascha@936: sascha@936: try { sascha@936: out = sascha@936: new PrintWriter( sascha@936: new FileWriter(file)); sascha@936: sascha@1820: for (Pair pair: csli.lines) { sascha@1820: out.println("# " + pair.getA().getDescription()); sascha@1820: for (CrossSectionPoint point: pair.getB().getPoints()) { sascha@1820: out.println( sascha@1820: point.getX().round(mc) + " " + sascha@1820: point.getY().round(mc)); sascha@1820: } sascha@936: } sascha@936: sascha@936: out.flush(); sascha@936: } sascha@936: catch (IOException ioe) { sascha@936: ioe.printStackTrace(); sascha@936: } sascha@936: finally { sascha@936: if (out != null) { sascha@936: out.close(); sascha@936: } sascha@936: } sascha@936: } sascha@936: sascha@1817: public void generateWaterLevels( sascha@1817: List points, sascha@1817: XYSeriesCollection collection sascha@938: ) { sascha@1817: if (points == null || points.isEmpty()) { sascha@1817: return; sascha@936: } sascha@936: sascha@1817: if (lastWaterLevel != null) { sascha@1817: double [][] data = Lines.createWaterLines(points, lastWaterLevel); sascha@1817: XYSeries series = sascha@1817: new XYSeries(String.valueOf(lastWaterLevel), false); sascha@1817: sascha@1817: double [] x = data[0]; sascha@1817: double [] y = data[1]; sascha@1817: for (int i = 0; i < x.length; ++i) { sascha@1817: series.add(x[i], y[i], false); sascha@1817: } sascha@1817: sascha@1817: collection.addSeries(series); sascha@938: } sascha@1817: } sascha@938: sascha@1817: public void generateProfile( sascha@1817: List points, sascha@1817: String legend, sascha@1817: XYSeriesCollection collection sascha@1817: ) { sascha@1817: if (points == null || points.isEmpty()) { sascha@1817: return; sascha@1817: } sascha@936: sascha@1651: double [][] values = CrossSectionLine.fetchCrossSectionProfile(points); sascha@1651: sascha@1817: XYSeries series = new XYSeries(legend, false); sascha@936: sascha@1817: double [] x = values[0]; sascha@1817: double [] y = values[1]; sascha@1817: for (int i = 0; i < x.length; ++i) { sascha@1817: series.add(x[i], y[i], false); sascha@1817: } sascha@1817: sascha@1817: collection.addSeries(series); sascha@936: } sascha@936: sascha@1817: public XYSeriesCollection generateDataset() { sascha@1817: XYSeriesCollection collection = new XYSeriesCollection(); sascha@1817: sascha@1817: CrossSectionLineItem csli = sascha@1817: (CrossSectionLineItem)crossSectionLinesCB.getSelectedItem(); sascha@1817: sascha@1817: for (int i = 0; i < drawCrossSection.length; ++i) { sascha@1817: List points = null; sascha@1817: sascha@1817: if (drawCrossSection[i]) { sascha@1817: CrossSection cs = crossSections.get(i); sascha@1817: for (Pair csl: csli.lines) { sascha@1817: if (csl.getA() == cs) { sascha@1817: points = csl.getB().fetchCrossSectionLinesPoints(); sascha@1817: generateProfile( sascha@1817: points, sascha@1817: cs.getDescription(), sascha@1817: collection); sascha@1817: break; sascha@1817: } sascha@1817: } sascha@1817: } sascha@1817: sascha@1817: if (drawWaterLevel[i]) { sascha@1817: CrossSection cs = crossSections.get(i); sascha@1817: for (Pair csl: csli.lines) { sascha@1817: if (csl.getA() == cs) { sascha@1817: if (points != null) { sascha@1817: points = csl.getB().fetchCrossSectionLinesPoints(); sascha@1817: } sascha@1817: generateWaterLevels( sascha@1817: points, sascha@1817: collection); sascha@1817: break; sascha@1817: } sascha@1817: } sascha@1817: } sascha@1817: sascha@936: } sascha@1817: sascha@1817: return collection; sascha@936: } sascha@936: sascha@1817: protected Object [] createCrossSectionLineItems( sascha@1817: Map>> km2lines sascha@1817: ) { sascha@1817: Object [] result = new Object[km2lines.size()]; sascha@1817: int i = 0; sascha@1817: for (Map.Entry>> entry: sascha@1817: km2lines.entrySet()) { sascha@1817: result[i++] = new CrossSectionLineItem( sascha@1817: entry.getKey(), sascha@1817: entry.getValue()); sascha@936: } sascha@936: return result; sascha@936: } sascha@936: sascha@936: sascha@1817: public static JFreeChart createChart(XYSeriesCollection collection) { sascha@936: JFreeChart chart = ChartFactory.createXYLineChart( sascha@936: null, sascha@936: "Abstand [m]", sascha@936: "H\u00f6he [m]", sascha@1817: collection, sascha@936: PlotOrientation.VERTICAL, sascha@936: true, sascha@936: true, sascha@936: false); sascha@938: sascha@938: XYPlot plot = chart.getXYPlot(); sascha@938: NumberAxis yAxis = (NumberAxis)plot.getRangeAxis(); sascha@938: yAxis.setAutoRangeIncludesZero(false); sascha@938: sascha@936: ChartUtilities.applyCurrentTheme(chart); sascha@936: return chart; sascha@936: } sascha@936: sascha@936: public static void main(String [] args) { sascha@936: CrossSectionApp csa = new CrossSectionApp("Querprofile"); sascha@936: csa.pack(); sascha@936: RefineryUtilities.centerFrameOnScreen(csa); sascha@936: csa.setVisible(true); sascha@936: } sascha@936: } sascha@936: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :