From 38d18db82436bf64895769dce9888cace9abe350 Mon Sep 17 00:00:00 2001 From: danesfeder Date: Thu, 5 Apr 2018 13:49:37 -0400 Subject: [PATCH] Move distance processing to RouteProcessor --- .../v5/milestone/TunnelMilestone.java | 214 ++++++++++++++++ .../navigation/NavigationRouteProcessor.java | 124 +++++++--- .../v5/routeprogress/RouteLegProgress.java | 121 ++++++--- .../v5/routeprogress/RouteProgress.java | 68 ++++-- .../v5/routeprogress/RouteStepProgress.java | 231 +++++------------- 5 files changed, 493 insertions(+), 265 deletions(-) create mode 100644 libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/milestone/TunnelMilestone.java diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/milestone/TunnelMilestone.java b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/milestone/TunnelMilestone.java new file mode 100644 index 00000000000..42db29852d3 --- /dev/null +++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/milestone/TunnelMilestone.java @@ -0,0 +1,214 @@ +package com.mapbox.services.android.navigation.v5.milestone; + +import android.support.annotation.NonNull; +import android.support.v4.util.Pair; + +import com.mapbox.api.directions.v5.models.DirectionsRoute; +import com.mapbox.api.directions.v5.models.LegStep; +import com.mapbox.api.directions.v5.models.StepIntersection; +import com.mapbox.api.directions.v5.models.VoiceInstructions; +import com.mapbox.geojson.LineString; +import com.mapbox.geojson.Point; +import com.mapbox.services.android.navigation.v5.instruction.Instruction; +import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress; +import com.mapbox.turf.TurfConstants; +import com.mapbox.turf.TurfMeasurement; +import com.mapbox.turf.TurfMisc; + +import java.util.ArrayList; +import java.util.List; + +public class TunnelMilestone extends Milestone { + + private static final int FIRST_STEP_INDEX = 0; + private static final String CLASS_TUNNEL = "tunnel"; + + private String announcement; + private String ssmlAnnouncement; + private DirectionsRoute currentRoute; + private LegStep currentStep; + private List stepVoiceInstructions; + + TunnelMilestone(Builder builder) { + super(builder); + } + + @Override + public boolean isOccurring(RouteProgress previousRouteProgress, RouteProgress routeProgress) { + if (newRoute(routeProgress)) { + clearInstructionList(); + } + if (shouldAddInstructions(routeProgress)) { + stepVoiceInstructions = routeProgress.currentLegProgress().currentStep().voiceInstructions(); + } + for (VoiceInstructions voice : stepVoiceInstructions) { + if (shouldBeVoiced(routeProgress, voice)) { + announcement = voice.announcement(); + ssmlAnnouncement = voice.ssmlAnnouncement(); + stepVoiceInstructions.remove(voice); + return true; + } + } + return false; + } + + @Override + public Instruction getInstruction() { + return new Instruction() { + @Override + public String buildInstruction(RouteProgress routeProgress) { + return announcement; + } + }; + } + + /** + * Provide the SSML instruction that can be used with Amazon's AWS Polly. + *

+ * This String will provide special markup denoting how certain portions of the announcement + * should be pronounced. + * + * @return announcement with SSML markup + * @since 0.8.0 + */ + public String getSsmlAnnouncement() { + return ssmlAnnouncement; + } + + /** + * Check if a new set of step instructions should be set. + * + * @param routeProgress the current route progress + * @return true if new instructions should be added to the list, false if not + */ + private boolean shouldAddInstructions(RouteProgress routeProgress) { + return newStep(routeProgress) || stepVoiceInstructions == null; + } + + /** + * Called when adding new instructions to the list. + *

+ * Make sure old announcements are not called (can happen in reroute scenarios). + */ + private void clearInstructionList() { + if (stepVoiceInstructions != null && !stepVoiceInstructions.isEmpty()) { + stepVoiceInstructions.clear(); + } + } + + /** + * Looks to see if we have a new step. + * + * @param routeProgress provides updated step information + * @return true if new step, false if not + */ + private boolean newStep(RouteProgress routeProgress) { + boolean newStep = currentStep == null || !currentStep.equals(routeProgress.currentLegProgress().currentStep()); + currentStep = routeProgress.currentLegProgress().currentStep(); + return newStep; + } + + /** + * Looks to see if we have a new route. + * + * @param routeProgress provides updated route information + * @return true if new route, false if not + */ + private boolean newRoute(RouteProgress routeProgress) { + boolean newRoute = currentRoute == null || !currentRoute.equals(routeProgress.directionsRoute()); + currentRoute = routeProgress.directionsRoute(); + return newRoute; + } + + /** + * Uses the current step distance remaining to check against voice instruction distance. + * + * @param routeProgress the current route progress + * @param voice a given voice instruction from the list of step instructions + * @return true if time to voice the announcement, false if not + */ + private boolean shouldBeVoiced(RouteProgress routeProgress, VoiceInstructions voice) { + return voice.distanceAlongGeometry() + >= routeProgress.currentLegProgress().currentStepProgress().distanceRemaining(); + } + + @NonNull + private List createTunnelIntersectionsList(LegStep step) { + List tunnelIntersections = new ArrayList<>(); + if (step.intersections().isEmpty()) { + return tunnelIntersections; + } + for (StepIntersection intersection : step.intersections()) { + boolean hasValidClasses = intersection.classes() != null && !intersection.classes().isEmpty(); + if (hasValidClasses) { + for (String intersectionClass : intersection.classes()) { + if (intersectionClass.contentEquals(CLASS_TUNNEL)) { + tunnelIntersections.add(intersection); + } + } + } + } + return tunnelIntersections; + } + + @NonNull + private List> createDistancesToTunnelIntersections(LegStep step, + List stepPoints, + List tunnels) { + List> distancesToTunnelIntersections = new ArrayList<>(); + if (stepPoints.isEmpty()) { + return distancesToTunnelIntersections; + } + if (tunnels.isEmpty()) { + return distancesToTunnelIntersections; + } + List stepIntersections = step.intersections(); + if (stepIntersections == null || stepIntersections.isEmpty()) { + return distancesToTunnelIntersections; + } + + LineString stepLineString = LineString.fromLngLats(stepPoints); + Point firstStepPoint = stepPoints.get(FIRST_STEP_INDEX); + + for (int i = 0; i < tunnels.size(); i++) { + StepIntersection tunnelIntersection = tunnels.get(i); + + Point tunnelBeginningPoint = tunnelIntersection.location(); + LineString beginningLineString = TurfMisc.lineSlice(firstStepPoint, tunnelBeginningPoint, stepLineString); + double distanceToBeginningOfTunnel = TurfMeasurement.length(beginningLineString, TurfConstants.UNIT_METERS); + + int tunnelIntersectionIndex = stepIntersections.indexOf(tunnelIntersection); + Point tunnelEndingPoint = stepIntersections.get(tunnelIntersectionIndex + 1).location(); + LineString endLineString = TurfMisc.lineSlice(firstStepPoint, tunnelEndingPoint, stepLineString); + double distanceToEndOfTunnel = TurfMeasurement.length(endLineString, TurfConstants.UNIT_METERS); + + distancesToTunnelIntersections.add(new Pair<>(distanceToBeginningOfTunnel, distanceToEndOfTunnel)); + } + return distancesToTunnelIntersections; + } + + public static final class Builder extends Milestone.Builder { + + private Trigger.Statement trigger; + + public Builder() { + super(); + } + + @Override + Trigger.Statement getTrigger() { + return trigger; + } + + @Override + public Builder setTrigger(Trigger.Statement trigger) { + this.trigger = trigger; + return this; + } + + @Override + public TunnelMilestone build() { + return new TunnelMilestone(this); + } + } +} \ No newline at end of file diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessor.java b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessor.java index 2a78c2aed37..ac4bbcdbb81 100644 --- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessor.java +++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/navigation/NavigationRouteProcessor.java @@ -1,10 +1,13 @@ package com.mapbox.services.android.navigation.v5.navigation; import android.location.Location; +import android.support.annotation.NonNull; import com.mapbox.api.directions.v5.models.DirectionsRoute; import com.mapbox.api.directions.v5.models.LegStep; import com.mapbox.api.directions.v5.models.RouteLeg; +import com.mapbox.api.directions.v5.models.StepIntersection; +import com.mapbox.geojson.LineString; import com.mapbox.geojson.Point; import com.mapbox.geojson.utils.PolylineUtils; import com.mapbox.services.android.navigation.v5.offroute.OffRoute; @@ -12,7 +15,11 @@ import com.mapbox.services.android.navigation.v5.offroute.OffRouteDetector; import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress; import com.mapbox.services.android.navigation.v5.utils.RouteUtils; +import com.mapbox.turf.TurfConstants; +import com.mapbox.turf.TurfMeasurement; +import com.mapbox.turf.TurfMisc; +import java.util.ArrayList; import java.util.List; import static com.mapbox.core.constants.Constants.PRECISION_6; @@ -28,11 +35,12 @@ class NavigationRouteProcessor implements OffRouteCallback { private static final int FIRST_LEG_INDEX = 0; private static final int FIRST_STEP_INDEX = 0; - private static final int SECOND_STEP_INDEX = 1; private RouteProgress routeProgress; private List currentStepPoints; private List upcomingStepPoints; + private List currentIntersections; + private List currentIntersectionDistances; private NavigationIndices indices; private boolean shouldIncreaseIndex; @@ -77,25 +85,7 @@ RouteProgress buildNewRouteProgress(MapboxNavigation mapboxNavigation, Location stepDistanceRemaining = calculateStepDistanceRemaining(location, directionsRoute); } - int legIndex = indices.legIndex(); - int stepIndex = indices.stepIndex(); - double legDistanceRemaining = legDistanceRemaining(stepDistanceRemaining, legIndex, stepIndex, directionsRoute); - double routeDistanceRemaining = routeDistanceRemaining(legDistanceRemaining, legIndex, directionsRoute); - - RouteProgress.Builder progressBuilder = RouteProgress.builder() - .stepDistanceRemaining(stepDistanceRemaining) - .legDistanceRemaining(legDistanceRemaining) - .distanceRemaining(routeDistanceRemaining) - .directionsRoute(directionsRoute) - .currentStepPoints(currentStepPoints) - .upcomingStepPoints(upcomingStepPoints) - .stepIndex(stepIndex) - .legIndex(legIndex); - - if (upcomingStepPoints != null && !upcomingStepPoints.isEmpty()) { - progressBuilder.upcomingStepPoints(upcomingStepPoints); - } - return progressBuilder.build(); + return assembleRouteProgress(directionsRoute, stepDistanceRemaining); } RouteProgress getRouteProgress() { @@ -155,14 +145,45 @@ Location buildSnappedLocation(MapboxNavigation mapboxNavigation, boolean snapToR */ private void advanceIndices(MapboxNavigation mapboxNavigation) { indices = increaseIndex(routeProgress, indices); - updateStepPoints(mapboxNavigation); + processNewIndex(mapboxNavigation); + } + + private RouteProgress assembleRouteProgress(DirectionsRoute directionsRoute, double stepDistanceRemaining) { + int legIndex = indices.legIndex(); + int stepIndex = indices.stepIndex(); + double legDistanceRemaining = legDistanceRemaining(stepDistanceRemaining, legIndex, stepIndex, directionsRoute); + double routeDistanceRemaining = routeDistanceRemaining(legDistanceRemaining, legIndex, directionsRoute); + + RouteProgress.Builder progressBuilder = RouteProgress.builder() + .stepDistanceRemaining(stepDistanceRemaining) + .legDistanceRemaining(legDistanceRemaining) + .distanceRemaining(routeDistanceRemaining) + .directionsRoute(directionsRoute) + .currentStepPoints(currentStepPoints) + .upcomingStepPoints(upcomingStepPoints) + .stepIndex(stepIndex) + .legIndex(legIndex) + .intersections(currentIntersections) + .intersectionDistancesAlongStep(currentIntersectionDistances); + + if (upcomingStepPoints != null && !upcomingStepPoints.isEmpty()) { + progressBuilder.upcomingStepPoints(upcomingStepPoints); + } + return progressBuilder.build(); } - private void updateStepPoints(MapboxNavigation mapboxNavigation) { + private void processNewIndex(MapboxNavigation mapboxNavigation) { DirectionsRoute route = mapboxNavigation.getRoute(); - currentStepPoints = decodeStepPoints(route, currentStepPoints, indices.legIndex(), indices.stepIndex()); - int upcomingStepIndex = indices.stepIndex() + 1; - upcomingStepPoints = decodeStepPoints(route, upcomingStepPoints, indices.legIndex(), upcomingStepIndex); + int legIndex = indices.legIndex(); + int stepIndex = indices.stepIndex(); + int upcomingStepIndex = stepIndex + 1; + List steps = route.legs().get(legIndex).steps(); + LegStep currentStep = steps.get(stepIndex); + LegStep upcomingStep = upcomingStepIndex < steps.size() ? steps.get(stepIndex) : null; + currentStepPoints = decodeStepPoints(route, currentStepPoints, legIndex, stepIndex); + upcomingStepPoints = decodeStepPoints(route, upcomingStepPoints, legIndex, upcomingStepIndex); + currentIntersections = createIntersectionsList(currentStep, upcomingStep); + currentIntersectionDistances = createDistancesToIntersections(currentStepPoints, currentIntersections); clearManeuverDistances(mapboxNavigation.getOffRouteEngine()); } @@ -215,22 +236,12 @@ private void checkNewRoute(MapboxNavigation mapboxNavigation) { DirectionsRoute directionsRoute = mapboxNavigation.getRoute(); if (RouteUtils.isNewRoute(routeProgress, directionsRoute)) { - currentStepPoints = decodeStepPoints(directionsRoute, currentStepPoints, FIRST_LEG_INDEX, FIRST_STEP_INDEX); - upcomingStepPoints = decodeStepPoints(directionsRoute, currentStepPoints, FIRST_LEG_INDEX, SECOND_STEP_INDEX); - clearManeuverDistances(mapboxNavigation.getOffRouteEngine()); - - routeProgress = RouteProgress.builder() - .stepDistanceRemaining(directionsRoute.legs().get(FIRST_LEG_INDEX).steps().get(FIRST_STEP_INDEX).distance()) - .legDistanceRemaining(directionsRoute.legs().get(FIRST_LEG_INDEX).distance()) - .distanceRemaining(directionsRoute.distance()) - .directionsRoute(directionsRoute) - .currentStepPoints(currentStepPoints) - .upcomingStepPoints(upcomingStepPoints) - .stepIndex(FIRST_STEP_INDEX) - .legIndex(FIRST_LEG_INDEX) - .build(); - indices = NavigationIndices.create(FIRST_LEG_INDEX, FIRST_STEP_INDEX); + processNewIndex(mapboxNavigation); + + RouteLeg firstLeg = directionsRoute.legs().get(FIRST_LEG_INDEX); + double stepDistanceRemaining = firstLeg.steps().get(FIRST_STEP_INDEX).distance(); + routeProgress = assembleRouteProgress(directionsRoute, stepDistanceRemaining); } } @@ -247,4 +258,37 @@ private double calculateStepDistanceRemaining(Location location, DirectionsRoute snappedPosition, indices.legIndex(), indices.stepIndex(), directionsRoute, currentStepPoints ); } + + @NonNull + private List createIntersectionsList(@NonNull LegStep step, LegStep upcomingStep) { + List intersectionsWithNextManeuver = new ArrayList<>(); + intersectionsWithNextManeuver.addAll(step.intersections()); + if (upcomingStep != null && !upcomingStep.intersections().isEmpty()) { + intersectionsWithNextManeuver.add(upcomingStep.intersections().get(0)); + } + return intersectionsWithNextManeuver; + } + + @NonNull + private List createDistancesToIntersections(List stepPoints, List intersections) { + List distancesToIntersections = new ArrayList<>(); + List stepIntersections = new ArrayList<>(intersections); + if (stepPoints.isEmpty()) { + return distancesToIntersections; + } + if (stepIntersections.isEmpty()) { + return distancesToIntersections; + } + + LineString stepLineString = LineString.fromLngLats(stepPoints); + Point firstStepPoint = intersections.remove(0).location(); + + for (StepIntersection intersection : intersections) { + Point intersectionPoint = intersection.location(); + LineString beginningLineString = TurfMisc.lineSlice(firstStepPoint, intersectionPoint, stepLineString); + double distanceToIntersection = TurfMeasurement.length(beginningLineString, TurfConstants.UNIT_METERS); + distancesToIntersections.add(distanceToIntersection); + } + return distancesToIntersections; + } } diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteLegProgress.java b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteLegProgress.java index a537f849ccb..f8a4c6af7d4 100644 --- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteLegProgress.java +++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteLegProgress.java @@ -6,6 +6,7 @@ import com.google.auto.value.AutoValue; import com.mapbox.api.directions.v5.models.LegStep; import com.mapbox.api.directions.v5.models.RouteLeg; +import com.mapbox.api.directions.v5.models.StepIntersection; import com.mapbox.geojson.Point; import java.util.List; @@ -25,39 +26,6 @@ @AutoValue public abstract class RouteLegProgress { - /** - * Not public since developer can access same information from {@link RouteProgress}. - */ - abstract RouteLeg routeLeg(); - - /** - * Constructor for the route leg progress information. - * - * @param routeLeg the current {@link RouteLeg} the user is traversing along - * @param stepIndex the current step index the user is on - * @param legDistanceRemaining the leg distance remaining which is calculated in navigation engine - * @param stepDistanceRemaining the step distance remaining which is calculated in navigation engine - * @since 0.1.0 - */ - static RouteLegProgress create(RouteLeg routeLeg, int stepIndex, double legDistanceRemaining, - List stepPoints, double stepDistanceRemaining) { - - int lastStepIndex = routeLeg.steps().size() - 1; - boolean isOnLastStep = stepIndex == lastStepIndex; - int nextStepIndex = stepIndex + 1; - LegStep nextStep = isOnLastStep ? null : routeLeg.steps().get(nextStepIndex); - - LegStep currentStep = routeLeg.steps().get(stepIndex); - RouteStepProgress stepProgress = RouteStepProgress.builder() - .step(currentStep) - .stepPoints(stepPoints) - .nextStep(nextStep) - .distanceRemaining(stepDistanceRemaining) - .build(); - - return new AutoValue_RouteLegProgress(routeLeg, stepIndex, legDistanceRemaining, stepProgress); - } - /** * Index representing the current step the user is on. * @@ -184,4 +152,91 @@ public LegStep followOnStep() { * @since 0.1.0 */ public abstract RouteStepProgress currentStepProgress(); + + /** + * Provides a list of points that represent the current step + * step geometry. + * + * @return list of points representing the current step + * @since 0.12.0 + */ + public abstract List currentStepPoints(); + + /** + * Provides a list of points that represent the upcoming step + * step geometry. + * + * @return list of points representing the upcoming step + * @since 0.12.0 + */ + @Nullable + public abstract List upcomingStepPoints(); + + /** + * Not public since developer can access same information from {@link RouteProgress}. + */ + abstract RouteLeg routeLeg(); + + abstract double stepDistanceRemaining(); + + abstract List intersections(); + + abstract List intersectionDistancesAlongStep(); + + @AutoValue.Builder + public abstract static class Builder { + + abstract Builder routeLeg(RouteLeg routeLeg); + + abstract RouteLeg routeLeg(); + + abstract Builder stepIndex(int stepIndex); + + abstract int stepIndex(); + + abstract Builder stepDistanceRemaining(double stepDistanceRemaining); + + abstract double stepDistanceRemaining(); + + abstract Builder distanceRemaining(double distanceRemaining); + + abstract Builder currentStepProgress(RouteStepProgress routeStepProgress); + + abstract Builder currentStepPoints(List currentStepPoints); + + abstract Builder upcomingStepPoints(@Nullable List upcomingStepPoints); + + abstract Builder intersections(List intersections); + + abstract List intersections(); + + abstract Builder intersectionDistancesAlongStep(List intersectionDistancesAlongStep); + + abstract List intersectionDistancesAlongStep(); + + abstract RouteLegProgress autoBuild(); // not public + + public RouteLegProgress build() { + int lastStepIndex = routeLeg().steps().size() - 1; + boolean isOnLastStep = stepIndex() == lastStepIndex; + int nextStepIndex = stepIndex() + 1; + LegStep nextStep = isOnLastStep ? null : routeLeg().steps().get(nextStepIndex); + + LegStep currentStep = routeLeg().steps().get(stepIndex()); + RouteStepProgress stepProgress = RouteStepProgress.builder() + .step(currentStep) + .nextStep(nextStep) + .distanceRemaining(stepDistanceRemaining()) + .intersections(intersections()) + .intersectionDistancesAlongStep(intersectionDistancesAlongStep()) + .build(); + currentStepProgress(stepProgress); + + return autoBuild(); + } + } + + public static Builder builder() { + return new AutoValue_RouteLegProgress.Builder(); + } } \ No newline at end of file diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteProgress.java b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteProgress.java index 19321b37bfb..0ca82edc0ac 100644 --- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteProgress.java +++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteProgress.java @@ -6,6 +6,7 @@ import com.google.auto.value.AutoValue; import com.mapbox.api.directions.v5.models.DirectionsRoute; import com.mapbox.api.directions.v5.models.RouteLeg; +import com.mapbox.api.directions.v5.models.StepIntersection; import com.mapbox.geojson.Point; import java.util.List; @@ -149,13 +150,19 @@ public int remainingWaypoints() { public abstract RouteProgress.Builder toBuilder(); + abstract int stepIndex(); + + abstract double legDistanceRemaining(); + + abstract double stepDistanceRemaining(); + + abstract List intersections(); + + abstract List intersectionDistancesAlongStep(); + @AutoValue.Builder public abstract static class Builder { - private int stepIndex; - private double legDistanceRemaining; - private double stepDistanceRemaining; - public abstract Builder directionsRoute(DirectionsRoute directionsRoute); abstract DirectionsRoute directionsRoute(); @@ -164,28 +171,35 @@ public abstract static class Builder { abstract int legIndex(); - public abstract Builder distanceRemaining(double distanceRemaining); + public abstract Builder stepIndex(int stepIndex); - public abstract Builder upcomingStepPoints(@Nullable List upcomingStepPoints); + abstract int stepIndex(); + + public abstract Builder legDistanceRemaining(double legDistanceRemaining); + + abstract double legDistanceRemaining(); + + public abstract Builder stepDistanceRemaining(double stepDistanceRemaining); + + abstract double stepDistanceRemaining(); public abstract Builder currentStepPoints(List currentStepPoints); abstract List currentStepPoints(); - public Builder stepIndex(int stepIndex) { - this.stepIndex = stepIndex; - return this; - } + public abstract Builder upcomingStepPoints(@Nullable List upcomingStepPoints); - public Builder legDistanceRemaining(double legDistanceRemaining) { - this.legDistanceRemaining = legDistanceRemaining; - return this; - } + abstract List upcomingStepPoints(); - public Builder stepDistanceRemaining(double stepDistanceRemaining) { - this.stepDistanceRemaining = stepDistanceRemaining; - return this; - } + public abstract Builder distanceRemaining(double distanceRemaining); + + public abstract Builder intersections(List intersections); + + abstract List intersections(); + + public abstract Builder intersectionDistancesAlongStep(List intersectionDistancesAlongStep); + + abstract List intersectionDistancesAlongStep(); abstract Builder currentLegProgress(RouteLegProgress routeLegProgress); @@ -193,14 +207,18 @@ public Builder stepDistanceRemaining(double stepDistanceRemaining) { public RouteProgress build() { RouteLeg currentLeg = directionsRoute().legs().get(legIndex()); - RouteLegProgress legProgress = RouteLegProgress.create( - currentLeg, - stepIndex, - legDistanceRemaining, - currentStepPoints(), - stepDistanceRemaining - ); + RouteLegProgress legProgress = RouteLegProgress.builder() + .routeLeg(currentLeg) + .stepIndex(stepIndex()) + .distanceRemaining(legDistanceRemaining()) + .stepDistanceRemaining(stepDistanceRemaining()) + .currentStepPoints(currentStepPoints()) + .upcomingStepPoints(upcomingStepPoints()) + .intersections(intersections()) + .intersectionDistancesAlongStep(intersectionDistancesAlongStep()) + .build(); currentLegProgress(legProgress); + return autoBuild(); } } diff --git a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteStepProgress.java b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteStepProgress.java index f4e76e692d9..ac8481804f2 100644 --- a/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteStepProgress.java +++ b/libandroid-navigation/src/main/java/com/mapbox/services/android/navigation/v5/routeprogress/RouteStepProgress.java @@ -3,18 +3,11 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.util.Pair; import com.google.auto.value.AutoValue; import com.mapbox.api.directions.v5.models.LegStep; import com.mapbox.api.directions.v5.models.StepIntersection; -import com.mapbox.geojson.LineString; -import com.mapbox.geojson.Point; -import com.mapbox.turf.TurfConstants; -import com.mapbox.turf.TurfMeasurement; -import com.mapbox.turf.TurfMisc; -import java.util.ArrayList; import java.util.List; @@ -31,14 +24,69 @@ @AutoValue public abstract class RouteStepProgress { - private static final String CLASS_TUNNEL = "tunnel"; - public static final int FIRST_STEP_POINT = 0; + public static Builder builder() { + return new AutoValue_RouteStepProgress.Builder(); + } - abstract LegStep step(); + /** + * Total distance in meters from user to end of step. + * + * @return double value representing the distance the user has remaining till they reach the end + * of the current step. Uses unit meters. + * @since 0.1.0 + */ + public abstract double distanceRemaining(); + + /** + * Returns distance user has traveled along current step in unit meters. + * + * @return double value representing the distance the user has traveled so far along the current + * step. Uses unit meters. + * @since 0.1.0 + */ + public abstract double distanceTraveled(); + + /** + * Get the fraction traveled along the current step, this is a float value between 0 and 1 and + * isn't guaranteed to reach 1 before the user reaches the next step (if another step exist in route). + * + * @return a float value between 0 and 1 representing the fraction the user has traveled along + * the current step. + * @since 0.1.0 + */ + public abstract float fractionTraveled(); - abstract List stepPoints(); + /** + * Provides the duration remaining in seconds till the user reaches the end of the current step. + * + * @return {@code long} value representing the duration remaining till end of step, in unit seconds. + * @since 0.1.0 + */ + public abstract double durationRemaining(); + + /** + * A collection of all the current steps intersections and the next steps maneuver location + * (if one exist). + * + * @return a list of {@link StepIntersection}s which may include the next steps maneuver + * intersection if it exist + * @since 0.7.0 + */ + public abstract List intersections(); + + /** + * Provides a list of pairs containing two distances, in meters, along the route. + *

+ * The first distance in the pair is the tunnel entrance along the step geometry. + * The second distance is the tunnel exit along the step geometry. + * + * @return list of pairs containing tunnnel entrance and exit distances + * @since 0.13.0 + */ + public abstract List intersectionDistancesAlongStep(); + + abstract LegStep step(); - @Nullable abstract LegStep nextStep(); @AutoValue.Builder @@ -48,18 +96,12 @@ abstract static class Builder { abstract LegStep step(); - abstract Builder stepPoints(List stepPoints); - - abstract List stepPoints(); - - abstract Builder nextStep(@Nullable LegStep nextStep); - - abstract LegStep nextStep(); - abstract Builder distanceRemaining(double distanceRemaining); abstract double distanceRemaining(); + abstract Builder nextStep(@Nullable LegStep nextStep); + abstract Builder distanceTraveled(double distanceTraveled); abstract Builder fractionTraveled(float fractionTraveled); @@ -68,11 +110,9 @@ abstract static class Builder { abstract Builder intersections(@NonNull List intersections); - abstract Builder tunnelIntersections(@NonNull List tunnelIntersections); - - abstract List tunnelIntersections(); + abstract Builder intersectionDistancesAlongStep(@NonNull List intersections); - abstract Builder tunnelIntersectionDistances(@NonNull List> tunnelIntersectionDistances); + abstract RouteStepProgress autoBuild(); RouteStepProgress build() { LegStep step = step(); @@ -82,16 +122,10 @@ RouteStepProgress build() { float fractionTraveled = calculateFractionTraveled(step, distanceTraveled); fractionTraveled(fractionTraveled); durationRemaining(calculateDurationRemaining(step, fractionTraveled)); - LegStep nextStep = nextStep(); - intersections(createIntersectionsList(step, nextStep)); - tunnelIntersections(createTunnelIntersectionsList(step)); - tunnelIntersectionDistances(createDistancesToTunnelIntersections(step, stepPoints(), tunnelIntersections())); return autoBuild(); } - abstract RouteStepProgress autoBuild(); - private double calculateDistanceTraveled(LegStep step, double distanceRemaining) { double distanceTraveled = step.distance() - distanceRemaining; if (distanceTraveled < 0) { @@ -115,142 +149,5 @@ private float calculateFractionTraveled(LegStep step, double distanceTraveled) { private double calculateDurationRemaining(LegStep step, float fractionTraveled) { return (1 - fractionTraveled) * step.duration(); } - - @NonNull - private List createIntersectionsList(@NonNull LegStep step, LegStep nextStep) { - List intersectionsWithNextManeuver = new ArrayList<>(); - intersectionsWithNextManeuver.addAll(step.intersections()); - if (nextStep != null && !nextStep.intersections().isEmpty()) { - intersectionsWithNextManeuver.add(nextStep.intersections().get(0)); - } - return intersectionsWithNextManeuver; - } - - @NonNull - private List createTunnelIntersectionsList(LegStep step) { - List tunnelIntersections = new ArrayList<>(); - if (step.intersections().isEmpty()) { - return tunnelIntersections; - } - for (StepIntersection intersection : step.intersections()) { - boolean hasValidClasses = intersection.classes() != null && !intersection.classes().isEmpty(); - if (hasValidClasses) { - for (String intersectionClass : intersection.classes()) { - if (intersectionClass.contentEquals(CLASS_TUNNEL)) { - tunnelIntersections.add(intersection); - } - } - } - } - return tunnelIntersections; - } - - @NonNull - private List> createDistancesToTunnelIntersections(LegStep step, - List stepPoints, - List tunnels) { - List> distancesToTunnelIntersections = new ArrayList<>(); - if (stepPoints.isEmpty()) { - return distancesToTunnelIntersections; - } - if (tunnels.isEmpty()) { - return distancesToTunnelIntersections; - } - List stepIntersections = step.intersections(); - if (stepIntersections == null || stepIntersections.isEmpty()) { - return distancesToTunnelIntersections; - } - - LineString stepLineString = LineString.fromLngLats(stepPoints); - Point firstStepPoint = stepPoints.get(FIRST_STEP_POINT); - - for (int i = 0; i < tunnels.size(); i++) { - StepIntersection tunnelIntersection = tunnels.get(i); - - Point tunnelBeginningPoint = tunnelIntersection.location(); - LineString beginningLineString = TurfMisc.lineSlice(firstStepPoint, tunnelBeginningPoint, stepLineString); - double distanceToBeginningOfTunnel = TurfMeasurement.length(beginningLineString, TurfConstants.UNIT_METERS); - - int tunnelIntersectionIndex = stepIntersections.indexOf(tunnelIntersection); - Point tunnelEndingPoint = stepIntersections.get(tunnelIntersectionIndex + 1).location(); - LineString endLineString = TurfMisc.lineSlice(firstStepPoint, tunnelEndingPoint, stepLineString); - double distanceToEndOfTunnel = TurfMeasurement.length(endLineString, TurfConstants.UNIT_METERS); - - distancesToTunnelIntersections.add(new Pair<>(distanceToBeginningOfTunnel, distanceToEndOfTunnel)); - } - return distancesToTunnelIntersections; - } - } - - public static Builder builder() { - return new AutoValue_RouteStepProgress.Builder(); } - - /** - * Total distance in meters from user to end of step. - * - * @return double value representing the distance the user has remaining till they reach the end - * of the current step. Uses unit meters. - * @since 0.1.0 - */ - public abstract double distanceRemaining(); - - /** - * Returns distance user has traveled along current step in unit meters. - * - * @return double value representing the distance the user has traveled so far along the current - * step. Uses unit meters. - * @since 0.1.0 - */ - public abstract double distanceTraveled(); - - /** - * Get the fraction traveled along the current step, this is a float value between 0 and 1 and - * isn't guaranteed to reach 1 before the user reaches the next step (if another step exist in route). - * - * @return a float value between 0 and 1 representing the fraction the user has traveled along - * the current step. - * @since 0.1.0 - */ - public abstract float fractionTraveled(); - - /** - * Provides the duration remaining in seconds till the user reaches the end of the current step. - * - * @return {@code long} value representing the duration remaining till end of step, in unit seconds. - * @since 0.1.0 - */ - public abstract double durationRemaining(); - - /** - * A collection of all the current steps intersections and the next steps maneuver location - * (if one exist). - * - * @return a list of {@link StepIntersection}s which may include the next steps maneuver - * intersection if it exist - * @since 0.7.0 - */ - public abstract List intersections(); - - /** - * Provides a list of intersections that have tunnel classes for - * the current step. - *

- * The returned list will be empty if not intersections are found. - * - * @return list of intersections containing a tunnel class - * @since 0.13.0 - */ - public abstract List tunnelIntersections(); - - /** - * Provides a list of pairs containing two distances, in meters, along the route. - *

- * The first distance in the pair is the tunnel entrance along the step geometry. - * The second distance is the tunnel exit along the step geometry. - * - * @return list of pairs containing tunnnel entrance and exit distances - * @since 0.13.0 - */ - public abstract List> tunnelIntersectionDistances(); } \ No newline at end of file