view artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractProcessor.java @ 9617:1d4262a68f1f

#12 Minuend/Subtrahend + MergeConflict #19 CollisionCalculation
author dnt_bjoernsen <d.tironi@bjoernsen.de>
date Thu, 10 Oct 2019 15:29:02 +0200
parents 9b8e8fc1f408
children
line wrap: on
line source
/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
 * Software engineering by
 *  Björnsen Beratende Ingenieure GmbH
 *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
 *
 * This file is Free Software under the GNU AGPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * documentation coming with Dive4Elements River for details.
 */

package org.dive4elements.river.artifacts.common;

import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
import org.dive4elements.artifactdatabase.state.Facet;
import org.dive4elements.artifacts.Artifact;
import org.dive4elements.artifacts.CallContext;
import org.dive4elements.river.artifacts.D4EArtifact;
import org.dive4elements.river.artifacts.access.RiverAccess;
import org.dive4elements.river.artifacts.context.RiverContext;
import org.dive4elements.river.artifacts.math.MovingAverage;
import org.dive4elements.river.artifacts.model.WQKms;
import org.dive4elements.river.artifacts.model.ZoomScale;
import org.dive4elements.river.artifacts.resources.Resources;
import org.dive4elements.river.artifacts.sinfo.common.AbstractTkhCalculationResult;
import org.dive4elements.river.artifacts.states.DefaultState.ComputeType;
import org.dive4elements.river.exports.DiagramGenerator;
import org.dive4elements.river.exports.StyledSeriesBuilder;
import org.dive4elements.river.exports.process.DefaultProcessor;
import org.dive4elements.river.jfree.StyledAreaSeriesCollection;
import org.dive4elements.river.jfree.StyledXYSeries;
import org.dive4elements.river.themes.ThemeDocument;

/**
 * Abstraction for some processor implementation within S-INFO. Probably this abstraction could also be used for other
 * cases as well.
 *
 * @author Gernot Belger
 *
 */

public abstract class AbstractProcessor extends DefaultProcessor {

    protected static final double GAP_DISTANCE = 0.101;

    private final static Logger log = Logger.getLogger(AbstractProcessor.class);

    private String yAxisLabel;

    private final Set<String> handled_facet_types;

    private final String i18n_axis_label;

    public AbstractProcessor(final String i18n_axis_label, final Set<String> handled_facet_types) {
        this.i18n_axis_label = i18n_axis_label;
        this.handled_facet_types = handled_facet_types;
    }

    @Override
    public final void doOut(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) {
        try {
            this.yAxisLabel = generateSeries(generator, bundle, theme, visible);
        }
        catch (final Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    protected static final AbstractCalculationResult getResult(final DiagramGenerator generator, final ArtifactAndFacet bundle) {
        final CallContext context = generator.getContext();
        final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context);
        if (data == null) {
            // Check has been here before so we keep it for security reasons
            // this should never happen though.
            final String facetName = bundle.getFacetName();
            throw new IllegalStateException("Data is null for facet: " + facetName);
        }

        return data;
    }

    /**
     * @return The axis label
     */
    protected abstract String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible);

    protected final String buildSeriesForType(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible,
            final IResultType resultType, final Double gapDistance) {

        final AbstractCalculationResult data = getResult(generator, bundle);

        final double[][] points = data.getStationPoints(resultType);

        return buildSeriesForPoints(points, generator, bundle, theme, visible, gapDistance);
    }

    protected final String buildSeriesForPoints(final double[][] points, final DiagramGenerator generator, final ArtifactAndFacet bundle,
            final ThemeDocument theme, final boolean visible, final Double gapDistance) {
        final CallContext context = generator.getContext();
        final Map<String, String> metaData = bundle.getFacet().getMetaData();

        final Artifact artifact = bundle.getArtifact();

        final String facetDescription = bundle.getFacetDescription();
        final String facetName = bundle.getFacetName();

        final StyledXYSeries series = new StyledXYSeries(facetName, facetDescription, theme);
        series.putMetaData(metaData, artifact, context);

        final double[][] filteredPoints = filterPoints(points, context, artifact, facetName);

        if (gapDistance == null)
            StyledSeriesBuilder.addPoints(series, filteredPoints, true);
        else
            StyledSeriesBuilder.addPoints(series, filteredPoints, true, gapDistance);

        generator.addAxisSeries(series, getAxisName(), visible);

        return metaData.get("Y");
    }

