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@1679:
teichmann@5831: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
teichmann@5831: import org.dive4elements.artifactdatabase.state.Facet;
teichmann@5867: import org.dive4elements.river.artifacts.D4EArtifact;
teichmann@5831: import org.dive4elements.river.artifacts.StaticWKmsArtifact;
teichmann@5831: import org.dive4elements.river.artifacts.WINFOArtifact;
teichmann@5831: import org.dive4elements.river.artifacts.model.FacetTypes;
teichmann@5831: import org.dive4elements.river.artifacts.model.WKms;
teichmann@5831: import org.dive4elements.river.artifacts.model.WQKms;
felix@6901: import org.dive4elements.river.exports.process.DischargeProcessor;
teichmann@5864: import org.dive4elements.river.jfree.RiverAnnotation;
teichmann@5831: import org.dive4elements.river.jfree.StickyAxisAnnotation;
teichmann@5831: import org.dive4elements.river.jfree.StyledXYSeries;
felix@1850:
teichmann@6905: import org.dive4elements.river.themes.ThemeDocument;
teichmann@5865: import org.dive4elements.river.utils.RiverUtils;
felix@5420:
felix@6423: import java.awt.Font;
felix@6423:
christian@3409: import java.util.ArrayList;
christian@3409: import java.util.List;
christian@3409:
felix@6423: import org.jfree.chart.axis.NumberAxis;
felix@6423: import org.jfree.data.xy.XYSeries;
felix@6423:
christian@3409: import org.apache.log4j.Logger;
felix@6423:
ingo@392:
ingo@392: /**
felix@6879: * An OutGenerator that generates discharge curves, also at locations
felix@6879: * not at a gauge.
ingo@392: *
ingo@392: * @author Ingo Weinzierl
ingo@392: */
ingo@696: public class ComputedDischargeCurveGenerator
ingo@696: extends DischargeCurveGenerator
ingo@696: implements FacetTypes
ingo@696: {
felix@1081: /** The logger used in this generator. */
ingo@392: private static Logger logger =
ingo@392: Logger.getLogger(ComputedDischargeCurveGenerator.class);
ingo@392:
ingo@408: public static final String I18N_CHART_TITLE =
ingo@408: "chart.computed.discharge.curve.title";
ingo@408:
ingo@414: public static final String I18N_CHART_SUBTITLE =
ingo@414: "chart.computed.discharge.curve.subtitle";
ingo@414:
ingo@408: public static final String I18N_YAXIS_LABEL =
ingo@408: "chart.computed.discharge.curve.yaxis.label";
ingo@408:
ingo@408: public static final String I18N_CHART_TITLE_DEFAULT = "Abflusskurve";
ingo@408: public static final String I18N_YAXIS_LABEL_DEFAULT = "W [NN + m]";
ingo@408:
felix@6424: protected NumberAxis firstYAxis;
felix@1083:
felix@1083: /** Trivial Constructor. */
felix@1083: public ComputedDischargeCurveGenerator () {
felix@1083: super();
felix@1083: }
felix@1083:
ingo@408:
ingo@392: @Override
ingo@2048: protected String getDefaultChartTitle() {
ingo@408: return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
ingo@400: }
ingo@400:
ingo@400:
ingo@400: @Override
ingo@2048: protected String getDefaultChartSubtitle() {
felix@1113: double[] dist = getRange();
ingo@414:
ingo@414: Object[] args = new Object[] {
ingo@414: getRiverName(),
ingo@414: dist[0]
ingo@414: };
ingo@414:
ingo@1989: return msg(I18N_CHART_SUBTITLE, "", args);
ingo@1989: }
ingo@1989:
ingo@1989:
felix@6423:
ingo@1989: @Override
ingo@2051: protected String getDefaultYAxisLabel(int pos) {
teichmann@5867: D4EArtifact flys = (D4EArtifact) master;
felix@5420:
teichmann@5865: String unit = RiverUtils.getRiver(flys).getWstUnit().getName();
felix@6454: if (pos == 0 && getCurrentGaugeDatum() != 0)
felix@6446: unit = "cm";
felix@5420:
felix@5420: return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT, new Object[] { unit });
ingo@400: }
ingo@400:
ingo@400:
felix@2731: /**
felix@6447: * Create Y (range) axis for given index, here with a special axis
felix@6447: * that depends on other axis (does translation and scaling for
felix@6447: * special case at gauge in cm).
felix@6789: * @return A NumberAxis, possibly scaled.
felix@6424: */
felix@6447: @Override
felix@6424: protected NumberAxis createYAxis(int index) {
felix@6424: if (index == 0) {
felix@6424: firstYAxis = super.createYAxis(0);
felix@6424: return firstYAxis;
felix@6424: }
felix@6424: YAxisWalker walker = getYAxisWalker();
felix@6424:
felix@6424: Font labelFont = new Font(
felix@6424: DEFAULT_FONT_NAME,
felix@6424: Font.BOLD,
felix@6424: getYAxisFontSize(index));
felix@6424:
felix@6424: SyncNumberAxis axis = new SyncNumberAxis(
felix@6424: walker.getId(index),
felix@6424: getYAxisLabel(index),
felix@6424: firstYAxis);
felix@6424:
felix@6424: axis.setAutoRangeIncludesZero(false);
felix@6424: axis.setLabelFont(labelFont);
felix@6424: axis.setTickLabelFont(labelFont);
felix@6441: axis.setShift((double)-getCurrentGaugeDatum());
felix@6424:
felix@6424: return axis;
felix@6424: }
felix@6424:
felix@6424:
felix@6424: /**
felix@2731: * Process data, build up plot.
felix@2731: */
ingo@400: @Override
ingo@1684: public void doOut(
felix@1944: ArtifactAndFacet artifactFacet,
teichmann@6905: ThemeDocument attr,
felix@1944: boolean visible
ingo@1684: ) {
felix@1944: String name = artifactFacet.getFacetName();
ingo@393:
ingo@696: logger.debug("ComputedDischargeCurveGenerator.doOut: " + name);
ingo@393:
felix@1085: if (name == null) {
felix@1085: logger.warn("Broken facet in computed discharge out generation.");
felix@1085: return;
felix@1085: }
felix@1085:
felix@6901: DischargeProcessor dProcessor = new DischargeProcessor(getRange()[0]);
felix@6901: if (dProcessor.canHandle(name)) {
felix@6901: dProcessor.doOut(this, artifactFacet, attr, visible, YAXIS.W.idx);
felix@6901: }
felix@6901: else if (name.equals(COMPUTED_DISCHARGE_Q)) {
felix@6429: doDischargeQOut((WQKms) artifactFacet.getData(context), artifactFacet, attr, visible);
ingo@696: }
felix@1901: else if (name.equals(STATIC_WQ)) {
ingo@2605: doWQOut(artifactFacet.getData(context), artifactFacet, attr, visible);
felix@1901: }
felix@1915: else if (name.equals(STATIC_WQ_ANNOTATIONS)) {
ingo@2325: doWQAnnotations(
ingo@2325: artifactFacet.getData(context),
ingo@2325: artifactFacet,
ingo@2325: attr,
ingo@2325: visible);
felix@1915: }
felix@6790: else if (STATIC_WKMS_INTERPOL.equals(name) ||
felix@6790: HEIGHTMARKS_POINTS.equals(name) ||
felix@6790: STATIC_WQKMS_W.equals(name)) {
ingo@2325: doWAnnotations(
ingo@2325: artifactFacet.getData(context),
ingo@2325: artifactFacet,
ingo@2325: attr,
ingo@2325: visible);
felix@1921: }
felix@2769: else if (name.equals(STATIC_WKMS)) {
felix@2769: doWAnnotations(
felix@2769: artifactFacet.getData(context),
felix@2769: artifactFacet,
felix@2769: attr,
felix@2769: visible);
felix@2769: }
felix@2206: else if (FacetTypes.IS.MANUALPOINTS(name)) {
felix@2206: doPoints(artifactFacet.getData(context),
ingo@2325: artifactFacet,
felix@2206: attr, visible, YAXIS.W.idx);
felix@2206: }
felix@2731: else if (name.equals(DISCHARGE_CURVE)) {
felix@2731: doDischargeOut(
felix@2731: (WINFOArtifact) artifactFacet.getArtifact(),
felix@2731: artifactFacet.getData(context),
felix@2731: artifactFacet.getFacetDescription(),
felix@2731: attr,
felix@2731: visible);
felix@2731: }
ingo@696: else {
ingo@696: logger.warn("Unknown facet type for computed discharge: " + name);
ingo@696: return;
ingo@696: }
ingo@696: }
ingo@696:
felix@2206:
felix@1901: /**
felix@1901: * Add WQ Data to plot.
felix@6789: * @param wq data as double[][]
felix@1901: */
felix@1901: protected void doWQOut(
felix@6789: Object wq,
ingo@2605: ArtifactAndFacet aaf,
teichmann@6905: ThemeDocument theme,
ingo@2605: boolean visible
felix@1901: ) {
felix@3054: logger.debug("ComputedDischargeCurveGenerator: doWQOut");
felix@6789: double [][] data = (double [][]) wq;
felix@1901:
ingo@2605: XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
felix@2685: StyledSeriesBuilder.addPoints(series, data, true);
felix@1902:
felix@1933: addAxisSeries(series, YAXIS.W.idx, visible);
felix@1901: }
ingo@696:
felix@1944:
felix@1083: /**
felix@6429: * Add discharge Q-Series to plot, scale if at gauge.
felix@6429: * @param wqkms actual data
felix@6429: * @param theme theme to use.
felix@6429: */
felix@6429: protected void doDischargeQOut(
felix@6429: WQKms wqkms,
felix@6429: ArtifactAndFacet aaf,
teichmann@6905: ThemeDocument theme,
felix@6429: boolean visible
felix@6429: ) {
felix@6429: logger.debug("ComputedDischargeCurveGenerator: doDischargeQOut");
felix@6429: XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
felix@6429:
felix@6445: double subtractPNP = getCurrentGaugeDatum();
felix@6429:
felix@6445: if (subtractPNP == 0d) {
felix@6429: StyledSeriesBuilder.addPointsQW(series, wqkms);
felix@6429: addAxisSeries(series, YAXIS.W.idx, visible);
felix@6429: }
felix@6429: else {
felix@6429: XYSeries series2 = new StyledXYSeries(aaf.getFacetDescription(), theme);
felix@6429: StyledSeriesBuilder.addPointsQW(series2, wqkms);
felix@6429: addAxisSeries(series2, YAXIS.W.idx, false);
felix@6429:
felix@6429: // Use second axis...
felix@6429: StyledSeriesBuilder.addPointsQW(series, wqkms, -subtractPNP, 100d);
felix@6429: addAxisSeries(series, YAXIS.WCm.idx, visible);
felix@6429: }
felix@6429: }
felix@6429:
felix@6429:
felix@6429: /**
felix@6464: * Add W/Q-Series to plot.
felix@1083: * @param wqkms actual data
felix@1083: * @param theme theme to use.
felix@1083: */
ingo@1712: protected void doQOut(
ingo@2605: WQKms wqkms,
ingo@2605: ArtifactAndFacet aaf,
teichmann@6905: ThemeDocument theme,
ingo@2605: boolean visible
ingo@1712: ) {
felix@6464: logger.debug("ComputedDischargeCurveGenerator: doQOut (add W/Q data).");
ingo@2605: XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
felix@1902: StyledSeriesBuilder.addPointsQW(series, wqkms);
ingo@393:
felix@1933: addAxisSeries(series, YAXIS.W.idx, visible);
ingo@393: }
felix@1915:
felix@1915:
felix@1915: /**
felix@1915: * Add WQ-Annotations to plot.
felix@1915: * @param wqkms actual data
felix@1915: * @param theme theme to use.
felix@1915: */
felix@1915: protected void doWQAnnotations(
felix@1915: Object wqkms,
ingo@2325: ArtifactAndFacet aandf,
teichmann@6905: ThemeDocument theme,
felix@1915: boolean visible
felix@1915: ) {
felix@2161: List xy = new ArrayList();
felix@1915: double [][] data = (double [][]) wqkms;
felix@1915: for (int i = 0; i< data[0].length; i++) {
felix@3054: // TODO we need linear interpolation?
ingo@2325: xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
felix@1915: (float) data[0][i], StickyAxisAnnotation.SimpleAxis.X_AXIS));
ingo@2325: xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
felix@1915: (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS));
felix@1915: }
felix@1915:
teichmann@5864: doAnnotations(new RiverAnnotation(aandf.getFacetDescription(), xy),
ingo@2325: aandf, theme, visible);
felix@1915: }
felix@1921:
felix@1944:
felix@1921: /**
felix@1921: * Add W-Annotations to plot.
felix@2570: * @param wqkms actual data (double[][]).
felix@1921: * @param theme theme to use.
felix@1921: */
felix@1921: protected void doWAnnotations(
felix@1921: Object wqkms,
ingo@2325: ArtifactAndFacet aandf,
teichmann@6905: ThemeDocument theme,
felix@1921: boolean visible
felix@1921: ) {
ingo@2325: Facet facet = aandf.getFacet();
ingo@2325:
felix@2161: List xy = new ArrayList();
felix@2731: // Try to find them as WKms as well...
felix@2731: if (wqkms instanceof double[][]) {
felix@3054: logger.debug("its double[][] time, baby");
felix@2731: double [][] data = (double [][]) wqkms;
felix@3054: // TODO Do we need interpolation?
felix@2731: for (int i = 0; i< data[0].length; i++) {
felix@2731: xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
felix@2731: (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS));
felix@2731: }
felix@2731:
teichmann@5864: doAnnotations(new RiverAnnotation(facet.getDescription(), xy),
felix@2731: aandf, theme, visible);
felix@2731: }
felix@2731: else {
felix@3054: logger.debug("its wkms time, baby");
felix@2731: WKms data = (WKms) wqkms;
felix@3054: // Assume its WKms.
teichmann@4047: // XXX DEAD CODE // double location = getRange()[0];
felix@4036: double w = StaticWKmsArtifact.getWAtKmLin(data, getRange()[0]);
ingo@2325: xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
felix@3054: (float) w, StickyAxisAnnotation.SimpleAxis.Y_AXIS));
felix@2731:
teichmann@5864: doAnnotations(new RiverAnnotation(facet.getDescription(), xy),
felix@2731: aandf, theme, visible);
felix@1921: }
felix@1921: }
ingo@392: }
ingo@392: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :