diff --git a/doc/opentracks-schema-1.0.xsd b/doc/opentracks-schema-1.0.xsd index 388083a8c..c49cffa54 100644 --- a/doc/opentracks-schema-1.0.xsd +++ b/doc/opentracks-schema-1.0.xsd @@ -29,11 +29,12 @@ - - 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. diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index 71862105d..32f4d0071 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -206,8 +206,7 @@ public class ExportImportTest { assertEquals(track.getIcon(), importedTrack.getIcon()); // 2. trackpoints - TrackPointAssert a = new TrackPointAssert() - .noAccuracy(); + TrackPointAssert a = new TrackPointAssert(); List actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId); a.assertEquals(trackPoints, actual); @@ -320,8 +319,7 @@ public class ExportImportTest { // Therefore, the track segmentation is changes. TrackPointAssert a = new TrackPointAssert() - .setDelta(0.05) - .noAccuracy(); // speed is not fully + .setDelta(0.05); // speed is not fully List actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId); a.assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:03Z")) @@ -330,7 +328,8 @@ public class ExportImportTest { .setAltitude(10) .setSpeed(Speed.of(15)) .setAltitudeLoss(1f) - .setAltitudeGain(1f), + .setAltitudeGain(1f) + .setHorizontalAccuracy(Distance.of(10)), new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:05Z")) .setLatitude(3) .setLongitude(14.001) @@ -341,21 +340,24 @@ public class ExportImportTest { .setSensorDistance(Distance.of(12)) .setHeartRate(66f) .setPower(50f) - .setCadence(3f), + .setCadence(3f) + .setHorizontalAccuracy(Distance.of(10)), new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:21Z")) .setLatitude(3) .setLongitude(14.002) .setAltitude(10) .setAltitudeLoss(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")) .setLatitude(3) .setLongitude(16) .setAltitude(10) .setAltitudeLoss(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")) .setLatitude(3) .setLongitude(16.001) @@ -363,6 +365,7 @@ public class ExportImportTest { .setAltitudeLoss(0f) .setAltitudeGain(0f) .setSpeed(Speed.of(15)) + .setHorizontalAccuracy(Distance.of(10)) ), actual); // 3. trackstatistics diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java index 1d5788c36..af568a728 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java @@ -8,8 +8,6 @@ import de.dennisguse.opentracks.data.models.TrackPoint; public class TrackPointAssert { - private boolean assertAccuracy = true; - private double delta = 0.001; public TrackPointAssert() { @@ -45,13 +43,9 @@ public class TrackPointAssert { Assert.assertEquals(expected.getSpeed().toMPS(), actual.getSpeed().toMPS(), delta); } - if (assertAccuracy) { - Assert.assertEquals(expected.hasHorizontalAccuracy(), actual.hasHorizontalAccuracy()); - if (expected.hasHorizontalAccuracy()) { - Assert.assertEquals(expected.getHorizontalAccuracy().toM(), actual.getHorizontalAccuracy().toM(), delta); - } - } else { - Assert.assertFalse(actual.hasHorizontalAccuracy()); + Assert.assertEquals(expected.hasHorizontalAccuracy(), actual.hasHorizontalAccuracy()); + if (expected.hasHorizontalAccuracy()) { + Assert.assertEquals(expected.getHorizontalAccuracy().toM(), actual.getHorizontalAccuracy().toM(), delta); } 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) { this.delta = delta; return this; diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java index 03029d80e..583dda826 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java @@ -359,7 +359,7 @@ public class GPXTrackExporter implements TrackExporter { } if (trackPoint.hasHorizontalAccuracy()) { - trackPointExtensionContent += ("" + DISTANCE_FORMAT.format(trackPoint.getHorizontalAccuracy().toM()) + ""); + trackPointExtensionContent += ("" + DISTANCE_FORMAT.format(trackPoint.getHorizontalAccuracy().toM()) + ""); } cumulativeDistance = Distance.ofOrNull(cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasSensorDistance() ? tp.getSensorDistance().toM() : null)); diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java index 639090e19..3862be74e 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java @@ -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_ALTITUDE_GAIN = "elevation_gain"; 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 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 heartRateList = new ArrayList<>(); private final List altitudeGainList = new ArrayList<>(); private final List altitudeLossList = new ArrayList<>(); + private final List accuracyHorizontal = new ArrayList<>(); public KMLTrackExporter(Context context, boolean exportPhotos) { this.context = context; @@ -333,6 +335,7 @@ public class KMLTrackExporter implements TrackExporter { heartRateList.clear(); altitudeGainList.clear(); altitudeLossList.clear(); + accuracyHorizontal.clear(); } } @@ -362,6 +365,9 @@ public class KMLTrackExporter implements TrackExporter { if (altitudeLossList.stream().anyMatch(Objects::nonNull)) { writeSimpleArrayData(altitudeLossList, EXTENDED_DATA_TYPE_ALTITUDE_LOSS); } + if (accuracyHorizontal.stream().anyMatch(Objects::nonNull)) { + writeSimpleArrayData(accuracyHorizontal, EXTENDED_DATA_TYPE_ACCURACY_HORIZONTAL); + } printWriter.println(""); printWriter.println(""); printWriter.println(""); @@ -387,6 +393,7 @@ public class KMLTrackExporter implements TrackExporter { altitudeGainList.add(trackPoint.hasAltitudeGain() ? trackPoint.getAltitudeGain() : null); altitudeLossList.add(trackPoint.hasAltitudeLoss() ? trackPoint.getAltitudeLoss() : null); + accuracyHorizontal.add(trackPoint.hasHorizontalAccuracy() ? (float) trackPoint.getHorizontalAccuracy().toM() : null); } } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/GpxTrackImporter.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/GpxTrackImporter.java index d98d80ea2..6e46450bb 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/importer/GpxTrackImporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/GpxTrackImporter.java @@ -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_LOSS = "opentracks:loss"; private static final String TAG_EXTENSION_DISTANCE = "opentracks:distance"; + private static final String TAG_EXTENSION_ACCURACY_HORIZONTAL = "opentracks:accuracy_horizontal"; private Locator locator; @@ -106,12 +107,13 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac private String heartrate; private String cadence; private String power; - protected String markerType; - protected String photoUrl; - protected String uuid; - protected String gain; - protected String loss; - protected String sensorDistance; + private String markerType; + private String photoUrl; + private String uuid; + private String gain; + private String loss; + private String sensorDistance; + private String accuracyHorizontal; private final LinkedList currentSegment = new LinkedList<>(); @@ -240,6 +242,11 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac sensorDistance = content.trim(); } break; + case TAG_EXTENSION_ACCURACY_HORIZONTAL: + if (content != null) { + accuracyHorizontal = content.trim(); + } + break; } 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); } } + 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; } @@ -357,6 +371,7 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac loss = null; sensorDistance = null; + accuracyHorizontal = null; power = null; heartrate = null; cadence = null; diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java index 52ba30e28..f23dc7715 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java @@ -89,6 +89,7 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac private final ArrayList sensorPowerList = new ArrayList<>(); private final ArrayList altitudeGainList = new ArrayList<>(); private final ArrayList altitudeLossList = new ArrayList<>(); + private final ArrayList accuracyHorizontal = new ArrayList<>(); private final ArrayList markers = new ArrayList<>(); @@ -294,6 +295,7 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac sensorPowerList.clear(); altitudeGainList.clear(); altitudeLossList.clear(); + accuracyHorizontal.clear(); } private void onTrackSegmentEnd() { @@ -333,6 +335,9 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac if (i < altitudeLossList.size()) { 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. TrackPoint.Type type = trackPoint.getType(); @@ -430,6 +435,9 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac case KMLTrackExporter.EXTENDED_DATA_TYPE_ALTITUDE_LOSS: altitudeLossList.add(value); break; + case KMLTrackExporter.EXTENDED_DATA_TYPE_ACCURACY_HORIZONTAL: + accuracyHorizontal.add(value); + break; default: Log.w(TAG, "Data from extended data " + extendedDataType + " is not (yet) supported."); }