view artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.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 3f0803009a8f
children
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
 * Software engineering by Intevation GmbH
 *
 * 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.exports;

import org.apache.log4j.Logger;
import org.dive4elements.river.artifacts.model.WKms;
import org.dive4elements.river.artifacts.model.WQKms;
import org.dive4elements.river.artifacts.model.WWQQ;
import org.jfree.data.xy.XYSeries;

/**
 * Helper to create and modify StyledXYSeries.
 */
public class StyledSeriesBuilder {

    /**
     * JFreeChart and the area calculation will fail if we use Double.INFINITY
     * or Double.MAX_VALUE (probably because these are really used in
     * calculations). We define and use a more handy value instead.
     */
    final static double BIG_DOUBLE_VALUE = 1234567d;

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

    /**
     * Trivial, hidden constructor.
     */
    private StyledSeriesBuilder() {
    }

    /**
     * Add points to series, create gaps if certain distance
     * between points is met.
     *
     * @param series
     *            Series to add points to.
     * @param points
     *            Points to add to series, points[0] to 1st dim, points[1]
     *            to 2nd dim.
     * @param skipNANs
     *            if true, skip NAN values in points parameter. Otherwise,
     *            the NaNs lead to gaps in graph.
     * @param distance
     *            if two consecutive entries in points[0] are more
     *            than distance apart, create a NaN value to skip
     *            in display.
     */
    public static void addPoints(final XYSeries series, final double[][] points, final boolean skipNANs, final double distance) {
        if (points == null || points.length <= 1) {
            return;
        }
        final double[] xPoints = points[0];
        final double[] yPoints = points[1];

        Integer lastNonNaNIndex = null;

        for (int i = 0; i < xPoints.length; i++) {
            if (skipNANs && (Double.isNaN(xPoints[i]) || Double.isNaN(yPoints[i]))) {
                continue;
            }

            // Create gap if distance between points > distance.
            if (i > 0 && lastNonNaNIndex != null) {
                final double distanceToLastNonNan = Math.abs(xPoints[lastNonNaNIndex] - xPoints[i]);
                if (distanceToLastNonNan > distance && !Double.isNaN(yPoints[lastNonNaNIndex]) && !Double.isNaN(yPoints[i]))
                    series.add((xPoints[i - 1] + xPoints[i]) / 2, Double.NaN, false);
            }
            series.add(xPoints[i], yPoints[i], false);

            // if (skipNANs && !Double.isNaN(xPoints[i]) && !Double.isNaN(yPoints[i]))
            if (!Double.isNaN(xPoints[i]) && !Double.isNaN(yPoints[i])) // skipNaN-State irrelevant, since lastNonNaNIndex is used for interpolation
                                                                        // after gap-distance-comparison
                lastNonNaNIndex = i;
        }
    }

    /**
     * Add points to series.
     *
     * @param series
     *            Series to add points to.
     * @param points
     *            Points to add to series, points[0] to 1st dim, points[1]
     *            to 2nd dim.
     * @param skipNANs
     *            if true, skip NAN values in points parameter.
     * @param transY
     *            translate y-values by this value (before scale).
     * @param factorY
     *            scale y-values by this value (after translation).
     */
    public static void addPoints(final XYSeries series, final double[][] points, final boolean skipNANs, final double transY, final double factorY) {
        if (transY == 0d && factorY == 1d) {
            addPoints(series, points, skipNANs);
            return;
        }
        if (points == null || points.length <= 1) {
            return;
        }
        final double[] xPoints = points[0];
        final double[] yPoints = points[1];
        for (int i = 0; i < xPoints.length; i++) {
            if (skipNANs && (Double.isNaN(xPoints[i]) || Double.isNaN(yPoints[i]))) {
                continue;
            }
            series.add(xPoints[i], factorY * (transY + yPoints[i]), false);
        }
    }

