Mercurial > dive4elements > river
diff artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/LinearInterpolator.java @ 8964:45f1ad66560e
Code cleanup concerning calculations: improved error handling; improved interpolation; bed heights are now always used for spatial discretisation
author | gernotbelger |
---|---|
date | Thu, 29 Mar 2018 15:48:17 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/LinearInterpolator.java Thu Mar 29 15:48:17 2018 +0200 @@ -0,0 +1,77 @@ +/** 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.sinfo.util; + +import java.util.Map.Entry; +import java.util.NavigableMap; +import java.util.TreeMap; + +import org.dive4elements.river.artifacts.math.Linear; +import org.dive4elements.river.artifacts.model.Calculation; + +import gnu.trove.TDoubleArrayList; + +/** + * Helper for interpolating values from a piecewise linear function defined by discrete values. + * + * @author Gernot Belger + */ +public final class LinearInterpolator { + + private final NavigableMap<Double, Double> data; + private final double maxDistance; + + private Calculation problems; + + public static LinearInterpolator create(final Calculation problems, final TDoubleArrayList xs, final TDoubleArrayList ys, final double maxDistance) { + if (xs.size() != ys.size()) + throw new IllegalArgumentException("Array sizes must be equal"); + + if (xs.size() < 2) + throw new IllegalArgumentException("Array must have at least 2 values"); + + final NavigableMap<Double, Double> data = new TreeMap<>(); + + for (int i = 0; i < xs.size(); i++) { + final double x = xs.getQuick(i); + final double y = ys.getQuick(i); + data.put(x, y); + } + + return new LinearInterpolator(problems, data, maxDistance); + } + + private LinearInterpolator(final Calculation problems, final NavigableMap<Double, Double> data, final double maxDistance) { + this.problems = problems; + this.data = data; + this.maxDistance = maxDistance; + } + + public double value(final double value) { + + final Entry<Double, Double> floorEntry = this.data.floorEntry(value); + final Entry<Double, Double> ceilingEntry = this.data.ceilingEntry(value); + + if (floorEntry == null || ceilingEntry == null) + return Double.NaN; + + final double floorKey = floorEntry.getKey(); + final double floorValue = floorEntry.getValue(); + final double ceilingKey = ceilingEntry.getKey(); + final double ceilingValue = ceilingEntry.getValue(); + + if (Math.abs(floorKey - ceilingKey) > this.maxDistance && this.problems != null) { + this.problems.addProblem(value, "linearInterpolator.maxdistance", this.maxDistance * 1000); + this.problems = null; + } + + return Linear.linear(value, floorKey, ceilingKey, floorValue, ceilingValue); + } +} \ No newline at end of file