forked from upstream-mirrors/OpenTracks
+18
-10
@@ -133,6 +133,7 @@ public class ExportImportTest {
|
||||
|
||||
// A sensor-only TrackPoint
|
||||
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||
mockAltitudeChange(trackPointCreator, 1);
|
||||
sendSensor(trackPointCreator, Instant.parse("2020-02-02T02:02:04Z"));
|
||||
|
||||
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||
@@ -255,10 +256,10 @@ public class ExportImportTest {
|
||||
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||
|
||||
assertEquals(originalTrackStatistics.getTotalAltitudeGain(), importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||
|
||||
assertEquals(originalTrackStatistics.getTotalAltitudeLoss(), importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||
|
||||
// 4. markers
|
||||
assertMarkers();
|
||||
@@ -326,6 +327,9 @@ public class ExportImportTest {
|
||||
// Therefore, the track segmentation is changes.
|
||||
List<TrackPoint> trackPointsWithCoordinates = trackPoints.stream().filter(it -> TrackPoint.Type.SEGMENT_START_AUTOMATIC.equals(it.getType()) || TrackPoint.Type.TRACKPOINT.equals(it.getType())).collect(Collectors.toList());
|
||||
trackPointsWithCoordinates.get(0).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||
trackPointsWithCoordinates.get(1).setSensorDistance(Distance.of(20));
|
||||
trackPointsWithCoordinates.get(1).setAltitudeGain(1f);
|
||||
trackPointsWithCoordinates.get(1).setAltitudeLoss(1f);
|
||||
trackPointsWithCoordinates.get(2).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||
|
||||
TrackPointAssert a = new TrackPointAssert()
|
||||
@@ -345,18 +349,18 @@ public class ExportImportTest {
|
||||
assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getMovingTime());
|
||||
|
||||
// Distance
|
||||
assertEquals(Distance.of(50), importedTrackStatistics.getTotalDistance()); //TODO Should be 60 due to SensorPoint
|
||||
assertEquals(Distance.of(60), importedTrackStatistics.getTotalDistance());
|
||||
|
||||
// Speed
|
||||
assertEquals(Speed.of(15), importedTrackStatistics.getMaxSpeed());
|
||||
assertEquals(Speed.of(12.5), importedTrackStatistics.getAverageSpeed());
|
||||
assertEquals(Speed.of(12.5), importedTrackStatistics.getAverageMovingSpeed());
|
||||
assertEquals(Speed.of(15), importedTrackStatistics.getAverageSpeed());
|
||||
assertEquals(Speed.of(15), importedTrackStatistics.getAverageMovingSpeed());
|
||||
|
||||
// Altitude
|
||||
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
||||
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||
|
||||
// 4. markers
|
||||
assertMarkers();
|
||||
@@ -437,6 +441,12 @@ public class ExportImportTest {
|
||||
});
|
||||
}
|
||||
|
||||
private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) {
|
||||
AltitudeSumManager altitudeSumManager = trackPointCreator.getAltitudeSumManager();
|
||||
altitudeSumManager.setAltitudeGain_m(altitudeGain);
|
||||
altitudeSumManager.setAltitudeLoss_m(altitudeGain);
|
||||
}
|
||||
|
||||
private void sendSensor(TrackPointCreator trackPointCreator, Instant time) {
|
||||
trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET")));
|
||||
trackPointCreator.onNewTrackPointWithoutGPS();
|
||||
@@ -450,9 +460,7 @@ public class ExportImportTest {
|
||||
location.setSpeed(speed);
|
||||
location.setAltitude(altitude);
|
||||
|
||||
AltitudeSumManager altitudeSumManager = trackPointCreator.getAltitudeSumManager();
|
||||
altitudeSumManager.setAltitudeGain_m(altitudeGain);
|
||||
altitudeSumManager.setAltitudeLoss_m(altitudeGain);
|
||||
mockAltitudeChange(trackPointCreator, altitudeGain);
|
||||
|
||||
trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET")));
|
||||
trackPointCreator.getGpsHandler().onLocationChanged(location);
|
||||
|
||||
@@ -24,7 +24,12 @@ import androidx.annotation.NonNull;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import de.dennisguse.opentracks.content.data.Marker;
|
||||
import de.dennisguse.opentracks.content.data.Track;
|
||||
@@ -123,6 +128,8 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
boolean wroteTrack = false;
|
||||
boolean wroteSegment = false;
|
||||
|
||||
LinkedList<TrackPoint> sensorPoints = new LinkedList<>();
|
||||
|
||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
||||
while (trackPointIterator.hasNext()) {
|
||||
if (Thread.interrupted()) throw new InterruptedException();
|
||||
@@ -150,10 +157,12 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
if (wroteSegment) writeCloseSegment();
|
||||
writeOpenSegment();
|
||||
wroteSegment = true;
|
||||
writeTrackPoint(trackPoint);
|
||||
|
||||
writeTrackPoint(trackPoint, sensorPoints);
|
||||
sensorPoints.clear();
|
||||
break;
|
||||
case SENSORPOINT:
|
||||
//TODO We need somehow to compute the sensor data (mainly sensorDistance if present) and add it to the TRACKPOINT (if no segment followed in between)?
|
||||
sensorPoints.add(trackPoint);
|
||||
break;
|
||||
case TRACKPOINT:
|
||||
if (!wroteSegment) {
|
||||
@@ -161,13 +170,21 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
writeOpenSegment();
|
||||
wroteSegment = true;
|
||||
}
|
||||
writeTrackPoint(trackPoint);
|
||||
|
||||
writeTrackPoint(trackPoint, sensorPoints);
|
||||
sensorPoints.clear();
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Exporting this TrackPoint type is not implemented: " + trackPoint.getType());
|
||||
}
|
||||
}
|
||||
|
||||
if (!sensorPoints.isEmpty()) {
|
||||
//TODO We might miss to export data; this happens if there are SENSORPOINTs after the final TRACKPOINT of a track.
|
||||
//For segments the data is added to the next segment.
|
||||
Log.d(TAG, "SENSORPOINTs after final TRACKPOINT; this data is not exported.");
|
||||
}
|
||||
|
||||
if (wroteSegment) {
|
||||
// Should not be necessary as tracks should end with SEGMENT_END_MANUAL.
|
||||
// Anyhow, make sure that the last segment is closed.
|
||||
@@ -293,7 +310,7 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
printWriter.println("</trkseg>");
|
||||
}
|
||||
|
||||
public void writeTrackPoint(TrackPoint trackPoint) {
|
||||
public void writeTrackPoint(TrackPoint trackPoint, List<TrackPoint> sensorPoints) {
|
||||
if (printWriter != null) {
|
||||
|
||||
printWriter.println("<trkpt " + formatLocation(trackPoint.getLatitude(), trackPoint.getLongitude()) + ">");
|
||||
@@ -304,44 +321,59 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
|
||||
printWriter.println("<time>" + StringUtils.formatDateTimeIso8601(trackPoint.getTime()) + "</time>");
|
||||
|
||||
if (trackPoint.hasSpeed() || trackPoint.hasHeartRate() || trackPoint.hasCadence() || trackPoint.hasAltitudeGain() || trackPoint.hasAltitudeLoss()) {
|
||||
printWriter.println("<extensions><gpxtpx:TrackPointExtension>");
|
||||
{
|
||||
String trackPointExtensionContent = "";
|
||||
|
||||
if (trackPoint.hasSpeed()) {
|
||||
printWriter.println("<gpxtpx:speed>" + SPEED_FORMAT.format(trackPoint.getSpeed().toMPS()) + "</gpxtpx:speed>");
|
||||
trackPointExtensionContent += "<gpxtpx:speed>" + SPEED_FORMAT.format(trackPoint.getSpeed().toMPS()) + "</gpxtpx:speed>\n";
|
||||
}
|
||||
|
||||
if (trackPoint.hasHeartRate()) {
|
||||
printWriter.println("<gpxtpx:hr>" + HEARTRATE_FORMAT.format(trackPoint.getHeartRate_bpm()) + "</gpxtpx:hr>");
|
||||
trackPointExtensionContent += "<gpxtpx:hr>" + HEARTRATE_FORMAT.format(trackPoint.getHeartRate_bpm()) + "</gpxtpx:hr>\n";
|
||||
}
|
||||
|
||||
if (trackPoint.hasCadence()) {
|
||||
printWriter.println("<gpxtpx:cad>" + CADENCE_FORMAT.format(trackPoint.getCadence_rpm()) + "</gpxtpx:cad>");
|
||||
trackPointExtensionContent += "<gpxtpx:cad>" + CADENCE_FORMAT.format(trackPoint.getCadence_rpm()) + "</gpxtpx:cad>\n";
|
||||
}
|
||||
|
||||
if (trackPoint.hasPower()) {
|
||||
printWriter.println("<pwr:PowerInWatts>" + POWER_FORMAT.format(trackPoint.getPower()) + "</pwr:PowerInWatts>");
|
||||
trackPointExtensionContent += "<pwr:PowerInWatts>" + POWER_FORMAT.format(trackPoint.getPower()) + "</pwr:PowerInWatts>\n";
|
||||
}
|
||||
|
||||
if (trackPoint.hasAltitudeGain()) {
|
||||
printWriter.println("<opentracks:gain>" + ALTITUDE_FORMAT.format(trackPoint.getAltitudeGain()) + "</opentracks:gain>");
|
||||
Double cumulativeGain = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeGain() ? (double) tp.getAltitudeGain() : null);
|
||||
if (cumulativeGain != null) {
|
||||
trackPointExtensionContent += ("<opentracks:gain>" + ALTITUDE_FORMAT.format(cumulativeGain) + "</opentracks:gain>\n");
|
||||
}
|
||||
|
||||
if (trackPoint.hasAltitudeLoss()) {
|
||||
printWriter.println("<opentracks:loss>" + ALTITUDE_FORMAT.format(trackPoint.getAltitudeLoss()) + "</opentracks:loss>");
|
||||
Double cumulativeLoss = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeLoss() ? (double) tp.getAltitudeLoss() : null);
|
||||
if (cumulativeLoss != null) {
|
||||
trackPointExtensionContent += ("<opentracks:loss>" + ALTITUDE_FORMAT.format(cumulativeLoss) + "</opentracks:loss>\n");
|
||||
}
|
||||
|
||||
if (trackPoint.hasSensorDistance()) {
|
||||
printWriter.println("<opentracks:distance>" + DISTANCE_FORMAT.format(trackPoint.getSensorDistance().toM()) + "</opentracks:distance>");
|
||||
Double cumulativeDistance = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasSensorDistance() ? tp.getSensorDistance().toM() : null);
|
||||
if (cumulativeDistance != null) {
|
||||
trackPointExtensionContent += ("<opentracks:distance>" + ALTITUDE_FORMAT.format(cumulativeDistance) + "</opentracks:distance>\n");
|
||||
}
|
||||
|
||||
printWriter.println("</gpxtpx:TrackPointExtension></extensions>");
|
||||
if (!trackPointExtensionContent.isEmpty()) {
|
||||
printWriter.println("<extensions><gpxtpx:TrackPointExtension>");
|
||||
printWriter.print(trackPointExtensionContent);
|
||||
printWriter.println("</gpxtpx:TrackPointExtension></extensions>");
|
||||
}
|
||||
}
|
||||
|
||||
printWriter.println("</trkpt>");
|
||||
}
|
||||
}
|
||||
|
||||
private Double cumulateSensorData(TrackPoint trackPoint, List<TrackPoint> sensorPoints, Function<TrackPoint, Double> map) {
|
||||
return Stream.concat(sensorPoints.stream(), Stream.of(trackPoint))
|
||||
.map(map)
|
||||
.filter(Objects::nonNull)
|
||||
.reduce((gain, next) -> gain + next)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private String formatLocation(double latitude, double longitude) {
|
||||
return "lat=\"" + COORDINATE_FORMAT.format(latitude) + "\" lon=\"" + COORDINATE_FORMAT.format(longitude) + "\"";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user