X-Git-Url: https://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fdata%2FAltitudeRange.java;h=6a9f65fb1d5fdaf087d118e686fd4991fe0f5c75;hb=92dad5df664287acb51728e9ea599f150765d34a;hp=6c7e5d55a286c1c0715227cc4a1a7204a9a164d2;hpb=d3679d647d57c2ee7376ddbf6def2d5b23c04307;p=GpsPrune.git diff --git a/tim/prune/data/AltitudeRange.java b/tim/prune/data/AltitudeRange.java index 6c7e5d5..6a9f65f 100644 --- a/tim/prune/data/AltitudeRange.java +++ b/tim/prune/data/AltitudeRange.java @@ -1,75 +1,230 @@ package tim.prune.data; +import tim.prune.config.Config; + /** * Represents a range of altitudes, taking units into account. * Values assumed to be >= 0. */ public class AltitudeRange { + /** Range of altitudes in metres */ private IntegerRange _range = new IntegerRange(); - private int _format = Altitude.FORMAT_NONE; + /** Flag for whether previous value exists or not */ + private boolean _gotPreviousValue; + /** Previous metric value */ + private int _previousValue; + /** Total climb in metres */ + private int _climb; + /** Total descent in metres */ + private int _descent; + /** Flags for whether minimum or maximum has been found */ + private boolean _gotPreviousMinimum = false, _gotPreviousMaximum = false; + /** Integer values of previous minimum and maximum, if any */ + private int _previousExtreme = 0; + /** + * Constructor + */ + public AltitudeRange() { + clear(); + } + /** * Clear the altitude range */ public void clear() { _range.clear(); - _format = Altitude.FORMAT_NONE; + _climb = _descent = 0; + _gotPreviousValue = false; + _previousValue = 0; + _gotPreviousMinimum = _gotPreviousMaximum = false; + _previousExtreme = 0; } /** * Add a value to the range - * @param inValue value to add, only positive values considered + * @param inAltitude value to add, only positive values considered */ public void addValue(Altitude inAltitude) { - if (inAltitude != null) + final int wiggleLimit = Config.getConfigInt(Config.KEY_ALTITUDE_TOLERANCE) / 100; + + if (inAltitude != null && inAltitude.isValid()) { - int altValue = inAltitude.getValue(_format); + int altValue = (int) inAltitude.getMetricValue(); _range.addValue(altValue); - if (_format == Altitude.FORMAT_NONE) + // Compare with previous value if any + if (_gotPreviousValue) + { + if (altValue != _previousValue) + { + // Got an altitude value which is different from the previous one + final boolean locallyUp = (altValue > _previousValue); + final boolean overallUp = _gotPreviousMinimum && _previousValue > _previousExtreme; + final boolean overallDn = _gotPreviousMaximum && _previousValue < _previousExtreme; + final boolean moreThanWiggle = Math.abs(altValue - _previousValue) > wiggleLimit; + // Do we know whether we're going up or down yet? + if (!_gotPreviousMinimum && !_gotPreviousMaximum) + { + // we don't know whether we're going up or down yet - check limit + if (moreThanWiggle) + { + if (locallyUp) {_gotPreviousMinimum = true;} + else {_gotPreviousMaximum = true;} + _previousExtreme = _previousValue; + _previousValue = altValue; + _gotPreviousValue = true; + } + } + else if (overallUp) + { + if (locallyUp) { + // we're still going up - do nothing + _previousValue = altValue; + } + else if (moreThanWiggle) + { + // we're going up but have dropped over a maximum + // Add the climb from _previousExtreme up to _previousValue + _climb += (_previousValue - _previousExtreme); + _previousExtreme = _previousValue; + _gotPreviousMinimum = false; _gotPreviousMaximum = true; + _previousValue = altValue; + _gotPreviousValue = true; + } + } + else if (overallDn) + { + if (locallyUp) { + if (moreThanWiggle) + { + // we're going down but have climbed up from a minimum + // Add the descent from _previousExtreme down to _previousValue + _descent += (_previousExtreme - _previousValue); + _previousExtreme = _previousValue; + _gotPreviousMinimum = true; _gotPreviousMaximum = false; + _previousValue = altValue; + _gotPreviousValue = true; + } + } + else { + // we're still going down - do nothing + _previousValue = altValue; + _gotPreviousValue = true; + } + } + // TODO: Behaviour when WIGGLE_LIMIT == 0 should be same as before, all differences cumulated + } + } + else { - _format = inAltitude.getFormat(); + // we haven't got a previous value at all, so it's the start of a new segment + _previousValue = altValue; + _gotPreviousValue = true; } + +// if (!_empty) +// { +// if (altValue > _previousValue) +// _climb += (altValue - _previousValue); +// else +// _descent += (_previousValue - altValue); +// } +// _previousValue = altValue; +// _empty = false; } } + /** + * Reset the climb/descent calculations starting from the given value + * @param inAltitude altitude value + */ + public void ignoreValue(Altitude inAltitude) + { + // Process the previous value, if any, to update climb/descent as that's the end of the previous segment + if (_gotPreviousValue && _gotPreviousMinimum && _previousValue > _previousExtreme) { + _climb += (_previousValue - _previousExtreme); + } + else if (_gotPreviousValue && _gotPreviousMaximum && _previousValue < _previousExtreme) { + _descent += (_previousExtreme - _previousValue); + } + // Eliminate the counting values to start the new segment + _gotPreviousMinimum = _gotPreviousMaximum = false; + _gotPreviousValue = false; + // Now process this value if there is one + if (inAltitude != null && inAltitude.isValid()) + { + final int altValue = (int) inAltitude.getMetricValue(); + _range.addValue(altValue); + _previousValue = altValue; + _gotPreviousValue = true; + } + } /** - * @return true if positive data values were found + * @return true if altitude range found */ - public boolean hasData() + public boolean hasRange() { - return (_range.hasData()); + return _range.hasValues(); } /** - * @return minimum value, or -1 if none found + * @param inUnit altitude units to use + * @return minimum value */ - public int getMinimum() + public int getMinimum(Unit inUnit) { - return _range.getMinimum(); + return (int) (_range.getMinimum() * inUnit.getMultFactorFromStd()); } + /** + * @param inUnit altitude units to use + * @return maximum value + */ + public int getMaximum(Unit inUnit) + { + return (int) (_range.getMaximum() * inUnit.getMultFactorFromStd()); + } /** - * @return maximum value, or -1 if none found + * @param inUnit altitude units to use + * @return total climb */ - public int getMaximum() + public int getClimb(Unit inUnit) { - return _range.getMaximum(); + // May need to add climb from last segment + int lastSegmentClimb = 0; + if (_gotPreviousValue && _gotPreviousMinimum && _previousValue > _previousExtreme) { + lastSegmentClimb = _previousValue - _previousExtreme; + } + return (int) ((_climb + lastSegmentClimb) * inUnit.getMultFactorFromStd()); } + /** + * @param inUnit altitude units to use + * @return total descent + */ + public int getDescent(Unit inUnit) + { + // May need to add descent from last segment + int lastSegmentDescent = 0; + if (_gotPreviousValue && _gotPreviousMaximum && _previousValue < _previousExtreme) { + lastSegmentDescent = _previousExtreme - _previousValue; + } + return (int) ((_descent + lastSegmentDescent) * inUnit.getMultFactorFromStd()); + } /** - * @return the altitude format used + * @return overall height gain in metres */ - public int getFormat() + public double getMetricHeightDiff() { - return _format; + return getClimb(UnitSetLibrary.UNITS_METRES) - getDescent(UnitSetLibrary.UNITS_METRES); } }