    /**
     * Add points to series.
     *
     * @param series
     *            Series to add points to.
     * @param points
     *            Points to add to series, points[0] to 1st dim, points[1]
     *            to 2nd dim.
     * @param skipNANs
     *            if true, skip NAN values in points parameter.
     */
    public static void addPoints(final XYSeries series, final double[][] points, final boolean skipNANs) {
        if (points == null || points.length <= 1) {
            return;
        }
        final double[] xPoints = points[0];
        final double[] yPoints = points[1];
        for (int i = 0; i < xPoints.length; i++) {
            if (skipNANs && (Double.isNaN(xPoints[i]) || Double.isNaN(yPoints[i]))) {
                continue;
            }
            series.add(xPoints[i], yPoints[i], false);
        }
    }

    /**
     * Add points to series (km to 1st dim, w to 2nd dim).
     *
     * @param series
     *            Series to add points to.
     * @param wkms
     *            WKms to add to series.
     */
    public static void addPoints(final XYSeries series, final WKms wkms) {
        if (wkms == null) {
            return;
        }

        final int size = wkms.size();

        for (int i = 0; i < size; i++) {
            series.add(wkms.getKm(i), wkms.getW(i), false);
        }
    }

    /**
     * Add points to dataset with an offset (shift all points by given amount).
     *
     * @param series
     *            series to add data to.
     * @param wkms
     *            WKms of which the Ws will be shifted.
     * @param off
     *            the offset.
     */
    public static void addUpperBand(final XYSeries series, final WKms wkms, final double off) {
        if (wkms == null) {
            return;
        }

        final int size = wkms.size();

        for (int i = 0; i < size; i++) {
            series.add(wkms.getKm(i), wkms.getW(i) + off, false);
        }
    }

    /**
     * Add points to dataset with an offset (shift all points 'down' by given
     * amount).
     *
     * @param series
     *            series to add data to.
     * @param wkms
     *            WKms of which the Ws will be shifted.
     * @param off
     *            the offset.
     */
    public static void addLowerBand(final XYSeries series, final WKms wkms, final double off) {
        addUpperBand(series, wkms, -off);
    }

    /**
     * Add points to series (km to 1st dim, q to 2nd dim).
     *
     * @param series
     *            Series to add points to.
     * @param wqkms
     *            WQKms to add to series.
     */
    public static void addPointsKmQ(final XYSeries series, final WQKms wqkms) {
        if (wqkms == null) {
            return;
        }

        final int size = wqkms.size();

        for (int i = 0; i < size; i++) {
            series.add(wqkms.getKm(i), wqkms.getQ(i), false);
        }
    }

    /**
     * Add points to series (km to 1st dim, q to 2nd dim), adding points
     * to achieve a step-like curve.
     *
     * @param series
     *            Series to add points to.
     * @param wqkms
     *            WQKms to add to series.
     */
    public static void addStepPointsKmQ(final XYSeries series, final WQKms wqkms) {
        if (wqkms == null) {
            return;
        }

        final int size = wqkms.size();

        for (int i = 0; i < size; i++) {
            if (i == 0) {
                series.add(wqkms.getKm(i), wqkms.getQ(i), false);
            } else if (i == size - 1) {
                series.add(wqkms.getKm(i), wqkms.getQ(i), false);
            } else {
                // Add two points.
                double prevX;
                double prevQ;
                if (wqkms.getKm(i + 1) < wqkms.getKm(i)) {
                    /*
                     * Depending on the data direction the previous km / q
                     * might have a larger index when we draw
                     * right to left data.
                     */
                    prevX = wqkms.getKm(i + 1);
                    prevQ = wqkms.getQ(i + 1);
                } else {
                    prevX = wqkms.getKm(i - 1);
                    prevQ = wqkms.getQ(i - 1);
                }
                final double halveX = (prevX + wqkms.getKm(i)) / 2d;
                series.add(halveX, prevQ, false);
                series.add(halveX, wqkms.getQ(i), false);
            }
        }
    }

    /**
     * Add points to series (q to 1st dim, w to 2nd dim).
     *
     * @param series
     *            Series to add points to.
     * @param wqkms
     *            WQKms to add to series.
     */
    public static void addPointsQW(final XYSeries series, final WQKms wqkms) {
        if (wqkms == null) {
            return;
        }

        final int size = wqkms.size();

        for (int i = 0; i < size; i++) {
            series.add(wqkms.getQ(i), wqkms.getW(i), false);
        }
    }

