File: RangeStats.java

package info (click to toggle)
gpsprune 26.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,824 kB
  • sloc: java: 52,154; sh: 25; makefile: 21; python: 15
file content (234 lines) | stat: -rw-r--r-- 6,231 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
package tim.prune.data;

/**
 * Class to do basic calculations of range statistics such as distances, durations,
 * and altitude ranges, and to hold the results of the calculations.
 */
public class RangeStats
{
	private int _numPoints   = 0;
	private int _numSegments = 0;
	private boolean _foundTrackPoint = false;
	protected final AltitudeRange _totalAltitudeRange;
	protected final AltitudeRange _movingAltitudeRange;
	private Timestamp _earliestTimestamp = null, _latestTimestamp = null, _movingTimestamp = null;
	private long _movingMilliseconds = 0L;
	private boolean _timesIncomplete = false;
	private boolean _timesOutOfSequence = false;
	protected double _totalDistanceRads = 0.0, _movingDistanceRads = 0.0;
	protected DataPoint _prevPoint = null;


	/** Constructor */
	public RangeStats(int inAltitudeTolerance)
	{
		_totalAltitudeRange = new AltitudeRange(inAltitudeTolerance);
		_movingAltitudeRange = new AltitudeRange(inAltitudeTolerance);
	}

	/**
	 * Constructor giving Track
	 * @param inTrack track object to calculate with
	 */
	public RangeStats(Track inTrack, int inStartIndex, int inEndIndex, int inAltitudeTolerance)
	{
		this(inAltitudeTolerance);
		populateFromTrack(inTrack, inStartIndex, inEndIndex);
	}

	/**
	 * Add the specified points from the given track to the calculations
	 * @param inTrack track object
	 * @param inStartIndex start index (inclusive)
	 * @param inEndIndex end index (inclusive)
	 */
	protected void populateFromTrack(Track inTrack, int inStartIndex, int inEndIndex)
	{
		for (int i=inStartIndex; i<=inEndIndex; i++) {
			addPoint(inTrack.getPoint(i));
		}
	}

	/**
	 * @param inPoint point to add to the calculations
	 */
	public void addPoint(DataPoint inPoint)
	{
		if (inPoint == null) {
			return;
		}
		_numPoints++;
		// ignore all waypoints
		if (inPoint.isWaypoint()) {
			return;
		}
		if (inPoint.getSegmentStart() || !_foundTrackPoint) {
			_numSegments++;
		}
		_foundTrackPoint = true;
		// Get the distance to the previous track point
		if (_prevPoint != null)
		{
			double rads = DataPoint.calculateRadiansBetween(_prevPoint, inPoint);
			_totalDistanceRads += rads;
			if (!inPoint.getSegmentStart()) {
				_movingDistanceRads += rads;
			}
		}

		// timestamps
		if (inPoint.getSegmentStart())
		{
			// reset movingTimestamp for moving time at the start
			// of each segment
			_movingTimestamp = null;
		}
		if (inPoint.hasTimestamp())
		{
			Timestamp currTstamp = inPoint.getTimestamp();
			if (_earliestTimestamp == null || currTstamp.isBefore(_earliestTimestamp)) {
				_earliestTimestamp = currTstamp;
			}
			if (_latestTimestamp == null || currTstamp.isAfter(_latestTimestamp)) {
				_latestTimestamp = currTstamp;
			}

			// Work out duration without segment gaps
			if (_movingTimestamp != null)
			{
				long millisLater = currTstamp.getMillisecondsSince(_movingTimestamp);
				if (millisLater < 0) {
					_timesOutOfSequence = true;
				}
				else {
					_movingMilliseconds += millisLater;
				}
			}
			_movingTimestamp = currTstamp;
		}
		else {
			_timesIncomplete = true;
		}

		// altitudes
		if (inPoint.hasAltitude())
		{
			Altitude altitude = inPoint.getAltitude();
			_totalAltitudeRange.addValue(altitude);
			if (inPoint.getSegmentStart()) {
				_movingAltitudeRange.ignoreValue(altitude);
			}
			else
			{
				_movingAltitudeRange.addValue(altitude);
			}
		}

		// allow child classes to do additional calculations
		doFurtherCalculations(inPoint);

		_prevPoint = inPoint;
	}

	/**
	 * Hook for subclasses to do what they want in addition
	 * @param inPoint incoming point
	 */
	protected void doFurtherCalculations(DataPoint inPoint)
	{
	}


	/** @return number of points in range */
	public int getNumPoints() {
		return _numPoints;
	}

	/** @return number of segments in range */
	public int getNumSegments() {
		return _numSegments;
	}

	/** @return altitude range of range including segment gaps */
	public AltitudeRange getTotalAltitudeRange() {
		return _totalAltitudeRange;
	}

	/** @return altitude range of range just within segments */
	public AltitudeRange getMovingAltitudeRange() {
		return _movingAltitudeRange;
	}

	/** @return the earliest timestamp found */
	public Timestamp getEarliestTimestamp() {
		return _earliestTimestamp;
	}

	/** @return the latest timestamp found */
	public Timestamp getLatestTimestamp() {
		return _latestTimestamp;
	}

	/** @return total number of seconds in the range */
	public long getTotalDurationInSeconds()
	{
		if (_earliestTimestamp != null && _latestTimestamp != null) {
			return _latestTimestamp.getSecondsSince(_earliestTimestamp);
		}
		return 0L;
	}

	/** @return number of seconds within the segments of the range */
	public long getMovingDurationInSeconds() {
		return _movingMilliseconds / 1000;
	}

	/** @return true if any timestamps are missing */
	public boolean getTimestampsIncomplete() {
		return _timesIncomplete;
	}

	/** @return true if any timestamps are out of sequence */
	public boolean getTimestampsOutOfSequence() {
		return _timesOutOfSequence;
	}

	/** @return total distance in the given distance units (km or mi) */
	public double getTotalDistance(Unit inUnit) {
		return Distance.convertRadiansToDistance(_totalDistanceRads, inUnit);
	}

	/** @return moving distance in the given distance units (km or mi) */
	public double getMovingDistance(Unit inUnit) {
		return Distance.convertRadiansToDistance(_movingDistanceRads, inUnit);
	}

	/** @return moving distance in km */
	public double getMovingDistanceKilometres() {
		return Distance.convertRadiansToDistance(_movingDistanceRads, UnitSetLibrary.UNITS_KILOMETRES);
	}

	/**
	 * @return the total vertical speed (including segment gaps) in metric units
	 */
	public double getTotalVerticalSpeed()
	{
		long time = getTotalDurationInSeconds();
		if (time > 0 && _totalAltitudeRange.hasRange()) {
			return _totalAltitudeRange.getMetricHeightDiff() / time;
		}
		return 0.0;
	}

	/**
	 * @return the moving vertical speed (ignoring segment gaps) in metric units
	 */
	public double getMovingVerticalSpeed()
	{
		long time = getMovingDurationInSeconds();
		if (time > 0 && _movingAltitudeRange.hasRange()) {
			return _movingAltitudeRange.getMetricHeightDiff() / time;
		}
		return 0.0;
	}
}