]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/data/AltitudeRange.java
Version 19.2, December 2018
[GpsPrune.git] / tim / prune / data / AltitudeRange.java
1 package tim.prune.data;
2
3 import tim.prune.config.Config;
4
5 /**
6  * Represents a range of altitudes, taking units into account.
7  * Values assumed to be >= 0.
8  */
9 public class AltitudeRange
10 {
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 */
18         private int _climb;
19         /** Total descent in metres */
20         private int _descent;
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;
25
26
27         /**
28          * Constructor
29          */
30         public AltitudeRange() {
31                 clear();
32         }
33
34         /**
35          * Clear the altitude range
36          */
37         public void clear()
38         {
39                 _range.clear();
40                 _climb = _descent = 0;
41                 _gotPreviousValue = false;
42                 _previousValue = 0;
43                 _gotPreviousMinimum = _gotPreviousMaximum = false;
44                 _previousExtreme = 0;
45         }
46
47
48         /**
49          * Add a value to the range
50          * @param inAltitude value to add, only positive values considered
51          */
52         public void addValue(Altitude inAltitude)
53         {
54                 final int wiggleLimit = Config.getConfigInt(Config.KEY_ALTITUDE_TOLERANCE) / 100;
55
56                 if (inAltitude != null && inAltitude.isValid())
57                 {
58                         int altValue = (int) inAltitude.getMetricValue();
59                         _range.addValue(altValue);
60                         // Compare with previous value if any
61                         if (_gotPreviousValue)
62                         {
63                                 if (altValue != _previousValue)
64                                 {
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)
72                                         {
73                                                 // we don't know whether we're going up or down yet - check limit
74                                                 if (moreThanWiggle)
75                                                 {
76                                                         if (locallyUp) {_gotPreviousMinimum = true;}
77                                                         else {_gotPreviousMaximum = true;}
78                                                         _previousExtreme = _previousValue;
79                                                         _previousValue = altValue;
80                                                         _gotPreviousValue = true;
81                                                 }
82                                         }
83                                         else if (overallUp)
84                                         {
85                                                 if (locallyUp) {
86                                                         // we're still going up - do nothing
87                                                         _previousValue = altValue;
88                                                 }
89                                                 else if (moreThanWiggle)
90                                                 {
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;
98                                                 }
99                                         }
100                                         else if (overallDn)
101                                         {
102                                                 if (locallyUp) {
103                                                         if (moreThanWiggle)
104                                                         {
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;
112                                                         }
113                                                 }
114                                                 else {
115                                                         // we're still going down - do nothing
116                                                         _previousValue = altValue;
117                                                         _gotPreviousValue = true;
118                                                 }
119                                         }
120                                         // TODO: Behaviour when WIGGLE_LIMIT == 0 should be same as before, all differences cumulated
121                                 }
122                         }
123                         else
124                         {
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;
128                         }
129                 }
130         }
131
132         /**
133          * Reset the climb/descent calculations starting from the given value
134          * @param inAltitude altitude value
135          */
136         public void ignoreValue(Altitude inAltitude)
137         {
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);
141                 }
142                 else if (_gotPreviousValue && _gotPreviousMaximum && _previousValue < _previousExtreme) {
143                         _descent += (_previousExtreme - _previousValue);
144                 }
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())
150                 {
151                         final int altValue = (int) inAltitude.getMetricValue();
152                         _range.addValue(altValue);
153                         _previousValue = altValue;
154                         _gotPreviousValue = true;
155                 }
156         }
157
158         /**
159          * @return true if altitude range found
160          */
161         public boolean hasRange()
162         {
163                 return _range.hasValues();
164         }
165
166
167         /**
168          * @param inUnit altitude units to use
169          * @return minimum value
170          */
171         public int getMinimum(Unit inUnit)
172         {
173                 return (int) (_range.getMinimum() * inUnit.getMultFactorFromStd());
174         }
175
176         /**
177          * @param inUnit altitude units to use
178          * @return maximum value
179          */
180         public int getMaximum(Unit inUnit)
181         {
182                 return (int) (_range.getMaximum() * inUnit.getMultFactorFromStd());
183         }
184
185         /**
186          * @param inUnit altitude units to use
187          * @return total climb
188          */
189         public int getClimb(Unit inUnit)
190         {
191                 // May need to add climb from last segment
192                 int lastSegmentClimb = 0;
193                 if (_gotPreviousValue && _gotPreviousMinimum && _previousValue > _previousExtreme) {
194                         lastSegmentClimb = _previousValue - _previousExtreme;
195                 }
196                 return (int) ((_climb + lastSegmentClimb) * inUnit.getMultFactorFromStd());
197         }
198
199         /**
200          * @param inUnit altitude units to use
201          * @return total descent
202          */
203         public int getDescent(Unit inUnit)
204         {
205                 // May need to add descent from last segment
206                 int lastSegmentDescent = 0;
207                 if (_gotPreviousValue && _gotPreviousMaximum && _previousValue < _previousExtreme) {
208                         lastSegmentDescent = _previousExtreme - _previousValue;
209                 }
210                 return (int) ((_descent + lastSegmentDescent) * inUnit.getMultFactorFromStd());
211         }
212
213         /**
214          * @return overall height gain in metres
215          */
216         public double getMetricHeightDiff()
217         {
218                 return getClimb(UnitSetLibrary.UNITS_METRES) - getDescent(UnitSetLibrary.UNITS_METRES);
219         }
220 }