    /**
     * Add points to series (q to 1st dim, w to 2nd dim), adding wTrans to the
     * W values and scaling it with wScale.
     *
     * @param series
     *            Series to add points to.
     * @param qws
     *            to add to series.
     * @param wAdd
     *            Value to add to each Q while adding to series.
     * @param wScale
     *            multiply with
     */
    public static void addPointsQW(final XYSeries series, final double[][] qws, final double wTrans, final double wScale) {
        if (qws == null || qws.length == 0) {
            return;
        }

        final double x[] = qws[0];
        final double y[] = qws[1];

        for (int i = 0; i < x.length; i++) {
            series.add(x[i], wScale * (y[i] + wTrans), false);
        }
    }

    /**
     * Add points to series (q to 1st dim, w to 2nd dim), adding wTrans to the
     * W values and scaling it with wScale.
     *
     * @param series
     *            Series to add points to.
     * @param wqkms
     *            WQKms to add to series.
     * @param wAdd
     *            Value to add to each Q while adding to series.
     * @param wScale
     *            multiply with
     */
    public static void addPointsQW(final XYSeries series, final WQKms wqkms, final double wTrans, final double wScale) {
        if (wqkms == null) {
            return;
        }

        final int size = wqkms.size();

        for (int i = 0; i < size; i++) {
            series.add(wqkms.getQ(i), wScale * (wqkms.getW(i) + wTrans), false);
        }
    }

    /**
     * Add points to series (q to 1st dim, w to 2nd dim).
     *
     * @param series
     *            Series to add points to.
     * @param qs
     *            the Qs to add, assumed same length than ws.
     * @param ws
     *            the Ws to add, assumed same length than qs.
     */
    public static void addPointsQW(final XYSeries series, final double[] qs, final double ws[]) {
        if (ws == null || qs == null) {
            return;
        }

        final int size = qs.length;

        for (int i = 0; i < size; i++) {
            series.add(qs[i], ws[i], false);
        }
    }

    /**
     * Add points to series (q to 1st dim, w to 2nd dim), with
     * scaling and translation.
     *
     * @param series
     *            Series to add points to.
     * @param qs
     *            the Qs to add, assumed same length than ws.
     * @param ws
     *            the Ws to add, assumed same length than qs.
     */
    public static void addPointsQW(final XYSeries series, final double[] qs, final double ws[], final double wTrans, final double wScale) {
        if (ws == null || qs == null) {
            return;
        }

        final int size = qs.length;

        for (int i = 0; i < size; i++) {
            series.add(qs[i], wScale * (ws[i] + wTrans), false);
        }
    }

    /**
     * Add points to series (q to 1st dim, w to 2nd dim).
     *
     * @param series
     *            Series to add points to.
     * @param wwqq
     *            WWQQ to add to series.
     */
    public static void addPoints(final XYSeries series, final WWQQ wwqq) {
        if (wwqq == null) {
            return;
        }

        final int size = wwqq.size();

        for (int i = 0; i < size; i++) {
            series.add(wwqq.getW1(i), wwqq.getW2(i), false);
        }
    }

    /**
     * Create a Series such that an infinitely big area can be filled
     * between the newly created and the given series.
     */
    public static XYSeries createGroundAtInfinity(final XYSeries series) {
        final XYSeries ground = new XYSeries(series.getKey() + /** TODO rand + */
                "INF");
        ground.add(series.getMinX(), -BIG_DOUBLE_VALUE);
        ground.add(series.getMaxX(), -BIG_DOUBLE_VALUE);
        return ground;
    }

    /**
     * Create a Series such that an infinitely big area can be filled
     * between the newly created and the given series.
     */
    public static XYSeries createCeilingAtInfinity(final XYSeries series) {
        final XYSeries ground = new XYSeries(series.getKey() + /** TODO rand + */
                "INF");
        ground.add(series.getMinX(), BIG_DOUBLE_VALUE);
        ground.add(series.getMaxX(), BIG_DOUBLE_VALUE);
        return ground;
    }

    /** Checks if a given value is the BIG_DOUBLE_VALUE */
    public static boolean isBigDoubleValue(final Number value) {
        if (value == null)
            return false;

        return Math.abs(BIG_DOUBLE_VALUE - Math.abs(value.doubleValue())) < 0.1;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org