forked from upstream-mirrors/OpenTracks
+18
-10
@@ -133,6 +133,7 @@ public class ExportImportTest {
|
|||||||
|
|
||||||
// A sensor-only TrackPoint
|
// A sensor-only TrackPoint
|
||||||
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||||
|
mockAltitudeChange(trackPointCreator, 1);
|
||||||
sendSensor(trackPointCreator, Instant.parse("2020-02-02T02:02:04Z"));
|
sendSensor(trackPointCreator, Instant.parse("2020-02-02T02:02:04Z"));
|
||||||
|
|
||||||
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||||
@@ -255,10 +256,10 @@ public class ExportImportTest {
|
|||||||
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||||
|
|
||||||
assertEquals(originalTrackStatistics.getTotalAltitudeGain(), importedTrackStatistics.getTotalAltitudeGain(), 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(originalTrackStatistics.getTotalAltitudeLoss(), importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||||
|
|
||||||
// 4. markers
|
// 4. markers
|
||||||
assertMarkers();
|
assertMarkers();
|
||||||
@@ -326,6 +327,9 @@ public class ExportImportTest {
|
|||||||
// Therefore, the track segmentation is changes.
|
// 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());
|
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(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);
|
trackPointsWithCoordinates.get(2).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||||
|
|
||||||
TrackPointAssert a = new TrackPointAssert()
|
TrackPointAssert a = new TrackPointAssert()
|
||||||
@@ -345,18 +349,18 @@ public class ExportImportTest {
|
|||||||
assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getMovingTime());
|
assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getMovingTime());
|
||||||
|
|
||||||
// Distance
|
// Distance
|
||||||
assertEquals(Distance.of(50), importedTrackStatistics.getTotalDistance()); //TODO Should be 60 due to SensorPoint
|
assertEquals(Distance.of(60), importedTrackStatistics.getTotalDistance());
|
||||||
|
|
||||||
// Speed
|
// Speed
|
||||||
assertEquals(Speed.of(15), importedTrackStatistics.getMaxSpeed());
|
assertEquals(Speed.of(15), importedTrackStatistics.getMaxSpeed());
|
||||||
assertEquals(Speed.of(12.5), importedTrackStatistics.getAverageSpeed());
|
assertEquals(Speed.of(15), importedTrackStatistics.getAverageSpeed());
|
||||||
assertEquals(Speed.of(12.5), importedTrackStatistics.getAverageMovingSpeed());
|
assertEquals(Speed.of(15), importedTrackStatistics.getAverageMovingSpeed());
|
||||||
|
|
||||||
// Altitude
|
// Altitude
|
||||||
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
||||||
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||||
|
|
||||||
// 4. markers
|
// 4. markers
|
||||||
assertMarkers();
|
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) {
|
private void sendSensor(TrackPointCreator trackPointCreator, Instant time) {
|
||||||
trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET")));
|
||||||
trackPointCreator.onNewTrackPointWithoutGPS();
|
trackPointCreator.onNewTrackPointWithoutGPS();
|
||||||
@@ -450,9 +460,7 @@ public class ExportImportTest {
|
|||||||
location.setSpeed(speed);
|
location.setSpeed(speed);
|
||||||
location.setAltitude(altitude);
|
location.setAltitude(altitude);
|
||||||
|
|
||||||
AltitudeSumManager altitudeSumManager = trackPointCreator.getAltitudeSumManager();
|
mockAltitudeChange(trackPointCreator, altitudeGain);
|
||||||
altitudeSumManager.setAltitudeGain_m(altitudeGain);
|
|
||||||
altitudeSumManager.setAltitudeLoss_m(altitudeGain);
|
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET")));
|
||||||
trackPointCreator.getGpsHandler().onLocationChanged(location);
|
trackPointCreator.getGpsHandler().onLocationChanged(location);
|
||||||
|
|||||||
@@ -24,7 +24,12 @@ import androidx.annotation.NonNull;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
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.Marker;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
@@ -123,6 +128,8 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
boolean wroteTrack = false;
|
boolean wroteTrack = false;
|
||||||
boolean wroteSegment = false;
|
boolean wroteSegment = false;
|
||||||
|
|
||||||
|
LinkedList<TrackPoint> sensorPoints = new LinkedList<>();
|
||||||
|
|
||||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
||||||
while (trackPointIterator.hasNext()) {
|
while (trackPointIterator.hasNext()) {
|
||||||
if (Thread.interrupted()) throw new InterruptedException();
|
if (Thread.interrupted()) throw new InterruptedException();
|
||||||
@@ -150,10 +157,12 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
if (wroteSegment) writeCloseSegment();
|
if (wroteSegment) writeCloseSegment();
|
||||||
writeOpenSegment();
|
writeOpenSegment();
|
||||||
wroteSegment = true;
|
wroteSegment = true;
|
||||||
writeTrackPoint(trackPoint);
|
|
||||||
|
writeTrackPoint(trackPoint, sensorPoints);
|
||||||
|
sensorPoints.clear();
|
||||||
break;
|
break;
|
||||||
case SENSORPOINT:
|
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;
|
break;
|
||||||
case TRACKPOINT:
|
case TRACKPOINT:
|
||||||
if (!wroteSegment) {
|
if (!wroteSegment) {
|
||||||
@@ -161,13 +170,21 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
writeOpenSegment();
|
writeOpenSegment();
|
||||||
wroteSegment = true;
|
wroteSegment = true;
|
||||||
}
|
}
|
||||||
writeTrackPoint(trackPoint);
|
|
||||||
|
writeTrackPoint(trackPoint, sensorPoints);
|
||||||
|
sensorPoints.clear();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("Exporting this TrackPoint type is not implemented: " + trackPoint.getType());
|
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) {
|
if (wroteSegment) {
|
||||||
// Should not be necessary as tracks should end with SEGMENT_END_MANUAL.
|
// Should not be necessary as tracks should end with SEGMENT_END_MANUAL.
|
||||||
// Anyhow, make sure that the last segment is closed.
|
// Anyhow, make sure that the last segment is closed.
|
||||||
@@ -293,7 +310,7 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
printWriter.println("</trkseg>");
|
printWriter.println("</trkseg>");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTrackPoint(TrackPoint trackPoint) {
|
public void writeTrackPoint(TrackPoint trackPoint, List<TrackPoint> sensorPoints) {
|
||||||
if (printWriter != null) {
|
if (printWriter != null) {
|
||||||
|
|
||||||
printWriter.println("<trkpt " + formatLocation(trackPoint.getLatitude(), trackPoint.getLongitude()) + ">");
|
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>");
|
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()) {
|
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()) {
|
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()) {
|
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()) {
|
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()) {
|
Double cumulativeGain = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeGain() ? (double) tp.getAltitudeGain() : null);
|
||||||
printWriter.println("<opentracks:gain>" + ALTITUDE_FORMAT.format(trackPoint.getAltitudeGain()) + "</opentracks:gain>");
|
if (cumulativeGain != null) {
|
||||||
|
trackPointExtensionContent += ("<opentracks:gain>" + ALTITUDE_FORMAT.format(cumulativeGain) + "</opentracks:gain>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackPoint.hasAltitudeLoss()) {
|
Double cumulativeLoss = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeLoss() ? (double) tp.getAltitudeLoss() : null);
|
||||||
printWriter.println("<opentracks:loss>" + ALTITUDE_FORMAT.format(trackPoint.getAltitudeLoss()) + "</opentracks:loss>");
|
if (cumulativeLoss != null) {
|
||||||
|
trackPointExtensionContent += ("<opentracks:loss>" + ALTITUDE_FORMAT.format(cumulativeLoss) + "</opentracks:loss>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackPoint.hasSensorDistance()) {
|
Double cumulativeDistance = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasSensorDistance() ? tp.getSensorDistance().toM() : null);
|
||||||
printWriter.println("<opentracks:distance>" + DISTANCE_FORMAT.format(trackPoint.getSensorDistance().toM()) + "</opentracks:distance>");
|
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>");
|
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) {
|
private String formatLocation(double latitude, double longitude) {
|
||||||
return "lat=\"" + COORDINATE_FORMAT.format(latitude) + "\" lon=\"" + COORDINATE_FORMAT.format(longitude) + "\"";
|
return "lat=\"" + COORDINATE_FORMAT.format(latitude) + "\" lon=\"" + COORDINATE_FORMAT.format(longitude) + "\"";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user