view gwt-client/src/main/java/org/dive4elements/river/client/client/ui/chart/DistinctValuesNaviChartStepper.java @ 9263:abf14917be32

Moved stepping behaviour of NaviOutputChart into an exchangeable strategy. Allows for distinct values stepping of sinfo flood duration.
author gernotbelger
date Tue, 17 Jul 2018 19:48:18 +0200
parents
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.client.client.ui.chart;

import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

/**
 * Allows stepping through a list of distinct (known) values.
 *
 * @author Gernot Belger
 */
public class DistinctValuesNaviChartStepper implements INaviChartStepper {

    private final TreeSet<Double> validSteps = new TreeSet<Double>();

    private double currentKm;

    public DistinctValuesNaviChartStepper(final Set<Double> validKms) {
        this.validSteps.addAll(validKms);

        if (this.validSteps.isEmpty())
            this.validSteps.add(-1d);

        this.currentKm = this.validSteps.first();
    }

    @Override
    public double getCurrentKm() {
        return this.currentKm;
    }

    @Override
    public double stepForward() {
        this.currentKm = calculateStepFormward();
        return this.currentKm;
    }

    private double calculateStepFormward() {
        // REMARK: can't use higher due to gwt bug
        // final Double next = this.validSteps.higher(this.currentKm);

        // REMAREK: add a bit, because tailSet is inclusive
        final SortedSet<Double> tailSet = this.validSteps.tailSet(this.currentKm + 1e-6);
        final Double next = tailSet.isEmpty() ? null : tailSet.first();

        if (next != null)
            return next;

        return this.validSteps.last();
    }

    @Override
    public double stepBackward() {
        this.currentKm = calculateStepBackward();
        return this.currentKm;
    }

    private double calculateStepBackward() {
        // REMARK: can't use lower due to gwt bug
        // final Double prev = this.validSteps.lower(this.currentKm);

        final SortedSet<Double> headSet = this.validSteps.headSet(this.currentKm);
        final Double prev = headSet.isEmpty() ? null : headSet.last();

        if (prev != null)
            return prev;

        return this.validSteps.first();
    }

    @Override
    public double setValidCurrentKm(final double currentKm) {
        this.currentKm = calculateValidCurrentKm(currentKm);
        return this.currentKm;
    }

    private double calculateValidCurrentKm(final double newKm) {

        if (this.validSteps.contains(newKm)) {
            /* special case, and because headSet() is not inclusive */
            return newKm;
        }

        final SortedSet<Double> headSet = this.validSteps.headSet(newKm);
        final SortedSet<Double> tailSet = this.validSteps.tailSet(newKm);

        // REMARK: can't use floor/ceiling because of gwt bug
        // final Double floor = this.validSteps.floor(currentKm);
        // final Double ceiling = this.validSteps.ceiling(currentKm);
        final Double floor = headSet.isEmpty() ? null : headSet.last();
        final Double ceiling = tailSet.isEmpty() ? null : tailSet.first();

        if (floor != null && ceiling == null)
            return floor;

        if (floor == null && ceiling != null)
            return ceiling;

        if (floor == null && ceiling == null) {
            /* should never happen as validKms is never empty */
            return this.currentKm;
        }

        if (floor == null || ceiling == null) {
            /* will never happen, but makes the NullPointer access checker happy, else we get warnings in the folowing code */
            return this.currentKm;
        }

        /* both not null; find nearest */
        final double floorDiff = Math.abs(newKm - floor);
        final double ceilingDiff = Math.abs(newKm - ceiling);
        if (floorDiff < ceilingDiff)
            return floor;

        return ceiling;
    }
}

http://dive4elements.wald.intevation.org