view artifacts/src/main/java/org/dive4elements/river/exports/process/FixWQProcessor.java @ 8206:436512d9bd94

Added processor for discharge curve in fixanalysis.
author Raimund Renkert <rrenkert@intevation.de>
date Fri, 05 Sep 2014 15:57:39 +0200
parents
children 9f9857f6c464
line wrap: on
line source
package org.dive4elements.river.exports.process;

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.dive4elements.artifactdatabase.state.ArtifactAndFacet;
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.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.exports.DiagramGenerator;
import org.dive4elements.river.exports.StyledSeriesBuilder;
import org.dive4elements.river.exports.fixings.FixChartGenerator;
import org.dive4elements.river.exports.fixings.FixWQCurveGenerator;
import org.dive4elements.river.java2d.ShapeUtils;
import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation;
import org.dive4elements.river.jfree.JFreeUtil;
import org.dive4elements.river.jfree.RiverAnnotation;
import org.dive4elements.river.jfree.StickyAxisAnnotation;
import org.dive4elements.river.jfree.StyledXYSeries;
import org.dive4elements.river.themes.ThemeDocument;
import org.jfree.chart.annotations.XYTextAnnotation;
import org.jfree.chart.plot.Marker;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.data.xy.XYSeries;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;


public class FixWQProcessor
extends DefaultProcessor
implements FacetTypes
{

    private static Logger logger = Logger.getLogger(FixWQProcessor.class);

    public FixWQProcessor() {
    }

    @Override
    public void doOut(
        DiagramGenerator generator,
        ArtifactAndFacet bundle,
        ThemeDocument theme,
        boolean visible
    ) {
        // TODO: Simplyfy this processor and move general facets/data to 
        // MiscDischargeProcessor or something...
        String facetType = bundle.getFacetName();
        logger.debug("facet: " + facetType + " name: " + bundle.getFacetDescription());
        if(facetType.startsWith(FIX_SECTOR_AVERAGE_WQ)) {
            doSectorAverageOut(generator, bundle, theme, visible);
        }
        else if(FIX_ANALYSIS_EVENTS_WQ.equals(facetType)
            || FIX_REFERENCE_EVENTS_WQ.equals(facetType)
            || FIX_EVENTS.equals(facetType)) {
            doEventsOut(generator, bundle, theme, visible);
        }
        else if(FIX_WQ_CURVE.equals(facetType)) {
            doWQCurveOut(generator, bundle, theme, visible);
        }
        else if(FIX_OUTLIER.equals(facetType)) {
            doOutlierOut(generator, bundle, theme, visible);
        }
        else if(QSECTOR.equals(facetType)) {
            doQSectorOut(generator, bundle, theme, visible);
        }
        else if(STATIC_WKMS_MARKS.equals(facetType) ||
                STATIC_WKMS.equals(facetType) ||
                HEIGHTMARKS_POINTS.equals(facetType) ) {
            doWAnnotations(generator, bundle, theme, visible);
        }
        else if (LONGITUDINAL_W.equals(facetType)
            || STATIC_WKMS_INTERPOL.equals(facetType)
            || FIX_WQ_LS.equals(facetType)) {
            doWQOut(generator, bundle, theme, visible);
        }
    }

    /** Add sector average points to chart. */
    protected void doSectorAverageOut(
        DiagramGenerator generator,
        ArtifactAndFacet bundle,
        ThemeDocument theme,
        boolean visible
    ) {
        logger.debug("doSectorAverageOut");
        QWDDateRange qwdd = (QWDDateRange)bundle.getData(generator.getCallContext());
        QWD qwd = qwdd != null ? qwdd.getQWD() : null;

        if(qwd != null) {
            XYSeries series = new StyledXYSeries(
                bundle.getFacetDescription(),
                false, true,
                theme);
            DateFormat dateFormat = DateFormat.getDateInstance(
                DateFormat.SHORT);

            //TODO: W in cm at Gauge!!!
            series.add(qwd.getQ(), qwd.getW(), false);

            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
                    dateFormat.format(qwd.getDate()),
                    qwd.getQ(),
                    qwd.getW());
            List<XYTextAnnotation> annos = new ArrayList<XYTextAnnotation>();
            annos.add(anno);
            generator.addAxisSeries(series, axisName, visible);

            if (visible && theme != null && theme.parseShowPointLabel()) {
                RiverAnnotation flysAnno =
                        new RiverAnnotation(null, null, null, theme);
                flysAnno.setTextAnnotations(annos);
                generator.addAnnotations(flysAnno);
            }
        }
        else {
            logger.debug("doSectorAverageOut: qwd == null");
        }
    }


    /** Add analysis event points to chart. */
    protected void doEventsOut(
        DiagramGenerator generator,
        ArtifactAndFacet bundle,
        ThemeDocument    theme,
        boolean          visible
    ) {
        logger.debug("doAnalysisEventsOut");

        QWD qwd = (QWD)bundle.getData(generator.getCallContext());

        if (qwd == null) {
            logger.debug("doAnalysisEventsOut: qwd == null");
            return;
        }
// TODO: W in cm at Gauge!!!
        //double gaugeDatum = getCurrentGaugeDatum();
        //boolean atGauge = gaugeDatum != 0d;

        //double factor = atGauge ? 100d : 1d;

        //double w = factor*(qwd.getW()-gaugeDatum);

        // Force empty symbol.
        if (qwd.getInterpolated()) {
            theme = new ThemeDocument(theme); // prevent potential side effects.
            theme.setValue(ThemeDocument.USE_FILL_PAINT, "true");
        }

        XYSeries series = new StyledXYSeries(
            bundle.getFacetDescription(),
            theme,
            qwd.getInterpolated()
                ? ShapeUtils.INTERPOLATED_SHAPE
                : ShapeUtils.MEASURED_SHAPE);

        series.add(qwd.getQ(), qwd.getW());

        generator.addAxisSeries(series, axisName, visible);

        if (visible && theme.parseShowPointLabel()) {

            List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>();

            DateFormat dateFormat = DateFormat.getDateInstance(
                DateFormat.SHORT);
            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
                dateFormat.format(qwd.getDate()),
                qwd.getQ(),
                qwd.getW());
            textAnnos.add(anno);

            RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, theme);
            flysAnno.setTextAnnotations(textAnnos);
            generator.addAnnotations(flysAnno);
        }
    }

    /** Add reference event points to chart. */
    protected void doReferenceEventsOut(
        DiagramGenerator generator,
        ArtifactAndFacet bundle,
        ThemeDocument theme,
        boolean visible) {
        logger.debug("doReferenceEventsOut");

        QWI qwd = (QWI)bundle.getData(generator.getCallContext());
        if (qwd == null) {
            logger.debug("doReferenceEventsOut: qwds == null in " + bundle.getFacetDescription());
            return;
        }

        // Force empty symbol.
        if (qwd.getInterpolated()) {
            theme = new ThemeDocument(theme); // prevent potential side effects.
            theme.setValue(ThemeDocument.USE_FILL_PAINT, "true");
        }

        XYSeries series = new StyledXYSeries(
            bundle.getFacetDescription(),
            false, true, theme,
            qwd.getInterpolated()
                ? ShapeUtils.INTERPOLATED_SHAPE
                : ShapeUtils.MEASURED_SHAPE);

// TODO: W in cm at gauge!!!
        //double gaugeDatum = getCurrentGaugeDatum();
        //boolean atGauge = gaugeDatum != 0d;

        //double factor = atGauge ? 100d : 1d;
        //double w = factor*(qwd.getW()-gaugeDatum);

        series.add(qwd.getQ(), qwd.getW(), false);

        if (visible && theme.parseShowPointLabel()) {
            DateFormat dateFormat = DateFormat.getDateInstance(
                DateFormat.SHORT);

            XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
                dateFormat.format(qwd.getDate()),
                qwd.getQ(),
                qwd.getW());

            List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>();
            textAnnos.add(anno);
            RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, theme);
            flysAnno.setTextAnnotations(textAnnos);
            generator.addAnnotations(flysAnno);
        }

        generator.addAxisSeries(series, axisName, visible);
    }

    protected void doWQCurveOut(
        DiagramGenerator generator,
        ArtifactAndFacet bundle,
        ThemeDocument theme,
        boolean visible
    ) {
        logger.debug("doWQCurveOut");

        FixWQCurveFacet facet = (FixWQCurveFacet)bundle.getFacet();
        FixFunction func = (FixFunction)facet.getData(
                bundle.getArtifact(), generator.getCallContext());

        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(),
                    theme,
                    bundle.getFacetDescription(),
                    500,   // number of samples
                    0.0 ,  // start
                    maxQ); // end

            //TODO: W in cm at gauge!!!
