mschaefer@9252: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde mschaefer@9252: * Software engineering by Intevation GmbH 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: 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; 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@9252: import org.dive4elements.river.artifacts.model.CalculationResult; 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; 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; mschaefer@9252: mschaefer@9252: mschaefer@9252: /** mschaefer@9252: * An OutGenerator that generates duration curves. mschaefer@9252: * mschaefer@9252: * @author Ingo Weinzierl mschaefer@9252: */ mschaefer@9252: public class FloodDurationCurveGenerator mschaefer@9252: extends XYChartGenerator mschaefer@9252: implements FacetTypes mschaefer@9252: { mschaefer@9252: public static enum YAXIS { mschaefer@9252: W(0), mschaefer@9252: Q(1); mschaefer@9252: public int idx; mschaefer@9252: private YAXIS(final int c) { mschaefer@9252: this.idx = c; mschaefer@9252: } mschaefer@9252: } mschaefer@9252: mschaefer@9252: /** Local log. */ mschaefer@9252: private static Logger log = mschaefer@9252: Logger.getLogger(FloodDurationCurveGenerator.class); mschaefer@9252: mschaefer@9252: public static final String I18N_CHART_TITLE = "sinfo.chart.flood_duration.curve.section.title"; mschaefer@9252: mschaefer@9252: public static final String I18N_CHART_SUBTITLE = "chart.duration.curve.subtitle"; mschaefer@9252: mschaefer@9252: public static final String I18N_XAXIS_LABEL = "sinfo.chart.flood_duration.curve.xaxis.label"; mschaefer@9252: mschaefer@9252: public static final String I18N_YAXIS_LABEL_W = "chart.duration.curve.yaxis.label.w"; mschaefer@9252: mschaefer@9252: public static final String I18N_YAXIS_LABEL_Q = "chart.duration.curve.yaxis.label.q"; mschaefer@9252: mschaefer@9252: public static final String I18N_CHART_TITLE_DEFAULT = "Dauerlinie"; mschaefer@9252: mschaefer@9252: public static final String I18N_XAXIS_LABEL_DEFAULT = "Überflutungsdauer [d/a]"; mschaefer@9252: mschaefer@9252: mschaefer@9252: public FloodDurationCurveGenerator() { mschaefer@9252: super(); mschaefer@9252: } mschaefer@9252: mschaefer@9252: mschaefer@9252: /** mschaefer@9252: * Create Axis for given index. 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); mschaefer@9252: 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: 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: mschaefer@9252: @Override mschaefer@9252: protected String getDefaultChartSubtitle(final CallContext context) { mschaefer@9252: mschaefer@9252: final double[] dist = getRange(); mschaefer@9252: return msg(I18N_CHART_SUBTITLE, "", getRiverName(), dist[0]); mschaefer@9252: } 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: 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()); mschaefer@9252: } mschaefer@9252: 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: 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: /** 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: 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: mschaefer@9252: if (name.equals(DURATION_W)) { mschaefer@9252: doWOut((WQDay) ((CalculationResult) artifactFacet.getData(context)).getData(), artifactFacet, attr, visible); mschaefer@9252: } mschaefer@9252: else if (name.equals(DURATION_Q)) { mschaefer@9252: doQOut((WQDay) ((CalculationResult) artifactFacet.getData(context)).getData(), artifactFacet, attr, visible); mschaefer@9252: } mschaefer@9259: 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); mschaefer@9252: } mschaefer@9259: else if (name.equals(FloodDurationCurveProcessor.FACET_FLOOD_DURATION_INFRASTRUCTURE) && (artifactFacet.getData(context) != null)) { mschaefer@9259: doAnnotations((RiverAnnotation) artifactFacet.getData(context), artifactFacet, 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); mschaefer@9252: } mschaefer@9252: 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: * mschaefer@9252: * @param wqdays 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"); mschaefer@9252: final XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); mschaefer@9252: final int size = wqdays.size(); mschaefer@9252: for (int i = 0; i < size; i++) { mschaefer@9252: 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"); mschaefer@9252: final XYSeries series = new StyledXYSeries(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: /** mschaefer@9252: * Creates the series for a duration curve's Q facet. mschaefer@9252: * mschaefer@9252: * @param wqdays 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"); mschaefer@9252: final XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); mschaefer@9252: final int size = wqdays.size(); mschaefer@9252: for (int i = 0; i < size; i++) { mschaefer@9252: 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: 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. mschaefer@9252: } mschaefer@9252: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :