sascha@936: package de.intevation.flys.artifacts.charts; sascha@936: sascha@936: import java.math.MathContext; sascha@936: sascha@936: import java.awt.Dimension; sascha@936: import java.awt.BorderLayout; sascha@936: import java.awt.FlowLayout; sascha@936: sascha@936: import javax.swing.JPanel; sascha@936: import javax.swing.JButton; sascha@936: import javax.swing.JComboBox; sascha@938: import javax.swing.JTextField; sascha@936: import javax.swing.DefaultComboBoxModel; sascha@936: sascha@936: import java.awt.event.ItemListener; sascha@936: import java.awt.event.ItemEvent; sascha@936: import java.awt.event.ActionListener; sascha@936: import java.awt.event.ActionEvent; sascha@936: sascha@938: import java.awt.geom.Point2D; sascha@938: import java.awt.geom.Line2D; sascha@938: sascha@936: import java.util.ArrayList; sascha@936: import java.util.List; sascha@936: import java.util.Comparator; sascha@936: import java.util.Collections; sascha@938: import java.util.Iterator; sascha@936: sascha@936: import java.io.File; sascha@936: import java.io.IOException; sascha@936: import java.io.FileWriter; sascha@936: import java.io.PrintWriter; sascha@936: sascha@936: import org.jfree.ui.ApplicationFrame; sascha@936: import org.jfree.ui.RefineryUtilities; sascha@936: sascha@936: import org.jfree.chart.ChartFactory; sascha@936: sascha@936: import org.jfree.chart.plot.PlotOrientation; sascha@938: import org.jfree.chart.plot.XYPlot; sascha@936: sascha@936: import org.jfree.chart.ChartUtilities; sascha@936: import org.jfree.chart.JFreeChart; sascha@936: import org.jfree.chart.ChartPanel; sascha@936: sascha@938: import org.jfree.chart.axis.NumberAxis; sascha@938: sascha@936: import org.jfree.data.xy.XYDataset; sascha@936: import org.jfree.data.xy.DefaultXYDataset; 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@938: import de.intevation.flys.geom.Lines; sascha@938: sascha@936: import de.intevation.flys.backend.SessionFactoryProvider; sascha@936: sascha@936: import org.hibernate.Session; sascha@936: import org.hibernate.Query; sascha@936: sascha@938: import gnu.trove.TDoubleArrayList; 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: public static final double TOO_SMALL = 0.2; sascha@938: public static final double TOO_BIG = 500; sascha@936: sascha@936: public static final Comparator COL_POS_CMP = sascha@936: new Comparator() { sascha@936: @Override sascha@936: public int compare(CrossSectionPoint a, CrossSectionPoint b) { felix@1122: // TODO evaluate: isnt it enough to felix@1122: // return (|d| > |EPS|) ? d : diff sascha@936: double xa = a.getX().doubleValue(); sascha@936: double xb = b.getX().doubleValue(); sascha@936: double d = xa - xb; sascha@936: if (d < -EPSILON) return -1; sascha@936: if (d > +EPSILON) return +1; sascha@936: int diff = a.getColPos() - b.getColPos(); sascha@936: return diff < 0 ? -1 : diff > 0 ? +1 : 0; sascha@936: } sascha@936: }; sascha@936: sascha@936: public static final boolean isValid(double x) { sascha@936: x = Math.abs(x); sascha@936: return x > TOO_SMALL && x < TOO_BIG; sascha@936: } sascha@936: sascha@936: protected Session session; sascha@936: sascha@936: protected JComboBox crossSectionsCB; 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@936: sascha@936: public static class CrossSectionItem { sascha@936: sascha@936: CrossSection crossSection; sascha@936: sascha@936: public CrossSectionItem(CrossSection crossSection) { sascha@936: this.crossSection = crossSection; sascha@936: } sascha@936: sascha@936: public String toString() { sascha@936: return crossSection.getDescription(); sascha@936: } sascha@936: } // CrossSectionItem sascha@936: sascha@936: public static class CrossSectionLineItem { sascha@936: sascha@936: CrossSectionLine line; sascha@936: sascha@936: public CrossSectionLineItem(CrossSectionLine line) { sascha@936: this.line = line; sascha@936: } sascha@936: sascha@936: public String toString() { sascha@936: double v = line.getKm().doubleValue(); sascha@936: return String.valueOf(Math.round(v * 1000.0)/1000d); 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@936: content.setPreferredSize(new Dimension(640, 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@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@936: Object [] csis = createCrossSectionItems(); sascha@936: crossSectionsCB = new JComboBox(csis); sascha@936: sascha@936: DefaultComboBoxModel dcbm; sascha@936: sascha@936: if (csis.length > 0) { sascha@936: Object [] cslis = sascha@936: createCrossSectionLineItems( sascha@936: ((CrossSectionItem)csis[0]).crossSection); sascha@936: dcbm = new DefaultComboBoxModel(cslis); sascha@936: if (cslis.length > 0) { sascha@936: dcbm.setSelectedItem(cslis[0]); sascha@936: } sascha@936: } sascha@936: else { sascha@936: dcbm = new DefaultComboBoxModel(new Object[0]); sascha@936: } sascha@936: sascha@936: crossSectionLinesCB = new JComboBox(dcbm); sascha@936: sascha@936: nav.add(crossSectionsCB); sascha@936: nav.add(crossSectionLinesCB); sascha@936: sascha@936: crossSectionsCB.addItemListener(new ItemListener() { sascha@936: public void itemStateChanged(ItemEvent ie) { sascha@936: if (ie.getStateChange() == ItemEvent.SELECTED) { sascha@936: updateCrossSection( sascha@936: ((CrossSectionItem)ie.getItem()).crossSection); sascha@936: } sascha@936: } sascha@936: }); sascha@936: sascha@936: crossSectionLinesCB.addItemListener(new ItemListener() { 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@936: sascha@938: waterlevelTF = new JTextField(5); sascha@936: sascha@938: waterlevelTF.addActionListener(new ActionListener() { 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@936: public void actionPerformed(ActionEvent ae) { sascha@936: dumpData(); sascha@936: } sascha@936: }); sascha@936: sascha@936: nav.add(dump); sascha@936: sascha@938: panel.add(nav, BorderLayout.SOUTH); sascha@938: sascha@938: chartPanel = createChartPanel(); sascha@938: sascha@938: panel.add(chartPanel, BorderLayout.CENTER); sascha@938: 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@938: ? new DefaultXYDataset() sascha@938: : generateDataset(csli.line, lastWaterLevel)); 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@938: ? new DefaultXYDataset() sascha@938: : generateDataset(csli.line, lastWaterLevel)); 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: CrossSectionLine line = csli.line; sascha@936: sascha@936: double km = Math.round(line.getKm().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: List points = line.getPoints(); 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@936: for (CrossSectionPoint point: points) { sascha@936: out.println( sascha@936: point.getX().round(mc) + " " + sascha@936: point.getY().round(mc)); 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: felix@1122: public static XYDataset generateDataset( sascha@938: CrossSectionLine line, sascha@938: Double waterlevel sascha@938: ) { sascha@936: DefaultXYDataset dataset = new DefaultXYDataset(); sascha@936: sascha@936: List ps = line.getPoints(); sascha@936: sascha@938: if (ps.isEmpty()) { sascha@938: return dataset; sascha@938: } sascha@938: sascha@938: Collections.sort(ps, COL_POS_CMP); sascha@938: sascha@938: List points = new ArrayList(ps.size()); sascha@936: sascha@936: for (CrossSectionPoint p: ps) { sascha@938: double x = p.getX().doubleValue(); sascha@938: double y = p.getY().doubleValue(); sascha@938: if (isValid(x) && isValid(y)) { sascha@938: points.add(new Point2D.Double(x, y)); sascha@936: } sascha@936: } sascha@936: sascha@936: if (points.isEmpty()) { sascha@936: return dataset; sascha@936: } sascha@936: sascha@936: double [] xs = new double[points.size()]; sascha@936: double [] ys = new double[xs.length]; sascha@936: sascha@938: xs[0] = points.get(0).getX(); sascha@938: ys[0] = points.get(0).getY(); sascha@936: sascha@936: for (int i = 1; i < xs.length; ++i) { sascha@938: Point2D p = points.get(i); sascha@938: double x = p.getX(); sascha@938: double y = p.getY(); sascha@936: sascha@936: if (x <= xs[i-1]) { sascha@936: x = xs[i-1] + EPSILON; sascha@936: } sascha@936: xs[i] = x; sascha@936: ys[i] = y; sascha@936: } sascha@936: sascha@938: if (waterlevel != null) { sascha@938: double [][] data = createWaterLines(points, waterlevel); sascha@938: dataset.addSeries(String.valueOf(waterlevel), data); sascha@938: } sascha@938: sascha@936: CrossSection cs = line.getCrossSection(); sascha@936: sascha@936: String legend = (cs != null ? cs.getDescription() : "???") sascha@936: + " " + Math.round(line.getKm().doubleValue() * 1000d)/1000d; sascha@936: sascha@936: dataset.addSeries(legend, new double [][] { xs, ys }); sascha@936: sascha@936: return dataset; sascha@936: } sascha@936: felix@1122: public static double [][] createWaterLines( sascha@938: List points, sascha@938: double waterlevel sascha@938: ) { sascha@938: List lines = Lines.fillWater(points, waterlevel); sascha@938: sascha@938: TDoubleArrayList lxs = new TDoubleArrayList(); sascha@938: TDoubleArrayList lys = new TDoubleArrayList(); sascha@938: sascha@938: for (Iterator iter = lines.iterator(); iter.hasNext();) { sascha@938: Line2D l = iter.next(); sascha@938: Point2D p1 = l.getP1(); sascha@938: Point2D p2 = l.getP2(); sascha@938: lxs.add(p1.getX()); sascha@938: lys.add(p1.getY()); sascha@938: lxs.add(p2.getX()); sascha@938: lys.add(p2.getY()); sascha@938: if (iter.hasNext()) { sascha@938: lxs.add(Double.NaN); sascha@938: lys.add(Double.NaN); sascha@938: } sascha@938: } sascha@938: sascha@938: return new double [][] { lxs.toNativeArray(), lys.toNativeArray() }; sascha@938: } sascha@938: sascha@936: protected void updateCrossSection(CrossSection crossSection) { sascha@936: Object [] cslis = createCrossSectionLineItems(crossSection); sascha@936: DefaultComboBoxModel dcbm = new DefaultComboBoxModel(cslis); sascha@936: if (cslis.length > 0) { sascha@936: dcbm.setSelectedItem(cslis[0]); sascha@936: } sascha@936: crossSectionLinesCB.setModel(dcbm); sascha@936: if (cslis.length > 0) { sascha@936: CrossSectionLine line = sascha@936: ((CrossSectionLineItem)cslis[0]).line; sascha@936: } sascha@938: updateChart(); sascha@936: } sascha@936: sascha@936: protected Object [] createCrossSectionLineItems(CrossSection cs) { sascha@936: List lines = cs.getLines(); sascha@936: Object [] result = new Object[lines.size()]; sascha@936: for (int i = 0; i < result.length; ++i) { sascha@936: result[i] = new CrossSectionLineItem(lines.get(i)); sascha@936: } sascha@936: return result; sascha@936: } sascha@936: sascha@936: sascha@936: protected Object [] createCrossSectionItems() { sascha@936: List crossSections = crossSections(RIVER); sascha@936: Object [] result = new Object[crossSections.size()]; sascha@936: for (int i = 0; i < result.length; ++i) { sascha@936: result[i] = new CrossSectionItem(crossSections.get(i)); sascha@936: } sascha@936: return result; sascha@936: } sascha@936: sascha@936: public static JFreeChart createChart(XYDataset dataset) { sascha@936: JFreeChart chart = ChartFactory.createXYLineChart( sascha@936: null, sascha@936: "Abstand [m]", sascha@936: "H\u00f6he [m]", sascha@936: dataset, 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 :