diff --git a/navigation/build.gradle b/navigation/build.gradle index d0aa70430cc..0f5b68c4730 100644 --- a/navigation/build.gradle +++ b/navigation/build.gradle @@ -6,6 +6,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:2.3.2' + classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -20,4 +21,4 @@ allprojects { task clean(type: Delete) { delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/navigation/libandroid-navigation/build.gradle b/navigation/libandroid-navigation/build.gradle index f73e329b15d..b1043cc8771 100644 --- a/navigation/libandroid-navigation/build.gradle +++ b/navigation/libandroid-navigation/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.library' +apply plugin: 'com.neenbedankt.android-apt' android { compileSdkVersion 25 @@ -36,6 +37,10 @@ dependencies { // Logging compile 'com.jakewharton.timber:timber:4.5.1' + // AutoValues + provided 'com.google.auto.value:auto-value:1.4.1' + apt 'com.google.auto.value:auto-value:1.4.1' + // Testing testCompile 'junit:junit:4.12' testCompile 'org.hamcrest:hamcrest-junit:2.0.0.0' diff --git a/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/NavigationEngine.java b/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/NavigationEngine.java index 6a73efba8d1..d21d6e249a0 100644 --- a/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/NavigationEngine.java +++ b/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/NavigationEngine.java @@ -9,6 +9,7 @@ import com.mapbox.services.android.navigation.v5.listeners.OffRouteListener; import com.mapbox.services.android.navigation.v5.listeners.ProgressChangeListener; import com.mapbox.services.api.directions.v5.models.DirectionsRoute; +import com.mapbox.services.commons.models.Position; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; @@ -60,7 +61,9 @@ class NavigationEngine { void onLocationChanged(DirectionsRoute directionsRoute, Location location) { // if the previousRouteProgress is null, the route has just begun and one needs to be created if (previousRouteProgress == null) { - previousRouteProgress = new RouteProgress(directionsRoute, location, 0, 0, NavigationConstants.NONE_ALERT_LEVEL); + Position currentPosition = Position.fromCoordinates(location.getLongitude(), location.getLatitude()); + previousRouteProgress = RouteProgress.create(directionsRoute, currentPosition, + 0, 0, NavigationConstants.NONE_ALERT_LEVEL); } if (!TextUtils.equals(directionsRoute.getGeometry(), previousRouteProgress.getRoute().getGeometry())) { @@ -81,8 +84,12 @@ void onLocationChanged(DirectionsRoute directionsRoute, Location location) { stepIndex = alertLevelState.getStepIndex(); legIndex = alertLevelState.getLegIndex(); - // Create a new RouteProgress object using the latest user location - RouteProgress routeProgress = new RouteProgress(directionsRoute, location, legIndex, stepIndex, alertLevel); + SnapLocation snapLocation = new SnapLocation(location, + previousRouteProgress.getCurrentLegProgress().getCurrentStep(), options); + + // Create a RouteProgress.create object using the latest user location + RouteProgress routeProgress = RouteProgress.create(directionsRoute, snapLocation.getUsersCurrentSnappedPosition(), + legIndex, stepIndex, alertLevel); // Determine if the user is off route or not UserOffRouteState userOffRouteState = new UserOffRouteState(location, routeProgress, options); @@ -90,8 +97,8 @@ void onLocationChanged(DirectionsRoute directionsRoute, Location location) { // Snap location to the route if they aren't off route and return the location object if (isSnapEnabled && !isUserOffRoute) { - SnapLocation snapLocation = new SnapLocation(location, routeProgress, options); location = snapLocation.getSnappedLocation(); + location.setBearing(snapLocation.snapUserBearing(routeProgress)); } notifyAlertLevelChange(routeProgress); diff --git a/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/RouteProgress.java b/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/RouteProgress.java index cb5abe30a06..1b850b8074b 100644 --- a/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/RouteProgress.java +++ b/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/RouteProgress.java @@ -1,15 +1,15 @@ package com.mapbox.services.android.navigation.v5; -import android.location.Location; - +import com.google.auto.value.AutoValue; import com.mapbox.services.Constants; import com.mapbox.services.Experimental; import com.mapbox.services.android.navigation.v5.models.RouteLegProgress; import com.mapbox.services.api.directions.v5.models.DirectionsRoute; import com.mapbox.services.api.directions.v5.models.RouteLeg; import com.mapbox.services.api.utils.turf.TurfConstants; +import com.mapbox.services.api.utils.turf.TurfMeasurement; import com.mapbox.services.api.utils.turf.TurfMisc; -import com.mapbox.services.commons.geojson.Feature; +import com.mapbox.services.commons.geojson.LineString; import com.mapbox.services.commons.geojson.Point; import com.mapbox.services.commons.models.Position; import com.mapbox.services.commons.utils.PolylineUtils; @@ -29,44 +29,35 @@ * @since 0.1.0 */ @Experimental -public class RouteProgress { +@AutoValue +public abstract class RouteProgress { + + public abstract RouteLegProgress currentLegProgress(); + + public abstract DirectionsRoute route(); + + public abstract Position userSnappedPosition(); - private RouteLegProgress currentLegProgress; - private DirectionsRoute route; - private Location location; - private int LegIndex; - private int alertUserLevel; - private double routeDistance; - private int stepIndex; + public abstract int legIndex(); + + public abstract int alertUserLevel(); /** * Constructor for the route routeProgress information. * - * @param route the {@link DirectionsRoute} being used for the navigation session. When a user is - * rerouted this route is updated. - * @param location the users location most recently used when creating this object. - * @param stepIndex an {@code integer} representing the current step index the user is on. - * @param alertUserLevel the most recently calculated alert level. + * @param route the {@link DirectionsRoute} being used for the navigation session. When a user is + * rerouted this route is updated. + * @param userSnappedPosition the users position most recently used when creating this object. + * @param stepIndex an {@code integer} representing the current step index the user is on. + * @param alertUserLevel the most recently calculated alert level. * @since 0.1.0 */ - RouteProgress(DirectionsRoute route, Location location, int legIndex, int stepIndex, int alertUserLevel) { - this.route = route; - this.alertUserLevel = alertUserLevel; - this.location = location; - this.LegIndex = legIndex; - this.stepIndex = stepIndex; - currentLegProgress = new RouteLegProgress(getCurrentLeg(), stepIndex, getUsersCurrentSnappedPosition()); - initialize(); - } - - private void initialize() { - // Measure route from beginning to end. This is done since the directions API gives a different distance then the - // one we measure using turf. - routeDistance = RouteUtils.getDistanceToEndOfRoute( - route.getLegs().get(0).getSteps().get(0).getManeuver().asPosition(), - route, - TurfConstants.UNIT_METERS - ); + public static RouteProgress create( + DirectionsRoute route, Position userSnappedPosition, int legIndex, int stepIndex, int alertUserLevel) { + RouteLegProgress routeLegProgress + = RouteLegProgress.create(route.getLegs().get(legIndex), stepIndex, userSnappedPosition); + return new AutoValue_RouteProgress( + routeLegProgress, route, userSnappedPosition, legIndex, alertUserLevel); } /** @@ -76,7 +67,7 @@ private void initialize() { * @since 0.1.0 */ public RouteLegProgress getCurrentLegProgress() { - return currentLegProgress; + return currentLegProgress(); } /** @@ -86,7 +77,7 @@ public RouteLegProgress getCurrentLegProgress() { * @since 0.1.0 */ public int getLegIndex() { - return LegIndex; + return legIndex(); } /** @@ -95,7 +86,7 @@ public int getLegIndex() { * @return a {@link RouteLeg} the user is currently on. */ public RouteLeg getCurrentLeg() { - return route.getLegs().get(getLegIndex()); + return route().getLegs().get(getLegIndex()); } /** @@ -105,7 +96,11 @@ public RouteLeg getCurrentLeg() { * @since 0.1.0 */ public double getDistanceTraveled() { - return routeDistance - getDistanceRemaining(); + double distanceTraveled = route().getDistance() - getDistanceRemaining(); + if (distanceTraveled < 0) { + distanceTraveled = 0; + } + return distanceTraveled; } /** @@ -114,8 +109,8 @@ public double getDistanceTraveled() { * @return {@code long} value representing the duration remaining till end of route, in unit seconds. * @since 0.1.0 */ - public long getDurationRemaining() { - return (long) ((1 - getFractionTraveled()) * route.getDuration()); + public double getDurationRemaining() { + return (1 - getFractionTraveled()) * route().getDuration(); } /** @@ -126,7 +121,12 @@ public long getDurationRemaining() { * @since 0.1.0 */ public float getFractionTraveled() { - return (float) (getDistanceTraveled() / routeDistance); + float fractionRemaining = 1; + + if (route().getDistance() > 0) { + fractionRemaining = (float) (getDistanceTraveled() / route().getDistance()); + } + return fractionRemaining; } /** @@ -136,7 +136,22 @@ public float getFractionTraveled() { * @since 0.1.0 */ public double getDistanceRemaining() { - return RouteUtils.getDistanceToEndOfRoute(getUsersCurrentSnappedPosition(), route, TurfConstants.UNIT_METERS); + double distanceRemaining = 0; + + List coords = PolylineUtils.decode(currentLegProgress().getCurrentStep().getGeometry(), + Constants.PRECISION_6); + if (coords.size() > 1) { + LineString slicedLine = TurfMisc.lineSlice( + Point.fromCoordinates(userSnappedPosition()), + Point.fromCoordinates(coords.get(coords.size() - 1)), + LineString.fromCoordinates(coords) + ); + distanceRemaining += TurfMeasurement.lineDistance(slicedLine, TurfConstants.UNIT_METERS); + } + for (int i = currentLegProgress().getStepIndex() + 1; i < getCurrentLeg().getSteps().size(); i++) { + distanceRemaining += getCurrentLeg().getSteps().get(i).getDistance(); + } + return distanceRemaining; } /** @@ -146,7 +161,7 @@ public double getDistanceRemaining() { * @since 0.1.0 */ public int getAlertUserLevel() { - return alertUserLevel; + return alertUserLevel(); } /** @@ -156,25 +171,6 @@ public int getAlertUserLevel() { * @since 0.1.0 */ public DirectionsRoute getRoute() { - return route; - } - - /** - * Provides the users location snapped to the current route they are navigating on. - * - * @return {@link Position} object with coordinates snapping the user to the route. - * @since 0.1.0 - */ - public Position getUsersCurrentSnappedPosition() { - Point locationToPoint = Point.fromCoordinates(new double[] {location.getLongitude(), location.getLatitude()}); - String stepGeometry = route.getLegs().get(getLegIndex()).getSteps().get(stepIndex).getGeometry(); - - // Decode the geometry - List coords = PolylineUtils.decode(stepGeometry, Constants.PRECISION_6); - - // Uses Turf's pointOnLine, which takes a Point and a LineString to calculate the closest - // Point on the LineString. - Feature feature = TurfMisc.pointOnLine(locationToPoint, coords); - return ((Point) feature.getGeometry()).getCoordinates(); + return route(); } } diff --git a/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/SnapLocation.java b/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/SnapLocation.java index 5b12132718c..3012d05574a 100644 --- a/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/SnapLocation.java +++ b/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/SnapLocation.java @@ -2,49 +2,70 @@ import android.location.Location; +import com.mapbox.services.Constants; import com.mapbox.services.android.telemetry.utils.MathUtils; +import com.mapbox.services.api.directions.v5.models.LegStep; import com.mapbox.services.api.utils.turf.TurfConstants; import com.mapbox.services.api.utils.turf.TurfMeasurement; +import com.mapbox.services.api.utils.turf.TurfMisc; +import com.mapbox.services.commons.geojson.Feature; import com.mapbox.services.commons.geojson.LineString; import com.mapbox.services.commons.geojson.Point; import com.mapbox.services.commons.models.Position; +import com.mapbox.services.commons.utils.PolylineUtils; + +import java.util.List; public class SnapLocation { private MapboxNavigationOptions options; - private RouteProgress routeProgress; + private LegStep currentStep; + private Location location; - SnapLocation(Location location, RouteProgress routeProgress, MapboxNavigationOptions options) { + SnapLocation(Location location, LegStep currentStep, MapboxNavigationOptions options) { this.location = location; - this.routeProgress = routeProgress; + this.currentStep = currentStep; this.options = options; } Location getSnappedLocation() { // Pass in the snapped location with all the other location data remaining intact for their use. - location.setLatitude(routeProgress.getUsersCurrentSnappedPosition().getLatitude()); - location.setLongitude(routeProgress.getUsersCurrentSnappedPosition().getLongitude()); - - location.setBearing(snapUserBearing()); - + location.setLatitude(getUsersCurrentSnappedPosition().getLatitude()); + location.setLongitude(getUsersCurrentSnappedPosition().getLongitude()); return location; } - private float snapUserBearing() { + /** + * Provides the users location snapped to the current route they are navigating on. + * + * @return {@link Position} object with coordinates snapping the user to the route. + * @since 0.1.0 + */ + Position getUsersCurrentSnappedPosition() { + Point locationToPoint = Point.fromCoordinates(new double[] {location.getLongitude(), location.getLatitude()}); + String stepGeometry = currentStep.getGeometry(); + + // Decode the geometry + List coords = PolylineUtils.decode(stepGeometry, Constants.PRECISION_6); + + // Uses Turf's pointOnLine, which takes a Point and a LineString to calculate the closest + // Point on the LineString. + Feature feature = TurfMisc.pointOnLine(locationToPoint, coords); + return ((Point) feature.getGeometry()).getCoordinates(); + } + + float snapUserBearing(RouteProgress routeProgress) { LineString lineString = LineString.fromPolyline(routeProgress.getRoute().getGeometry(), com.mapbox.services.Constants.PRECISION_6); Position newCoordinate; - newCoordinate = routeProgress.getUsersCurrentSnappedPosition(); + newCoordinate = getUsersCurrentSnappedPosition(); double userDistanceBuffer = location.getSpeed() * options.getDeadReckoningTimeInterval(); if (routeProgress.getDistanceTraveled() + userDistanceBuffer - > RouteUtils.getDistanceToEndOfRoute( - routeProgress.getRoute().getLegs().get(0).getSteps().get(0).getManeuver().asPosition(), - routeProgress.getRoute(), - TurfConstants.UNIT_METERS)) { + > routeProgress.getRoute().getDistance()) { // If the user is near the end of the route, take the remaining distance and divide by two userDistanceBuffer = routeProgress.getDistanceRemaining() / 2; } diff --git a/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/models/RouteLegProgress.java b/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/models/RouteLegProgress.java index db486305c8e..86ab4abae91 100644 --- a/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/models/RouteLegProgress.java +++ b/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/models/RouteLegProgress.java @@ -1,22 +1,34 @@ package com.mapbox.services.android.navigation.v5.models; +import android.support.annotation.NonNull; + +import com.google.auto.value.AutoValue; import com.mapbox.services.Constants; import com.mapbox.services.Experimental; -import com.mapbox.services.android.navigation.v5.RouteUtils; import com.mapbox.services.api.ServicesException; import com.mapbox.services.api.directions.v5.models.LegStep; import com.mapbox.services.api.directions.v5.models.RouteLeg; import com.mapbox.services.api.utils.turf.TurfConstants; +import com.mapbox.services.api.utils.turf.TurfMeasurement; +import com.mapbox.services.api.utils.turf.TurfMisc; +import com.mapbox.services.commons.geojson.LineString; +import com.mapbox.services.commons.geojson.Point; import com.mapbox.services.commons.models.Position; +import com.mapbox.services.commons.utils.PolylineUtils; + +import java.util.List; @Experimental -public class RouteLegProgress { +@AutoValue +public abstract class RouteLegProgress { + + public abstract RouteLeg routeLeg(); - private RouteLeg routeLeg; - private int stepIndex; - private Position userSnappedPosition; - private RouteStepProgress currentStepProgress; - private double legDistance; + public abstract int stepIndex(); + + public abstract Position userSnappedPosition(); + + public abstract RouteStepProgress currentStepProgress(); /** * Constructor for the route leg routeProgress information. @@ -26,18 +38,10 @@ public class RouteLegProgress { * @param userSnappedPosition the users snapped location when routeProgress was last updated. * @since 0.1.0 */ - public RouteLegProgress(RouteLeg routeLeg, int stepIndex, Position userSnappedPosition) { - this.routeLeg = routeLeg; - this.stepIndex = stepIndex; - this.userSnappedPosition = userSnappedPosition; - currentStepProgress = new RouteStepProgress(routeLeg, stepIndex, userSnappedPosition); - - legDistance = RouteUtils.getDistanceToNextLeg( - routeLeg.getSteps().get(0).getManeuver().asPosition(), - routeLeg, - TurfConstants.UNIT_METERS, - Constants.PRECISION_6 - ); + public static RouteLegProgress create( + @NonNull RouteLeg routeLeg, int stepIndex, @NonNull Position userSnappedPosition) { + RouteStepProgress routeStepProgress = RouteStepProgress.create(routeLeg, stepIndex, userSnappedPosition); + return new AutoValue_RouteLegProgress(routeLeg, stepIndex, userSnappedPosition, routeStepProgress); } /** @@ -47,7 +51,7 @@ public RouteLegProgress(RouteLeg routeLeg, int stepIndex, Position userSnappedPo * @since 0.1.0 */ public RouteStepProgress getCurrentStepProgress() { - return currentStepProgress; + return currentStepProgress(); } /** @@ -57,10 +61,10 @@ public RouteStepProgress getCurrentStepProgress() { * @since 0.1.0 */ public int getStepIndex() { - if (stepIndex < 0 || stepIndex > routeLeg.getSteps().size() - 1) { + if (stepIndex() < 0 || stepIndex() > routeLeg().getSteps().size() - 1) { throw new ServicesException("RouteProgress step index is outside its index limit."); } - return stepIndex; + return stepIndex(); } /** @@ -71,7 +75,11 @@ public int getStepIndex() { * @since 0.1.0 */ public double getDistanceTraveled() { - return legDistance - getDistanceRemaining(); + double distanceTraveled = routeLeg().getDistance() - getDistanceRemaining(); + if (distanceTraveled < 0) { + distanceTraveled = 0; + } + return distanceTraveled; } /** @@ -81,9 +89,22 @@ public double getDistanceTraveled() { * @since 0.1.0 */ public double getDistanceRemaining() { - return RouteUtils.getDistanceToNextLeg( - userSnappedPosition, routeLeg, TurfConstants.UNIT_METERS, Constants.PRECISION_6 - ); + double distanceRemaining = 0; + + List coords = PolylineUtils.decode(getCurrentStep().getGeometry(), Constants.PRECISION_6); + if (coords.size() > 1) { + LineString slicedLine = TurfMisc.lineSlice( + Point.fromCoordinates(userSnappedPosition()), + Point.fromCoordinates(coords.get(coords.size() - 1)), + LineString.fromCoordinates(coords) + ); + distanceRemaining += TurfMeasurement.lineDistance(slicedLine, TurfConstants.UNIT_METERS); + } + for (int i = stepIndex() + 1; i < routeLeg().getSteps().size(); i++) { + distanceRemaining += routeLeg().getSteps().get(i).getDistance(); + } + + return distanceRemaining; } /** @@ -92,8 +113,8 @@ public double getDistanceRemaining() { * @return {@code long} value representing the duration remaining till end of step, in unit seconds. * @since 0.1.0 */ - public long getDurationRemaining() { - return (long) ((1 - getFractionTraveled()) * routeLeg.getDuration()); + public double getDurationRemaining() { + return (1 - getFractionTraveled()) * routeLeg().getDuration(); } /** @@ -104,7 +125,15 @@ public long getDurationRemaining() { * @since 0.1.0 */ public float getFractionTraveled() { - return (float) (getDistanceTraveled() / legDistance); + float fractionTraveled = 1; + + if (routeLeg().getDistance() > 0) { + fractionTraveled = (float) (getDistanceTraveled() / routeLeg().getDistance()); + if (fractionTraveled < 0) { + fractionTraveled = 0; + } + } + return fractionTraveled; } /** @@ -118,7 +147,7 @@ public LegStep getPreviousStep() { if (getStepIndex() == 0) { return null; } - return routeLeg.getSteps().get(getStepIndex() - 1); + return routeLeg().getSteps().get(getStepIndex() - 1); } /** @@ -128,7 +157,7 @@ public LegStep getPreviousStep() { * @since 0.1.0 */ public LegStep getCurrentStep() { - return routeLeg.getSteps().get(getStepIndex()); + return routeLeg().getSteps().get(getStepIndex()); } /** @@ -139,8 +168,8 @@ public LegStep getCurrentStep() { * @since 0.1.0 */ public LegStep getUpComingStep() { - if (routeLeg.getSteps().size() > getStepIndex()) { - return routeLeg.getSteps().get(getStepIndex() + 1); + if (routeLeg().getSteps().size() - 1 > getStepIndex()) { + return routeLeg().getSteps().get(getStepIndex() + 1); } return null; } diff --git a/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/models/RouteStepProgress.java b/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/models/RouteStepProgress.java index 3abaf4fd144..ce66cd61e2b 100644 --- a/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/models/RouteStepProgress.java +++ b/navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/models/RouteStepProgress.java @@ -3,6 +3,7 @@ import android.support.annotation.NonNull; +import com.google.auto.value.AutoValue; import com.mapbox.services.Constants; import com.mapbox.services.Experimental; import com.mapbox.services.api.directions.v5.models.LegStep; @@ -18,11 +19,12 @@ import java.util.List; @Experimental -public class RouteStepProgress { +@AutoValue +public abstract class RouteStepProgress { - private LegStep step; - private Position userSnappedPosition; - private double stepDistance; + public abstract LegStep step(); + + public abstract Position userSnappedPosition(); /** * Constructor for the step progress. @@ -31,21 +33,10 @@ public class RouteStepProgress { * @param userSnappedPosition the users snapped location when routeProgress was last updated. * @since 0.1.0 */ - RouteStepProgress(@NonNull RouteLeg routeLeg, int stepIndex, @NonNull Position userSnappedPosition) { - this.userSnappedPosition = userSnappedPosition; - this.step = routeLeg.getSteps().get(stepIndex); - - // Decode the geometry - List coords = PolylineUtils.decode(step.getGeometry(), Constants.PRECISION_6); - - if (coords.size() > 1) { - LineString slicedLine = TurfMisc.lineSlice( - Point.fromCoordinates(step.getManeuver().asPosition()), - Point.fromCoordinates(coords.get(coords.size() - 1)), - LineString.fromCoordinates(coords) - ); - stepDistance = TurfMeasurement.lineDistance(slicedLine, TurfConstants.UNIT_METERS); - } + static RouteStepProgress create( + @NonNull RouteLeg routeLeg, int stepIndex, @NonNull Position userSnappedPosition) { + LegStep step = routeLeg.getSteps().get(stepIndex); + return new AutoValue_RouteStepProgress(step, userSnappedPosition); } /** @@ -56,7 +47,11 @@ public class RouteStepProgress { * @since 0.1.0 */ public double getDistanceTraveled() { - return stepDistance - getDistanceRemaining(); + double distanceTraveled = step().getDistance() - getDistanceRemaining(); + if (distanceTraveled < 0) { + distanceTraveled = 0; + } + return distanceTraveled; } /** @@ -70,11 +65,11 @@ public double getDistanceRemaining() { double distanceRemaining = 0; // Decode the geometry - List coords = PolylineUtils.decode(step.getGeometry(), Constants.PRECISION_6); + List coords = PolylineUtils.decode(step().getGeometry(), Constants.PRECISION_6); if (coords.size() > 1) { LineString slicedLine = TurfMisc.lineSlice( - Point.fromCoordinates(userSnappedPosition), + Point.fromCoordinates(userSnappedPosition()), Point.fromCoordinates(coords.get(coords.size() - 1)), LineString.fromCoordinates(coords) ); @@ -91,12 +86,15 @@ public double getDistanceRemaining() { * @since 0.1.0 */ public float getFractionTraveled() { - float fractionRemaining = 1; + float fractionTraveled = 1; - if (stepDistance > 0) { - fractionRemaining = (float) (getDistanceTraveled() / stepDistance); + if (step().getDistance() > 0) { + fractionTraveled = (float) (getDistanceTraveled() / step().getDistance()); + if (fractionTraveled < 0) { + fractionTraveled = 0; + } } - return fractionRemaining; + return fractionTraveled; } /** @@ -105,8 +103,8 @@ public float getFractionTraveled() { * @return {@code long} value representing the duration remaining till end of step, in unit seconds. * @since 0.1.0 */ - public long getDurationRemaining() { - return (long) ((1 - getFractionTraveled()) * step.getDuration()); + public double getDurationRemaining() { + return (1 - getFractionTraveled()) * step().getDuration(); } diff --git a/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/BaseTest.java b/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/BaseTest.java index 8decdf088f9..007591881c0 100644 --- a/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/BaseTest.java +++ b/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/BaseTest.java @@ -10,8 +10,9 @@ public class BaseTest { public static final double DELTA = 1E-10; - private static final String BASE_PATH = "/res/"; + public static final double LARGE_DELTA = 0.1; + private static final String BASE_PATH = "/res/"; private static final String LOG_TAG = BaseTest.class.getSimpleName(); protected String readPath(String path) { diff --git a/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/RouteProgressTest.java b/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/RouteProgressTest.java index 596a9609ea3..82008ab372f 100644 --- a/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/RouteProgressTest.java +++ b/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/RouteProgressTest.java @@ -1,34 +1,174 @@ package com.mapbox.services.android.navigation.v5; -import android.location.Location; - import com.google.gson.Gson; +import com.mapbox.services.Constants; import com.mapbox.services.api.directions.v5.models.DirectionsResponse; import com.mapbox.services.api.directions.v5.models.DirectionsRoute; +import com.mapbox.services.api.directions.v5.models.RouteLeg; +import com.mapbox.services.api.utils.turf.TurfConstants; +import com.mapbox.services.api.utils.turf.TurfMeasurement; +import com.mapbox.services.commons.geojson.LineString; +import com.mapbox.services.commons.models.Position; + +import junit.framework.Assert; import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; import static junit.framework.Assert.assertNotNull; public class RouteProgressTest extends BaseTest { - private DirectionsResponse response; + // Fixtures + private static final String PRECISION_6 = "directions_v5_precision_6.json"; + private DirectionsRoute route; + private RouteLeg firstLeg; + private Position userSnappedPosition; @Before public void setup() { Gson gson = new Gson(); - String body = readPath("directions_v5.json"); - response = gson.fromJson(body, DirectionsResponse.class); + String body = readPath(PRECISION_6); + DirectionsResponse response = gson.fromJson(body, DirectionsResponse.class); route = response.getRoutes().get(0); + firstLeg = route.getLegs().get(0); + userSnappedPosition = firstLeg.getSteps().get(4).getManeuver().asPosition(); } @Test public void sanityTest() { - RouteProgress routeProgress = new RouteProgress(route, Mockito.mock(Location.class), 0, 0, 0); + RouteProgress routeProgress = RouteProgress.create(route, userSnappedPosition, 0, 0, 0); assertNotNull("should not be null", routeProgress); } -} + @Test + public void getRoute_returnsDirectionsRoute() { + RouteProgress routeProgress + = RouteProgress.create(route, userSnappedPosition, 0, 0, NavigationConstants.DEPART_ALERT_LEVEL); + + Assert.assertEquals(route, routeProgress.getRoute()); + } + + @Test + public void getAlertLevel_returnsCorrectAlertLevel() { + RouteProgress routeProgress + = RouteProgress.create(route, userSnappedPosition, 0, 0, NavigationConstants.LOW_ALERT_LEVEL); + + Assert.assertEquals(NavigationConstants.LOW_ALERT_LEVEL, routeProgress.getAlertUserLevel()); + Assert.assertNotSame(NavigationConstants.HIGH_ALERT_LEVEL, routeProgress.getAlertUserLevel()); + } + + @Test + public void getDistanceRemaining_equalsZeroAtEndOfRoute() { + RouteProgress routeProgress + = RouteProgress.create( + route, firstLeg.getSteps().get(firstLeg.getSteps().size() - 1).getManeuver().asPosition(), + route.getLegs().size() - 1, firstLeg.getSteps().size() - 1, NavigationConstants.LOW_ALERT_LEVEL); + + Assert.assertEquals(0, routeProgress.getDistanceRemaining(), DELTA); + } + + @Test + public void getDistanceRemaining_equalsRouteDistanceAtBeginning() { + RouteProgress routeProgress + = RouteProgress.create( + route, firstLeg.getSteps().get(0).getManeuver().asPosition(), + 0, 0, NavigationConstants.LOW_ALERT_LEVEL); + + Assert.assertEquals(route.getDistance(), routeProgress.getDistanceRemaining(), LARGE_DELTA); + } + + @Test + public void getFractionTraveled_equalsZeroAtBeginning() { + RouteProgress routeProgress + = RouteProgress.create(route, firstLeg.getSteps().get(0).getManeuver().asPosition(), + 0, 0, NavigationConstants.DEPART_ALERT_LEVEL); + + Assert.assertEquals(0, routeProgress.getFractionTraveled(), BaseTest.LARGE_DELTA); + } + + @Test + public void getFractionTraveled_equalsCorrectValueAtIntervals() { + LineString lineString = LineString.fromPolyline(route.getGeometry(), Constants.PRECISION_6); + + double stepSegments = 500; // meters + + // Chop the line in small pieces + for (double i = 0; i < route.getDistance(); i += stepSegments) { + Position position = TurfMeasurement.along(lineString, i, TurfConstants.UNIT_METERS).getCoordinates(); + + RouteProgress routeProgress = RouteProgress.create(route, position, 0, 0, NavigationConstants.DEPART_ALERT_LEVEL); + float fractionRemaining = (float) (routeProgress.getDistanceTraveled() / route.getDistance()); + Assert.assertEquals(fractionRemaining, routeProgress.getFractionTraveled(), BaseTest.DELTA); + } + } + + @Test + public void getFractionTraveled_equalsOneAtEndOfRoute() { + Position lastCoordinate + = route.getLegs().get(0).getSteps().get(route.getLegs().get(0).getSteps().size() - 1).getManeuver().asPosition(); + + RouteProgress routeProgress = RouteProgress.create(route, lastCoordinate, + route.getLegs().size() - 1, firstLeg.getSteps().size() - 1, NavigationConstants.ARRIVE_ALERT_LEVEL); + + Assert.assertEquals(1.0, routeProgress.getFractionTraveled(), DELTA); + } + + @Test + public void getDurationRemaining_equalsRouteDurationAtBeginning() { + RouteProgress routeProgress + = RouteProgress.create(route, firstLeg.getSteps().get(0).getManeuver().asPosition(), + 0, 0, NavigationConstants.DEPART_ALERT_LEVEL); + + Assert.assertEquals(3535.2, routeProgress.getDurationRemaining(), BaseTest.DELTA); + } + + @Test + public void getDurationRemaining_equalsZeroAtEndOfRoute() { + Position lastCoordinate + = route.getLegs().get(0).getSteps().get(route.getLegs().get(0).getSteps().size() - 1).getManeuver().asPosition(); + + RouteProgress routeProgress = RouteProgress.create(route, lastCoordinate, + route.getLegs().size() - 1, firstLeg.getSteps().size() - 1, NavigationConstants.ARRIVE_ALERT_LEVEL); + + Assert.assertEquals(0, routeProgress.getDurationRemaining(), BaseTest.DELTA); + } + + @Test + public void getDistanceTraveled_equalsZeroAtBeginning() { + RouteProgress routeProgress + = RouteProgress.create(route, firstLeg.getSteps().get(0).getManeuver().asPosition(), + 0, 0, NavigationConstants.DEPART_ALERT_LEVEL); + Assert.assertEquals(0, routeProgress.getDistanceTraveled(), BaseTest.DELTA); + } + + @Test + public void getDistanceTraveled_equalsRouteDistanceAtEndOfRoute() { + Position lastCoordinate + = route.getLegs().get(0).getSteps().get(route.getLegs().get(0).getSteps().size() - 1).getManeuver().asPosition(); + + RouteProgress routeProgress = RouteProgress.create(route, lastCoordinate, + route.getLegs().size() - 1, firstLeg.getSteps().size() - 1, NavigationConstants.ARRIVE_ALERT_LEVEL); + + Assert.assertEquals(route.getDistance(), routeProgress.getDistanceTraveled(), BaseTest.DELTA); + } + + @Test + public void getCurrentLeg_returnsCurrentLeg() { + RouteProgress routeProgress + = RouteProgress.create(route, firstLeg.getSteps().get(0).getManeuver().asPosition(), + 0, 0, NavigationConstants.DEPART_ALERT_LEVEL); + + Assert.assertEquals(route.getLegs().get(0), routeProgress.getCurrentLeg()); + } + + @Test + public void getLegIndex_returnsCurrentLegIndex() { + RouteProgress routeProgress + = RouteProgress.create(route, firstLeg.getSteps().get(0).getManeuver().asPosition(), + 0, 0, NavigationConstants.DEPART_ALERT_LEVEL); + + Assert.assertEquals(0, routeProgress.getLegIndex()); + } +} \ No newline at end of file diff --git a/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/SnapLocationTest.java b/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/SnapLocationTest.java index a37f399958f..3d4ec596f0b 100644 --- a/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/SnapLocationTest.java +++ b/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/SnapLocationTest.java @@ -2,6 +2,8 @@ import android.location.Location; +import com.mapbox.services.api.directions.v5.models.LegStep; + import org.junit.Test; import org.mockito.Mockito; @@ -11,7 +13,7 @@ public class SnapLocationTest extends BaseTest { @Test public void sanityTest() { - SnapLocation snapLocation = new SnapLocation(Mockito.mock(Location.class), Mockito.mock(RouteProgress.class), + SnapLocation snapLocation = new SnapLocation(Mockito.mock(Location.class), Mockito.mock(LegStep.class), new MapboxNavigationOptions()); assertNotNull("should not be null", snapLocation); } diff --git a/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/models/RouteLegProgressTest.java b/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/models/RouteLegProgressTest.java new file mode 100644 index 00000000000..821d2d38b2a --- /dev/null +++ b/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/models/RouteLegProgressTest.java @@ -0,0 +1,177 @@ +package com.mapbox.services.android.navigation.v5.models; + +import com.google.gson.Gson; +import com.mapbox.services.Constants; +import com.mapbox.services.android.navigation.v5.BaseTest; +import com.mapbox.services.api.directions.v5.models.DirectionsResponse; +import com.mapbox.services.api.directions.v5.models.DirectionsRoute; +import com.mapbox.services.api.directions.v5.models.RouteLeg; +import com.mapbox.services.api.utils.turf.TurfConstants; +import com.mapbox.services.api.utils.turf.TurfMeasurement; +import com.mapbox.services.commons.geojson.LineString; +import com.mapbox.services.commons.models.Position; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class RouteLegProgressTest extends BaseTest { + + // Fixtures + private static final String PRECISION_6 = "directions_v5_precision_6.json"; + + private DirectionsRoute route; + private RouteLeg firstLeg; + + @Before + public void setup() { + Gson gson = new Gson(); + String body = readPath(PRECISION_6); + DirectionsResponse response = gson.fromJson(body, DirectionsResponse.class); + route = response.getRoutes().get(0); + firstLeg = route.getLegs().get(0); + } + + @Test + public void sanityTest() { + RouteLegProgress routeLegProgress + = RouteLegProgress.create(firstLeg, 0, Mockito.mock(Position.class)); + Assert.assertNotNull("should not be null", routeLegProgress); + } + + @Test + public void getUpComingStep_returnsNextStepInLeg() { + RouteLegProgress routeLegProgress + = RouteLegProgress.create(firstLeg, 5, firstLeg.getSteps().get(4).getManeuver().asPosition()); + + // TODO replace with equalsTo once https://github.com/mapbox/mapbox-java/pull/450 merged + Assert.assertTrue(routeLegProgress.getUpComingStep().getGeometry() + .startsWith("so{gfA~}xpgFzOyNnRoOdVqXzLmQbDiGhKqQ|Vie@`X{g@dkAw{B~NcXhPoWlRmXfSeW|U")); + } + + @Test + public void getUpComingStep_returnsNull() { + int lastStepIndex = firstLeg.getSteps().size() - 1; + RouteLegProgress routeLegProgress + = RouteLegProgress.create(firstLeg, lastStepIndex, + firstLeg.getSteps().get(lastStepIndex - 2).getManeuver().asPosition()); + + Assert.assertNull(routeLegProgress.getUpComingStep()); + } + + @Test + public void getCurrentStep_returnsCurrentStep() { + RouteLegProgress routeLegProgress + = RouteLegProgress.create(firstLeg, 5, firstLeg.getSteps().get(4).getManeuver().asPosition()); + + // TODO replace with equalsTo once https://github.com/mapbox/mapbox-java/pull/450 merged + Assert.assertEquals( + firstLeg.getSteps().get(5).getGeometry(), routeLegProgress.getCurrentStep().getGeometry() + ); + Assert.assertNotSame( + firstLeg.getSteps().get(6).getGeometry(), routeLegProgress.getCurrentStep().getGeometry() + ); + } + + @Test + public void getPreviousStep_returnsPreviousStep() { + RouteLegProgress routeLegProgress + = RouteLegProgress.create(firstLeg, 5, firstLeg.getSteps().get(4).getManeuver().asPosition()); + + // TODO replace with equalsTo once https://github.com/mapbox/mapbox-java/pull/450 merged + Assert.assertEquals( + firstLeg.getSteps().get(4).getGeometry(), routeLegProgress.getPreviousStep().getGeometry() + ); + Assert.assertNotSame( + firstLeg.getSteps().get(5).getGeometry(), routeLegProgress.getPreviousStep().getGeometry() + ); + } + + @Test + public void getStepIndex_returnsCurrentStepIndex() { + RouteLegProgress routeLegProgress = RouteLegProgress.create(firstLeg, 3, + firstLeg.getSteps().get(4).getManeuver().asPosition()); + + Assert.assertEquals(3, routeLegProgress.getStepIndex(), BaseTest.DELTA); + } + + @Test + public void getFractionTraveled_equalsZeroAtBeginning() { + RouteLegProgress routeLegProgress + = RouteLegProgress.create(firstLeg, 0, firstLeg.getSteps().get(0).getManeuver().asPosition()); + + Assert.assertEquals(0.0, routeLegProgress.getFractionTraveled(), BaseTest.DELTA); + } + + @Test + public void getFractionTraveled_equalsCorrectValueAtIntervals() { + double stepSegments = 5000; // meters + + // Chop the line in small pieces + LineString lineString = LineString.fromPolyline(route.getGeometry(), Constants.PRECISION_6); + for (double i = 0; i < firstLeg.getDistance(); i += stepSegments) { + Position position = TurfMeasurement.along(lineString, i, TurfConstants.UNIT_METERS).getCoordinates(); + + RouteLegProgress routeLegProgress = RouteLegProgress.create(firstLeg, 0, position); + float fractionRemaining = (float) (routeLegProgress.getDistanceTraveled() / firstLeg.getDistance()); + Assert.assertEquals(fractionRemaining, routeLegProgress.getFractionTraveled(), BaseTest.DELTA); + } + } + + @Test + public void getFractionTraveled_equalsOneAtEndOfLeg() { + RouteLegProgress routeLegProgress = RouteLegProgress.create(firstLeg, firstLeg.getSteps().size() - 1, + firstLeg.getSteps().get(firstLeg.getSteps().size() - 1).getManeuver().asPosition()); + + Assert.assertEquals(1.0, routeLegProgress.getFractionTraveled(), BaseTest.DELTA); + } + + @Test + public void getDistanceRemaining_equalsLegDistanceAtBeginning() { + RouteLegProgress routeLegProgress + = RouteLegProgress.create(firstLeg, 0, firstLeg.getSteps().get(0).getManeuver().asPosition()); + + Assert.assertEquals(firstLeg.getDistance(), routeLegProgress.getDistanceRemaining(), BaseTest.LARGE_DELTA); + } + + @Test + public void getDistanceRemaining_equalsZeroAtEndOfLeg() { + RouteLegProgress routeLegProgress = RouteLegProgress.create(firstLeg, firstLeg.getSteps().size() - 1, + firstLeg.getSteps().get(firstLeg.getSteps().size() - 1).getManeuver().asPosition()); + + Assert.assertEquals(0, routeLegProgress.getDistanceRemaining(), BaseTest.DELTA); + } + + @Test + public void getDistanceTraveled_equalsZeroAtBeginning() { + RouteLegProgress routeLegProgress + = RouteLegProgress.create(firstLeg, 0, firstLeg.getSteps().get(0).getManeuver().asPosition()); + Assert.assertEquals(0, routeLegProgress.getDistanceTraveled(), BaseTest.DELTA); + } + + @Test + public void getDistanceTraveled_equalsLegDistanceAtEndOfLeg() { + RouteLegProgress routeLegProgress = RouteLegProgress.create(firstLeg, firstLeg.getSteps().size() - 1, + firstLeg.getSteps().get(firstLeg.getSteps().size() - 1).getManeuver().asPosition()); + + Assert.assertEquals(firstLeg.getDistance(), routeLegProgress.getDistanceTraveled(), BaseTest.DELTA); + } + + @Test + public void getDurationRemaining_equalsLegDurationAtBeginning() { + RouteLegProgress routeLegProgress + = RouteLegProgress.create(firstLeg, 0, firstLeg.getSteps().get(0).getManeuver().asPosition()); + + Assert.assertEquals(3535.2, routeLegProgress.getDurationRemaining(), BaseTest.DELTA); + } + + @Test + public void getDurationRemaining_equalsZeroAtEndOfLeg() { + RouteLegProgress routeLegProgress = RouteLegProgress.create(firstLeg, firstLeg.getSteps().size() - 1, + firstLeg.getSteps().get(firstLeg.getSteps().size() - 1).getManeuver().asPosition()); + + Assert.assertEquals(0, routeLegProgress.getDurationRemaining(), BaseTest.DELTA); + } +} diff --git a/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/models/RouteStepProgressTest.java b/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/models/RouteStepProgressTest.java index bffbbba619a..fc0016a993d 100644 --- a/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/models/RouteStepProgressTest.java +++ b/navigation/libandroid-navigation/src/test/java/com/mapbox/services/android/navigation/v5/models/RouteStepProgressTest.java @@ -48,12 +48,12 @@ public void setup() { @Test public void sanityTest() { RouteStepProgress routeStepProgress - = new RouteStepProgress(firstLeg, 0, Mockito.mock(Position.class)); + = RouteStepProgress.create(firstLeg, 0, Mockito.mock(Position.class)); assertNotNull("should not be null", routeStepProgress); } @Test - public void getStepDistance_equalsZeroOnOneCoordSteps() throws Exception { + public void getStepDistance_equalsZeroOnOneCoordSteps() { Gson gson = new Gson(); String body = readPath(DCMAPBOX_CHIPOLTLE); response = gson.fromJson(body, DirectionsResponse.class); @@ -62,7 +62,7 @@ public void getStepDistance_equalsZeroOnOneCoordSteps() throws Exception { int totalStepCountInLeg = lastLeg.getSteps().size() - 1; RouteStepProgress routeStepProgress = - new RouteStepProgress(lastLeg, totalStepCountInLeg, Mockito.mock(Position.class)); + RouteStepProgress.create(lastLeg, totalStepCountInLeg, Mockito.mock(Position.class)); assertNotNull("should not be null", routeStepProgress); assertEquals(1, routeStepProgress.getFractionTraveled(), DELTA); assertEquals(0, routeStepProgress.getDistanceRemaining(), DELTA); @@ -77,7 +77,7 @@ public void getDistanceRemaining_equalsStepDistanceAtBeginning() { double stepDistance = TurfMeasurement.lineDistance(lineString, TurfConstants.UNIT_METERS); RouteStepProgress routeStepProgress - = new RouteStepProgress(firstLeg, 5, firstLeg.getSteps().get(4).getManeuver().asPosition()); + = RouteStepProgress.create(firstLeg, 5, firstLeg.getSteps().get(4).getManeuver().asPosition()); Assert.assertEquals(stepDistance, routeStepProgress.getDistanceRemaining(), BaseTest.DELTA); } @@ -99,18 +99,136 @@ public void getDistanceRemaining_equalsCorrectValueAtIntervals() { double distance = TurfMeasurement.lineDistance(slicedLine, TurfConstants.UNIT_METERS); - RouteStepProgress routeStepProgress = new RouteStepProgress(firstLeg, 0, position); + RouteStepProgress routeStepProgress = RouteStepProgress.create(firstLeg, 0, position); Assert.assertEquals(distance, routeStepProgress.getDistanceRemaining(), BaseTest.DELTA); } } @Test public void getDistanceRemaining_equalsZeroAtEndOfStep() { - RouteStepProgress routeStepProgress = new RouteStepProgress(firstLeg, 3, + RouteStepProgress routeStepProgress = RouteStepProgress.create(firstLeg, 3, firstLeg.getSteps().get(4).getManeuver().asPosition()); Assert.assertEquals(0, routeStepProgress.getDistanceRemaining(), BaseTest.DELTA); } -} + @Test + public void getDistanceTraveled_equalsZeroAtBeginning() { + RouteStepProgress routeStepProgress + = RouteStepProgress.create(firstLeg, 5, firstLeg.getSteps().get(4).getManeuver().asPosition()); + Assert.assertEquals(0, routeStepProgress.getDistanceTraveled(), BaseTest.DELTA); + } + + @Test + public void getDistanceTraveled_equalsCorrectValueAtIntervals() { + LineString lineString = LineString.fromPolyline(firstStep.getGeometry(), Constants.PRECISION_6); + + double stepSegments = 5; // meters + + // Chop the line in small pieces + for (double i = 0; i < firstStep.getDistance(); i += stepSegments) { + Position position = TurfMeasurement.along(lineString, i, TurfConstants.UNIT_METERS).getCoordinates(); + + LineString slicedLine = TurfMisc.lineSlice(Point.fromCoordinates(position), + Point.fromCoordinates(route.getLegs().get(0).getSteps().get(1).getManeuver().asPosition()), lineString); + + double distance = TurfMeasurement.lineDistance(slicedLine, TurfConstants.UNIT_METERS); + distance = firstStep.getDistance() - distance; + if (distance < 0) { + distance = 0; + } + + RouteStepProgress routeStepProgress = RouteStepProgress.create(firstLeg, 0, position); + Assert.assertEquals(distance, routeStepProgress.getDistanceTraveled(), BaseTest.DELTA); + } + } + + @Test + public void getDistanceTraveled_equalsStepDistanceAtEndOfStep() { + RouteStepProgress routeStepProgress = RouteStepProgress.create(firstLeg, 3, + firstLeg.getSteps().get(4).getManeuver().asPosition()); + + Assert.assertEquals(firstLeg.getSteps().get(3).getDistance(), + routeStepProgress.getDistanceTraveled(), BaseTest.DELTA); + } + + @Test + public void getFractionTraveled_equalsZeroAtBeginning() { + RouteStepProgress routeStepProgress + = RouteStepProgress.create(firstLeg, 5, firstLeg.getSteps().get(4).getManeuver().asPosition()); + + Assert.assertEquals(0, routeStepProgress.getFractionTraveled(), BaseTest.DELTA); + } + + @Test + public void getFractionTraveled_equalsCorrectValueAtIntervals() { + LineString lineString + = LineString.fromPolyline(firstStep.getGeometry(), Constants.PRECISION_6); + + double stepSegments = 5; // meters + + // Chop the line in small pieces + for (double i = 0; i < firstStep.getDistance(); i += stepSegments) { + Position position = TurfMeasurement.along(lineString, i, TurfConstants.UNIT_METERS).getCoordinates(); + + LineString slicedLine = TurfMisc.lineSlice(Point.fromCoordinates(position), + Point.fromCoordinates(route.getLegs().get(0).getSteps().get(1).getManeuver().asPosition()), lineString); + + double distance = TurfMeasurement.lineDistance(slicedLine, TurfConstants.UNIT_METERS); + + RouteStepProgress routeStepProgress = RouteStepProgress.create(firstLeg, 0, position); + float fractionRemaining = (float) ((firstStep.getDistance() - distance) / firstStep.getDistance()); + if (fractionRemaining < 0) { + fractionRemaining = 0; + } + Assert.assertEquals(fractionRemaining, routeStepProgress.getFractionTraveled(), DELTA); + } + } + + @Test + public void getFractionTraveled_equalsOneAtEndOfStep() { + RouteStepProgress routeStepProgress = RouteStepProgress.create(firstLeg, 3, + firstLeg.getSteps().get(4).getManeuver().asPosition()); + + Assert.assertEquals(1.0, routeStepProgress.getFractionTraveled(), BaseTest.DELTA); + } + + @Test + public void getDurationRemaining_equalsStepDurationAtBeginning() { + RouteStepProgress routeStepProgress + = RouteStepProgress.create(firstLeg, 5, firstLeg.getSteps().get(4).getManeuver().asPosition()); + + Assert.assertEquals(41.5, routeStepProgress.getDurationRemaining(), BaseTest.DELTA); + } + + @Test + public void getDurationRemaining_equalsCorrectValueAtIntervals() { + LineString lineString + = LineString.fromPolyline(firstStep.getGeometry(), Constants.PRECISION_6); + + double stepSegments = 5; // meters + + // Chop the line in small pieces + for (double i = 0; i < firstStep.getDistance(); i += stepSegments) { + Position position = TurfMeasurement.along(lineString, i, TurfConstants.UNIT_METERS).getCoordinates(); + + LineString slicedLine = TurfMisc.lineSlice(Point.fromCoordinates(position), + Point.fromCoordinates(route.getLegs().get(0).getSteps().get(1).getManeuver().asPosition()), lineString); + double distance = TurfMeasurement.lineDistance(slicedLine, TurfConstants.UNIT_METERS); + + RouteStepProgress routeStepProgress = RouteStepProgress.create(firstLeg, 0, position); + double fractionRemaining = (firstStep.getDistance() - distance) / firstStep.getDistance(); + Assert.assertEquals((1.0 - fractionRemaining) * firstStep.getDuration(), + routeStepProgress.getDurationRemaining(), BaseTest.LARGE_DELTA); + } + } + + @Test + public void getDurationRemaining_equalsZeroAtEndOfStep() { + RouteStepProgress routeStepProgress = RouteStepProgress.create(firstLeg, 3, + firstLeg.getSteps().get(4).getManeuver().asPosition()); + + Assert.assertEquals(0, routeStepProgress.getDurationRemaining(), BaseTest.DELTA); + } +} \ No newline at end of file