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;
132 // if (altValue > _previousValue)
133 // _climb += (altValue - _previousValue);
135 // _descent += (_previousValue - altValue);
137 // _previousValue = altValue;
143 * Reset the climb/descent calculations starting from the given value
144 * @param inAltitude altitude value
146 public void ignoreValue(Altitude inAltitude)
148 // Process the previous value, if any, to update climb/descent as that's the end of the previous segment
149 if (_gotPreviousValue && _gotPreviousMinimum && _previousValue > _previousExtreme) {
150 _climb += (_previousValue - _previousExtreme);
152 else if (_gotPreviousValue && _gotPreviousMaximum && _previousValue < _previousExtreme) {
153 _descent += (_previousExtreme - _previousValue);
155 // Eliminate the counting values to start the new segment
156 _gotPreviousMinimum = _gotPreviousMaximum = false;
157 _gotPreviousValue = false;
158 // Now process this value if there is one
159 if (inAltitude != null && inAltitude.isValid())
161 final int altValue = (int) inAltitude.getMetricValue();
162 _range.addValue(altValue);
163 _previousValue = altValue;
164 _gotPreviousValue = true;
169 * @return true if altitude range found
171 public boolean hasRange()
173 return _range.getMaximum() > _range.getMinimum();
178 * @param inUnit altitude units to use
179 * @return minimum value, or -1 if none found
181 public int getMinimum(Unit inUnit)
183 if (_range.getMinimum() <= 0) return _range.getMinimum();
184 return (int) (_range.getMinimum() * inUnit.getMultFactorFromStd());
188 * @param inUnit altitude units to use
189 * @return maximum value, or -1 if none found
191 public int getMaximum(Unit inUnit)
193 if (_range.getMaximum() <= 0) return _range.getMaximum();
194 return (int) (_range.getMaximum() * inUnit.getMultFactorFromStd());
198 * @param inUnit altitude units to use
199 * @return total climb
201 public int getClimb(Unit inUnit)
203 // May need to add climb from last segment
204 int lastSegmentClimb = 0;
205 if (_gotPreviousValue && _gotPreviousMinimum && _previousValue > _previousExtreme) {
206 lastSegmentClimb = _previousValue - _previousExtreme;
208 return (int) ((_climb + lastSegmentClimb) * inUnit.getMultFactorFromStd());
212 * @param inUnit altitude units to use
213 * @return total descent
215 public int getDescent(Unit inUnit)
217 // May need to add descent from last segment
218 int lastSegmentDescent = 0;
219 if (_gotPreviousValue && _gotPreviousMaximum && _previousValue < _previousExtreme) {
220 lastSegmentDescent = _previousExtreme - _previousValue;
222 return (int) ((_descent + lastSegmentDescent) * inUnit.getMultFactorFromStd());
226 * @return overall height gain in metres
228 public double getMetricHeightDiff()
230 return getClimb(UnitSetLibrary.UNITS_METRES) - getDescent(UnitSetLibrary.UNITS_METRES);