Import/Export: horizontal accuracy.

Fixes #683.
This commit is contained in:
Dennis Guse
2022-04-17 23:33:26 +02:00
parent fb70486bdc
commit 5cf8b67954
7 changed files with 54 additions and 31 deletions
+3 -2
View File
@@ -29,11 +29,12 @@
</xsd:documentation> </xsd:documentation>
</xsd:annotation> </xsd:annotation>
</xsd:element> </xsd:element>
<xsd:element name="accuracy" <xsd:element name="accuracy_horizontal"
type="xsd:float"> type="xsd:float">
<xsd:annotation> <xsd:annotation>
<xsd:documentation xml:lang="en"> <xsd:documentation xml:lang="en">
Accuracy in meters of the current TrackPoint. Accuracy in meters of the current TrackPoint; 68% chance that the actual location is
within this radius around the measured location.
Only used in GPX. Only used in GPX.
</xsd:documentation> </xsd:documentation>
</xsd:annotation> </xsd:annotation>
@@ -206,8 +206,7 @@ public class ExportImportTest {
assertEquals(track.getIcon(), importedTrack.getIcon()); assertEquals(track.getIcon(), importedTrack.getIcon());
// 2. trackpoints // 2. trackpoints
TrackPointAssert a = new TrackPointAssert() TrackPointAssert a = new TrackPointAssert();
.noAccuracy();
List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId); List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
a.assertEquals(trackPoints, actual); a.assertEquals(trackPoints, actual);
@@ -320,8 +319,7 @@ public class ExportImportTest {
// Therefore, the track segmentation is changes. // Therefore, the track segmentation is changes.
TrackPointAssert a = new TrackPointAssert() TrackPointAssert a = new TrackPointAssert()
.setDelta(0.05) .setDelta(0.05); // speed is not fully
.noAccuracy(); // speed is not fully
List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId); List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
a.assertEquals(List.of( a.assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:03Z")) new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:03Z"))
@@ -330,7 +328,8 @@ public class ExportImportTest {
.setAltitude(10) .setAltitude(10)
.setSpeed(Speed.of(15)) .setSpeed(Speed.of(15))
.setAltitudeLoss(1f) .setAltitudeLoss(1f)
.setAltitudeGain(1f), .setAltitudeGain(1f)
.setHorizontalAccuracy(Distance.of(10)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:05Z")) new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:05Z"))
.setLatitude(3) .setLatitude(3)
.setLongitude(14.001) .setLongitude(14.001)
@@ -341,21 +340,24 @@ public class ExportImportTest {
.setSensorDistance(Distance.of(12)) .setSensorDistance(Distance.of(12))
.setHeartRate(66f) .setHeartRate(66f)
.setPower(50f) .setPower(50f)
.setCadence(3f), .setCadence(3f)
.setHorizontalAccuracy(Distance.of(10)),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:21Z")) new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:21Z"))
.setLatitude(3) .setLatitude(3)
.setLongitude(14.002) .setLongitude(14.002)
.setAltitude(10) .setAltitude(10)
.setAltitudeLoss(0f) .setAltitudeLoss(0f)
.setAltitudeGain(0f) .setAltitudeGain(0f)
.setSpeed(Speed.of(15)), .setSpeed(Speed.of(15))
.setHorizontalAccuracy(Distance.of(10)),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:22Z")) new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:22Z"))
.setLatitude(3) .setLatitude(3)
.setLongitude(16) .setLongitude(16)
.setAltitude(10) .setAltitude(10)
.setAltitudeLoss(0f) .setAltitudeLoss(0f)
.setAltitudeGain(0f) .setAltitudeGain(0f)
.setSpeed(Speed.of(15)), .setSpeed(Speed.of(15))
.setHorizontalAccuracy(Distance.of(10)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:23Z")) new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:23Z"))
.setLatitude(3) .setLatitude(3)
.setLongitude(16.001) .setLongitude(16.001)
@@ -363,6 +365,7 @@ public class ExportImportTest {
.setAltitudeLoss(0f) .setAltitudeLoss(0f)
.setAltitudeGain(0f) .setAltitudeGain(0f)
.setSpeed(Speed.of(15)) .setSpeed(Speed.of(15))
.setHorizontalAccuracy(Distance.of(10))
), actual); ), actual);
// 3. trackstatistics // 3. trackstatistics
@@ -8,8 +8,6 @@ import de.dennisguse.opentracks.data.models.TrackPoint;
public class TrackPointAssert { public class TrackPointAssert {
private boolean assertAccuracy = true;
private double delta = 0.001; private double delta = 0.001;
public TrackPointAssert() { public TrackPointAssert() {
@@ -45,13 +43,9 @@ public class TrackPointAssert {
Assert.assertEquals(expected.getSpeed().toMPS(), actual.getSpeed().toMPS(), delta); Assert.assertEquals(expected.getSpeed().toMPS(), actual.getSpeed().toMPS(), delta);
} }
if (assertAccuracy) { Assert.assertEquals(expected.hasHorizontalAccuracy(), actual.hasHorizontalAccuracy());
Assert.assertEquals(expected.hasHorizontalAccuracy(), actual.hasHorizontalAccuracy()); if (expected.hasHorizontalAccuracy()) {
if (expected.hasHorizontalAccuracy()) { Assert.assertEquals(expected.getHorizontalAccuracy().toM(), actual.getHorizontalAccuracy().toM(), delta);
Assert.assertEquals(expected.getHorizontalAccuracy().toM(), actual.getHorizontalAccuracy().toM(), delta);
}
} else {
Assert.assertFalse(actual.hasHorizontalAccuracy());
} }
Assert.assertEquals(expected.hasSensorDistance(), actual.hasSensorDistance()); Assert.assertEquals(expected.hasSensorDistance(), actual.hasSensorDistance());
@@ -96,11 +90,6 @@ public class TrackPointAssert {
} }
} }
public TrackPointAssert noAccuracy() {
this.assertAccuracy = false;
return this;
}
public TrackPointAssert setDelta(double delta) { public TrackPointAssert setDelta(double delta) {
this.delta = delta; this.delta = delta;
return this; return this;
@@ -359,7 +359,7 @@ public class GPXTrackExporter implements TrackExporter {
} }
if (trackPoint.hasHorizontalAccuracy()) { if (trackPoint.hasHorizontalAccuracy()) {
trackPointExtensionContent += ("<opentracks:accuracy>" + DISTANCE_FORMAT.format(trackPoint.getHorizontalAccuracy().toM()) + "</opentracks:accuracy>"); trackPointExtensionContent += ("<opentracks:accuracy_horizontal>" + DISTANCE_FORMAT.format(trackPoint.getHorizontalAccuracy().toM()) + "</opentracks:accuracy_horizontal>");
} }
cumulativeDistance = Distance.ofOrNull(cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasSensorDistance() ? tp.getSensorDistance().toM() : null)); cumulativeDistance = Distance.ofOrNull(cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasSensorDistance() ? tp.getSensorDistance().toM() : null));
@@ -65,6 +65,7 @@ public class KMLTrackExporter implements TrackExporter {
public static final String EXTENDED_DATA_TYPE_POWER = "power"; public static final String EXTENDED_DATA_TYPE_POWER = "power";
public static final String EXTENDED_DATA_TYPE_ALTITUDE_GAIN = "elevation_gain"; public static final String EXTENDED_DATA_TYPE_ALTITUDE_GAIN = "elevation_gain";
public static final String EXTENDED_DATA_TYPE_ALTITUDE_LOSS = "elevation_loss"; public static final String EXTENDED_DATA_TYPE_ALTITUDE_LOSS = "elevation_loss";
public static final String EXTENDED_DATA_TYPE_ACCURACY_HORIZONTAL = "accuracy_horizontal";
private static final String MARKER_ICON = "http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png"; private static final String MARKER_ICON = "http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png";
private static final String TRACK_ICON = "http://earth.google.com/images/kml-icons/track-directional/track-0.png"; private static final String TRACK_ICON = "http://earth.google.com/images/kml-icons/track-directional/track-0.png";
@@ -88,6 +89,7 @@ public class KMLTrackExporter implements TrackExporter {
private final List<Float> heartRateList = new ArrayList<>(); private final List<Float> heartRateList = new ArrayList<>();
private final List<Float> altitudeGainList = new ArrayList<>(); private final List<Float> altitudeGainList = new ArrayList<>();
private final List<Float> altitudeLossList = new ArrayList<>(); private final List<Float> altitudeLossList = new ArrayList<>();
private final List<Float> accuracyHorizontal = new ArrayList<>();
public KMLTrackExporter(Context context, boolean exportPhotos) { public KMLTrackExporter(Context context, boolean exportPhotos) {
this.context = context; this.context = context;
@@ -333,6 +335,7 @@ public class KMLTrackExporter implements TrackExporter {
heartRateList.clear(); heartRateList.clear();
altitudeGainList.clear(); altitudeGainList.clear();
altitudeLossList.clear(); altitudeLossList.clear();
accuracyHorizontal.clear();
} }
} }
@@ -362,6 +365,9 @@ public class KMLTrackExporter implements TrackExporter {
if (altitudeLossList.stream().anyMatch(Objects::nonNull)) { if (altitudeLossList.stream().anyMatch(Objects::nonNull)) {
writeSimpleArrayData(altitudeLossList, EXTENDED_DATA_TYPE_ALTITUDE_LOSS); writeSimpleArrayData(altitudeLossList, EXTENDED_DATA_TYPE_ALTITUDE_LOSS);
} }
if (accuracyHorizontal.stream().anyMatch(Objects::nonNull)) {
writeSimpleArrayData(accuracyHorizontal, EXTENDED_DATA_TYPE_ACCURACY_HORIZONTAL);
}
printWriter.println("</SchemaData>"); printWriter.println("</SchemaData>");
printWriter.println("</ExtendedData>"); printWriter.println("</ExtendedData>");
printWriter.println("</gx:Track>"); printWriter.println("</gx:Track>");
@@ -387,6 +393,7 @@ public class KMLTrackExporter implements TrackExporter {
altitudeGainList.add(trackPoint.hasAltitudeGain() ? trackPoint.getAltitudeGain() : null); altitudeGainList.add(trackPoint.hasAltitudeGain() ? trackPoint.getAltitudeGain() : null);
altitudeLossList.add(trackPoint.hasAltitudeLoss() ? trackPoint.getAltitudeLoss() : null); altitudeLossList.add(trackPoint.hasAltitudeLoss() ? trackPoint.getAltitudeLoss() : null);
accuracyHorizontal.add(trackPoint.hasHorizontalAccuracy() ? (float) trackPoint.getHorizontalAccuracy().toM() : null);
} }
} }
@@ -82,6 +82,7 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac
private static final String TAG_EXTENSION_GAIN = "opentracks:gain"; private static final String TAG_EXTENSION_GAIN = "opentracks:gain";
private static final String TAG_EXTENSION_LOSS = "opentracks:loss"; private static final String TAG_EXTENSION_LOSS = "opentracks:loss";
private static final String TAG_EXTENSION_DISTANCE = "opentracks:distance"; private static final String TAG_EXTENSION_DISTANCE = "opentracks:distance";
private static final String TAG_EXTENSION_ACCURACY_HORIZONTAL = "opentracks:accuracy_horizontal";
private Locator locator; private Locator locator;
@@ -106,12 +107,13 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac
private String heartrate; private String heartrate;
private String cadence; private String cadence;
private String power; private String power;
protected String markerType; private String markerType;
protected String photoUrl; private String photoUrl;
protected String uuid; private String uuid;
protected String gain; private String gain;
protected String loss; private String loss;
protected String sensorDistance; private String sensorDistance;
private String accuracyHorizontal;
private final LinkedList<TrackPoint> currentSegment = new LinkedList<>(); private final LinkedList<TrackPoint> currentSegment = new LinkedList<>();
@@ -240,6 +242,11 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac
sensorDistance = content.trim(); sensorDistance = content.trim();
} }
break; break;
case TAG_EXTENSION_ACCURACY_HORIZONTAL:
if (content != null) {
accuracyHorizontal = content.trim();
}
break;
} }
content = ""; content = "";
@@ -342,6 +349,13 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac
throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse distance: %s", sensorDistance)), e); throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse distance: %s", sensorDistance)), e);
} }
} }
if (accuracyHorizontal != null) {
try {
trackPoint.setHorizontalAccuracy(Distance.of(accuracyHorizontal));
} catch (NumberFormatException e) {
throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse accuracy_horizontal: %s", sensorDistance)), e);
}
}
return trackPoint; return trackPoint;
} }
@@ -357,6 +371,7 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac
loss = null; loss = null;
sensorDistance = null; sensorDistance = null;
accuracyHorizontal = null;
power = null; power = null;
heartrate = null; heartrate = null;
cadence = null; cadence = null;
@@ -89,6 +89,7 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
private final ArrayList<Float> sensorPowerList = new ArrayList<>(); private final ArrayList<Float> sensorPowerList = new ArrayList<>();
private final ArrayList<Float> altitudeGainList = new ArrayList<>(); private final ArrayList<Float> altitudeGainList = new ArrayList<>();
private final ArrayList<Float> altitudeLossList = new ArrayList<>(); private final ArrayList<Float> altitudeLossList = new ArrayList<>();
private final ArrayList<Float> accuracyHorizontal = new ArrayList<>();
private final ArrayList<Marker> markers = new ArrayList<>(); private final ArrayList<Marker> markers = new ArrayList<>();
@@ -294,6 +295,7 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
sensorPowerList.clear(); sensorPowerList.clear();
altitudeGainList.clear(); altitudeGainList.clear();
altitudeLossList.clear(); altitudeLossList.clear();
accuracyHorizontal.clear();
} }
private void onTrackSegmentEnd() { private void onTrackSegmentEnd() {
@@ -333,6 +335,9 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
if (i < altitudeLossList.size()) { if (i < altitudeLossList.size()) {
trackPoint.setAltitudeLoss(altitudeLossList.get(i)); trackPoint.setAltitudeLoss(altitudeLossList.get(i));
} }
if (i < accuracyHorizontal.size() && accuracyHorizontal.get(i) != null) {
trackPoint.setHorizontalAccuracy(Distance.of(accuracyHorizontal.get(i)));
}
// Update TrackPoint type for START / STOP. // Update TrackPoint type for START / STOP.
TrackPoint.Type type = trackPoint.getType(); TrackPoint.Type type = trackPoint.getType();
@@ -430,6 +435,9 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
case KMLTrackExporter.EXTENDED_DATA_TYPE_ALTITUDE_LOSS: case KMLTrackExporter.EXTENDED_DATA_TYPE_ALTITUDE_LOSS:
altitudeLossList.add(value); altitudeLossList.add(value);
break; break;
case KMLTrackExporter.EXTENDED_DATA_TYPE_ACCURACY_HORIZONTAL:
accuracyHorizontal.add(value);
break;
default: default:
Log.w(TAG, "Data from extended data " + extendedDataType + " is not (yet) supported."); Log.w(TAG, "Data from extended data " + extendedDataType + " is not (yet) supported.");
} }