Skip to content

Commit 9f6f7e7

Browse files
author
Cameron Mace
authored
Merge pull request #74 from mapbox/route-progress-test
route progress test added
2 parents d76c3d8 + b201b1f commit 9f6f7e7

12 files changed

Lines changed: 655 additions & 160 deletions

File tree

navigation/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ buildscript {
66
}
77
dependencies {
88
classpath 'com.android.tools.build:gradle:2.3.2'
9+
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
910

1011
// NOTE: Do not place your application dependencies here; they belong
1112
// in the individual module build.gradle files
@@ -20,4 +21,4 @@ allprojects {
2021

2122
task clean(type: Delete) {
2223
delete rootProject.buildDir
23-
}
24+
}

navigation/libandroid-navigation/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
apply plugin: 'com.android.library'
2+
apply plugin: 'com.neenbedankt.android-apt'
23

34
android {
45
compileSdkVersion 25
@@ -36,6 +37,10 @@ dependencies {
3637
// Logging
3738
compile 'com.jakewharton.timber:timber:4.5.1'
3839

40+
// AutoValues
41+
provided 'com.google.auto.value:auto-value:1.4.1'
42+
apt 'com.google.auto.value:auto-value:1.4.1'
43+
3944
// Testing
4045
testCompile 'junit:junit:4.12'
4146
testCompile 'org.hamcrest:hamcrest-junit:2.0.0.0'

navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/NavigationEngine.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.mapbox.services.android.navigation.v5.listeners.OffRouteListener;
1010
import com.mapbox.services.android.navigation.v5.listeners.ProgressChangeListener;
1111
import com.mapbox.services.api.directions.v5.models.DirectionsRoute;
12+
import com.mapbox.services.commons.models.Position;
1213

1314
import java.util.concurrent.CopyOnWriteArrayList;
1415
import java.util.concurrent.TimeUnit;
@@ -60,7 +61,9 @@ class NavigationEngine {
6061
void onLocationChanged(DirectionsRoute directionsRoute, Location location) {
6162
// if the previousRouteProgress is null, the route has just begun and one needs to be created
6263
if (previousRouteProgress == null) {
63-
previousRouteProgress = new RouteProgress(directionsRoute, location, 0, 0, NavigationConstants.NONE_ALERT_LEVEL);
64+
Position currentPosition = Position.fromCoordinates(location.getLongitude(), location.getLatitude());
65+
previousRouteProgress = RouteProgress.create(directionsRoute, currentPosition,
66+
0, 0, NavigationConstants.NONE_ALERT_LEVEL);
6467
}
6568

6669
if (!TextUtils.equals(directionsRoute.getGeometry(), previousRouteProgress.getRoute().getGeometry())) {
@@ -81,17 +84,21 @@ void onLocationChanged(DirectionsRoute directionsRoute, Location location) {
8184
stepIndex = alertLevelState.getStepIndex();
8285
legIndex = alertLevelState.getLegIndex();
8386

84-
// Create a new RouteProgress object using the latest user location
85-
RouteProgress routeProgress = new RouteProgress(directionsRoute, location, legIndex, stepIndex, alertLevel);
87+
SnapLocation snapLocation = new SnapLocation(location,
88+
previousRouteProgress.getCurrentLegProgress().getCurrentStep(), options);
89+
90+
// Create a RouteProgress.create object using the latest user location
91+
RouteProgress routeProgress = RouteProgress.create(directionsRoute, snapLocation.getUsersCurrentSnappedPosition(),
92+
legIndex, stepIndex, alertLevel);
8693

8794
// Determine if the user is off route or not
8895
UserOffRouteState userOffRouteState = new UserOffRouteState(location, routeProgress, options);
8996
boolean isUserOffRoute = userOffRouteState.isUserOffRoute();
9097

9198
// Snap location to the route if they aren't off route and return the location object
9299
if (isSnapEnabled && !isUserOffRoute) {
93-
SnapLocation snapLocation = new SnapLocation(location, routeProgress, options);
94100
location = snapLocation.getSnappedLocation();
101+
location.setBearing(snapLocation.snapUserBearing(routeProgress));
95102
}
96103

97104
notifyAlertLevelChange(routeProgress);
Lines changed: 59 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package com.mapbox.services.android.navigation.v5;
22

3-
import android.location.Location;
4-
3+
import com.google.auto.value.AutoValue;
54
import com.mapbox.services.Constants;
65
import com.mapbox.services.Experimental;
76
import com.mapbox.services.android.navigation.v5.models.RouteLegProgress;
87
import com.mapbox.services.api.directions.v5.models.DirectionsRoute;
98
import com.mapbox.services.api.directions.v5.models.RouteLeg;
109
import com.mapbox.services.api.utils.turf.TurfConstants;
10+
import com.mapbox.services.api.utils.turf.TurfMeasurement;
1111
import com.mapbox.services.api.utils.turf.TurfMisc;
12-
import com.mapbox.services.commons.geojson.Feature;
12+
import com.mapbox.services.commons.geojson.LineString;
1313
import com.mapbox.services.commons.geojson.Point;
1414
import com.mapbox.services.commons.models.Position;
1515
import com.mapbox.services.commons.utils.PolylineUtils;
@@ -29,44 +29,35 @@
2929
* @since 0.1.0
3030
*/
3131
@Experimental
32-
public class RouteProgress {
32+
@AutoValue
33+
public abstract class RouteProgress {
34+
35+
public abstract RouteLegProgress currentLegProgress();
36+
37+
public abstract DirectionsRoute route();
38+
39+
public abstract Position userSnappedPosition();
3340

34-
private RouteLegProgress currentLegProgress;
35-
private DirectionsRoute route;
36-
private Location location;
37-
private int LegIndex;
38-
private int alertUserLevel;
39-
private double routeDistance;
40-
private int stepIndex;
41+
public abstract int legIndex();
42+
43+
public abstract int alertUserLevel();
4144

4245
/**
4346
* Constructor for the route routeProgress information.
4447
*
45-
* @param route the {@link DirectionsRoute} being used for the navigation session. When a user is
46-
* rerouted this route is updated.
47-
* @param location the users location most recently used when creating this object.
48-
* @param stepIndex an {@code integer} representing the current step index the user is on.
49-
* @param alertUserLevel the most recently calculated alert level.
48+
* @param route the {@link DirectionsRoute} being used for the navigation session. When a user is
49+
* rerouted this route is updated.
50+
* @param userSnappedPosition the users position most recently used when creating this object.
51+
* @param stepIndex an {@code integer} representing the current step index the user is on.
52+
* @param alertUserLevel the most recently calculated alert level.
5053
* @since 0.1.0
5154
*/
52-
RouteProgress(DirectionsRoute route, Location location, int legIndex, int stepIndex, int alertUserLevel) {
53-
this.route = route;
54-
this.alertUserLevel = alertUserLevel;
55-
this.location = location;
56-
this.LegIndex = legIndex;
57-
this.stepIndex = stepIndex;
58-
currentLegProgress = new RouteLegProgress(getCurrentLeg(), stepIndex, getUsersCurrentSnappedPosition());
59-
initialize();
60-
}
61-
62-
private void initialize() {
63-
// Measure route from beginning to end. This is done since the directions API gives a different distance then the
64-
// one we measure using turf.
65-
routeDistance = RouteUtils.getDistanceToEndOfRoute(
66-
route.getLegs().get(0).getSteps().get(0).getManeuver().asPosition(),
67-
route,
68-
TurfConstants.UNIT_METERS
69-
);
55+
public static RouteProgress create(
56+
DirectionsRoute route, Position userSnappedPosition, int legIndex, int stepIndex, int alertUserLevel) {
57+
RouteLegProgress routeLegProgress
58+
= RouteLegProgress.create(route.getLegs().get(legIndex), stepIndex, userSnappedPosition);
59+
return new AutoValue_RouteProgress(
60+
routeLegProgress, route, userSnappedPosition, legIndex, alertUserLevel);
7061
}
7162

7263
/**
@@ -76,7 +67,7 @@ private void initialize() {
7667
* @since 0.1.0
7768
*/
7869
public RouteLegProgress getCurrentLegProgress() {
79-
return currentLegProgress;
70+
return currentLegProgress();
8071
}
8172

8273
/**
@@ -86,7 +77,7 @@ public RouteLegProgress getCurrentLegProgress() {
8677
* @since 0.1.0
8778
*/
8879
public int getLegIndex() {
89-
return LegIndex;
80+
return legIndex();
9081
}
9182

9283
/**
@@ -95,7 +86,7 @@ public int getLegIndex() {
9586
* @return a {@link RouteLeg} the user is currently on.
9687
*/
9788
public RouteLeg getCurrentLeg() {
98-
return route.getLegs().get(getLegIndex());
89+
return route().getLegs().get(getLegIndex());
9990
}
10091

10192
/**
@@ -105,7 +96,11 @@ public RouteLeg getCurrentLeg() {
10596
* @since 0.1.0
10697
*/
10798
public double getDistanceTraveled() {
108-
return routeDistance - getDistanceRemaining();
99+
double distanceTraveled = route().getDistance() - getDistanceRemaining();
100+
if (distanceTraveled < 0) {
101+
distanceTraveled = 0;
102+
}
103+
return distanceTraveled;
109104
}
110105

111106
/**
@@ -114,8 +109,8 @@ public double getDistanceTraveled() {
114109
* @return {@code long} value representing the duration remaining till end of route, in unit seconds.
115110
* @since 0.1.0
116111
*/
117-
public long getDurationRemaining() {
118-
return (long) ((1 - getFractionTraveled()) * route.getDuration());
112+
public double getDurationRemaining() {
113+
return (1 - getFractionTraveled()) * route().getDuration();
119114
}
120115

121116
/**
@@ -126,7 +121,12 @@ public long getDurationRemaining() {
126121
* @since 0.1.0
127122
*/
128123
public float getFractionTraveled() {
129-
return (float) (getDistanceTraveled() / routeDistance);
124+
float fractionRemaining = 1;
125+
126+
if (route().getDistance() > 0) {
127+
fractionRemaining = (float) (getDistanceTraveled() / route().getDistance());
128+
}
129+
return fractionRemaining;
130130
}
131131

132132
/**
@@ -136,7 +136,22 @@ public float getFractionTraveled() {
136136
* @since 0.1.0
137137
*/
138138
public double getDistanceRemaining() {
139-
return RouteUtils.getDistanceToEndOfRoute(getUsersCurrentSnappedPosition(), route, TurfConstants.UNIT_METERS);
139+
double distanceRemaining = 0;
140+
141+
List<Position> coords = PolylineUtils.decode(currentLegProgress().getCurrentStep().getGeometry(),
142+
Constants.PRECISION_6);
143+
if (coords.size() > 1) {
144+
LineString slicedLine = TurfMisc.lineSlice(
145+
Point.fromCoordinates(userSnappedPosition()),
146+
Point.fromCoordinates(coords.get(coords.size() - 1)),
147+
LineString.fromCoordinates(coords)
148+
);
149+
distanceRemaining += TurfMeasurement.lineDistance(slicedLine, TurfConstants.UNIT_METERS);
150+
}
151+
for (int i = currentLegProgress().getStepIndex() + 1; i < getCurrentLeg().getSteps().size(); i++) {
152+
distanceRemaining += getCurrentLeg().getSteps().get(i).getDistance();
153+
}
154+
return distanceRemaining;
140155
}
141156

142157
/**
@@ -146,7 +161,7 @@ public double getDistanceRemaining() {
146161
* @since 0.1.0
147162
*/
148163
public int getAlertUserLevel() {
149-
return alertUserLevel;
164+
return alertUserLevel();
150165
}
151166

152167
/**
@@ -156,25 +171,6 @@ public int getAlertUserLevel() {
156171
* @since 0.1.0
157172
*/
158173
public DirectionsRoute getRoute() {
159-
return route;
160-
}
161-
162-
/**
163-
* Provides the users location snapped to the current route they are navigating on.
164-
*
165-
* @return {@link Position} object with coordinates snapping the user to the route.
166-
* @since 0.1.0
167-
*/
168-
public Position getUsersCurrentSnappedPosition() {
169-
Point locationToPoint = Point.fromCoordinates(new double[] {location.getLongitude(), location.getLatitude()});
170-
String stepGeometry = route.getLegs().get(getLegIndex()).getSteps().get(stepIndex).getGeometry();
171-
172-
// Decode the geometry
173-
List<Position> coords = PolylineUtils.decode(stepGeometry, Constants.PRECISION_6);
174-
175-
// Uses Turf's pointOnLine, which takes a Point and a LineString to calculate the closest
176-
// Point on the LineString.
177-
Feature feature = TurfMisc.pointOnLine(locationToPoint, coords);
178-
return ((Point) feature.getGeometry()).getCoordinates();
174+
return route();
179175
}
180176
}

navigation/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/SnapLocation.java

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,70 @@
22

33
import android.location.Location;
44

5+
import com.mapbox.services.Constants;
56
import com.mapbox.services.android.telemetry.utils.MathUtils;
7+
import com.mapbox.services.api.directions.v5.models.LegStep;
68
import com.mapbox.services.api.utils.turf.TurfConstants;
79
import com.mapbox.services.api.utils.turf.TurfMeasurement;
10+
import com.mapbox.services.api.utils.turf.TurfMisc;
11+
import com.mapbox.services.commons.geojson.Feature;
812
import com.mapbox.services.commons.geojson.LineString;
913
import com.mapbox.services.commons.geojson.Point;
1014
import com.mapbox.services.commons.models.Position;
15+
import com.mapbox.services.commons.utils.PolylineUtils;
16+
17+
import java.util.List;
1118

1219
public class SnapLocation {
1320

1421
private MapboxNavigationOptions options;
15-
private RouteProgress routeProgress;
22+
private LegStep currentStep;
23+
1624
private Location location;
1725

18-
SnapLocation(Location location, RouteProgress routeProgress, MapboxNavigationOptions options) {
26+
SnapLocation(Location location, LegStep currentStep, MapboxNavigationOptions options) {
1927
this.location = location;
20-
this.routeProgress = routeProgress;
28+
this.currentStep = currentStep;
2129
this.options = options;
2230
}
2331

2432
Location getSnappedLocation() {
2533
// Pass in the snapped location with all the other location data remaining intact for their use.
26-
location.setLatitude(routeProgress.getUsersCurrentSnappedPosition().getLatitude());
27-
location.setLongitude(routeProgress.getUsersCurrentSnappedPosition().getLongitude());
28-
29-
location.setBearing(snapUserBearing());
30-
34+
location.setLatitude(getUsersCurrentSnappedPosition().getLatitude());
35+
location.setLongitude(getUsersCurrentSnappedPosition().getLongitude());
3136
return location;
3237
}
3338

34-
private float snapUserBearing() {
39+
/**
40+
* Provides the users location snapped to the current route they are navigating on.
41+
*
42+
* @return {@link Position} object with coordinates snapping the user to the route.
43+
* @since 0.1.0
44+
*/
45+
Position getUsersCurrentSnappedPosition() {
46+
Point locationToPoint = Point.fromCoordinates(new double[] {location.getLongitude(), location.getLatitude()});
47+
String stepGeometry = currentStep.getGeometry();
48+
49+
// Decode the geometry
50+
List<Position> coords = PolylineUtils.decode(stepGeometry, Constants.PRECISION_6);
51+
52+
// Uses Turf's pointOnLine, which takes a Point and a LineString to calculate the closest
53+
// Point on the LineString.
54+
Feature feature = TurfMisc.pointOnLine(locationToPoint, coords);
55+
return ((Point) feature.getGeometry()).getCoordinates();
56+
}
57+
58+
float snapUserBearing(RouteProgress routeProgress) {
3559
LineString lineString = LineString.fromPolyline(routeProgress.getRoute().getGeometry(),
3660
com.mapbox.services.Constants.PRECISION_6);
3761

3862
Position newCoordinate;
39-
newCoordinate = routeProgress.getUsersCurrentSnappedPosition();
63+
newCoordinate = getUsersCurrentSnappedPosition();
4064

4165
double userDistanceBuffer = location.getSpeed() * options.getDeadReckoningTimeInterval();
4266

4367
if (routeProgress.getDistanceTraveled() + userDistanceBuffer
44-
> RouteUtils.getDistanceToEndOfRoute(
45-
routeProgress.getRoute().getLegs().get(0).getSteps().get(0).getManeuver().asPosition(),
46-
routeProgress.getRoute(),
47-
TurfConstants.UNIT_METERS)) {
68+
> routeProgress.getRoute().getDistance()) {
4869
// If the user is near the end of the route, take the remaining distance and divide by two
4970
userDistanceBuffer = routeProgress.getDistanceRemaining() / 2;
5071
}

0 commit comments

Comments
 (0)