1 package tim.prune.data;
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.
7 public class RangeStats
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;
27 * Constructor giving Track
28 * @param inTrack track object to calculate with
30 public RangeStats(Track inTrack, int inStartIndex, int inEndIndex)
32 populateFromTrack(inTrack, inStartIndex, inEndIndex);
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)
41 protected void populateFromTrack(Track inTrack, int inStartIndex, int inEndIndex)
43 for (int i=inStartIndex; i<=inEndIndex; i++)
45 addPoint(inTrack.getPoint(i));
50 * @param inPoint point to add to the calculations
52 public void addPoint(DataPoint inPoint)
59 // ignore all waypoints
60 if (inPoint.isWaypoint()) {
63 if (inPoint.getSegmentStart() || !_foundTrackPoint) {
66 _foundTrackPoint = true;
67 // Get the distance to the previous track point
68 if (_prevPoint != null)
70 double rads = DataPoint.calculateRadiansBetween(_prevPoint, inPoint);
71 _totalDistanceRads += rads;
72 if (!inPoint.getSegmentStart()) {
73 _movingDistanceRads += rads;
78 if (inPoint.hasTimestamp())
80 Timestamp currTstamp = inPoint.getTimestamp();
81 if (_earliestTimestamp == null || currTstamp.isBefore(_earliestTimestamp)) {
82 _earliestTimestamp = currTstamp;
84 if (_latestTimestamp == null || currTstamp.isAfter(_latestTimestamp)) {
85 _latestTimestamp = currTstamp;
87 // Work out duration without segment gaps
88 if (!inPoint.getSegmentStart() && _prevPoint != null && _prevPoint.hasTimestamp())
90 long millisLater = currTstamp.getMillisecondsSince(_prevPoint.getTimestamp());
91 if (millisLater < 0) {
92 _timesOutOfSequence = true;
95 _movingMilliseconds += millisLater;
100 _timesIncomplete = true;
104 if (inPoint.hasAltitude())
106 Altitude altitude = inPoint.getAltitude();
107 _totalAltitudeRange.addValue(altitude);
108 if (inPoint.getSegmentStart()) {
109 _movingAltitudeRange.ignoreValue(altitude);
113 _movingAltitudeRange.addValue(altitude);
117 // allow child classes to do additional calculations
118 doFurtherCalculations(inPoint);
120 _prevPoint = inPoint;
124 * Hook for subclasses to do what they want in addition
125 * @param inPoint incoming point
127 protected void doFurtherCalculations(DataPoint inPoint)
132 /** @return number of points in range */
133 public int getNumPoints() {
137 /** @return number of segments in range */
138 public int getNumSegments() {
142 /** @return altitude range of range including segment gaps */
143 public AltitudeRange getTotalAltitudeRange() {
144 return _totalAltitudeRange;
147 /** @return altitude range of range just within segments */
148 public AltitudeRange getMovingAltitudeRange() {
149 return _movingAltitudeRange;
152 /** @return the earliest timestamp found */
153 public Timestamp getEarliestTimestamp() {
154 return _earliestTimestamp;
157 /** @return the latest timestamp found */
158 public Timestamp getLatestTimestamp() {
159 return _latestTimestamp;
162 /** @return total number of seconds in the range */
163 public long getTotalDurationInSeconds()
165 if (_earliestTimestamp != null && _latestTimestamp != null) {
166 return _latestTimestamp.getSecondsSince(_earliestTimestamp);
171 /** @return number of seconds within the segments of the range */
172 public long getMovingDurationInSeconds()
174 return _movingMilliseconds / 1000;
177 /** @return true if any timestamps are missing */
178 public boolean getTimestampsIncomplete() {
179 return _timesIncomplete;
182 /** @return true if any timestamps are out of sequence */
183 public boolean getTimestampsOutOfSequence() {
184 return _timesOutOfSequence;
187 /** @return total distance in the current distance units (km or mi) */
188 public double getTotalDistance() {
189 return Distance.convertRadiansToDistance(_totalDistanceRads);
192 /** @return moving distance in the current distance units (km or mi) */
193 public double getMovingDistance() {
194 return Distance.convertRadiansToDistance(_movingDistanceRads);
197 /** @return moving distance in km */
198 public double getMovingDistanceKilometres() {
199 return Distance.convertRadiansToDistance(_movingDistanceRads, UnitSetLibrary.UNITS_KILOMETRES);
203 * @return the total vertical speed (including segment gaps) in metric units
205 public double getTotalVerticalSpeed()
207 long time = getTotalDurationInSeconds();
208 if (time > 0 && _totalAltitudeRange.hasRange()) {
209 return _totalAltitudeRange.getMetricHeightDiff() / time;
215 * @return the moving vertical speed (ignoring segment gaps) in metric units
217 public double getMovingVerticalSpeed()
219 long time = getMovingDurationInSeconds();
220 if (time > 0 && _movingAltitudeRange.hasRange()) {
221 return _movingAltitudeRange.getMetricHeightDiff() / time;