//            double gaugeDatum = getCurrentGaugeDatum();

//            if (gaugeDatum == 0d) {
                generator.addAxisSeries(series, axisName, visible);
//            }
/*            else {
                StyledXYSeries series2 = JFreeUtil.sampleFunction2D(
                        func.getFunction(),
                        doc,
                        aaf.getFacetDescription(),
                        500,   // number of samples
                        0.0 ,  // start
                        maxQ); // end
                addAxisSeries(series2, YAXIS.W.idx, false);
                // Use second axis at cm if at gauge.
                for (int i = 0, N = series.getItemCount(); i < N; i++) {
                    series.updateByIndex(
                        i, new Double(100d*(series.getY(i).doubleValue()-gaugeDatum)));
                }
                addAxisSeries(series, YAXIS.WCm.idx, visible);
            }*/
        }
        else {
            logger.warn("doWQCurveOut: maxQ <= 0");
        }
    }

    protected void doOutlierOut(
        DiagramGenerator generator,
        ArtifactAndFacet bundle,
        ThemeDocument theme,
        boolean visible
    ) {
        logger.debug("doOutlierOut");

        QWI[] qws = (QWI[])bundle.getData(generator.getCallContext());
        if(qws != null) {
            XYSeries series = new StyledXYSeries(
                bundle.getFacetDescription(),
                false, true,
                theme);
            DateFormat dateFormat = DateFormat.getDateInstance(
                DateFormat.SHORT);

            List<XYTextAnnotation> annos = new ArrayList<XYTextAnnotation>();
            //TODO: W in cm at Gauge!!!
            for (QWI qw: qws) {
                series.add(qw.getQ(), qw.getW(), false);

                XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
                        dateFormat.format(qw.getDate()),
                        qw.getQ(),
                        qw.getW());
                annos.add(anno);
            }
            generator.addAxisSeries(series, axisName, visible);

            if (visible && theme != null && theme.parseShowPointLabel()) {
                RiverAnnotation flysAnno =
                        new RiverAnnotation(null, null, null, theme);
                flysAnno.setTextAnnotations(annos);
                generator.addAnnotations(flysAnno);
            }
        }
        else {
            logger.debug("doOutlierOut: qwd == null");
        }
    }

    /** Add markers for q sectors. */
    protected void doQSectorOut(
        DiagramGenerator generator,
        ArtifactAndFacet bundle,
        ThemeDocument theme,
        boolean visible
    ) {
        logger.debug("doQSectorOut");
        if (!visible) {
            return;
        }

        Object qsectorsObj = bundle.getData(generator.getCallContext());
        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 = theme.parseLineStyle();
            int size       = theme.parseLineWidth();
            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 (theme.parseShowLineLabel()) {
                m.setLabel(qsector.getName());
                m.setPaint(theme.parseTextColor());
                m.setLabelFont(theme.parseTextFont());
            }
            Color paint = theme.parseLineColorField();
            if (paint != null) {
                m.setPaint(paint);
            }
            m.setLabelAnchor(RectangleAnchor.TOP_LEFT);
            m.setLabelTextAnchor(TextAnchor.TOP_LEFT);
            m.setLabelOffset(new RectangleInsets(5, 5, 10, 10));
            generator.addDomainMarker(m);
        }
    }

    /**
     * Add W-Annotations to plot.
     * @param wqkms actual data (double[][]).
     * @param theme theme to use.
     */
    protected void doWAnnotations(
        DiagramGenerator generator,
        ArtifactAndFacet bundle,
        ThemeDocument    theme,
        boolean          visible
    ) {
        Object data = bundle.getData(generator.getCallContext());
        List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>();
        if (data instanceof double[][]) {
            logger.debug("Got double[][]");
            double [][] values = (double [][]) data;
            for (int i = 0; i< values[0].length; i++) {
                xy.add(new StickyAxisAnnotation(bundle.getFacetDescription(),
                        (float) values[1][i], StickyAxisAnnotation.SimpleAxis.Y_AXIS));
            }

            if (visible) {
                generator.addAnnotations(
                    new RiverAnnotation(
                        bundle.getFacetDescription(), xy, null, theme));
            }
        }
        else {
            // Assume its WKms.
            logger.debug("Got WKms");
            /* TODO
            WKms wkms = (WKms) data;

            Double ckm =
                (Double) generator.getCallContext().getContextValue(FixChartGenerator.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 RiverAnnotation(facet.getDescription(), xy),
                    aandf, theme, visible);*/
        }
    }

    /**
     * Add WQ Data to plot.
     * @param wqkms data as double[][]
     */
    protected void doWQOut(
        DiagramGenerator generator,
        ArtifactAndFacet bundle,
        ThemeDocument    theme,
        boolean          visible
    ) {
        logger.debug("FixWQCurveGenerator: doWQOut");
        Object data = bundle.getData(generator.getCallContext());
        if (data instanceof WQKms) {
            WQKms wqkms = (WQKms)data;
            // TODO As in doEventsOut, the value-searching should
            // be delivered by the facet already (instead of in the Generator).
            logger.debug("FixWQCurveGenerator: doWQOut: WQKms");
            XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
            // TODO: Remove dependency to FixChartGenerator. 
            Double ckm = (Double) generator.getCallContext().getContextValue(FixChartGenerator.CURRENT_KM);
            if (wqkms == null || wqkms.getKms().length == 0 || ckm == null) {
                logger.info("addPointFromWQKms: No event data to show.");
                return;
            }
            double[] kms = wqkms.getKms();
            // TODO W in cm at gauge!!!
            //double gaugeDatum = getCurrentGaugeDatum();
            //double factor = (gaugeDatum == 0d) ? 1d : 100d;
            for (int i = 0 ; i< kms.length; i++) {
                // TODO: Remove dependency to FixWQCurveGenerator.
                if (Math.abs(kms[i] - ckm) <= FixWQCurveGenerator.EPSILON) {
                    series.add(wqkms.getQ(i), wqkms.getW(i), false);
                    generator.addAxisSeries(series, axisName, visible);
                    if(visible && theme.parseShowPointLabel()) {
                        List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>();
                        XYTextAnnotation anno = new CollisionFreeXYTextAnnotation(
                            bundle.getFacetDescription(),
                            wqkms.getQ(i),
                            wqkms.getW(i));
                        textAnnos.add(anno);
                        RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, theme);
                        flysAnno.setTextAnnotations(textAnnos);
                        generator.addAnnotations(flysAnno);
                    }
                    return;
                }
            }
        }
        else {
            logger.debug("FixWQCurveGenerator: doWQOut: double[][]");
            double [][] values = (double [][]) data;

            XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), false, true, theme);
            StyledSeriesBuilder.addPoints(series, values, true);

            generator.addAxisSeries(series, axisName, visible);
        }
    }

    @Override
    public boolean canHandle(String facettype) {
        return facettype.startsWith(FIX_SECTOR_AVERAGE_WQ)
            || FIX_ANALYSIS_EVENTS_WQ.equals(facettype)
            || FIX_REFERENCE_EVENTS_WQ.equals(facettype)
            || FIX_EVENTS.equals(facettype)
            || FIX_WQ_CURVE.equals(facettype)
            || FIX_OUTLIER.equals(facettype)
            || QSECTOR.equals(facettype)
            || STATIC_WKMS_MARKS.equals(facettype)
            || STATIC_WKMS.equals(facettype)
            || HEIGHTMARKS_POINTS.equals(facettype)
            || LONGITUDINAL_W.equals(facettype)
            || STATIC_WKMS_INTERPOL.equals(facettype)
            || FIX_WQ_LS.equals(facettype);
    }
}

http://dive4elements.wald.intevation.org