Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

route progress test added #74

Merged
merged 10 commits into from
Jun 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion navigation/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -20,4 +21,4 @@ allprojects {

task clean(type: Delete) {
delete rootProject.buildDir
}
}
5 changes: 5 additions & 0 deletions navigation/libandroid-navigation/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
apply plugin: 'com.android.library'
apply plugin: 'com.neenbedankt.android-apt'

android {
compileSdkVersion 25
Expand Down Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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())) {
Expand All @@ -81,17 +84,21 @@ 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);
boolean isUserOffRoute = userOffRouteState.isUserOffRoute();

// 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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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);
}

/**
Expand All @@ -76,7 +67,7 @@ private void initialize() {
* @since 0.1.0
*/
public RouteLegProgress getCurrentLegProgress() {
return currentLegProgress;
return currentLegProgress();
}

/**
Expand All @@ -86,7 +77,7 @@ public RouteLegProgress getCurrentLegProgress() {
* @since 0.1.0
*/
public int getLegIndex() {
return LegIndex;
return legIndex();
}

/**
Expand All @@ -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());
}

/**
Expand All @@ -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;
}

/**
Expand All @@ -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();
}

/**
Expand All @@ -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;
}

/**
Expand All @@ -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<Position> 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;
}

/**
Expand All @@ -146,7 +161,7 @@ public double getDistanceRemaining() {
* @since 0.1.0
*/
public int getAlertUserLevel() {
return alertUserLevel;
return alertUserLevel();
}

/**
Expand All @@ -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<Position> 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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Position> 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;
}
Expand Down
Loading