teichmann@5863: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5863: * Software engineering by Intevation GmbH teichmann@5863: * teichmann@5994: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5863: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5994: * documentation coming with Dive4Elements River for details. teichmann@5863: */ teichmann@5863: teichmann@5831: package org.dive4elements.river.exports; ingo@299: teichmann@5831: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; teichmann@5867: import org.dive4elements.river.artifacts.D4EArtifact; teichmann@5831: import org.dive4elements.river.artifacts.model.FacetTypes; teichmann@5831: import org.dive4elements.river.artifacts.model.WQKms; teichmann@5831: import org.dive4elements.river.jfree.Bounds; teichmann@5864: import org.dive4elements.river.jfree.RiverAnnotation; felix@6453: import org.dive4elements.river.jfree.StickyAxisAnnotation; teichmann@5831: import org.dive4elements.river.jfree.StyledXYSeries; teichmann@5831: import org.dive4elements.river.model.Gauge; teichmann@5831: import org.dive4elements.river.model.River; teichmann@5865: import org.dive4elements.river.utils.RiverUtils; christian@3409: ingo@299: import org.apache.log4j.Logger; felix@6453: import org.jfree.chart.annotations.XYTextAnnotation; ingo@728: import org.jfree.chart.axis.ValueAxis; ingo@375: import org.jfree.chart.plot.XYPlot; ingo@728: import org.jfree.data.Range; ingo@923: import org.jfree.data.xy.XYSeries; christian@3409: import org.w3c.dom.Document; felix@1103: felix@2302: ingo@299: /** ingo@299: * An OutGenerator that generates discharge curves. ingo@299: * ingo@299: * @author Ingo Weinzierl ingo@299: */ felix@1812: public class DischargeCurveGenerator felix@1812: extends XYChartGenerator felix@1812: implements FacetTypes { ingo@299: felix@6882: /** Beware, in this implementation, the W axis is also in cm! */ felix@1933: public static enum YAXIS { felix@6453: WCm(0), felix@6453: W(1); felix@1933: protected int idx; felix@1933: private YAXIS(int c) { felix@1933: idx = c; felix@1933: } felix@1933: } felix@1933: felix@1070: /** The logger used in this generator. */ ingo@299: private static Logger logger = ingo@299: Logger.getLogger(DischargeCurveGenerator.class); ingo@299: ingo@408: public static final String I18N_CHART_TITLE = ingo@408: "chart.discharge.curve.title"; ingo@408: ingo@414: public static final String I18N_CHART_SUBTITLE = ingo@414: "chart.discharge.curve.subtitle"; ingo@414: ingo@408: public static final String I18N_XAXIS_LABEL = ingo@408: "chart.discharge.curve.xaxis.label"; ingo@408: ingo@408: public static final String I18N_YAXIS_LABEL = ingo@408: "chart.discharge.curve.yaxis.label"; ingo@408: ingo@408: public static final String I18N_CHART_TITLE_DEFAULT = "Abflusskurven"; sascha@664: public static final String I18N_XAXIS_LABEL_DEFAULT = "Q [m\u00b3/s]"; ingo@408: public static final String I18N_YAXIS_LABEL_DEFAULT = "W [cm]"; ingo@408: ingo@408: felix@6445: /** felix@6445: * Returns the PNP (Datum) of gauge, if at gauge, 0 otherwise. felix@6445: */ felix@6463: public static double getCurrentGaugeDatum(double km, D4EArtifact artifact, double tolerance) { felix@6739: // Look if there is a gauge at chosen km: felix@6739: // Get gauge which is defined for km felix@6739: Gauge gauge = felix@6739: RiverUtils.getRiver(artifact).determineGauge(km-0.1d, km+0.1d); felix@6445: double subtractPNP = 0d; felix@6739: // Compare to km. felix@6463: if (Math.abs(km - gauge.getStation().doubleValue()) < tolerance) { felix@6445: subtractPNP = gauge.getDatum().doubleValue(); felix@6445: } felix@6445: return subtractPNP; felix@6445: } felix@6445: felix@6453: felix@6882: /** Get the current Gauge datum with default distance tolerance. */ felix@6445: public double getCurrentGaugeDatum() { felix@6463: return getCurrentGaugeDatum(getRange()[0], felix@6463: (D4EArtifact) getMaster(), 1e-4); felix@6445: } felix@6445: felix@6445: felix@6559: /** Overriden to show second axis also if no visible data present. */ felix@6559: @Override felix@6559: protected void adjustAxes(XYPlot plot) { felix@6559: super.adjustAxes(plot); felix@6559: if (getCurrentGaugeDatum() != 0d) { felix@6559: // Show the W[*m] axis even if there is no data. felix@6559: plot.setRangeAxis(1, createYAxis(YAXIS.W.idx)); felix@6559: } felix@6559: } felix@6559: felix@6559: ingo@299: public DischargeCurveGenerator() { ingo@348: super(); ingo@299: } ingo@299: ingo@299: ingo@2000: @Override ingo@2000: protected YAxisWalker getYAxisWalker() { ingo@2000: return new YAxisWalker() { ingo@2000: @Override ingo@2000: public int length() { ingo@2000: return YAXIS.values().length; ingo@2000: } ingo@2000: ingo@2000: @Override ingo@2000: public String getId(int idx) { ingo@2000: YAXIS[] yaxes = YAXIS.values(); ingo@2000: return yaxes[idx].toString(); ingo@2000: } ingo@2000: }; ingo@2000: } ingo@2000: ingo@2000: christian@3409: /** christian@3409: * Returns always null to suppress subtitles. christian@3409: */ ingo@2048: @Override ingo@2048: protected String getDefaultChartTitle() { christian@3409: return null; ingo@414: } ingo@414: ingo@414: ingo@2051: @Override ingo@2051: protected String getDefaultXAxisLabel() { ingo@408: return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); ingo@369: } ingo@369: ingo@2051: @Override ingo@2051: protected String getDefaultYAxisLabel(int pos) { ingo@408: return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); ingo@369: } ingo@369: ingo@369: felix@2302: /* TODO is this one really needed? */ ingo@728: @Override ingo@2587: protected boolean zoomX(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) { ingo@2587: boolean zoomin = super.zoom(plot, axis, bounds, x); ingo@728: ingo@728: if (!zoomin) { ingo@728: axis.setLowerBound(0d); ingo@728: } ingo@728: ingo@728: return zoomin; ingo@728: } ingo@728: felix@6526: /** Translate River annotations if a gauge. */ felix@6453: public void translateRiverAnnotation(RiverAnnotation riverAnnotation) { felix@6453: if (getCurrentGaugeDatum() == 0d) { felix@6453: return; felix@6453: } felix@6453: logger.debug("Translate some river annotation."); felix@6453: double translate = getCurrentGaugeDatum(); felix@6453: double factor = 100d; felix@6453: for (StickyAxisAnnotation annotation: riverAnnotation.getAxisTextAnnotations()){ felix@6453: if (!annotation.atX()) { felix@6453: annotation.setPos((annotation.getPos() - translate)*factor); felix@6453: } felix@6453: } felix@6453: for (XYTextAnnotation annotation: riverAnnotation.getTextAnnotations()) { felix@6453: annotation.setY((annotation.getY() - translate)*factor); felix@6453: } felix@6453: } felix@6453: felix@2302: christian@3409: @Override ingo@1684: public void doOut( felix@1944: ArtifactAndFacet artifactFacet, felix@1944: Document theme, felix@1944: boolean visible ingo@1684: ) { felix@1944: String name = artifactFacet.getFacetName(); felix@1944: logger.debug("DischargeCurveGenerator.doOut: " + name); ingo@299: bjoern@3997: if (name.equals(DISCHARGE_CURVE) bjoern@3997: || name.equals(GAUGE_DISCHARGE_CURVE)) { felix@1812: doDischargeOut( teichmann@5867: (D4EArtifact)artifactFacet.getArtifact(), felix@1944: artifactFacet.getData(context), felix@1944: artifactFacet.getFacetDescription(), felix@1812: theme, felix@1812: visible); felix@1812: } felix@1812: else if (name.equals(COMPUTED_DISCHARGE_MAINVALUES_Q) felix@1848: || name.equals(MAINVALUES_Q) felix@1848: || name.equals(COMPUTED_DISCHARGE_MAINVALUES_W) felix@1812: || name.equals(MAINVALUES_W)) felix@1812: { felix@6453: RiverAnnotation mainValues = (RiverAnnotation) artifactFacet.getData(context); felix@6453: translateRiverAnnotation(mainValues); felix@6453: doAnnotations( felix@6453: mainValues, ingo@2325: artifactFacet, theme, visible); felix@1812: } felix@2302: else if (FacetTypes.IS.MANUALPOINTS(name)) { felix@2302: doPoints(artifactFacet.getData(context), ingo@2325: artifactFacet, felix@2302: theme, visible, YAXIS.W.idx); felix@2302: } felix@6883: else if (STATIC_WQ.equals(name)) { felix@6883: doWQOut(artifactFacet.getData(context), felix@6883: artifactFacet, felix@6883: theme, felix@6883: visible); felix@6883: } felix@1812: else { felix@1812: logger.warn("DischargeCurveGenerator.doOut: Unknown facet name: " + name); felix@1812: return; felix@1812: } felix@1812: } felix@1812: felix@1812: felix@1812: /** felix@1812: * Add series with discharge curve to diagram. felix@1812: */ felix@1812: protected void doDischargeOut( teichmann@5867: D4EArtifact artifact, felix@1944: Object o, felix@1944: String description, felix@1944: Document theme, felix@1944: boolean visible) felix@1812: { felix@6882: logger.debug("DischargeCurveGenerator.doDischargeOut"); felix@1812: WQKms wqkms = (WQKms) o; sascha@721: sascha@721: String gaugeName = wqkms.getName(); sascha@721: teichmann@5865: River river = RiverUtils.getRiver(artifact); sascha@721: sascha@721: if (river == null) { sascha@721: logger.debug("no river found"); sascha@721: return; ingo@299: } ingo@299: sascha@721: Gauge gauge = river.determineGaugeByName(gaugeName); ingo@299: sascha@721: if (gauge == null) { sascha@721: logger.debug("no gauge found"); sascha@721: return; sascha@721: } ingo@454: felix@1812: XYSeries series = new StyledXYSeries(description, theme); ingo@923: felix@1812: StyledSeriesBuilder.addPointsQW(series, wqkms); ingo@923: felix@1933: addAxisSeries(series, YAXIS.W.idx, visible); ingo@299: } felix@6883: felix@6883: /** felix@6883: * Add W/Q-Series to plot. felix@6883: * @param wqkms actual data felix@6883: * @param theme theme to use. felix@6883: */ felix@6883: protected void doQOut( felix@6883: Object wqkms, felix@6883: ArtifactAndFacet aaf, felix@6883: Document theme, felix@6883: boolean visible felix@6883: ) { felix@6883: logger.debug("DischargeCurveGenerator: doQOut (add W/Q data)."); felix@6883: XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); felix@6883: felix@6883: StyledSeriesBuilder.addPointsQW(series, (WQKms) wqkms); felix@6883: felix@6883: addAxisSeries(series, YAXIS.W.idx, visible); felix@6883: } felix@6883: felix@6883: /** felix@6883: * Add WQ Data to plot. felix@6883: * @param wq data as double[][] felix@6883: */ felix@6883: protected void doWQOut( felix@6883: Object wq, felix@6883: ArtifactAndFacet aaf, felix@6883: Document theme, felix@6883: boolean visible felix@6883: ) { felix@6883: logger.debug("DischargeCurveGenerator: doWQOut"); felix@6883: double [][] data = (double [][]) wq; felix@6883: felix@6883: XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); felix@6883: felix@6883: double translate = getCurrentGaugeDatum(); felix@6883: if (translate != 0d) { felix@6883: StyledSeriesBuilder.addPointsQW(series, data, -translate, 100d); felix@6883: addAxisSeries(series, YAXIS.W.idx, visible); felix@6883: } felix@6883: else { felix@6883: StyledSeriesBuilder.addPoints(series, data, true); felix@6883: addAxisSeries(series, YAXIS.W.idx, visible); felix@6883: } felix@6883: } felix@6883: ingo@299: } ingo@299: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :