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;
}
}
|