]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/data/RangeStats.java
Version 20.4, May 2021
[GpsPrune.git] / src / tim / prune / data / RangeStats.java
1 package tim.prune.data;
2
3 /**
4  * Class to do basic calculations of range statistics such as distances, durations,
5  * and altitude ranges, and to hold the results of the calculations.
6  */
7 public class RangeStats
8 {
9         private int _numPoints   = 0;
10         private int _numSegments = 0;
11         private boolean _foundTrackPoint = false;
12         protected AltitudeRange _totalAltitudeRange = new AltitudeRange();
13         protected AltitudeRange _movingAltitudeRange = new AltitudeRange();
14         private Timestamp _earliestTimestamp = null, _latestTimestamp = null, _movingTimestamp = null;
15         private long _movingMilliseconds = 0L;
16         private boolean _timesIncomplete = false;
17         private boolean _timesOutOfSequence = false;
18         protected double _totalDistanceRads = 0.0, _movingDistanceRads = 0.0;
19         protected DataPoint _prevPoint = null;
20
21
22         /** Constructor */
23         public RangeStats()
24         {}
25
26         /**
27          * Constructor giving Track
28          * @param inTrack track object to calculate with
29          */
30         public RangeStats(Track inTrack, int inStartIndex, int inEndIndex)
31         {
32                 populateFromTrack(inTrack, inStartIndex, inEndIndex);
33         }
34
35         /**
36          * Add the specified points from the given track to the calculations
37          * @param inTrack track object
38          * @param inStartIndex start index (inclusive)
39          * @param inEndIndex end index (inclusive)
40          */
41         protected void populateFromTrack(Track inTrack, int inStartIndex, int inEndIndex)
42         {
43                 for (int i=inStartIndex; i<=inEndIndex; i++)
44                 {
45                         addPoint(inTrack.getPoint(i));
46                 }
47         }
48
49         /**
50          * @param inPoint point to add to the calculations
51          */
52         public void addPoint(DataPoint inPoint)
53         {
54                 if (inPoint == null)
55                 {
56                         return;
57                 }
58                 _numPoints++;
59                 // ignore all waypoints
60                 if (inPoint.isWaypoint()) {
61                         return;
62                 }
63                 if (inPoint.getSegmentStart() || !_foundTrackPoint) {
64                         _numSegments++;
65                 }
66                 _foundTrackPoint = true;
67                 // Get the distance to the previous track point
68                 if (_prevPoint != null)
69                 {
70                         double rads = DataPoint.calculateRadiansBetween(_prevPoint, inPoint);
71                         _totalDistanceRads += rads;
72                         if (!inPoint.getSegmentStart()) {
73                                 _movingDistanceRads += rads;
74                         }
75                 }
76
77                 // timestamps
78                 if (inPoint.getSegmentStart())
79                 {
80                         // reset movingTimestamp for moving time at the start
81                         // of each segment
82                         _movingTimestamp = null;
83                 }
84                 if (inPoint.hasTimestamp())
85                 {
86                         Timestamp currTstamp = inPoint.getTimestamp();
87                         if (_earliestTimestamp == null || currTstamp.isBefore(_earliestTimestamp)) {
88                                 _earliestTimestamp = currTstamp;
89                         }
90                         if (_latestTimestamp == null || currTstamp.isAfter(_latestTimestamp)) {
91                                 _latestTimestamp = currTstamp;
92                         }
93
94                         // Work out duration without segment gaps
95                         if (_movingTimestamp != null)
96                         {
97                                 long millisLater = currTstamp.getMillisecondsSince(_movingTimestamp);
98                                 if (millisLater < 0) {
99                                         _timesOutOfSequence = true;
100                                 }
101                                 else {
102                                         _movingMilliseconds += millisLater;
103                                 }
104                         }
105                         _movingTimestamp = currTstamp;
106                 }
107                 else {
108                         _timesIncomplete = true;
109                 }
110
111                 // altitudes
112                 if (inPoint.hasAltitude())
113                 {
114                         Altitude altitude = inPoint.getAltitude();
115                         _totalAltitudeRange.addValue(altitude);
116                         if (inPoint.getSegmentStart()) {
117                                 _movingAltitudeRange.ignoreValue(altitude);
118                         }
119                         else
120                         {
121                                 _movingAltitudeRange.addValue(altitude);
122                         }
123                 }
124
125                 // allow child classes to do additional calculations
126                 doFurtherCalculations(inPoint);
127
128                 _prevPoint = inPoint;
129         }
130
131         /**
132          * Hook for subclasses to do what they want in addition
133          * @param inPoint incoming point
134          */
135         protected void doFurtherCalculations(DataPoint inPoint)
136         {
137         }
138
139
140         /** @return number of points in range */
141         public int getNumPoints() {
142                 return _numPoints;
143         }
144
145         /** @return number of segments in range */
146         public int getNumSegments() {
147                 return _numSegments;
148         }
149
150         /** @return altitude range of range including segment gaps */
151         public AltitudeRange getTotalAltitudeRange() {
152                 return _totalAltitudeRange;
153         }
154
155         /** @return altitude range of range just within segments */
156         public AltitudeRange getMovingAltitudeRange() {
157                 return _movingAltitudeRange;
158         }
159
160         /** @return the earliest timestamp found */
161         public Timestamp getEarliestTimestamp() {
162                 return _earliestTimestamp;
163         }
164
165         /** @return the latest timestamp found */
166         public Timestamp getLatestTimestamp() {
167                 return _latestTimestamp;
168         }
169
170         /** @return total number of seconds in the range */
171         public long getTotalDurationInSeconds()
172         {
173                 if (_earliestTimestamp != null && _latestTimestamp != null) {
174                         return _latestTimestamp.getSecondsSince(_earliestTimestamp);
175                 }
176                 return 0L;
177         }
178
179         /** @return number of seconds within the segments of the range */
180         public long getMovingDurationInSeconds()
181         {
182                 return _movingMilliseconds / 1000;
183         }
184
185         /** @return true if any timestamps are missing */
186         public boolean getTimestampsIncomplete() {
187                 return _timesIncomplete;
188         }
189
190         /** @return true if any timestamps are out of sequence */
191         public boolean getTimestampsOutOfSequence() {
192                 return _timesOutOfSequence;
193         }
194
195         /** @return total distance in the current distance units (km or mi) */
196         public double getTotalDistance() {
197                 return Distance.convertRadiansToDistance(_totalDistanceRads);
198         }
199
200         /** @return moving distance in the current distance units (km or mi) */
201         public double getMovingDistance() {
202                 return Distance.convertRadiansToDistance(_movingDistanceRads);
203         }
204
205         /** @return moving distance in km */
206         public double getMovingDistanceKilometres() {
207                 return Distance.convertRadiansToDistance(_movingDistanceRads, UnitSetLibrary.UNITS_KILOMETRES);
208         }
209
210         /**
211          * @return the total vertical speed (including segment gaps) in metric units
212          */
213         public double getTotalVerticalSpeed()
214         {
215                 long time = getTotalDurationInSeconds();
216                 if (time > 0 && _totalAltitudeRange.hasRange()) {
217                         return _totalAltitudeRange.getMetricHeightDiff() / time;
218                 }
219                 return 0.0;
220         }
221
222         /**
223          * @return the moving vertical speed (ignoring segment gaps) in metric units
224          */
225         public double getMovingVerticalSpeed()
226         {
227                 long time = getMovingDurationInSeconds();
228                 if (time > 0 && _movingAltitudeRange.hasRange()) {
229                         return _movingAltitudeRange.getMetricHeightDiff() / time;
230                 }
231                 return 0.0;
232         }
233 }