    protected final String buildStepLineSeriesForType(final double[][] points, final DiagramGenerator generator, final ArtifactAndFacet bundle,
            final ThemeDocument theme, final boolean visible) {

        final CallContext context = generator.getContext();
        final Map<String, String> metaData = bundle.getFacet().getMetaData();

        final Artifact artifact = bundle.getArtifact();

        final String facetName = bundle.getFacetName();
        final String facetDescription = bundle.getFacetDescription();

        final StyledXYSeries series = new StyledXYSeries(facetName, facetDescription, theme);
        series.putMetaData(metaData, artifact, context);

        // Create WQKms to use the step points method
        // REMARK: must have any values in w array; not sure whether the name is needed
        final WQKms wqkms = new WQKms(points[0], points[1], points[1], facetName);

        StyledSeriesBuilder.addStepPointsKmQ(series, wqkms);

        generator.addAxisSeries(series, getAxisName(), visible);

        return metaData.get("Y");
    }

    protected final String buildSeriesForTkh(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme,
            final boolean visible) {

        final AbstractTkhCalculationResult data = (AbstractTkhCalculationResult) getResult(generator, bundle);

        final String facetName = bundle.getFacetName();
        final String facetDescription = bundle.getFacetDescription();

        final StyledXYSeries seriesUp = new StyledXYSeries(facetName, facetDescription, theme);
        final double[][] pointsUp = data.getTkhUpPoints();
        StyledSeriesBuilder.addPoints(seriesUp, pointsUp, true);

        // REMARK: we add " " because the description is misused as id, which must be unique.
        final StyledXYSeries seriesDown = new StyledXYSeries(facetName, facetDescription + " ", theme);
        final double[][] pointsDown = data.getTkhDownPoints();
        StyledSeriesBuilder.addPoints(seriesDown, pointsDown, true);

        final StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(facetName, theme);
        area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN);
        area.addSeries(seriesUp);
        area.addSeries(seriesDown);

        generator.addAxisDataset(area, getAxisName(), visible);

        return null;
    }

    private Double findRadius(final CallContext context, final Artifact artifact) {
        final Double start = (Double) context.getContextValue("startkm");
        final Double end = (Double) context.getContextValue("endkm");

        if (start == null || end == null)
            return null;

        final RiverContext fc = (RiverContext) context.globalContext();
        final ZoomScale scales = (ZoomScale) fc.get("zoomscale");
        final RiverAccess access = new RiverAccess((D4EArtifact) artifact);
        final String river = access.getRiverName();

        return scales.getRadius(river, start, end);
    }

    private double[][] filterPoints(final double[][] points, final CallContext context, final Artifact artifact, final String facetName) {

        if (facetName.endsWith(".filtered")) {
            final Double radius = findRadius(context, artifact);
            return movingAverage(radius, points);
        }

        return points;
    }

    private double[][] movingAverage(final Double radius, final double[][] points) {

        if (radius == null)
            return points;

        return MovingAverage.weighted(points, radius);
    }

    @Override
    public final boolean canHandle(final String facettype) {
        return this.handled_facet_types.contains(facettype);
    }

    @Override
    public final String getAxisLabel(final DiagramGenerator generator) {
        if (this.yAxisLabel != null && !this.yAxisLabel.isEmpty()) {
            // REMARK/UNINTENDED: yAxisLabel may also be a resolved message (side-effect of StyledXYSeries#putMetadata),
            // and cannot be resolved, so we need to give the resolved value as default
            // TODO: In other implementations (i.e. FlowVelocityProcessor), an explicit (German) default label is given here,
            // probably the English version will also show German (CHECK)
            return generator.msg(this.yAxisLabel, this.yAxisLabel);
        }
        return generator.msg(this.i18n_axis_label, "MISSING");
    }

    protected static final Facet createFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
            final int resultIndex, final String axisLabel, final String facetId, final String description) {
        final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), description, description, result.getLabel());
        return new ResultFacet(resultIndex, facetId, facetFlowDepthFilteredDescription, axisLabel, ComputeType.ADVANCE, id, hash);
    }

    protected static final Facet createFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result,
            final int resultIndex, final String axisLabel, final String facetId, final String description, final String resultLabel) {
        final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), description, description, resultLabel);
        return new ResultFacet(resultIndex, facetId, facetFlowDepthFilteredDescription, axisLabel, ComputeType.ADVANCE, id, hash);
    }
}

http://dive4elements.wald.intevation.org