forked from upstream-mirrors/OpenTracks
@@ -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