mschaefer@9398: /** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde mschaefer@9398: * Software engineering by mschaefer@9398: * Björnsen Beratende Ingenieure GmbH mschaefer@9398: * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt mschaefer@9252: * mschaefer@9252: * This file is Free Software under the GNU AGPL (>=v3) mschaefer@9252: * and comes with ABSOLUTELY NO WARRANTY! Check out the mschaefer@9252: * documentation coming with Dive4Elements River for details. mschaefer@9252: */ mschaefer@9252: package org.dive4elements.river.artifacts.sinfo.flood_duration; mschaefer@9252: mschaefer@9252: import java.awt.Font; mschaefer@9252: import java.awt.geom.Point2D; gernotbelger@9268: import java.io.OutputStream; mschaefer@9252: mschaefer@9252: import org.apache.log4j.Logger; mschaefer@9252: import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; mschaefer@9252: import org.dive4elements.artifacts.CallContext; mschaefer@9595: import org.dive4elements.river.artifacts.MainValuesArtifact; mschaefer@9252: import org.dive4elements.river.artifacts.model.FacetTypes; mschaefer@9252: import org.dive4elements.river.artifacts.model.WQDay; mschaefer@9252: import org.dive4elements.river.exports.IdentifiableNumberAxis; mschaefer@9252: import org.dive4elements.river.exports.XYChartGenerator; gernotbelger@9268: import org.dive4elements.river.exports.fixings.FixChartGenerator; mschaefer@9252: import org.dive4elements.river.jfree.Bounds; mschaefer@9252: import org.dive4elements.river.jfree.RiverAnnotation; mschaefer@9252: import org.dive4elements.river.jfree.StyledXYSeries; mschaefer@9252: import org.dive4elements.river.themes.ThemeDocument; mschaefer@9252: import org.jfree.chart.axis.NumberAxis; mschaefer@9252: import org.jfree.chart.axis.ValueAxis; mschaefer@9252: import org.jfree.chart.plot.XYPlot; mschaefer@9252: import org.jfree.data.Range; mschaefer@9252: import org.jfree.data.xy.XYSeries; gernotbelger@9268: import org.w3c.dom.Document; mschaefer@9252: mschaefer@9252: /** mschaefer@9398: * An OutGenerator that generates flood duration curves. mschaefer@9398: * (based upon a copy of DurationCurveGenerator) mschaefer@9252: */ gernotbelger@9265: public class FloodDurationCurveGenerator extends XYChartGenerator implements FacetTypes { mschaefer@9252: public static enum YAXIS { gernotbelger@9265: W(0), Q(1); mschaefer@9252: public int idx; gernotbelger@9265: mschaefer@9252: private YAXIS(final int c) { mschaefer@9252: this.idx = c; mschaefer@9252: } mschaefer@9252: } mschaefer@9252: mschaefer@9252: /** Local log. */ gernotbelger@9265: private static Logger log = Logger.getLogger(FloodDurationCurveGenerator.class); mschaefer@9252: gernotbelger@9265: private static final String I18N_CHART_TITLE = "sinfo.chart.flood_duration.curve.section.title"; mschaefer@9252: gernotbelger@9265: private static final String I18N_CHART_SUBTITLE = "chart.duration.curve.subtitle"; mschaefer@9252: gernotbelger@9265: private static final String I18N_XAXIS_LABEL = "sinfo.chart.flood_duration.curve.xaxis.label"; mschaefer@9252: gernotbelger@9265: private static final String I18N_YAXIS_LABEL_W = "chart.duration.curve.yaxis.label.w"; mschaefer@9252: gernotbelger@9312: private static final String I18N_YAXIS_LABEL_Q = "common.export.csv.header.q"; gernotbelger@9265: gernotbelger@9265: private static final String I18N_CHART_TITLE_DEFAULT = "Dauerlinie"; gernotbelger@9265: gernotbelger@9265: private static final String I18N_XAXIS_LABEL_DEFAULT = "Überflutungsdauer [d/a]"; mschaefer@9252: mschaefer@9252: public FloodDurationCurveGenerator() { mschaefer@9252: super(); mschaefer@9252: } mschaefer@9252: gernotbelger@9268: @Override gernotbelger@9268: public void init(final String outName, final Document request, final OutputStream out, final CallContext context) { gernotbelger@9268: super.init(outName, request, out, context); gernotbelger@9268: gernotbelger@9268: FixChartGenerator.initCurrentKm(request, context); gernotbelger@9268: } gernotbelger@9268: mschaefer@9252: /** mschaefer@9252: * Create Axis for given index. gernotbelger@9265: * mschaefer@9252: * @return axis with according internationalized label. mschaefer@9252: */ mschaefer@9252: @Override mschaefer@9252: protected NumberAxis createYAxis(final int index) { mschaefer@9252: final Font labelFont = new Font("Tahoma", Font.BOLD, 14); gernotbelger@9265: final String label = getYAxisLabel(index); mschaefer@9252: mschaefer@9252: final NumberAxis axis = createNumberAxis(index, label); mschaefer@9252: if (index == YAXIS.W.idx) { mschaefer@9252: axis.setAutoRangeIncludesZero(false); mschaefer@9252: } mschaefer@9252: axis.setLabelFont(labelFont); mschaefer@9252: return axis; mschaefer@9252: } mschaefer@9252: mschaefer@9252: @Override mschaefer@9252: protected String getDefaultChartTitle(final CallContext context) { mschaefer@9252: return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); mschaefer@9252: } mschaefer@9252: mschaefer@9252: @Override gernotbelger@9268: protected String getChartSubtitle(final CallContext context) { gernotbelger@9268: // REMARK: can't use getDeaultChartSubtitle, because the standard implementation of getChartSubtitle will gernotbelger@9268: // always use the subtitle from the settings, which will automatically be set during init. gernotbelger@9268: final double currentKm = FixChartGenerator.getCurrentKm(context); gernotbelger@9268: return msg(I18N_CHART_SUBTITLE, "", getRiverName(), currentKm); mschaefer@9252: } mschaefer@9252: mschaefer@9252: @Override mschaefer@9252: protected String getDefaultXAxisLabel(final CallContext context) { mschaefer@9252: return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); mschaefer@9252: } mschaefer@9252: mschaefer@9252: @Override mschaefer@9252: protected String getDefaultYAxisLabel(final int index) { mschaefer@9252: mschaefer@9252: String label = "default"; mschaefer@9252: if (index == YAXIS.W.idx) { mschaefer@9252: label = msg(I18N_YAXIS_LABEL_W, I18N_YAXIS_LABEL_W, getRiverUnit()); gernotbelger@9265: } else if (index == YAXIS.Q.idx) { mschaefer@9252: label = msg(I18N_YAXIS_LABEL_Q); mschaefer@9252: } mschaefer@9252: return label; mschaefer@9252: } mschaefer@9252: mschaefer@9252: @Override mschaefer@9252: protected boolean zoomX(final XYPlot plot, final ValueAxis axis, final Bounds bounds, final Range x) { mschaefer@9252: mschaefer@9252: final boolean zoomin = super.zoom(plot, axis, bounds, x); mschaefer@9252: if (!zoomin) mschaefer@9252: axis.setLowerBound(0d); mschaefer@9257: axis.setUpperBound(364); mschaefer@9252: return zoomin; mschaefer@9252: } mschaefer@9252: mschaefer@9252: /** mschaefer@9252: * This method overrides the method in the parent class to set the lower mschaefer@9252: * bounds of the Q axis to 0. This axis should never display negative mschaefer@9252: * values on its own. mschaefer@9252: */ mschaefer@9252: @Override mschaefer@9252: protected boolean zoomY(final XYPlot plot, final ValueAxis axis, final Bounds bounds, final Range x) { mschaefer@9252: mschaefer@9252: final boolean zoomin = super.zoom(plot, axis, bounds, x); mschaefer@9252: if (!zoomin && axis instanceof IdentifiableNumberAxis) { mschaefer@9252: final String id = ((IdentifiableNumberAxis) axis).getId(); mschaefer@9252: if (YAXIS.Q.toString().equals(id)) mschaefer@9252: axis.setLowerBound(0d); mschaefer@9252: } mschaefer@9252: return zoomin; mschaefer@9252: } mschaefer@9252: mschaefer@9252: @Override mschaefer@9252: public void doOut(final ArtifactAndFacet artifactFacet, final ThemeDocument attr, final boolean visible) { mschaefer@9252: mschaefer@9252: final String name = artifactFacet.getFacetName(); mschaefer@9252: mschaefer@9252: log.debug("FloodDurationCurveGenerator.doOut: " + name); mschaefer@9252: mschaefer@9252: if (name == null || name.length() == 0) { mschaefer@9252: log.error("No facet given. Cannot create dataset."); mschaefer@9252: return; mschaefer@9252: } mschaefer@9252: mschaefer@9252: final CallContext context = getContext(); mschaefer@9252: gernotbelger@9556: // TODO: mainvalues.q gernotbelger@9556: // TODO: mainvalues.w gernotbelger@9556: // } else if (name.equals(MAINVALUES_Q) || name.equals(MAINVALUES_W)) { gernotbelger@9556: // doAnnotations((RiverAnnotation) artifactFacet.getData(context), artifactFacet, attr, visible); gernotbelger@9556: mschaefer@9252: if (name.equals(DURATION_W)) { gernotbelger@9265: doWOut((WQDay) (artifactFacet.getData(context)), artifactFacet, attr, visible); gernotbelger@9312: } else if (name.equals(DURATION_Q)) { gernotbelger@9265: doQOut((WQDay) artifactFacet.getData(context), artifactFacet, attr, visible); gernotbelger@9312: } else if (name.equals(FloodDurationCurveProcessor.FACET_FLOOD_DURATION_MAINVALUES_Q) mschaefer@9259: || name.equals(FloodDurationCurveProcessor.FACET_FLOOD_DURATION_MAINVALUES_W)) { mschaefer@9252: doAnnotations((RiverAnnotation) artifactFacet.getData(context), artifactFacet, attr, visible); gernotbelger@9556: } else if (FloodDurationCurveProcessor.isInfrastructureFacet(name) && (artifactFacet.getData(context) != null)) { gernotbelger@9556: doAnnotations((RiverAnnotation) artifactFacet.getData(context), artifactFacet, attr, visible); gernotbelger@9556: } else if (name.equals(MAINVALUES_Q) || name.equals(MAINVALUES_W)) { mschaefer@9595: final MainValuesArtifact mva = new MainValuesArtifactWrapper((MainValuesArtifact) artifactFacet.getArtifact()); mschaefer@9595: if (context.getContextValue("currentKm") != null) mschaefer@9595: mva.addStringData("ld_locations", context.getContextValue("currentKm").toString()); mschaefer@9595: final ArtifactAndFacet mvaf = new ArtifactAndFacet(mva, artifactFacet.getFacet()); mschaefer@9595: doAnnotations((RiverAnnotation) mvaf.getData(context), mvaf, attr, visible); mschaefer@9252: } mschaefer@9259: // else if (name.equals(RELATIVE_POINT)) { mschaefer@9259: // doPointOut((Point2D) artifactFacet.getData(context), artifactFacet, attr, visible); mschaefer@9259: // } mschaefer@9252: else if (FacetTypes.IS.MANUALPOINTS(name)) { mschaefer@9252: doPoints(artifactFacet.getData(context), artifactFacet, attr, visible, YAXIS.W.idx); gernotbelger@9312: } else { mschaefer@9252: log.warn("Unknown facet name: " + name); mschaefer@9252: return; mschaefer@9252: } mschaefer@9252: } mschaefer@9252: mschaefer@9252: /** mschaefer@9252: * Creates the series for a duration curve's W facet. mschaefer@9252: * gernotbelger@9265: * @param wqdays gernotbelger@9265: * The WQDay store that contains the Ws. mschaefer@9252: * @param theme mschaefer@9252: */ mschaefer@9252: protected void doWOut(final WQDay wqdays, final ArtifactAndFacet aaf, final ThemeDocument theme, final boolean visible) { mschaefer@9252: mschaefer@9252: // log.debug("DurationCurveGenerator.doWOut"); gernotbelger@9556: final XYSeries series = new StyledXYSeries(aaf.getFacetName(), aaf.getFacetDescription(), theme); mschaefer@9252: final int size = wqdays.size(); mschaefer@9252: for (int i = 0; i < size; i++) { gernotbelger@9265: final int day = wqdays.getDay(i); mschaefer@9252: final double w = wqdays.getW(i); mschaefer@9252: series.add(day, w); mschaefer@9252: } mschaefer@9252: addAxisSeries(series, YAXIS.W.idx, visible); mschaefer@9252: } mschaefer@9252: mschaefer@9252: protected void doPointOut(final Point2D point, final ArtifactAndFacet aandf, final ThemeDocument theme, final boolean visible) { mschaefer@9252: mschaefer@9252: // log.debug("DurationCurveGenerator.doPointOut"); gernotbelger@9556: final XYSeries series = new StyledXYSeries(aandf.getFacetName(), aandf.getFacetDescription(), theme); mschaefer@9252: series.add(point.getX(), point.getY()); mschaefer@9252: addAxisSeries(series, YAXIS.W.idx, visible); mschaefer@9252: } mschaefer@9252: mschaefer@9252: /** mschaefer@9252: * Creates the series for a duration curve's Q facet. mschaefer@9252: * gernotbelger@9265: * @param wqdays gernotbelger@9265: * The WQDay store that contains the Qs. mschaefer@9252: * @param theme mschaefer@9252: */ mschaefer@9252: protected void doQOut(final WQDay wqdays, final ArtifactAndFacet aaf, final ThemeDocument theme, final boolean visible) { mschaefer@9252: mschaefer@9252: // log.debug("DurationCurveGenerator.doQOut"); gernotbelger@9556: final XYSeries series = new StyledXYSeries(aaf.getFacetName(), aaf.getFacetDescription(), theme); mschaefer@9252: final int size = wqdays.size(); mschaefer@9252: for (int i = 0; i < size; i++) { gernotbelger@9265: final int day = wqdays.getDay(i); mschaefer@9252: final double q = wqdays.getQ(i); mschaefer@9252: series.add(day, q); mschaefer@9252: } mschaefer@9252: addAxisSeries(series, YAXIS.Q.idx, visible); mschaefer@9252: } mschaefer@9252: mschaefer@9252: @Override mschaefer@9252: protected YAxisWalker getYAxisWalker() { mschaefer@9252: return new YAxisWalker() { mschaefer@9252: @Override mschaefer@9252: public int length() { mschaefer@9252: return YAXIS.values().length; mschaefer@9252: } mschaefer@9252: mschaefer@9252: @Override mschaefer@9252: public String getId(final int idx) { mschaefer@9252: final YAXIS[] yaxes = YAXIS.values(); mschaefer@9252: return yaxes[idx].toString(); mschaefer@9252: } mschaefer@9252: }; mschaefer@9252: } mschaefer@9252: mschaefer@9252: // MainValue-Annotations should be visualized by mschaefer@9252: // a line that goes to the curve itself. gernotbelger@9265: }