diff flys-artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixWQCurveGenerator.java @ 5831:bd047b71ab37

Repaired internal references
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 25 Apr 2013 12:06:39 +0200
parents flys-artifacts/src/main/java/de/intevation/flys/exports/fixings/FixWQCurveGenerator.java@0516c1f8f674
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flys-artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixWQCurveGenerator.java	Thu Apr 25 12:06:39 2013 +0200
@@ -0,0 +1,620 @@
+package org.dive4elements.river.exports.fixings;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.annotations.XYTextAnnotation;
+import org.jfree.chart.plot.Marker;
+import org.jfree.chart.plot.ValueMarker;
+import org.jfree.chart.title.TextTitle;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.ui.RectangleAnchor;
+import org.jfree.ui.RectangleInsets;
+import org.jfree.ui.TextAnchor;
+import org.w3c.dom.Document;
+
+import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
+import org.dive4elements.artifactdatabase.state.Facet;
+import org.dive4elements.river.artifacts.FLYSArtifact;
+import org.dive4elements.river.artifacts.StaticWKmsArtifact;
+import org.dive4elements.river.artifacts.WINFOArtifact;
+import org.dive4elements.river.artifacts.access.FixAnalysisAccess;
+import org.dive4elements.river.artifacts.model.DateRange;
+import org.dive4elements.river.artifacts.model.FacetTypes;
+import org.dive4elements.river.artifacts.model.NamedDouble;
+import org.dive4elements.river.artifacts.model.QWDDateRange;
+import org.dive4elements.river.artifacts.model.WKms;
+import org.dive4elements.river.artifacts.model.WQKms;
+import org.dive4elements.river.artifacts.model.fixings.FixFunction;
+import org.dive4elements.river.artifacts.model.fixings.FixWQCurveFacet;
+import org.dive4elements.river.artifacts.model.fixings.QWD;
+import org.dive4elements.river.artifacts.model.fixings.QWI;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.exports.ChartGenerator;
+import org.dive4elements.river.exports.StyledSeriesBuilder;
+import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation;
+import org.dive4elements.river.jfree.FLYSAnnotation;
+import org.dive4elements.river.jfree.JFreeUtil;
+import org.dive4elements.river.jfree.StickyAxisAnnotation;
+import org.dive4elements.river.jfree.StyledXYSeries;
+import org.dive4elements.river.model.Gauge;
+import org.dive4elements.river.model.River;
+import org.dive4elements.river.utils.FLYSUtils;
+import org.dive4elements.river.utils.ThemeUtil;
+
+/**
+ * Generator for WQ fixing charts.
+ * @author <a href="mailto:christian.lins@intevation.de">Christian Lins</a>
+ */
+public class FixWQCurveGenerator
+extends      FixChartGenerator
+implements   FacetTypes
+{
+    /** Private logger. */
+    private static Logger logger =
+            Logger.getLogger(FixWQCurveGenerator.class);
+
+    public static final String I18N_CHART_TITLE =
+            "chart.fixings.wq.title";
+
+    public static final String I18N_CHART_SUBTITLE =
+            "chart.fixings.wq.subtitle";
+
+    public static final String I18N_CHART_SUBTITLE1 =
+            "chart.fixings.wq.subtitle1";
+
+    public static final String I18N_XAXIS_LABEL =
+            "chart.fixings.wq.xaxis.label";
+
+    public static final String I18N_YAXIS_LABEL =
+            "chart.fixings.wq.yaxis.label";
+
+    public static final String I18N_CHART_TITLE_DEFAULT  =
+            "Fixierungsanalyse";
+
+    public static final String I18N_XAXIS_LABEL_DEFAULT  =
+            "Q [m\u00B3/s]";
+
+    public static final String I18N_YAXIS_LABEL_DEFAULT  =
+            "W [NN + m]";
+
+    public static final double EPSILON = 0.001d;
+
+    public static enum YAXIS {
+        W(0),
+        Q(1);
+        public int idx;
+        private YAXIS(int c) {
+            idx = c;
+        }
+    }
+
+
+    /** Needed to access data to create subtitle. */
+    protected FLYSArtifact artifact;
+
+
+    @Override
+    public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doOut: " + aaf.getFacetName());
+        if (!prepareChartData(aaf, doc, visible)) {
+            logger.warn("Unknown facet, name " + aaf.getFacetName());
+        }
+    }
+
+
+    /** Return true if data could be handled. */
+    public boolean prepareChartData(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        String name = aaf.getFacetName();
+
+        this.artifact = (FLYSArtifact)aaf.getArtifact();
+
+        if(name.startsWith(FIX_SECTOR_AVERAGE_WQ)) {
+            doSectorAverageOut(aaf, doc, visible);
+        }
+        else if(FIX_ANALYSIS_EVENTS_WQ.equals(name)) {
+            doAnalysisEventsOut(aaf, doc, visible);
+        }
+        else if(FIX_REFERENCE_EVENTS_WQ.equals(name)) {
+            doReferenceEventsOut(aaf, doc, visible);
+        }
+        else if(FIX_WQ_CURVE.equals(name)) {
+            doWQCurveOut(aaf, doc, visible);
+        }
+        else if(FIX_OUTLIER.equals(name)) {
+            doOutlierOut(aaf, doc, visible);
+        }
+        else if(QSECTOR.equals(name)) {
+            doQSectorOut(aaf, doc, visible);
+        }
+        else if(FIX_EVENTS.equals(name)) {
+            doEventsOut(aaf, doc, visible);
+        }
+        else if(/*STATIC_WKMS_INTERPOL.equals(name) ||*/
+                STATIC_WKMS_MARKS.equals(name) ||
+                STATIC_WKMS.equals(name) ||
+                HEIGHTMARKS_POINTS.equals(name) ) {
+            doWAnnotations(
+                    aaf.getData(context),
+                    aaf,
+                    doc,
+                    visible);
+        }
+        else if (LONGITUDINAL_W.equals(name) || STATIC_WQ.equals(name)
+                        || STATIC_WKMS_INTERPOL.equals(name)) {
+            doWQOut(aaf.getData(context), aaf, doc, visible);
+        }
+        else if (name.equals(DISCHARGE_CURVE)) {
+            doDischargeOut(
+                    (WINFOArtifact) aaf.getArtifact(),
+                    aaf.getData(context),
+                    aaf.getFacetDescription(),
+                    doc,
+                    visible);
+        }
+        else if (FacetTypes.IS.MANUALPOINTS(aaf.getFacetName())) {
+            doPoints(aaf.getData(context),
+                    aaf,
+                    doc, visible, YAXIS.W.idx);
+        }
+        else {
+            return false;
+        }
+        return true;
+    }
+
+
+    /** Add sector average points to chart */
+    protected void doSectorAverageOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doSectorAverageOut");
+
+        QWDDateRange qwdd = (QWDDateRange) aaf.getData(context);
+        QWD qwd = qwdd != null ? qwdd.getQWD() : null;
+
+        if(qwd != null) {
+            addQWSeries(new QWD[] { qwd }, aaf, doc, visible);
+        }
+        else {
+            logger.debug("doSectorAverageOut: qwd == null");
+        }
+    }
+
+    /** Add analysis event points to chart */
+    protected void doAnalysisEventsOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doAnalysisEventsOut");
+
+        QWD qwd = (QWD)aaf.getData(context);
+        if(qwd != null) {
+            XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc);
+            List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>();
+
+            DateFormat dateFormat = DateFormat.getDateInstance(
+                    DateFormat.SHORT);
+
+            series.add(qwd.getQ(), qwd.getW());
+
+            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
+                    dateFormat.format(qwd.getDate()),
+                    qwd.getQ(),
+                    qwd.getW());
+            textAnnos.add(anno);
+
+            addAxisSeries(series, 0, visible);
+            if(visible && ThemeUtil.parseShowPointLabel(doc)) {
+                FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, doc);
+                flysAnno.setTextAnnotations(textAnnos);
+                addAnnotations(flysAnno);
+            }
+        }
+        else {
+            logger.debug("doAnalysisEventsOut: qwds == null");
+        }
+    }
+
+
+    /** Add reference event points to chart */
+    protected void doReferenceEventsOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doReferenceEventsOut");
+
+        QWI qwd = (QWI)aaf.getData(context);
+        if(qwd != null) {
+            XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc);
+            List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>();
+
+            DateFormat dateFormat = DateFormat.getDateInstance(
+                    DateFormat.SHORT);
+
+            series.add(qwd.getQ(), qwd.getW());
+
+            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
+                    dateFormat.format(qwd.getDate()),
+                    qwd.getQ(),
+                    qwd.getW());
+            textAnnos.add(anno);
+
+            addAxisSeries(series, 0, visible);
+            if(visible && ThemeUtil.parseShowPointLabel(doc)) {
+                FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, doc);
+                flysAnno.setTextAnnotations(textAnnos);
+                addAnnotations(flysAnno);
+            }
+        }
+        else {
+            logger.debug("doReferenceEventsOut: qwds == null");
+        }
+    }
+
+
+    private void addPointFromWQKms(WQKms wqkms,
+        String title,
+        Document theme,
+        boolean visible
+    ) {
+        XYSeries series = new StyledXYSeries(title, theme);
+        Double ckm = (Double) context.getContextValue(CURRENT_KM);
+        if (wqkms == null || wqkms.getKms().length == 0 || ckm == null) {
+            logger.info("addPointFromWQKms: No event data to show.");
+            return;
+        }
+        double[] kms = wqkms.getKms();
+        for (int i = 0 ; i< kms.length; i++) {
+            if (Math.abs(kms[i] - ckm) <= EPSILON) {
+                series.add(wqkms.getQ(i), wqkms.getW(i));
+                addAxisSeries(series, YAXIS.W.idx, visible);
+                return;
+            }
+        }
+    }
+
+    protected void doEventsOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doEventsOut");
+        // Find W/Q at km.
+        addPointFromWQKms((WQKms) aaf.getData(context),
+            aaf.getFacetDescription(), doc, visible);
+    }
+
+
+    protected void doWQCurveOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doWQCurveOut");
+
+        FixWQCurveFacet facet = (FixWQCurveFacet)aaf.getFacet();
+        FixFunction func = (FixFunction)facet.getData(
+                aaf.getArtifact(), context);
+
+        if (func == null) {
+            logger.warn("doWQCurveOut: Facet does not contain FixFunction");
+            return;
+        }
+
+        double maxQ = func.getMaxQ();
+
+        if (maxQ > 0) {
+            StyledXYSeries series = JFreeUtil.sampleFunction2D(
+                    func.getFunction(),
+                    doc,
+                    aaf.getFacetDescription(),
+                    500,   // number of samples
+                    0.0 ,  // start
+                    maxQ); // end
+
+            addAxisSeries(series, 0, visible);
+        }
+        else {
+            logger.warn("doWQCurveOut: maxQ <= 0");
+        }
+    }
+
+    protected void doOutlierOut(ArtifactAndFacet aaf, Document doc, boolean visible) {
+        logger.debug("doOutlierOut");
+
+        QWI[] qws = (QWI[])aaf.getData(context);
+        addQWSeries(qws, aaf, doc, visible);
+    }
+
+
+    /** Add markers for q sectors. */
+    protected void doQSectorOut(ArtifactAndFacet aaf, Document theme, boolean visible) {
+        logger.debug("doQSectorOut");
+        if (!visible) {
+            return;
+        }
+
+        Object qsectorsObj = aaf.getData(context);
+        if (qsectorsObj == null || !(qsectorsObj instanceof List)) {
+            logger.warn("No QSectors coming from data.");
+            return;
+        }
+
+        List<?> qsectorsList = (List<?>) qsectorsObj;
+        if (qsectorsList.size() == 0 || !(qsectorsList.get(0) instanceof NamedDouble)) {
+            logger.warn("No QSectors coming from data.");
+            return;
+        }
+
+        @SuppressWarnings("unchecked")
+        List<NamedDouble> qsectors = (List<NamedDouble>) qsectorsList;
+
+        for (NamedDouble qsector : qsectors) {
+            if (Double.isNaN(qsector.getValue())) {
+                continue;
+            }
+            Marker m = new ValueMarker(qsector.getValue());
+            m.setPaint(Color.black);
+
+            float[] dashes = ThemeUtil.parseLineStyle(theme);
+            int size       = ThemeUtil.parseLineWidth(theme);
+            BasicStroke stroke;
+            if (dashes.length <= 1) {
+                stroke = new BasicStroke(size);
+            }
+            else {
+                stroke = new BasicStroke(size,
+                        BasicStroke.CAP_BUTT,
+                        BasicStroke.JOIN_ROUND,
+                        1.0f,
+                        dashes,
+                        0.0f);
+            }
+            m.setStroke(stroke);
+
+            if (ThemeUtil.parseShowLineLabel(theme)) {
+                m.setLabel(qsector.getName());
+                m.setPaint(ThemeUtil.parseTextColor(theme));
+                m.setLabelFont(ThemeUtil.parseTextFont(theme));
+            }
+            Color paint = ThemeUtil.parseLineColorField(theme);
+            if (paint != null) {
+                m.setPaint(paint);
+            }
+            m.setLabelAnchor(RectangleAnchor.TOP_LEFT);
+            m.setLabelTextAnchor(TextAnchor.TOP_LEFT);
+            m.setLabelOffset(new RectangleInsets(5, 5, 10, 10));
+            addDomainMarker(m);
+        }
+    }
+
+
+    /**
+     * Add W-Annotations to plot.
+     * @param wqkms actual data (double[][]).
+     * @param theme theme to use.
+     */
+    protected void doWAnnotations(
+            Object   wqkms,
+            ArtifactAndFacet aandf,
+            Document theme,
+            boolean  visible
+            ) {
+        Facet facet = aandf.getFacet();
+
+        List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>();
+        if (wqkms instanceof double[][]) {
+            logger.debug("Got double[][]");
+            double [][] data = (double [][]) wqkms;
+            for (int i = 0; i< data[0].length; i++) {
+                xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
+                        (float) data[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS));
+            }
+
+            doAnnotations(new FLYSAnnotation(facet.getDescription(), xy),
+                    aandf, theme, visible);
+        }
+        else {
+            // Assume its WKms.
+            logger.debug("Got WKms");
+            WKms data = (WKms) wqkms;
+
+            Double ckm = (Double) context.getContextValue(CURRENT_KM);
+            double location = (ckm != null)
+                    ? ckm.doubleValue()
+                    : getRange()[0];
+            double w = StaticWKmsArtifact.getWAtKmLin(data, location);
+            xy.add(new StickyAxisAnnotation(aandf.getFacetDescription(),
+                    (float) w, StickyAxisAnnotation.SimpleAxis.Y_AXIS));
+
+            doAnnotations(new FLYSAnnotation(facet.getDescription(), xy),
+                    aandf, theme, visible);
+        }
+    }
+
+
+    /**
+     * Add series with discharge curve to diagram.
+     */
+    protected void doDischargeOut(
+            WINFOArtifact artifact,
+            Object        o,
+            String        description,
+            Document      theme,
+            boolean       visible)
+    {
+        WQKms wqkms = (WQKms) o;
+
+        String gaugeName = wqkms.getName();
+
+        River river = FLYSUtils.getRiver(artifact);
+
+        if (river == null) {
+            logger.debug("no river found");
+            return;
+        }
+
+        Gauge gauge = river.determineGaugeByName(gaugeName);
+
+        if (gauge == null) {
+            logger.debug("no gauge found");
+            return;
+        }
+
+        XYSeries series = new StyledXYSeries(description, theme);
+        StyledSeriesBuilder.addPointsQW(series, wqkms);
+        addAxisSeries(series, YAXIS.W.idx, visible);
+    }
+
+
+    /**
+     * Add WQ Data to plot.
+     * @param wqkms data as double[][]
+     */
+    protected void doWQOut(
+            Object           wqkms,
+            ArtifactAndFacet aaf,
+            Document         theme,
+            boolean          visible
+            ) {
+        logger.debug("FixWQCurveGenerator: doWQOut");
+        if (wqkms instanceof WQKms) {
+            // TODO As in doEventsOut, the value-searching should
+            // be delivered by the facet already (instead of in the Generator).
+            logger.debug("FixWQCurveGenerator: doWQOut: WQKms");
+
+            addPointFromWQKms((WQKms) aaf.getData(context), aaf.getFacetDescription(), theme, visible);
+        }
+        else {
+            logger.debug("FixWQCurveGenerator: doWQOut: double[][]");
+            double [][] data = (double [][]) wqkms;
+
+            XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
+            StyledSeriesBuilder.addPoints(series, data, true);
+
+            addAxisSeries(series, YAXIS.W.idx, visible);
+        }
+    }
+
+
+    protected void addQWSeries(
+            QWI []           qws,
+            ArtifactAndFacet aaf,
+            Document         theme,
+            boolean          visible
+            ) {
+        if (qws == null) {
+            return;
+        }
+
+        XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme);
+        List<XYTextAnnotation> textAnnos =
+                new ArrayList<XYTextAnnotation>(qws.length);
+
+        DateFormat dateFormat = DateFormat.getDateInstance(
+                DateFormat.SHORT);
+
+        for (QWI qw: qws) {
+            series.add(qw.getQ(), qw.getW());
+
+            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
+                    dateFormat.format(qw.getDate()),
+                    qw.getQ(),
+                    qw.getW());
+            textAnnos.add(anno);
+        }
+
+        addAxisSeries(series, 0, visible);
+        if (visible && ThemeUtil.parseShowPointLabel(theme)) {
+            FLYSAnnotation flysAnno =
+                    new FLYSAnnotation(null, null, null, theme);
+            flysAnno.setTextAnnotations(textAnnos);
+            addAnnotations(flysAnno);
+        }
+    }
+
+    @Override
+    protected String getChartTitle() {
+        return Resources.format(
+                context.getMeta(),
+                I18N_CHART_TITLE,
+                I18N_CHART_TITLE_DEFAULT,
+                context.getContextValue(CURRENT_KM));
+    }
+
+    @Override
+    protected String getDefaultChartTitle() {
+        return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultChartSubtitle() {
+        FixAnalysisAccess access = new FixAnalysisAccess(artifact, context);
+        DateRange dateRange = access.getDateRange();
+        DateRange refRange  = access.getReferencePeriod();
+
+        if (dateRange != null && refRange != null) {
+            return Resources.format(
+                    context.getMeta(),
+                    I18N_CHART_SUBTITLE,
+                    "",
+                    access.getRiver(),
+                    dateRange.getFrom(),
+                    dateRange.getTo(),
+                    refRange.getFrom(),
+                    refRange.getTo());
+        }
+
+        return null;
+    }
+
+    @Override
+    protected void addSubtitles(JFreeChart chart) {
+        String defaultSubtitle = getDefaultChartSubtitle();
+
+        if (defaultSubtitle == null || defaultSubtitle.length() == 0) {
+            return;
+        }
+
+        chart.addSubtitle(new TextTitle(defaultSubtitle));
+
+        StringBuilder buf = new StringBuilder();
+
+        // Add analysis periods as additional subtitle
+        FixAnalysisAccess access = new FixAnalysisAccess(artifact, context);
+        DateRange[] aperiods = access.getAnalysisPeriods();
+        buf.append(msg("fix.analysis.periods"));
+        buf.append(": ");
+        for(int n = 0; n < aperiods.length; n++) {
+            buf.append(
+                    Resources.format(
+                            context.getMeta(),
+                            I18N_CHART_SUBTITLE1,
+                            "",
+                            aperiods[n].getFrom(),
+                            aperiods[n].getTo()));
+            if(n + 1 < aperiods.length) {
+                buf.append("; ");
+            }
+        }
+
+        chart.addSubtitle(new TextTitle(buf.toString()));
+    }
+
+    @Override
+    protected String getDefaultXAxisLabel() {
+        return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT);
+    }
+
+    @Override
+    protected String getDefaultYAxisLabel(int pos) {
+        return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT);
+    }
+
+    @Override
+    protected ChartGenerator.YAxisWalker getYAxisWalker() {
+        return new YAxisWalker() {
+            @Override
+            public int length() {
+                return YAXIS.values().length;
+            }
+
+            @Override
+            public String getId(int idx) {
+                YAXIS[] yaxes = YAXIS.values();
+                return yaxes[idx].toString();
+            }
+        };
+    }
+}
+// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org