]> 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;
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.hasTimestamp())
79                 {
80                         Timestamp currTstamp = inPoint.getTimestamp();
81                         if (_earliestTimestamp == null || currTstamp.isBefore(_earliestTimestamp)) {
82                                 _earliestTimestamp = currTstamp;
83                         }
84                         if (_latestTimestamp == null || currTstamp.isAfter(_latestTimestamp)) {
85                                 _latestTimestamp = currTstamp;
86                         }
87                         // Work out duration without segment gaps
88                         if (!inPoint.getSegmentStart() && _prevPoint != null && _prevPoint.hasTimestamp())
89                         {
90                                 long millisLater = currTstamp.getMillisecondsSince(_prevPoint.getTimestamp());
91                                 if (millisLater < 0) {
92                                         _timesOutOfSequence = true;
93                                 }
94                                 else {
95                                         _movingMilliseconds += millisLater;
96                                 }
97                         }
98                 }
99                 else {
100                         _timesIncomplete = true;
101                 }
102
103                 // altitudes
104                 if (inPoint.hasAltitude())
105                 {
106                         Altitude altitude = inPoint.getAltitude();
107                         _totalAltitudeRange.addValue(altitude);
108                         if (inPoint.getSegmentStart()) {
109                                 _movingAltitudeRange.ignoreValue(altitude);
110                         }
111                         else
112                         {
113                                 _movingAltitudeRange.addValue(altitude);
114                         }
115                 }
116
117                 // allow child classes to do additional calculations
118                 doFurtherCalculations(inPoint);
119
120                 _prevPoint = inPoint;
121         }
122
123         /**
124          * Hook for subclasses to do what they want in addition
125          * @param inPoint incoming point
126          */
127         protected void doFurtherCalculations(DataPoint inPoint)
128         {
129         }
130
131
132         /** @return number of points in range */
133         public int getNumPoints() {
134                 return _numPoints;
135         }
136
137         /** @return number of segments in range */
138         public int getNumSegments() {
139                 return _numSegments;
140         }
141
142         /** @return altitude range of range including segment gaps */
143         public AltitudeRange getTotalAltitudeRange() {
144                 return _totalAltitudeRange;
145         }
146
147         /** @return altitude range of range just within segments */
148         public AltitudeRange getMovingAltitudeRange() {
149                 return _movingAltitudeRange;
150         }
151
152         /** @return the earliest timestamp found */
153         public Timestamp getEarliestTimestamp() {
154                 return _earliestTimestamp;
155         }
156
157         /** @return the latest timestamp found */
158         public Timestamp getLatestTimestamp() {
159                 return _latestTimestamp;
160         }
161
162         /** @return total number of seconds in the range */
163         public long getTotalDurationInSeconds()
164         {
165                 if (_earliestTimestamp != null && _latestTimestamp != null) {
166                         return _latestTimestamp.getSecondsSince(_earliestTimestamp);
167                 }
168                 return 0L;
169         }
170
171         /** @return number of seconds within the segments of the range */
172         public long getMovingDurationInSeconds()
173         {
174                 return _movingMilliseconds / 1000;
175         }
176
177         /** @return true if any timestamps are missing */
178         public boolean getTimestampsIncomplete() {
179                 return _timesIncomplete;
180         }
181
182         /** @return true if any timestamps are out of sequence */
183         public boolean getTimestampsOutOfSequence() {
184                 return _timesOutOfSequence;
185         }
186
187         /** @return total distance in the current distance units (km or mi) */
188         public double getTotalDistance() {
189                 return Distance.convertRadiansToDistance(_totalDistanceRads);
190         }
191
192         /** @return moving distance in the current distance units (km or mi) */
193         public double getMovingDistance() {
194                 return Distance.convertRadiansToDistance(_movingDistanceRads);
195         }
196
197         /** @return moving distance in km */
198         public double getMovingDistanceKilometres() {
199                 return Distance.convertRadiansToDistance(_movingDistanceRads, UnitSetLibrary.UNITS_KILOMETRES);
200         }
201
202         /**
203          * @return the total vertical speed (including segment gaps) in metric units
204          */
205         public double getTotalVerticalSpeed()
206         {
207                 long time = getTotalDurationInSeconds();
208                 if (time > 0 && _totalAltitudeRange.hasRange()) {
209                         return _totalAltitudeRange.getMetricHeightDiff() / time;
210                 }
211                 return 0.0;
212         }
213
214         /**
215          * @return the moving vertical speed (ignoring segment gaps) in metric units
216          */
217         public double getMovingVerticalSpeed()
218         {
219                 long time = getMovingDurationInSeconds();
220                 if (time > 0 && _movingAltitudeRange.hasRange()) {
221                         return _movingAltitudeRange.getMetricHeightDiff() / time;
222                 }
223                 return 0.0;
224         }
225 }