1 package tim.prune.data;
3 import tim.prune.config.Config;
6 * Represents a range of altitudes, taking units into account.
7 * Values assumed to be >= 0.
9 public class AltitudeRange
11 /** Range of altitudes in metres */
12 private IntegerRange _range = new IntegerRange();
13 /** Flag for whether previous value exists or not */
14 private boolean _gotPreviousValue;
15 /** Previous metric value */
16 private int _previousValue;
17 /** Total climb in metres */
19 /** Total descent in metres */
21 /** Flags for whether minimum or maximum has been found */
22 private boolean _gotPreviousMinimum = false, _gotPreviousMaximum = false;
23 /** Integer values of previous minimum and maximum, if any */
24 private int _previousExtreme = 0;
30 public AltitudeRange() {
35 * Clear the altitude range
40 _climb = _descent = 0;
41 _gotPreviousValue = false;
43 _gotPreviousMinimum = _gotPreviousMaximum = false;
49 * Add a value to the range
50 * @param inAltitude value to add, only positive values considered
52 public void addValue(Altitude inAltitude)
54 final int wiggleLimit = Config.getConfigInt(Config.KEY_ALTITUDE_TOLERANCE) / 100;
56 if (inAltitude != null && inAltitude.isValid())
58 int altValue = (int) inAltitude.getMetricValue();
59 _range.addValue(altValue);
60 // Compare with previous value if any
61 if (_gotPreviousValue)
63 if (altValue != _previousValue)
65 // Got an altitude value which is different from the previous one
66 final boolean locallyUp = (altValue > _previousValue);
67 final boolean overallUp = _gotPreviousMinimum && _previousValue > _previousExtreme;
68 final boolean overallDn = _gotPreviousMaximum && _previousValue < _previousExtreme;
69 final boolean moreThanWiggle = Math.abs(altValue - _previousValue) > wiggleLimit;
70 // Do we know whether we're going up or down yet?
71 if (!_gotPreviousMinimum && !_gotPreviousMaximum)
73 // we don't know whether we're going up or down yet - check limit
76 if (locallyUp) {_gotPreviousMinimum = true;}
77 else {_gotPreviousMaximum = true;}
78 _previousExtreme = _previousValue;
79 _previousValue = altValue;
80 _gotPreviousValue = true;
86 // we're still going up - do nothing
87 _previousValue = altValue;
89 else if (moreThanWiggle)
91 // we're going up but have dropped over a maximum
92 // Add the climb from _previousExtreme up to _previousValue
93 _climb += (_previousValue - _previousExtreme);
94 _previousExtreme = _previousValue;
95 _gotPreviousMinimum = false; _gotPreviousMaximum = true;
96 _previousValue = altValue;
97 _gotPreviousValue = true;
105 // we're going down but have climbed up from a minimum
106 // Add the descent from _previousExtreme down to _previousValue
107 _descent += (_previousExtreme - _previousValue);
108 _previousExtreme = _previousValue;
109 _gotPreviousMinimum = true; _gotPreviousMaximum = false;
110 _previousValue = altValue;
111 _gotPreviousValue = true;
115 // we're still going down - do nothing
116 _previousValue = altValue;
117 _gotPreviousValue = true;
120 // TODO: Behaviour when WIGGLE_LIMIT == 0 should be same as before, all differences cumulated
125 // we haven't got a previous value at all, so it's the start of a new segment
126 _previousValue = altValue;
127 _gotPreviousValue = true;
133 * Reset the climb/descent calculations starting from the given value
134 * @param inAltitude altitude value
136 public void ignoreValue(Altitude inAltitude)
138 // Process the previous value, if any, to update climb/descent as that's the end of the previous segment
139 if (_gotPreviousValue && _gotPreviousMinimum && _previousValue > _previousExtreme) {
140 _climb += (_previousValue - _previousExtreme);
142 else if (_gotPreviousValue && _gotPreviousMaximum && _previousValue < _previousExtreme) {
143 _descent += (_previousExtreme - _previousValue);
145 // Eliminate the counting values to start the new segment
146 _gotPreviousMinimum = _gotPreviousMaximum = false;
147 _gotPreviousValue = false;
148 // Now process this value if there is one
149 if (inAltitude != null && inAltitude.isValid())
151 final int altValue = (int) inAltitude.getMetricValue();
152 _range.addValue(altValue);
153 _previousValue = altValue;
154 _gotPreviousValue = true;
159 * @return true if altitude range found
161 public boolean hasRange()
163 return _range.hasValues();
168 * @param inUnit altitude units to use
169 * @return minimum value
171 public int getMinimum(Unit inUnit)
173 return (int) (_range.getMinimum() * inUnit.getMultFactorFromStd());
177 * @param inUnit altitude units to use
178 * @return maximum value
180 public int getMaximum(Unit inUnit)
182 return (int) (_range.getMaximum() * inUnit.getMultFactorFromStd());
186 * @param inUnit altitude units to use
187 * @return total climb
189 public int getClimb(Unit inUnit)
191 // May need to add climb from last segment
192 int lastSegmentClimb = 0;
193 if (_gotPreviousValue && _gotPreviousMinimum && _previousValue > _previousExtreme) {
194 lastSegmentClimb = _previousValue - _previousExtreme;
196 return (int) ((_climb + lastSegmentClimb) * inUnit.getMultFactorFromStd());
200 * @param inUnit altitude units to use
201 * @return total descent
203 public int getDescent(Unit inUnit)
205 // May need to add descent from last segment
206 int lastSegmentDescent = 0;
207 if (_gotPreviousValue && _gotPreviousMaximum && _previousValue < _previousExtreme) {
208 lastSegmentDescent = _previousExtreme - _previousValue;
210 return (int) ((_descent + lastSegmentDescent) * inUnit.getMultFactorFromStd());
214 * @return overall height gain in metres
216 public double getMetricHeightDiff()
218 return getClimb(UnitSetLibrary.UNITS_METRES) - getDescent(UnitSetLibrary.UNITS_METRES);