X-Git-Url: http://gitweb.fperrin.net/?p=GpsPrune.git;a=blobdiff_plain;f=src%2Ftim%2Fprune%2Fdata%2FAltitudeRange.java;fp=src%2Ftim%2Fprune%2Fdata%2FAltitudeRange.java;h=b4b501b9ec917d6c5554c4b23e8446c06b0742a0;hp=0000000000000000000000000000000000000000;hb=ce6f2161b8596f7018d6a76bff79bc9e571f35fd;hpb=2d8cb72e84d5cc1089ce77baf1e34ea3ea2f8465 diff --git a/src/tim/prune/data/AltitudeRange.java b/src/tim/prune/data/AltitudeRange.java new file mode 100644 index 0000000..b4b501b --- /dev/null +++ b/src/tim/prune/data/AltitudeRange.java @@ -0,0 +1,220 @@ +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(); + /** 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(); + _climb = _descent = 0; + _gotPreviousValue = false; + _previousValue = 0; + _gotPreviousMinimum = _gotPreviousMaximum = false; + _previousExtreme = 0; + } + + + /** + * Add a value to the range + * @param inAltitude value to add, only positive values considered + */ + public void addValue(Altitude inAltitude) + { + final int wiggleLimit = Config.getConfigInt(Config.KEY_ALTITUDE_TOLERANCE) / 100; + + if (inAltitude != null && inAltitude.isValid()) + { + int altValue = (int) inAltitude.getMetricValue(); + _range.addValue(altValue); + // 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 + { + // we haven't got a previous value at all, so it's the start of a new segment + _previousValue = altValue; + _gotPreviousValue = true; + } + } + } + + /** + * 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 altitude range found + */ + public boolean hasRange() + { + return _range.hasValues(); + } + + + /** + * @param inUnit altitude units to use + * @return minimum value + */ + public int getMinimum(Unit inUnit) + { + 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()); + } + + /** + * @param inUnit altitude units to use + * @return total climb + */ + public int getClimb(Unit inUnit) + { + // 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 overall height gain in metres + */ + public double getMetricHeightDiff() + { + return getClimb(UnitSetLibrary.UNITS_METRES) - getDescent(UnitSetLibrary.UNITS_METRES); + } +}