TrackStatistics and ChartView: handle altitude and speed as optional with null as default value.

Then only the relevant part of the y-axis is shown.

Fixes #795.
This commit is contained in:
Dennis Guse
2021-12-29 23:12:49 +01:00
parent 8c20d5583a
commit 07074ad260
11 changed files with 172 additions and 73 deletions
@@ -24,6 +24,7 @@ import androidx.annotation.VisibleForTesting;
import java.time.Duration;
import java.util.List;
import de.dennisguse.opentracks.content.data.Altitude;
import de.dennisguse.opentracks.content.data.Distance;
import de.dennisguse.opentracks.content.data.Speed;
import de.dennisguse.opentracks.content.data.TrackPoint;
@@ -61,8 +62,8 @@ public class TrackStatisticsUpdater {
private final TrackStatistics trackStatistics;
private final DoubleRingBuffer altitudeBuffer_m;
private final DoubleRingBuffer speedBuffer_mps;
private final AltitudeRingBuffer altitudeBuffer;
private final SpeedRingBuffer speedBuffer;
// The current segment's statistics
private final TrackStatistics currentSegment;
@@ -82,16 +83,16 @@ public class TrackStatisticsUpdater {
this.trackStatistics = trackStatistics;
this.currentSegment = new TrackStatistics();
altitudeBuffer_m = new DoubleRingBuffer(ALTITUDE_SMOOTHING_FACTOR);
speedBuffer_mps = new DoubleRingBuffer(SPEED_SMOOTHING_FACTOR);
altitudeBuffer = new AltitudeRingBuffer(ALTITUDE_SMOOTHING_FACTOR);
speedBuffer = new SpeedRingBuffer(SPEED_SMOOTHING_FACTOR);
}
public TrackStatisticsUpdater(TrackStatisticsUpdater toCopy) {
this.currentSegment = new TrackStatistics(toCopy.currentSegment);
this.trackStatistics = new TrackStatistics(toCopy.trackStatistics);
this.altitudeBuffer_m = new DoubleRingBuffer(toCopy.altitudeBuffer_m);
this.speedBuffer_mps = new DoubleRingBuffer(toCopy.speedBuffer_mps);
this.altitudeBuffer = new AltitudeRingBuffer(toCopy.altitudeBuffer);
this.speedBuffer = new SpeedRingBuffer(toCopy.speedBuffer);
this.lastTrackPoint = toCopy.lastTrackPoint;
}
@@ -136,7 +137,11 @@ public class TrackStatisticsUpdater {
//Update absolute (GPS-based) altitude
if (trackPoint.hasAltitude()) {
updateAbsoluteAltitude(trackPoint.getAltitude().toM());
// Update altitude using the smoothed average
altitudeBuffer.setNext(trackPoint.getAltitude());
Altitude newAverage = altitudeBuffer.getAverage();
currentSegment.updateAltitudeExtremities(newAverage);
}
// Update total distance
@@ -164,7 +169,7 @@ public class TrackStatisticsUpdater {
// Update max speed
updateSpeed(trackPoint, lastTrackPoint);
} else {
speedBuffer_mps.reset();
speedBuffer.reset();
}
@@ -183,20 +188,20 @@ public class TrackStatisticsUpdater {
currentSegment.reset(trackPoint.getTime());
lastTrackPoint = null;
altitudeBuffer_m.reset();
speedBuffer_mps.reset();
altitudeBuffer.reset();
speedBuffer.reset();
}
/**
* Gets the smoothed altitude over several readings.
* The altitude readings is noisy so the smoothed altitude is better than the raw altitude for many tasks.
*/
public double getSmoothedAltitude() {
return altitudeBuffer_m.getAverage();
public Altitude getSmoothedAltitude() {
return altitudeBuffer.getAverage();
}
public Speed getSmoothedSpeed() {
return Speed.of(speedBuffer_mps.getAverage());
return speedBuffer.getAverage();
}
/**
@@ -205,10 +210,10 @@ public class TrackStatisticsUpdater {
@VisibleForTesting
private void updateSpeed(@NonNull TrackPoint trackPoint, @NonNull TrackPoint lastTrackPoint) {
if (!trackPoint.isMoving()) {
speedBuffer_mps.reset();
speedBuffer.reset();
} else if (isValidSpeed(trackPoint, lastTrackPoint)) {
speedBuffer_mps.setNext(trackPoint.getSpeed().toMPS());
Speed average = Speed.of(speedBuffer_mps.getAverage());
speedBuffer.setNext(trackPoint.getSpeed());
Speed average = speedBuffer.getAverage();
if (average.greaterThan(currentSegment.getMaxSpeed())) {
currentSegment.setMaxSpeed(average);
}
@@ -217,14 +222,6 @@ public class TrackStatisticsUpdater {
}
}
private void updateAbsoluteAltitude(double altitude) {
// Update altitude using the smoothed average
altitudeBuffer_m.setNext(altitude);
double newAverage = altitudeBuffer_m.getAverage();
currentSegment.updateAltitudeExtremities(newAverage);
}
private boolean isValidSpeed(@NonNull TrackPoint trackPoint, @NonNull TrackPoint lastTrackPoint) {
// There are a lot of noisy speed readings. Do the cheapest checks first, most expensive last.
if (trackPoint.getSpeed().isZero()) {
@@ -242,8 +239,8 @@ public class TrackStatisticsUpdater {
}
// Only check if the speed buffer is full. Check that the speed is less than 10X the smoothed average and the speed difference doesn't imply 2g acceleration.
if (speedBuffer_mps.isFull()) {
Speed average = Speed.of(speedBuffer_mps.getAverage());
if (speedBuffer.isFull()) {
Speed average = speedBuffer.getAverage();
Speed speedDifference = Speed.absDiff(average, trackPoint.getSpeed());
return trackPoint.getSpeed().lessThan(average.mul(10)) && speedDifference.lessThan(maxAcceleration);