From ba97a2cf5f53d9dde0d010627ed0c86e22a463fe Mon Sep 17 00:00:00 2001 From: Seth Bourget Date: Tue, 4 Oct 2022 12:43:11 -0700 Subject: [PATCH 1/7] wip --- .../core/MapboxRouteLineAndArrowActivity.kt | 59 +++- .../layout_activity_routeline_example.xml | 1 - .../internal/route/line/LocationSearchTree.kt | 71 +++++ .../internal/route/line/LocationTreeNode.kt | 150 ++++++++++ .../route/line/MapboxRouteLineUtils.kt | 48 ++- .../route/line/NearestNeighborCollector.kt | 52 ++++ .../maps/internal/route/line/PointProvider.kt | 10 + .../line/MapboxRouteLineApiExtensions.kt | 2 + .../maps/route/line/api/MapboxRouteLineApi.kt | 91 +++--- .../maps/route/line/api/VanishingRouteLine.kt | 278 +++++++++--------- .../maps/route/line/model/RouteFeatureData.kt | 2 +- .../line/model/RouteLineDistancesIndex.kt | 7 +- .../line/model/RouteLineGranularDistances.kt | 4 +- .../route/line/model/RouteLineSourceKey.kt | 2 +- .../ui/maps/util/DistanceComparator.kt | 14 + .../line/MapboxRouteLineUtilsRoboTest.kt | 9 + .../line/api/MapboxRouteLineApiRoboTest.kt | 2 +- .../line/api/VanishingRouteLineRoboTest.kt | 7 +- 18 files changed, 598 insertions(+), 211 deletions(-) create mode 100644 libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationSearchTree.kt create mode 100644 libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationTreeNode.kt create mode 100644 libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/NearestNeighborCollector.kt create mode 100644 libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/PointProvider.kt create mode 100644 libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/DistanceComparator.kt diff --git a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt index 1a993a1ef9d..713f01f1935 100644 --- a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt +++ b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt @@ -16,13 +16,19 @@ import com.mapbox.android.core.location.LocationEngineResult import com.mapbox.android.gestures.Utils import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.api.directions.v5.models.RouteOptions +import com.mapbox.geojson.Feature +import com.mapbox.geojson.FeatureCollection import com.mapbox.geojson.Point import com.mapbox.maps.CameraOptions import com.mapbox.maps.EdgeInsets import com.mapbox.maps.MapboxMap import com.mapbox.maps.Style import com.mapbox.maps.extension.observable.eventdata.MapLoadingErrorEventData +import com.mapbox.maps.extension.style.layers.generated.CircleLayer import com.mapbox.maps.extension.style.layers.properties.generated.Visibility +import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource +import com.mapbox.maps.extension.style.sources.generated.geoJsonSource +import com.mapbox.maps.extension.style.sources.getSource import com.mapbox.maps.plugin.LocationPuck2D import com.mapbox.maps.plugin.animation.MapAnimationOptions import com.mapbox.maps.plugin.animation.camera @@ -61,6 +67,8 @@ import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions import com.mapbox.navigation.ui.maps.route.line.model.RouteLine import com.mapbox.navigation.ui.maps.route.line.model.RouteLineColorResources import com.mapbox.navigation.ui.maps.route.line.model.RouteLineResources +import com.mapbox.navigation.utils.internal.InternalJobControlFactory +import kotlinx.coroutines.cancelChildren import java.lang.ref.WeakReference /** @@ -75,6 +83,7 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe private val replayRouteMapper = ReplayRouteMapper() private val replayProgressObserver = ReplayProgressObserver(mapboxReplayer) private var trafficGradientSoft = false + private val jobControl = InternalJobControlFactory.createDefaultScopeJobControl() private val viewBinding: LayoutActivityRoutelineExampleBinding by lazy { LayoutActivityRoutelineExampleBinding.inflate(layoutInflater) @@ -203,7 +212,7 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe null, ContextCompat.getDrawable( this@MapboxRouteLineAndArrowActivity, - R.drawable.mapbox_navigation_puck_icon + R.drawable.custom_user_puck_icon ), null, null @@ -227,7 +236,6 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe // to the MapboxRouteLineApi to generate the data necessary to draw the route(s) // on the map. val routeLines = result.routes.map { RouteLine(it, null) } - routeLineApi.setRoutes( routeLines ) { value -> @@ -253,13 +261,15 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe } private val routeProgressObserver = RouteProgressObserver { routeProgress -> + + //todo remove this // RouteLine: This line is only necessary if the vanishing route line feature // is enabled. - routeLineApi.updateWithRouteProgress(routeProgress) { result -> - mapboxMap.getStyle()?.apply { - routeLineView.renderRouteLineUpdate(this, result) - } - } + // routeLineApi.updateWithRouteProgress(routeProgress) { result -> + // mapboxMap.getStyle()?.apply { + // routeLineView.renderRouteLineUpdate(this, result) + // } + // } // RouteArrow: The next maneuver arrows are driven by route progress events. // Generate the next maneuver arrow update data and pass it to the view class @@ -316,7 +326,7 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe // The lines below are related to the navigation simulator. mapboxReplayer.pushRealLocation(this, 0.0) - mapboxReplayer.playbackSpeed(1.5) + //mapboxReplayer.playbackSpeed(1.5) mapboxReplayer.play() } @@ -359,6 +369,8 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe locationEngineCallback ) viewBinding.mapView.gestures.addOnMapLongClickListener(this) + + initPointLayer(style) }, object : OnMapLoadErrorListener { override fun onMapLoadError(eventData: MapLoadingErrorEventData) { @@ -476,6 +488,7 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe override fun onStop() { super.onStop() + jobControl.job.cancelChildren() locationComponent.removeOnIndicatorPositionChangedListener(onPositionChangedListener) mapboxNavigation.unregisterRouteProgressObserver(replayProgressObserver) mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver) @@ -514,4 +527,34 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe override fun onFailure(exception: Exception) { } } + + private val LINE_END_LAYER_ID = "DRAW_UTIL_LINE_END_LAYER_ID" + private val LINE_END_SOURCE_ID = "DRAW_UTIL_LINE_END_SOURCE_ID" + private fun initPointLayer(style: Style) { + if (!style.styleSourceExists(LINE_END_SOURCE_ID)) { + geoJsonSource(LINE_END_SOURCE_ID) {}.bindTo(style) + } + + if (!style.styleLayerExists(LINE_END_LAYER_ID)) { + CircleLayer(LINE_END_LAYER_ID, LINE_END_SOURCE_ID) + .circleRadius(5.0) + .circleOpacity(1.0) + .circleColor(Color.BLACK) + .bindTo(style) + } + } + + // todo remove this + private fun addPointToPixelMapPoints(points: List) { + val features = points.map { Feature.fromGeometry(it) } + + (mapboxMap.getStyle()!!.getSource(LINE_END_SOURCE_ID) as GeoJsonSource).apply { + this.featureCollection(FeatureCollection.fromFeatures(features)) + } + } + + // fun getRoute(): DirectionsRoute { + // val routeJson = "{\"country_crossed\":false,\"weight_typical\":373.949,\"routeIndex\":\"0\",\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DAChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\oMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTIWzeA\",\"weight\":373.949,\"weight_name\":\"auto\",\"legs\":[{\"weight_typical\":373.949,\"weight\":373.949,\"via_waypoints\":[],\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"summary\":\"West Fourth Plain Boulevard, Kauffman Avenue\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"weight_typical\":111.941,\"distance\":634.918,\"duration\":86.844,\"duration_typical\":86.844,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DA\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.63447],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":634.918,\"announcement\":\"Drive north on Main Street for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eDrive north on \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eMain Street\\u003c/say-as\\u003e for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West Fourth Plain Boulevard.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest Fourth Plain Boulevard\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":42.667,\"announcement\":\"Turn left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":634.918,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":true,\"active_direction\":\"left\"},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"right\"],\"active\":false}]}}],\"driving_side\":\"right\",\"weight\":111.941,\"intersections\":[{\"duration\":7.315,\"weight\":8.778,\"location\":[-122.671531,45.63447],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.937,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.201,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":9.919,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":12.88,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":4.031,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.914,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.832,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.945,\"location\":[-122.671487,45.63679],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.844,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.186,\"location\":[-122.671483,45.637018],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.874,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.998,\"location\":[-122.671477,45.637323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.254,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.237,\"location\":[-122.671473,45.637532],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":2.918,\"turn_duration\":2.019,\"turn_weight\":0.5,\"duration\":3.993,\"location\":[-122.67147,45.63769],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":2.779,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.881,\"location\":[-122.671468,45.63784],\"bearings\":[1,181,267],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":12,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.619,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.41,\"location\":[-122.671464,45.638047],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":7.363,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":9.496,\"location\":[-122.671459,45.638323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":14,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":10.819,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":14.23,\"location\":[-122.67145,45.638782],\"bearings\":[1,75,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.75,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":4.346,\"location\":[-122.671438,45.63946],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671435,45.639654],\"bearings\":[1,90,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":18,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":104.434,\"distance\":744.28,\"duration\":79.063,\"duration_typical\":79.063,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"y}s`vAdsg~hFChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\\",\"name\":\"West Fourth Plain Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671427,45.640173],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West Fourth Plain Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":730.946,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":66.667,\"announcement\":\"Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":744.28,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\",\"right\"],\"active\":true,\"active_direction\":\"right\"}]}}],\"driving_side\":\"right\",\"weight\":104.434,\"intersections\":[{\"weight\":12.272,\"turn_duration\":7.622,\"turn_weight\":10,\"duration\":9.476,\"location\":[-122.671427,45.640173],\"bearings\":[15,90,181,271],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"right\"]}],\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":4.93,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":6.514,\"location\":[-122.671647,45.640175],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":22,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.821,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":3.93,\"location\":[-122.67223,45.64018],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":24,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.672503,45.640182],\"bearings\":[91,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":25,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.673074,45.640185],\"bearings\":[90,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":26,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":5.138,\"turn_duration\":2.021,\"turn_weight\":1.5,\"duration\":4.991,\"location\":[-122.673636,45.640188],\"bearings\":[91,179,271,359],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":28,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":6.75,\"turn_weight\":0.5,\"weight\":8.769,\"location\":[-122.674055,45.640192],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":30,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.784,\"turn_weight\":1,\"turn_duration\":0.021,\"weight\":5.61,\"location\":[-122.675017,45.640202],\"bearings\":[1,91,191,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":31,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":8.007,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":10.1,\"location\":[-122.675603,45.640202],\"bearings\":[0,90,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":32,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.455,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":9.221,\"location\":[-122.676886,45.640215],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":33,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.844,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":2.704,\"location\":[-122.677966,45.64022],\"bearings\":[90,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":34,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.246,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":7.97,\"location\":[-122.678293,45.640224],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":35,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.971,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.84,\"location\":[-122.679353,45.640231],\"bearings\":[91,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":36,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.301,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":4.436,\"location\":[-122.679682,45.640235],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":37,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":0.548,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":1.132,\"location\":[-122.680211,45.640242],\"bearings\":[91,180,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":38,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.046,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.93,\"location\":[-122.680286,45.640243],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":39,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":0.5,\"location\":[-122.680518,45.640246],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":40,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":131.023,\"distance\":877.516,\"duration\":91.718,\"duration_typical\":91.718,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"wbt`vAxhz~hFoMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTI\",\"name\":\"Kauffman Avenue\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680989,45.640252],\"bearing_before\":271.0,\"bearing_after\":1.0,\"instruction\":\"Turn right onto Kauffman Avenue.\",\"type\":\"turn\",\"modifier\":\"right\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":864.182,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West 36th Street.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":91.111,\"announcement\":\"Turn left onto West 36th Street. Then Your destination will be on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e. Then Your destination will be on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":877.516,\"primary\":{\"text\":\"West 36th Street\",\"components\":[{\"text\":\"West 36th Street\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":131.023,\"intersections\":[{\"weight\":19.48,\"turn_duration\":4.005,\"turn_weight\":7,\"duration\":14.405,\"location\":[-122.680989,45.640252],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"right\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":41,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":5.119,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.87,\"location\":[-122.680982,45.640484],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":42,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.276,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.059,\"location\":[-122.680974,45.64079],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":43,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":7.069,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":9.21,\"location\":[-122.680973,45.640821],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":44,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.467,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":4.886,\"location\":[-122.680949,45.641665],\"bearings\":[0,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":45,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.059,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.798,\"location\":[-122.680943,45.642072],\"bearings\":[1,89,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":47,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.752,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":5.98,\"location\":[-122.680937,45.642508],\"bearings\":[1,92,181,267],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":48,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.019,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.35,\"location\":[-122.680933,45.64276],\"bearings\":[1,181,270],\"entry\":[true,false,false],\"in\":1,\"out\":0,\"geometry_index\":49,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":6.869,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":8.969,\"location\":[-122.680929,45.643071],\"bearings\":[0,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":50,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.294,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.88,\"location\":[-122.68092,45.643769],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":52,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.619,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":2.67,\"location\":[-122.680909,45.644285],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":53,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.866,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.166,\"location\":[-122.680905,45.644465],\"bearings\":[1,181,276],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":54,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.795,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":6.031,\"location\":[-122.680898,45.64477],\"bearings\":[1,90,181,269],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":56,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.804,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.197,\"location\":[-122.680892,45.645153],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":57,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.204,\"turn_weight\":2,\"turn_duration\":0.021,\"weight\":6.916,\"location\":[-122.680885,45.645518],\"bearings\":[0,90,181,265],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":58,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.71,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":1.575,\"location\":[-122.680881,45.645902],\"bearings\":[1,90,180],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":59,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.062,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":3.151,\"location\":[-122.68088,45.645973],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":60,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.149,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.778,\"location\":[-122.680877,45.646162],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":62,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.533,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.354,\"location\":[-122.680868,45.646675],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":63,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.118,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":5.14,\"location\":[-122.680867,45.646729],\"bearings\":[0,92,181,284],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":64,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.579,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":3.771,\"location\":[-122.680864,45.647059],\"bearings\":[1,180,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":65,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.819,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.39,\"location\":[-122.680858,45.647327],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":66,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"turn_duration\":0.019,\"location\":[-122.680842,45.647797],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":68,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"weight_typical\":26.551,\"distance\":88.242,\"duration\":17.84,\"duration_typical\":17.84,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kocavAh_z~hFWzeA\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680837,45.648134],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West 36th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":44.444,\"announcement\":\"Your destination is on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eYour destination is on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":88.242,\"primary\":{\"text\":\"Your destination will be on the left\",\"components\":[{\"text\":\"Your destination will be on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":44.444,\"primary\":{\"text\":\"Your destination is on the left\",\"components\":[{\"text\":\"Your destination is on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":26.551,\"intersections\":[{\"turn_weight\":12.5,\"turn_duration\":5.622,\"location\":[-122.680837,45.648134],\"bearings\":[0,181,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":69,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"weight_typical\":0,\"distance\":0.0,\"duration\":0.0,\"duration_typical\":0.0,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"cpcavAdf|~hF??\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.681971,45.648146],\"bearing_before\":271.0,\"bearing_after\":0.0,\"instruction\":\"Your destination is on the left.\",\"type\":\"arrive\",\"modifier\":\"left\"},\"voiceInstructions\":[],\"bannerInstructions\":[],\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.681971,45.648146],\"bearings\":[91],\"entry\":[true],\"in\":0,\"geometry_index\":70,\"admin_index\":0}]}],\"annotation\":{\"distance\":[45.0,48.6,37.3,88.4,39.0,25.4,33.9,23.3,9.7,7.9,7.8,8.9,23.0,30.8,51.1,10.8,64.6,21.6,48.9,8.9,9.1,8.0,39.0,6.4,21.3,44.4,35.2,8.6,7.7,24.9,74.9,45.6,99.8,84.1,25.4,82.5,25.7,41.1,5.9,18.0,36.7,25.8,34.1,3.5,93.9,9.9,35.4,48.6,28.0,34.6,18.5,59.3,57.4,20.0,20.9,13.1,42.6,40.7,42.7,7.9,10.6,10.5,57.1,6.0,36.7,29.9,24.6,27.7,37.5,88.3],\"duration\":[7.315,8.552,3.937,9.919,4.031,2.832,3.844,2.874,1.249,1.004,2.94,1.053,2.779,3.619,7.363,1.564,9.255,2.75,8.429,1.533,8.608,0.868,4.239,0.69,2.821,5.867,4.718,1.148,2.73,2.261,6.75,3.784,8.007,6.455,1.844,6.246,1.971,3.301,0.547,2.046,4.163,14.405,5.119,0.276,7.069,0.774,2.693,5.059,3.752,3.019,1.649,5.22,4.294,1.619,1.764,1.101,3.795,3.804,4.204,0.71,1.046,1.016,5.149,0.533,3.118,2.579,2.276,2.543,3.128,17.84],\"speed\":[6.1,7.4,9.5,8.9,9.7,9.0,8.9,8.1,7.9,7.9,8.5,8.5,8.3,8.5,7.0,7.0,7.0,7.9,5.8,5.8,9.2,9.2,9.2,9.2,7.6,7.6,7.5,7.5,11.0,11.0,11.1,12.1,12.5,13.1,13.9,13.3,13.1,12.6,11.1,8.9,8.8,2.5,6.7,13.4,13.3,13.1,13.1,9.6,7.5,11.5,11.3,11.3,13.4,12.5,11.9,11.9,11.3,10.7,10.2,11.3,10.3,10.3,11.1,11.7,11.9,11.6,10.9,10.9,12.1,7.2],\"maxspeed\":[{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"}],\"congestion_numeric\":[0,24,9,9,0,0,0,null,null,null,0,0,0,null,6,9,9,14,null,null,9,9,9,9,30,30,30,30,12,12,12,4,3,1,0,0,null,3,null,0,0,null,null,null,0,null,null,null,null,null,null,null,null,null,null,null,0,null,null,null,0,0,null,null,null,null,null,null,0,null]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6716938,45.6344717;-122.681974,45.6479927\",\"alternatives\":true,\"language\":\"en\",\"layers\":\";\",\"continue_straight\":true,\"roundabout_exits\":true,\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,maxspeed,closure,speed,duration,distance\",\"voice_instructions\":true,\"banner_instructions\":true,\"voice_units\":\"imperial\",\"enable_refresh\":true},\"voiceLocale\":\"en-US\",\"requestUuid\":\"VA6i2dqAyEvoC4gS25Y14Z6gAE6c2fe_Tpq4H9voaY7FjLb-IUIcYQ\\u003d\\u003d\"}" + // return DirectionsRoute.fromJson(routeJson) + // } } diff --git a/examples/src/main/res/layout/layout_activity_routeline_example.xml b/examples/src/main/res/layout/layout_activity_routeline_example.xml index e2168e68666..99d198708e7 100644 --- a/examples/src/main/res/layout/layout_activity_routeline_example.xml +++ b/examples/src/main/res/layout/layout_activity_routeline_example.xml @@ -64,5 +64,4 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:visibility="invisible"/> - \ No newline at end of file diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationSearchTree.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationSearchTree.kt new file mode 100644 index 00000000000..7c3bba9ef22 --- /dev/null +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationSearchTree.kt @@ -0,0 +1,71 @@ +package com.mapbox.navigation.ui.maps.internal.route.line + +import com.mapbox.geojson.Point +import com.mapbox.turf.TurfConstants +import com.mapbox.turf.TurfMeasurement +import java.util.function.Supplier + +class LocationSearchTree>(private val capacity: Int = 10) { + private var rootNode: LocationTreeNode? = null + + fun size() = rootNode?.size() ?: 0 + + fun isEmpty() = size() == 0 + + fun add(point: T) { + addAll(listOf(point)) + } + + fun addAll(points: List) { + if (rootNode == null) { + rootNode = LocationTreeNode(points.toMutableList(), capacity, distanceCalcFunction) + } else { + if (points.isNotEmpty()) { + points.forEach { + rootNode?.add(it) + } + rootNode?.initializeNode() + } + } + } + + fun remove(point: T) { + removeAll(listOf(point)) + } + + fun removeAll(points: List) { + var pointRemoved = false + rootNode?.let { theRootNode -> + points.forEach { + pointRemoved = theRootNode.remove(it) || pointRemoved + } + + if (pointRemoved) { + theRootNode.initializeNode() + } + } + } + + fun clear() { + rootNode = null + } + + fun getNearestNeighbor(target: Point) = getNearestNeighbors(target, 1).firstOrNull() + + fun getNearestNeighbors(target: Point, maxResults: Int): List { + return if (rootNode == null) { + listOf() + } else { + val collector: NearestNeighborCollector = NearestNeighborCollector( + target, + maxResults + ) + rootNode?.collectNearestNeighbors(collector) + collector.toSortedList() + } + } + + private val distanceCalcFunction = { point1: Point, point2: Point -> + TurfMeasurement.distance(point1, point2, TurfConstants.UNIT_METERS) + } +} diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationTreeNode.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationTreeNode.kt new file mode 100644 index 00000000000..9097a209f52 --- /dev/null +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationTreeNode.kt @@ -0,0 +1,150 @@ +package com.mapbox.navigation.ui.maps.internal.route.line + +import com.mapbox.geojson.Point +import java.util.function.Supplier + +class LocationTreeNode>( + private val points: MutableList, + private val capacity: Int = 32, + private val distanceCalcFunction: (Point, Point) -> Double +) { + + private val vantagePoint: Point by lazy { + points.random().get() + } + + private var threshold = 0.0 + + private var closer: LocationTreeNode? = null + private var farther: LocationTreeNode? = null + + init { + initializeNode() + } + + internal fun initializeNode() { + if (points.isEmpty()) { + if (closer?.size() == 0 || farther?.size() == 0) { + // Prune empty child nodes. + addAllPointsToCollection(points) + closer = null + farther = null + initializeNode() + } else { + closer?.initializeNode() + farther?.initializeNode() + } + } else { + // What matters is that the points with in the distance threshold of the + // vantage point are on the left of the vantage point index in the list. + points.sortBy { distanceCalcFunction(vantagePoint, it.get()) } + if (points.size > capacity) { + threshold = distanceCalcFunction(vantagePoint, points[points.size / 2].get()) + when (val firstPastThreshold = + partitionPoints(vantagePoint, points.map { it.get() }, threshold)) { + in 0 .. Int.MAX_VALUE -> { + closer = LocationTreeNode( + points.subList(0, firstPastThreshold).toMutableList(), + capacity, + distanceCalcFunction + ) + farther = LocationTreeNode( + points.subList(firstPastThreshold, points.size).toMutableList(), + capacity, + distanceCalcFunction + ) + points.clear() + } + else -> { + closer = null + farther = null + } + } + } + } + } + + fun size(): Int { + return if (this.points.isEmpty()) { + (closer?.size() ?: 0) + (farther?.size() ?: 0) + } else { + this.points.size + } + } + + fun add(point: T) { + if (points.isEmpty()) { + getChildNodeForPoint(point.get())?.add(point) + } else { + points.add(point) + } + } + + fun remove(point: T): Boolean { + return if (points.isEmpty()) { + getChildNodeForPoint(point.get())?.remove(point) ?: false + } else { + points.remove(point) + } + } + + fun collectNearestNeighbors(collector: NearestNeighborCollector) { + if (points.isEmpty()) { + val firstNodeSearched = getChildNodeForPoint(collector.queryPoint) + firstNodeSearched?.collectNearestNeighbors(collector) + + val distanceFromVantagePointToQueryPoint = distanceCalcFunction( + vantagePoint, + collector.queryPoint + ) + val distanceFromQueryPointToFarthestPoint = if (collector.getFarthestPoint() != null) { + distanceCalcFunction(collector.queryPoint, collector.getFarthestPoint()!!) + } else { + Double.MAX_VALUE + } + + if (firstNodeSearched == closer) { + val distanceFromQueryPointToThreshold = + threshold - distanceFromVantagePointToQueryPoint + + if (distanceFromQueryPointToFarthestPoint > distanceFromQueryPointToThreshold) { + farther?.collectNearestNeighbors(collector) + } + } else { + val distanceFromQueryPointToThreshold = + distanceFromVantagePointToQueryPoint - threshold + + if (distanceFromQueryPointToThreshold <= distanceFromQueryPointToFarthestPoint) { + closer?.collectNearestNeighbors(collector) + } + } + } else { + points.forEach { + collector.offerPoint(it) + } + } + } + + private fun getChildNodeForPoint(point: Point): LocationTreeNode? { + return if (distanceCalcFunction(vantagePoint, point) <= threshold) { + closer + } else { + farther + } + } + + private fun addAllPointsToCollection(collection: MutableList) { + if (points.isEmpty()) { + closer?.addAllPointsToCollection(collection) + farther?.addAllPointsToCollection(collection) + } else { + collection.addAll(points) + } + } + + private fun partitionPoints(vantagePoint: Point, points: List, threshold: Double): Int { + return points.map { + Pair(it, distanceCalcFunction(vantagePoint, it)) + }.indexOfFirst { it.second > threshold } + } +} diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt index b6b200ccb04..723876eb560 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt @@ -57,13 +57,14 @@ import com.mapbox.navigation.ui.utils.internal.ifNonNull import com.mapbox.navigation.utils.internal.logE import com.mapbox.navigation.utils.internal.logW import com.mapbox.turf.TurfConstants +import com.mapbox.turf.TurfMeasurement import com.mapbox.turf.TurfMisc import kotlin.math.ln import kotlin.math.max import kotlin.math.sin import kotlin.math.sqrt -internal object MapboxRouteLineUtils { +object MapboxRouteLineUtils { private const val LOG_CATEGORY = "MapboxRouteLineUtils" internal const val VANISH_POINT_STOP_GAP = .00000000001 @@ -716,7 +717,7 @@ internal object MapboxRouteLineUtils { /** * Decodes the route and produces [RouteLineGranularDistances]. */ - internal val granularDistancesProvider: ( + val granularDistancesProvider: ( route: NavigationRoute, ) -> RouteLineGranularDistances? = { route: NavigationRoute -> @@ -876,11 +877,10 @@ internal object MapboxRouteLineUtils { private fun generateFeatureCollection(route: NavigationRouteLine): RouteFeatureData = generateRouteFeatureData(route.route, route.identifier) - private fun calculateGranularDistances( + private fun calculateGranularDistances( stepsPoints: List>> ): RouteLineGranularDistances { var distance = 0.0 - val stepsArray = stepsPoints.map { pointsPerLeg -> pointsPerLeg.map { stepPoints -> // there can be a lot of points for each step @@ -955,6 +955,46 @@ internal object MapboxRouteLineUtils { ) } + fun getFillerPointsForStepPoints(nextSteps: Array): List { + val fillerPoints = mutableListOf() + nextSteps.forEachIndexed { index, routeLineDistancesIndex -> + if (index < nextSteps.lastIndex) { + getFillerPoints(routeLineDistancesIndex, nextSteps[index + 1]).apply { + fillerPoints.addAll(this) + } + } + } + return fillerPoints + } + + //todo the variable names below should be named better + fun getFillerPoints(startPoint: RouteLineDistancesIndex, endPoint: RouteLineDistancesIndex): List { + val gapDist = 1.0 // meters + val turfDistance = TurfMeasurement.distance(startPoint.point, endPoint.point, TurfConstants.UNIT_METERS) + val fillerPoints = mutableListOf() + val bearing = TurfMeasurement.bearing(startPoint.point, endPoint.point) + var lastCalculatedPoint = startPoint + val count = (turfDistance / gapDist).toInt() + val delta = startPoint.distanceRemaining - endPoint.distanceRemaining + val itemDist = delta / count + + fillerPoints.add(startPoint) + var dist = startPoint.distanceRemaining + repeat(count) { + val fillerPoint = TurfMeasurement.destination( + lastCalculatedPoint.point, + gapDist, + bearing, + TurfConstants.UNIT_METERS + ) + + dist -= itemDist + fillerPoints.add(RouteLineDistancesIndex(fillerPoint, dist)) + lastCalculatedPoint = fillerPoints.last() + } + return fillerPoints + } + private val generateRouteFeatureData: ( route: NavigationRoute, identifier: String? diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/NearestNeighborCollector.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/NearestNeighborCollector.kt new file mode 100644 index 00000000000..8f0d1d6e169 --- /dev/null +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/NearestNeighborCollector.kt @@ -0,0 +1,52 @@ +package com.mapbox.navigation.ui.maps.internal.route.line + +import com.mapbox.geojson.Point +import com.mapbox.navigation.ui.maps.util.DistanceComparator +import com.mapbox.navigation.ui.utils.internal.ifNonNull +import com.mapbox.turf.TurfConstants +import com.mapbox.turf.TurfMeasurement +import java.util.Collections +import java.util.PriorityQueue +import java.util.function.Supplier + +class NearestNeighborCollector>(val queryPoint: Point, private val capacity: Int) { + + private val distanceComparator by lazy { + DistanceComparator(queryPoint) + } + + private val priorityQueue by lazy { + PriorityQueue(capacity, Collections.reverseOrder(distanceComparator)) + } + + private var distanceToFarthestPoint: Double = 0.0 + + fun offerPoint(offeredPoint: T) { + val pointAdded = if (priorityQueue.size < this.capacity) { + priorityQueue.add(offeredPoint) + } else { + if (priorityQueue.isNotEmpty()) { + val distanceToNewPoint = TurfMeasurement.distance(queryPoint, offeredPoint.get(), TurfConstants.UNIT_METERS) + if (distanceToNewPoint < distanceToFarthestPoint) { + priorityQueue.poll() + priorityQueue.add(offeredPoint) + true + } else { + false + } + } else { + false + } + } + + if (pointAdded && priorityQueue.isNotEmpty()) { + distanceToFarthestPoint = ifNonNull(priorityQueue.peek()) { pointSupplier: Supplier -> + TurfMeasurement.distance(queryPoint, pointSupplier.get(), TurfConstants.UNIT_METERS) + } ?: Double.MAX_VALUE + } + } + + fun getFarthestPoint(): Point? = priorityQueue.peek()?.get() + + fun toSortedList() = priorityQueue.toList().sortedWith(distanceComparator) +} diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/PointProvider.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/PointProvider.kt new file mode 100644 index 00000000000..bc3dd7c0990 --- /dev/null +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/PointProvider.kt @@ -0,0 +1,10 @@ +package com.mapbox.navigation.ui.maps.internal.route.line + +import com.mapbox.geojson.Point +import java.util.function.Supplier + +class PointProvider(private val p: Point): Supplier { + override fun get(): Point { + return p + } +} diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt index 5cd0dcd6dec..e8cbb6c8ef6 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt @@ -4,6 +4,8 @@ import androidx.annotation.ColorInt import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.bindgen.Expected import com.mapbox.bindgen.ExpectedFactory +import com.mapbox.geojson.Feature +import com.mapbox.geojson.FeatureCollection import com.mapbox.geojson.Point import com.mapbox.maps.MapboxMap import com.mapbox.maps.extension.style.expressions.generated.Expression diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt index ce5c15e8499..571db812850 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt @@ -54,13 +54,11 @@ import com.mapbox.navigation.ui.maps.route.line.model.RouteLineTrimOffset import com.mapbox.navigation.ui.maps.route.line.model.RouteLineUpdateValue import com.mapbox.navigation.ui.maps.route.line.model.RouteNotFound import com.mapbox.navigation.ui.maps.route.line.model.RouteSetValue -import com.mapbox.navigation.ui.maps.route.line.model.VanishingPointState import com.mapbox.navigation.ui.maps.route.line.model.toNavigationRouteLines import com.mapbox.navigation.ui.maps.util.CacheResultUtils import com.mapbox.navigation.ui.maps.util.CacheResultUtils.cacheResult import com.mapbox.navigation.ui.utils.internal.ifNonNull import com.mapbox.navigation.utils.internal.InternalJobControlFactory -import com.mapbox.navigation.utils.internal.logE import com.mapbox.navigation.utils.internal.logW import com.mapbox.navigation.utils.internal.parallelMap import com.mapbox.turf.TurfConstants @@ -439,26 +437,27 @@ class MapboxRouteLineApi( point: Point ): Expected { val currentNanoTime = System.nanoTime() - if (routeLineOptions.vanishingRouteLine?.vanishingPointState == - VanishingPointState.DISABLED || currentNanoTime - lastIndexUpdateTimeNano > - RouteLayerConstants.MAX_ELAPSED_SINCE_INDEX_UPDATE_NANO || - currentNanoTime - lastPointUpdateTimeNano < - routeLineOptions.vanishingRouteLineUpdateIntervalNano - ) { - return ExpectedFactory.createError( - RouteLineError( - "Vanishing point state is disabled or the update doesn't fall" + - "within the configured interval window.", - null - ) - ) - } - val stopGap: Double = ifNonNull(primaryRoute?.directionsRoute) { route -> - RouteLayerConstants.SOFT_GRADIENT_STOP_GAP_METERS / route.distance() - } ?: .00000000001 // an arbitrarily small value so Expression values are in ascending order + //todo does the VanishingPointState matter anymore? + //todo is the nano time still needed? + + // if (routeLineOptions.vanishingRouteLine?.vanishingPointState == + // VanishingPointState.DISABLED || currentNanoTime - lastIndexUpdateTimeNano > + // RouteLayerConstants.MAX_ELAPSED_SINCE_INDEX_UPDATE_NANO || + // currentNanoTime - lastPointUpdateTimeNano < + // routeLineOptions.vanishingRouteLineUpdateIntervalNano + // ) { + // return ExpectedFactory.createError( + // RouteLineError( + // "Vanishing point state is disabled or the update doesn't fall" + + // "within the configured interval window.", + // null + // ) + // ) + // } val routeLineExpressionProviders = ifNonNull(primaryRoute) { route -> + val stopGap: Double = RouteLayerConstants.SOFT_GRADIENT_STOP_GAP_METERS / route.directionsRoute.distance() ifNonNull(granularDistancesProvider(route)) { granularDistances -> if (routeLineOptions.styleInactiveRouteLegsIndependently) { val workingRouteLineExpressionData = @@ -474,7 +473,6 @@ class MapboxRouteLineApi( } routeLineOptions.vanishingRouteLine?.getTraveledRouteLineExpressions( point, - granularDistances, workingRouteLineExpressionData, restrictedExpressionData, routeLineOptions.resourceProvider, @@ -483,10 +481,7 @@ class MapboxRouteLineApi( routeLineOptions.displaySoftGradientForTraffic, ) } else { - routeLineOptions.vanishingRouteLine?.getTraveledRouteLineExpressions( - point, - granularDistances - ) + routeLineOptions.vanishingRouteLine?.getTraveledRouteLineExpressions(point) } } } @@ -701,27 +696,27 @@ class MapboxRouteLineApi( routeProgress: RouteProgress, consumer: MapboxNavigationConsumer> ) { - val currentPrimaryRoute = primaryRoute - if (currentPrimaryRoute == null) { - val msg = "You're calling #updateWithRouteProgress without any routes being set." - consumer.accept( - ExpectedFactory.createError(RouteLineError(msg, throwable = null)) - ) - logW(msg, LOG_CATEGORY) - return - } else if (currentPrimaryRoute.id != routeProgress.navigationRoute.id) { - val msg = "Provided primary route (#setNavigationRoutes, ID: " + - "${currentPrimaryRoute.id}) and navigated route (#updateWithRouteProgress, ID: " + - "${routeProgress.navigationRoute.id}) are not the same. Aborting the update." - consumer.accept( - ExpectedFactory.createError(RouteLineError(msg, throwable = null)) - ) - logE(msg, LOG_CATEGORY) - return - } - - updateUpcomingRoutePointIndex(routeProgress) - updateVanishingPointState(routeProgress.currentState) + // val currentPrimaryRoute = primaryRoute + // if (currentPrimaryRoute == null) { + // val msg = "You're calling #updateWithRouteProgress without any routes being set." + // consumer.accept( + // ExpectedFactory.createError(RouteLineError(msg, throwable = null)) + // ) + // logW(msg, LOG_CATEGORY) + // return + // } else if (currentPrimaryRoute.id != routeProgress.navigationRoute.id) { + // val msg = "Provided primary route (#setNavigationRoutes, ID: " + + // "${currentPrimaryRoute.id}) and navigated route (#updateWithRouteProgress, ID: " + + // "${routeProgress.navigationRoute.id}) are not the same. Aborting the update." + // consumer.accept( + // ExpectedFactory.createError(RouteLineError(msg, throwable = null)) + // ) + // logE(msg, LOG_CATEGORY) + // return + // } + // + // updateUpcomingRoutePointIndex(routeProgress) + // updateVanishingPointState(routeProgress.currentState) // If the de-emphasize inactive route legs feature is enabled and the vanishing route line // feature is enabled and the active leg index has changed, then calling the @@ -1079,6 +1074,7 @@ class MapboxRouteLineApi( } } + //todo remove this internal fun updateUpcomingRoutePointIndex(routeProgress: RouteProgress) { ifNonNull( routeProgress.currentLegProgress, @@ -1139,6 +1135,7 @@ class MapboxRouteLineApi( lastIndexUpdateTimeNano = System.nanoTime() } + // todo remove this internal fun updateVanishingPointState(routeProgressState: RouteProgressState) { routeLineOptions.vanishingRouteLine?.updateVanishingPointState(routeProgressState) } @@ -1192,7 +1189,9 @@ class MapboxRouteLineApi( if (routes.isEmpty()) return withContext(jobControl.scope.coroutineContext) { if (vanishingRouteLineEnabled) { - granularDistancesProvider(routes.first()) + granularDistancesProvider(routes.first())?.let { + routeLineOptions.vanishingRouteLine?.setGranularDistances(it) + } } if (alternativeRouteMetadataAvailable) { routes.drop(1).forEach { diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt index bb8f88fbef6..c46f6665864 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt @@ -4,9 +4,11 @@ import android.graphics.Color import com.mapbox.geojson.Point import com.mapbox.maps.extension.style.expressions.dsl.generated.literal import com.mapbox.navigation.base.trip.model.RouteProgressState +import com.mapbox.navigation.ui.maps.internal.route.line.LocationSearchTree import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils import com.mapbox.navigation.ui.maps.route.RouteLayerConstants import com.mapbox.navigation.ui.maps.route.line.model.ExtractedRouteRestrictionData +import com.mapbox.navigation.ui.maps.route.line.model.RouteLineDistancesIndex import com.mapbox.navigation.ui.maps.route.line.model.RouteLineExpressionData import com.mapbox.navigation.ui.maps.route.line.model.RouteLineGranularDistances import com.mapbox.navigation.ui.maps.route.line.model.RouteLineResources @@ -15,6 +17,8 @@ import com.mapbox.navigation.ui.maps.route.line.model.VanishingPointState import com.mapbox.navigation.ui.maps.route.line.model.VanishingRouteLineExpressions import com.mapbox.navigation.ui.utils.internal.ifNonNull import com.mapbox.navigation.utils.internal.logD +import com.mapbox.turf.TurfConstants +import com.mapbox.turf.TurfMeasurement /** * This class implements a feature that can change the appearance of the route line behind the puck. @@ -59,97 +63,39 @@ internal class VanishingRouteLine { } } - private fun getOffset( - point: Point, - granularDistances: RouteLineGranularDistances, - index: Int - ): Double? { - val upcomingIndex = granularDistances.flatStepDistances.getOrNull(index) - if (upcomingIndex == null) { - logD( - "Upcoming route line index is null.", - "VanishingRouteLine" - ) - return null - } - val upcomingPoint = upcomingIndex.point - if (index > 0) { - val distanceToLine = MapboxRouteLineUtils.findDistanceToNearestPointOnCurrentLine( - point, - granularDistances, - index - ) - if ( - distanceToLine > - RouteLayerConstants.ROUTE_LINE_UPDATE_MAX_DISTANCE_THRESHOLD_IN_METERS - ) { - return null - } + fun getTraveledRouteLineExpressions( + point: Point + ): VanishingRouteLineExpressions? { + return ifNonNull(getOffset(point)) { offset -> + getTraveledRouteLineExpressions(offset) } + } - /** - * Take the remaining distance from the upcoming point on the route and extends it - * by the exact position of the puck. - */ - val remainingDistance = - upcomingIndex.distanceRemaining + MapboxRouteLineUtils.calculateDistance( - upcomingPoint, - point - ) - - /** - * Calculate the percentage of the route traveled and update the expression. - */ - /** - * Calculate the percentage of the route traveled and update the expression. - */ - val offset = if (granularDistances.completeDistance >= remainingDistance) { - (1.0 - remainingDistance / granularDistances.completeDistance) - } else { - 0.0 + fun getTraveledRouteLineExpressions(offset: Double): VanishingRouteLineExpressions { + vanishPointOffset = offset + val trimmedOffsetExpression = literal(listOf(0.0, offset)) + val trafficLineExpressionProvider = RouteLineTrimExpressionProvider { + trimmedOffsetExpression } - - if (vanishingPointState == VanishingPointState.ONLY_INCREASE_PROGRESS && - vanishPointOffset > offset - ) { - return null + val routeLineExpressionProvider = RouteLineTrimExpressionProvider { + trimmedOffsetExpression } - return offset - } - - internal fun getTraveledRouteLineExpressions( - point: Point, - granularDistances: RouteLineGranularDistances - ): VanishingRouteLineExpressions? { - return ifNonNull(primaryRouteRemainingDistancesIndex) { index -> - ifNonNull(getOffset(point, granularDistances, index)) { offset -> - vanishPointOffset = offset - val trimmedOffsetExpression = literal(listOf(0.0, offset)) - val trafficLineExpressionProvider = RouteLineTrimExpressionProvider { - trimmedOffsetExpression - } - val routeLineExpressionProvider = RouteLineTrimExpressionProvider { - trimmedOffsetExpression - } - val routeLineCasingExpressionProvider = RouteLineTrimExpressionProvider { - trimmedOffsetExpression - } - val restrictedRoadExpressionProvider = RouteLineTrimExpressionProvider { - trimmedOffsetExpression - } - VanishingRouteLineExpressions( - trafficLineExpressionProvider, - routeLineExpressionProvider, - routeLineCasingExpressionProvider, - restrictedRoadExpressionProvider - ) - } + val routeLineCasingExpressionProvider = RouteLineTrimExpressionProvider { + trimmedOffsetExpression + } + val restrictedRoadExpressionProvider = RouteLineTrimExpressionProvider { + trimmedOffsetExpression } + return VanishingRouteLineExpressions( + trafficLineExpressionProvider, + routeLineExpressionProvider, + routeLineCasingExpressionProvider, + restrictedRoadExpressionProvider + ) } internal fun getTraveledRouteLineExpressions( point: Point, - granularDistances: RouteLineGranularDistances, routeLineExpressionData: List, restrictedLineExpressionData: List?, routeResourceProvider: RouteLineResources, @@ -157,73 +103,125 @@ internal class VanishingRouteLine { softGradientTransition: Double, useSoftGradient: Boolean, ): VanishingRouteLineExpressions? { - return ifNonNull( - primaryRouteRemainingDistancesIndex - ) { index -> - ifNonNull(getOffset(point, granularDistances, index)) { offset -> - vanishPointOffset = offset - val trafficLineExpressionProvider = if (useSoftGradient) { - { - MapboxRouteLineUtils.getTrafficLineExpressionSoftGradient( - offset, - routeResourceProvider.routeLineColorResources.routeLineTraveledColor, - routeResourceProvider - .routeLineColorResources - .routeUnknownCongestionColor, - softGradientTransition, - routeLineExpressionData - ) - } - } else { - { - MapboxRouteLineUtils.getTrafficLineExpression( - offset, - routeResourceProvider.routeLineColorResources.routeLineTraveledColor, - routeResourceProvider - .routeLineColorResources - .routeUnknownCongestionColor, - routeLineExpressionData - ) - } - } - val routeLineExpressionProvider = { - MapboxRouteLineUtils.getRouteLineExpression( + return ifNonNull(getOffset(point)) { offset -> + vanishPointOffset = offset + val trafficLineExpressionProvider = if (useSoftGradient) { + { + MapboxRouteLineUtils.getTrafficLineExpressionSoftGradient( offset, - routeLineExpressionData, routeResourceProvider.routeLineColorResources.routeLineTraveledColor, - routeResourceProvider.routeLineColorResources.routeDefaultColor, - routeResourceProvider.routeLineColorResources.inActiveRouteLegsColor, - activeLegIndex + routeResourceProvider + .routeLineColorResources + .routeUnknownCongestionColor, + softGradientTransition, + routeLineExpressionData ) } - val routeLineCasingExpressionProvider = { - MapboxRouteLineUtils.getRouteLineExpression( + } else { + { + MapboxRouteLineUtils.getTrafficLineExpression( offset, - routeLineExpressionData, - routeResourceProvider.routeLineColorResources.routeLineTraveledCasingColor, - routeResourceProvider.routeLineColorResources.routeCasingColor, - Color.TRANSPARENT, - activeLegIndex + routeResourceProvider.routeLineColorResources.routeLineTraveledColor, + routeResourceProvider + .routeLineColorResources + .routeUnknownCongestionColor, + routeLineExpressionData ) } - val restrictedRoadExpressionProvider = - ifNonNull(restrictedLineExpressionData) { expressionData -> - { - MapboxRouteLineUtils.getRestrictedLineExpression( - offset, - activeLegIndex, - routeResourceProvider.routeLineColorResources.restrictedRoadColor, - expressionData - ) - } + } + val routeLineExpressionProvider = { + MapboxRouteLineUtils.getRouteLineExpression( + offset, + routeLineExpressionData, + routeResourceProvider.routeLineColorResources.routeLineTraveledColor, + routeResourceProvider.routeLineColorResources.routeDefaultColor, + routeResourceProvider.routeLineColorResources.inActiveRouteLegsColor, + activeLegIndex + ) + } + val routeLineCasingExpressionProvider = { + MapboxRouteLineUtils.getRouteLineExpression( + offset, + routeLineExpressionData, + routeResourceProvider.routeLineColorResources.routeLineTraveledCasingColor, + routeResourceProvider.routeLineColorResources.routeCasingColor, + Color.TRANSPARENT, + activeLegIndex + ) + } + val restrictedRoadExpressionProvider = + ifNonNull(restrictedLineExpressionData) { expressionData -> + { + MapboxRouteLineUtils.getRestrictedLineExpression( + offset, + activeLegIndex, + routeResourceProvider.routeLineColorResources.restrictedRoadColor, + expressionData + ) } + } - VanishingRouteLineExpressions( - trafficLineExpressionProvider, - routeLineExpressionProvider, - routeLineCasingExpressionProvider, - restrictedRoadExpressionProvider - ) + VanishingRouteLineExpressions( + trafficLineExpressionProvider, + routeLineExpressionProvider, + routeLineCasingExpressionProvider, + restrictedRoadExpressionProvider + ) + } + } + + + //////////// + + private var granularDistances: RouteLineGranularDistances? = null + private val locationSearchTree = LocationSearchTree() + private var stepsPoints: List> = emptyList() + private val stepPointsInTree = mutableListOf>() + private var indexOfLastStepPointsLoadedInTree = 0 + + fun setGranularDistances(distances: RouteLineGranularDistances) { + granularDistances = distances + stepsPoints = granularDistances!!.stepsDistances.flatten() // todo test for multileg routes + locationSearchTree.clear() + stepPointsInTree.clear() + indexOfLastStepPointsLoadedInTree = 0 + + if (stepsPoints.isNotEmpty()) { + val firstSteps = stepsPoints.first() + val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(firstSteps) + locationSearchTree.addAll(fillerPoints) + stepPointsInTree.add(firstSteps) + } + } + + fun getOffset(point: Point): Double? { + val offset = ifNonNull(locationSearchTree.getNearestNeighbor(point), granularDistances) { closestPoint, distances -> + //todo check max distance threshold + (1.0 - closestPoint.distanceRemaining / distances.completeDistance) + } + trimTree(point) + return offset + } + + // todo put this on background thread + private fun trimTree(point: Point) { + //if getting close to the last step point, load the points for the next step + //and remove the points long since passed. + if (stepPointsInTree.isNotEmpty()) { + val nearEndStepPoint = stepPointsInTree.last()[stepPointsInTree.last().lastIndex] + val distanceToNearEndStepPoint = TurfMeasurement.distance(point, nearEndStepPoint.point, TurfConstants.UNIT_METERS) + if (distanceToNearEndStepPoint <= 10.0) { + if (indexOfLastStepPointsLoadedInTree < stepsPoints.size) { + val nextSteps = stepsPoints[indexOfLastStepPointsLoadedInTree + 1] + val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(nextSteps) + locationSearchTree.addAll(fillerPoints) + stepPointsInTree.add(nextSteps) + indexOfLastStepPointsLoadedInTree++ + if (stepPointsInTree.size == 3) { + val pointsToDrop = stepPointsInTree.removeAt(0) + locationSearchTree.removeAll(pointsToDrop.toList()) + } + } } } } diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteFeatureData.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteFeatureData.kt index a99c007b275..39f0afc762e 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteFeatureData.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteFeatureData.kt @@ -12,7 +12,7 @@ import com.mapbox.navigation.base.route.NavigationRoute * @param featureCollection a FeatureCollection created using the route * @param lineString a LineString derived from the route's geometry. */ -internal data class RouteFeatureData constructor( +data class RouteFeatureData constructor( // fixme make internal val route: NavigationRoute, val featureCollection: FeatureCollection, val lineString: LineString diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineDistancesIndex.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineDistancesIndex.kt index e43d9f35d87..f85d08f1a48 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineDistancesIndex.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineDistancesIndex.kt @@ -1,9 +1,14 @@ package com.mapbox.navigation.ui.maps.route.line.model import com.mapbox.geojson.Point +import java.util.function.Supplier /** * @param point the upcoming, not yet visited point on the route * @param distanceRemaining distance remaining from the upcoming point */ -data class RouteLineDistancesIndex(val point: Point, val distanceRemaining: Double) +data class RouteLineDistancesIndex(val point: Point, val distanceRemaining: Double): Supplier { + override fun get(): Point { + return point + } +} diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineGranularDistances.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineGranularDistances.kt index 028c8e7e9f8..f79d9acac08 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineGranularDistances.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineGranularDistances.kt @@ -11,10 +11,10 @@ import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils * @param routeDistances values in this array are matching indices of all points in the full route geometry * @param legsDistances values in this array are matching indices of all points in each of the route legs * @param stepsDistances values in this array are matching indices of all points in each of the leg steps - * @param flatStepDistances values in this array are matching indices a flatted [stepsDistances]. + * @param flatStepDistances values in this array are matching indices a flattened [stepsDistances]. * This means that **duplicate start/end points of adjacent steps are not filtered out**. */ -internal data class RouteLineGranularDistances constructor( +data class RouteLineGranularDistances constructor( val completeDistance: Double, val routeDistances: Array, val legsDistances: Array>, diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineSourceKey.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineSourceKey.kt index 604f085fb41..74c6be317c6 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineSourceKey.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineSourceKey.kt @@ -1,4 +1,4 @@ package com.mapbox.navigation.ui.maps.route.line.model @JvmInline -internal value class RouteLineSourceKey(val sourceId: String) +value class RouteLineSourceKey(val sourceId: String) //fixme me make internal diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/DistanceComparator.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/DistanceComparator.kt new file mode 100644 index 00000000000..76dbcb98a52 --- /dev/null +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/DistanceComparator.kt @@ -0,0 +1,14 @@ +package com.mapbox.navigation.ui.maps.util + +import com.mapbox.geojson.Point +import com.mapbox.turf.TurfConstants +import com.mapbox.turf.TurfMeasurement +import java.util.function.Supplier + +class DistanceComparator(private val origin: Point): Comparator> { + + override fun compare(p0: Supplier, p1: Supplier): Int { + return TurfMeasurement.distance(origin, p0.get(), TurfConstants.UNIT_METERS) + .compareTo(TurfMeasurement.distance(origin, p1.get(), TurfConstants.UNIT_METERS)) + } +} diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt index f5e2809063d..7d10625fd27 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt @@ -51,10 +51,18 @@ import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.ORIGIN_MARKER_NAM import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.TOP_LEVEL_ROUTE_LINE_LAYER_ID import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.WAYPOINT_LAYER_ID import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.WAYPOINT_SOURCE_ID +import com.mapbox.navigation.ui.maps.route.line.api.VanishingRouteLine +import com.mapbox.navigation.ui.maps.route.line.model.ExtractedRouteData import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions import com.mapbox.navigation.ui.maps.route.line.model.RouteLineColorResources +import com.mapbox.navigation.ui.maps.route.line.model.RouteLineDistancesIndex +import com.mapbox.navigation.ui.maps.route.line.model.RouteLineGranularDistances +import com.mapbox.navigation.ui.maps.route.line.model.RoutePoints import com.mapbox.navigation.ui.maps.testing.TestingUtil.loadNavigationRoute import com.mapbox.navigator.RouteInterface +import com.mapbox.turf.TurfConstants +import com.mapbox.turf.TurfMeasurement +import com.mapbox.turf.TurfMisc import io.mockk.every import io.mockk.mockk import io.mockk.mockkObject @@ -70,6 +78,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import java.util.UUID +import kotlin.math.abs @RunWith(RobolectricTestRunner::class) class MapboxRouteLineUtilsRoboTest { diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt index 17a42bf51fb..2e45b6379d6 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt @@ -1004,7 +1004,7 @@ class MapboxRouteLineApiRoboTest { emptyArray(), emptyArray(), emptyArray(), - emptyArray() + emptyArray(), ) } ) diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLineRoboTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLineRoboTest.kt index 08969efbd8a..fb9d5e1a304 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLineRoboTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLineRoboTest.kt @@ -115,7 +115,6 @@ class VanishingRouteLineRoboTest { val result = vanishingRouteLine.getTraveledRouteLineExpressions( lineString.coordinates()[0], - granularDistances = MapboxRouteLineUtils.granularDistancesProvider(route)!!, segments, null, genericMockResourceProvider, @@ -153,8 +152,7 @@ class VanishingRouteLineRoboTest { vanishingRouteLine.primaryRouteRemainingDistancesIndex = 1 val result = vanishingRouteLine.getTraveledRouteLineExpressions( - lineString.coordinates()[0], - granularDistances = MapboxRouteLineUtils.granularDistancesProvider(route)!!, + lineString.coordinates()[0] ) assertEquals( @@ -203,7 +201,6 @@ class VanishingRouteLineRoboTest { val result = vanishingRouteLine.getTraveledRouteLineExpressions( lineString.coordinates()[0], - granularDistances = MapboxRouteLineUtils.granularDistancesProvider(route)!!, segments, restrictedSegments, genericMockResourceProvider, @@ -249,7 +246,6 @@ class VanishingRouteLineRoboTest { val result = vanishingRouteLine.getTraveledRouteLineExpressions( lineString.coordinates()[0], - granularDistances = MapboxRouteLineUtils.granularDistancesProvider(route)!!, segments, null, genericMockResourceProvider, @@ -304,7 +300,6 @@ class VanishingRouteLineRoboTest { val result = vanishingRouteLine.getTraveledRouteLineExpressions( Point.fromLngLat(-122.52351984901476, 37.97384101461195), - granularDistances = MapboxRouteLineUtils.granularDistancesProvider(route)!!, segments, null, RouteLineResources.Builder().build(), From 10205d5548b5f0116be46e05b12cb60540f1e52d Mon Sep 17 00:00:00 2001 From: Seth Bourget Date: Fri, 14 Oct 2022 15:17:33 -0700 Subject: [PATCH 2/7] wip --- .../core/MapboxRouteLineAndArrowActivity.kt | 77 ++++++++--- .../layout_activity_routeline_example.xml | 7 + .../route/line/MapboxRouteLineUtils.kt | 4 +- .../maps/route/line/api/MapboxRouteLineApi.kt | 87 ++---------- .../maps/route/line/api/VanishingRouteLine.kt | 127 ++++++++++-------- 5 files changed, 153 insertions(+), 149 deletions(-) diff --git a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt index 713f01f1935..fe1f7fd2e0f 100644 --- a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt +++ b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt @@ -41,9 +41,11 @@ import com.mapbox.maps.plugin.locationcomponent.location import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions import com.mapbox.navigation.base.extensions.applyLanguageAndVoiceUnitOptions import com.mapbox.navigation.base.options.NavigationOptions +import com.mapbox.navigation.base.route.RouteRefreshOptions import com.mapbox.navigation.base.route.RouterCallback import com.mapbox.navigation.base.route.RouterFailure import com.mapbox.navigation.base.route.RouterOrigin +import com.mapbox.navigation.base.utils.DecodeUtils.stepGeometryToPoints import com.mapbox.navigation.core.MapboxNavigationProvider import com.mapbox.navigation.core.directions.session.RoutesObserver import com.mapbox.navigation.core.replay.MapboxReplayer @@ -271,6 +273,15 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe // } // } + routeProgress.currentLegProgress?.currentStepProgress?.step?.apply { + val points = routeProgress.route.stepGeometryToPoints(this) + addPointToPixelMapPoints(points) + } + + routeLineApi.deleteMeGetTreePoints().apply { + addTreePoints(this) + } + // RouteArrow: The next maneuver arrows are driven by route progress events. // Generate the next maneuver arrow update data and pass it to the view class // to visualize the updates on the map. @@ -342,17 +353,19 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe } private fun updateCamera(location: Location) { - val mapAnimationOptionsBuilder = MapAnimationOptions.Builder() - mapCamera.easeTo( - CameraOptions.Builder() - .center(Point.fromLngLat(location.longitude, location.latitude)) - .bearing(location.bearing.toDouble()) - .pitch(45.0) - .zoom(17.0) - .padding(EdgeInsets(1000.0, 0.0, 0.0, 0.0)) - .build(), - mapAnimationOptionsBuilder.build() - ) + if (cameraUpdatesAllowed) { + val mapAnimationOptionsBuilder = MapAnimationOptions.Builder() + mapCamera.easeTo( + CameraOptions.Builder() + .center(Point.fromLngLat(location.longitude, location.latitude)) + .bearing(location.bearing.toDouble()) + .pitch(45.0) + .zoom(17.0) + .padding(EdgeInsets(1000.0, 0.0, 0.0, 0.0)) + .build(), + mapAnimationOptionsBuilder.build() + ) + } } private fun getMapboxAccessTokenFromResources(): String { @@ -371,6 +384,7 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe viewBinding.mapView.gestures.addOnMapLongClickListener(this) initPointLayer(style) + initTreePointLayer(style) }, object : OnMapLoadErrorListener { override fun onMapLoadError(eventData: MapLoadingErrorEventData) { @@ -416,7 +430,8 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe private val routesReqCallback: RouterCallback = object : RouterCallback { override fun onRoutesReady(routes: List, routerOrigin: RouterOrigin) { - mapboxNavigation.setRoutes(routes) + mapboxNavigation.setRoutes(listOf(getRoute())) + //mapboxNavigation.setRoutes(routes) if (routes.isNotEmpty()) { viewBinding.routeLoadingProgressBar.visibility = View.INVISIBLE viewBinding.startNavigation.visibility = View.VISIBLE @@ -465,8 +480,13 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe startSimulation(route) } } + + viewBinding.btnTemp.setOnClickListener { + cameraUpdatesAllowed = !cameraUpdatesAllowed + } viewBinding.mapView.gestures.addOnMapClickListener(mapClickListener) } + var cameraUpdatesAllowed = true // Starts the navigation simulator private fun startSimulation(route: DirectionsRoute) { @@ -544,6 +564,22 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe } } + private val TREE_LINE_LAYER_ID = "TREE_LINE_LAYER_ID" + private val TREE_LINE_SOURCE_ID = "TREE_LINE_SOURCE_ID" + private fun initTreePointLayer(style: Style) { + if (!style.styleSourceExists(TREE_LINE_SOURCE_ID)) { + geoJsonSource(TREE_LINE_SOURCE_ID) {}.bindTo(style) + } + + if (!style.styleLayerExists(TREE_LINE_LAYER_ID)) { + CircleLayer(TREE_LINE_LAYER_ID, TREE_LINE_SOURCE_ID) + .circleRadius(2.0) + .circleOpacity(.75) + .circleColor(Color.MAGENTA) + .bindTo(style) + } + } + // todo remove this private fun addPointToPixelMapPoints(points: List) { val features = points.map { Feature.fromGeometry(it) } @@ -553,8 +589,17 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe } } - // fun getRoute(): DirectionsRoute { - // val routeJson = "{\"country_crossed\":false,\"weight_typical\":373.949,\"routeIndex\":\"0\",\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DAChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\oMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTIWzeA\",\"weight\":373.949,\"weight_name\":\"auto\",\"legs\":[{\"weight_typical\":373.949,\"weight\":373.949,\"via_waypoints\":[],\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"summary\":\"West Fourth Plain Boulevard, Kauffman Avenue\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"weight_typical\":111.941,\"distance\":634.918,\"duration\":86.844,\"duration_typical\":86.844,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DA\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.63447],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":634.918,\"announcement\":\"Drive north on Main Street for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eDrive north on \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eMain Street\\u003c/say-as\\u003e for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West Fourth Plain Boulevard.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest Fourth Plain Boulevard\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":42.667,\"announcement\":\"Turn left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":634.918,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":true,\"active_direction\":\"left\"},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"right\"],\"active\":false}]}}],\"driving_side\":\"right\",\"weight\":111.941,\"intersections\":[{\"duration\":7.315,\"weight\":8.778,\"location\":[-122.671531,45.63447],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.937,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.201,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":9.919,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":12.88,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":4.031,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.914,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.832,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.945,\"location\":[-122.671487,45.63679],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.844,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.186,\"location\":[-122.671483,45.637018],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.874,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.998,\"location\":[-122.671477,45.637323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.254,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.237,\"location\":[-122.671473,45.637532],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":2.918,\"turn_duration\":2.019,\"turn_weight\":0.5,\"duration\":3.993,\"location\":[-122.67147,45.63769],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":2.779,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.881,\"location\":[-122.671468,45.63784],\"bearings\":[1,181,267],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":12,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.619,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.41,\"location\":[-122.671464,45.638047],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":7.363,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":9.496,\"location\":[-122.671459,45.638323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":14,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":10.819,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":14.23,\"location\":[-122.67145,45.638782],\"bearings\":[1,75,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.75,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":4.346,\"location\":[-122.671438,45.63946],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671435,45.639654],\"bearings\":[1,90,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":18,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":104.434,\"distance\":744.28,\"duration\":79.063,\"duration_typical\":79.063,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"y}s`vAdsg~hFChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\\",\"name\":\"West Fourth Plain Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671427,45.640173],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West Fourth Plain Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":730.946,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":66.667,\"announcement\":\"Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":744.28,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\",\"right\"],\"active\":true,\"active_direction\":\"right\"}]}}],\"driving_side\":\"right\",\"weight\":104.434,\"intersections\":[{\"weight\":12.272,\"turn_duration\":7.622,\"turn_weight\":10,\"duration\":9.476,\"location\":[-122.671427,45.640173],\"bearings\":[15,90,181,271],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"right\"]}],\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":4.93,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":6.514,\"location\":[-122.671647,45.640175],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":22,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.821,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":3.93,\"location\":[-122.67223,45.64018],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":24,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.672503,45.640182],\"bearings\":[91,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":25,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.673074,45.640185],\"bearings\":[90,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":26,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":5.138,\"turn_duration\":2.021,\"turn_weight\":1.5,\"duration\":4.991,\"location\":[-122.673636,45.640188],\"bearings\":[91,179,271,359],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":28,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":6.75,\"turn_weight\":0.5,\"weight\":8.769,\"location\":[-122.674055,45.640192],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":30,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.784,\"turn_weight\":1,\"turn_duration\":0.021,\"weight\":5.61,\"location\":[-122.675017,45.640202],\"bearings\":[1,91,191,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":31,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":8.007,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":10.1,\"location\":[-122.675603,45.640202],\"bearings\":[0,90,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":32,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.455,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":9.221,\"location\":[-122.676886,45.640215],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":33,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.844,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":2.704,\"location\":[-122.677966,45.64022],\"bearings\":[90,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":34,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.246,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":7.97,\"location\":[-122.678293,45.640224],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":35,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.971,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.84,\"location\":[-122.679353,45.640231],\"bearings\":[91,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":36,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.301,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":4.436,\"location\":[-122.679682,45.640235],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":37,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":0.548,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":1.132,\"location\":[-122.680211,45.640242],\"bearings\":[91,180,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":38,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.046,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.93,\"location\":[-122.680286,45.640243],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":39,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":0.5,\"location\":[-122.680518,45.640246],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":40,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":131.023,\"distance\":877.516,\"duration\":91.718,\"duration_typical\":91.718,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"wbt`vAxhz~hFoMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTI\",\"name\":\"Kauffman Avenue\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680989,45.640252],\"bearing_before\":271.0,\"bearing_after\":1.0,\"instruction\":\"Turn right onto Kauffman Avenue.\",\"type\":\"turn\",\"modifier\":\"right\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":864.182,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West 36th Street.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":91.111,\"announcement\":\"Turn left onto West 36th Street. Then Your destination will be on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e. Then Your destination will be on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":877.516,\"primary\":{\"text\":\"West 36th Street\",\"components\":[{\"text\":\"West 36th Street\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":131.023,\"intersections\":[{\"weight\":19.48,\"turn_duration\":4.005,\"turn_weight\":7,\"duration\":14.405,\"location\":[-122.680989,45.640252],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"right\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":41,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":5.119,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.87,\"location\":[-122.680982,45.640484],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":42,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.276,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.059,\"location\":[-122.680974,45.64079],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":43,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":7.069,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":9.21,\"location\":[-122.680973,45.640821],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":44,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.467,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":4.886,\"location\":[-122.680949,45.641665],\"bearings\":[0,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":45,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.059,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.798,\"location\":[-122.680943,45.642072],\"bearings\":[1,89,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":47,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.752,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":5.98,\"location\":[-122.680937,45.642508],\"bearings\":[1,92,181,267],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":48,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.019,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.35,\"location\":[-122.680933,45.64276],\"bearings\":[1,181,270],\"entry\":[true,false,false],\"in\":1,\"out\":0,\"geometry_index\":49,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":6.869,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":8.969,\"location\":[-122.680929,45.643071],\"bearings\":[0,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":50,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.294,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.88,\"location\":[-122.68092,45.643769],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":52,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.619,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":2.67,\"location\":[-122.680909,45.644285],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":53,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.866,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.166,\"location\":[-122.680905,45.644465],\"bearings\":[1,181,276],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":54,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.795,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":6.031,\"location\":[-122.680898,45.64477],\"bearings\":[1,90,181,269],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":56,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.804,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.197,\"location\":[-122.680892,45.645153],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":57,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.204,\"turn_weight\":2,\"turn_duration\":0.021,\"weight\":6.916,\"location\":[-122.680885,45.645518],\"bearings\":[0,90,181,265],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":58,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.71,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":1.575,\"location\":[-122.680881,45.645902],\"bearings\":[1,90,180],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":59,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.062,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":3.151,\"location\":[-122.68088,45.645973],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":60,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.149,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.778,\"location\":[-122.680877,45.646162],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":62,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.533,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.354,\"location\":[-122.680868,45.646675],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":63,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.118,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":5.14,\"location\":[-122.680867,45.646729],\"bearings\":[0,92,181,284],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":64,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.579,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":3.771,\"location\":[-122.680864,45.647059],\"bearings\":[1,180,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":65,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.819,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.39,\"location\":[-122.680858,45.647327],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":66,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"turn_duration\":0.019,\"location\":[-122.680842,45.647797],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":68,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"weight_typical\":26.551,\"distance\":88.242,\"duration\":17.84,\"duration_typical\":17.84,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kocavAh_z~hFWzeA\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680837,45.648134],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West 36th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":44.444,\"announcement\":\"Your destination is on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eYour destination is on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":88.242,\"primary\":{\"text\":\"Your destination will be on the left\",\"components\":[{\"text\":\"Your destination will be on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":44.444,\"primary\":{\"text\":\"Your destination is on the left\",\"components\":[{\"text\":\"Your destination is on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":26.551,\"intersections\":[{\"turn_weight\":12.5,\"turn_duration\":5.622,\"location\":[-122.680837,45.648134],\"bearings\":[0,181,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":69,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"weight_typical\":0,\"distance\":0.0,\"duration\":0.0,\"duration_typical\":0.0,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"cpcavAdf|~hF??\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.681971,45.648146],\"bearing_before\":271.0,\"bearing_after\":0.0,\"instruction\":\"Your destination is on the left.\",\"type\":\"arrive\",\"modifier\":\"left\"},\"voiceInstructions\":[],\"bannerInstructions\":[],\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.681971,45.648146],\"bearings\":[91],\"entry\":[true],\"in\":0,\"geometry_index\":70,\"admin_index\":0}]}],\"annotation\":{\"distance\":[45.0,48.6,37.3,88.4,39.0,25.4,33.9,23.3,9.7,7.9,7.8,8.9,23.0,30.8,51.1,10.8,64.6,21.6,48.9,8.9,9.1,8.0,39.0,6.4,21.3,44.4,35.2,8.6,7.7,24.9,74.9,45.6,99.8,84.1,25.4,82.5,25.7,41.1,5.9,18.0,36.7,25.8,34.1,3.5,93.9,9.9,35.4,48.6,28.0,34.6,18.5,59.3,57.4,20.0,20.9,13.1,42.6,40.7,42.7,7.9,10.6,10.5,57.1,6.0,36.7,29.9,24.6,27.7,37.5,88.3],\"duration\":[7.315,8.552,3.937,9.919,4.031,2.832,3.844,2.874,1.249,1.004,2.94,1.053,2.779,3.619,7.363,1.564,9.255,2.75,8.429,1.533,8.608,0.868,4.239,0.69,2.821,5.867,4.718,1.148,2.73,2.261,6.75,3.784,8.007,6.455,1.844,6.246,1.971,3.301,0.547,2.046,4.163,14.405,5.119,0.276,7.069,0.774,2.693,5.059,3.752,3.019,1.649,5.22,4.294,1.619,1.764,1.101,3.795,3.804,4.204,0.71,1.046,1.016,5.149,0.533,3.118,2.579,2.276,2.543,3.128,17.84],\"speed\":[6.1,7.4,9.5,8.9,9.7,9.0,8.9,8.1,7.9,7.9,8.5,8.5,8.3,8.5,7.0,7.0,7.0,7.9,5.8,5.8,9.2,9.2,9.2,9.2,7.6,7.6,7.5,7.5,11.0,11.0,11.1,12.1,12.5,13.1,13.9,13.3,13.1,12.6,11.1,8.9,8.8,2.5,6.7,13.4,13.3,13.1,13.1,9.6,7.5,11.5,11.3,11.3,13.4,12.5,11.9,11.9,11.3,10.7,10.2,11.3,10.3,10.3,11.1,11.7,11.9,11.6,10.9,10.9,12.1,7.2],\"maxspeed\":[{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"}],\"congestion_numeric\":[0,24,9,9,0,0,0,null,null,null,0,0,0,null,6,9,9,14,null,null,9,9,9,9,30,30,30,30,12,12,12,4,3,1,0,0,null,3,null,0,0,null,null,null,0,null,null,null,null,null,null,null,null,null,null,null,0,null,null,null,0,0,null,null,null,null,null,null,0,null]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6716938,45.6344717;-122.681974,45.6479927\",\"alternatives\":true,\"language\":\"en\",\"layers\":\";\",\"continue_straight\":true,\"roundabout_exits\":true,\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,maxspeed,closure,speed,duration,distance\",\"voice_instructions\":true,\"banner_instructions\":true,\"voice_units\":\"imperial\",\"enable_refresh\":true},\"voiceLocale\":\"en-US\",\"requestUuid\":\"VA6i2dqAyEvoC4gS25Y14Z6gAE6c2fe_Tpq4H9voaY7FjLb-IUIcYQ\\u003d\\u003d\"}" - // return DirectionsRoute.fromJson(routeJson) - // } + private fun addTreePoints(points: List) { + val features = points.map { Feature.fromGeometry(it) } + + (mapboxMap.getStyle()!!.getSource(TREE_LINE_SOURCE_ID) as GeoJsonSource).apply { + this.featureCollection(FeatureCollection.fromFeatures(features)) + } + } + + fun getRoute(): DirectionsRoute { + val routeJson = "{\"routeIndex\":\"0\",\"distance\":728.195,\"duration\":178.495,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@YEnd@I|_@|]HrTJxf@B~FgAPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"weight\":241.413,\"weight_name\":\"auto\",\"legs\":[{\"weight\":241.413,\"via_waypoints\":[],\"distance\":728.195,\"duration\":178.495,\"summary\":\"Main Street, West McLoughlin Boulevard\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"distance\":220.325,\"duration\":29.108,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@Y\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.634461],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"driving_side\":\"right\",\"weight\":35.461,\"intersections\":[{\"duration\":7.5,\"weight\":9,\"location\":[-122.671531,45.634461],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.719,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.94,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"distance\":87.726,\"duration\":31.082,\"geometry\":\"otl`vAlwg~hFEnd@I|_@\",\"name\":\"West 20th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671495,45.63644],\"bearing_before\":1.0,\"bearing_after\":270.0,\"instruction\":\"Turn left onto West 20th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":45.681,\"intersections\":[{\"duration\":19.722,\"turn_weight\":12.5,\"turn_duration\":5.622,\"weight\":29.773,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.007,\"location\":[-122.672095,45.636443],\"bearings\":[1,90,182,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":179.057,\"duration\":68.349,\"geometry\":\"_ul`vAz}i~hF|]HrTJxf@B~FgA\",\"name\":\"Washington Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672622,45.636448],\"bearing_before\":271.0,\"bearing_after\":180.0,\"instruction\":\"Turn left onto Washington Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":88.24,\"intersections\":[{\"duration\":30.372,\"turn_weight\":10,\"turn_duration\":5.622,\"weight\":39.7,\"location\":[-122.672622,45.636448],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":2,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"duration\":17.558,\"turn_weight\":1,\"turn_duration\":0.008,\"weight\":22.06,\"location\":[-122.672627,45.635953],\"bearings\":[0,92,181],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.019,\"location\":[-122.672633,45.635607],\"bearings\":[1,92,180,270],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":241.086,\"duration\":49.955,\"geometry\":\"spi`vAl|i~hFPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672599,45.634842],\"bearing_before\":169.0,\"bearing_after\":91.0,\"instruction\":\"Turn left onto West McLoughlin Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":72.031,\"intersections\":[{\"duration\":22.522,\"turn_weight\":12.5,\"turn_duration\":3.622,\"weight\":35.18,\"location\":[-122.672599,45.634842],\"bearings\":[91,182,270,349],\"entry\":[true,true,true,false],\"in\":3,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":14.931,\"turn_duration\":2.008,\"turn_weight\":3,\"duration\":11.951,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,182,259],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":1.371,\"turn_weight\":0.75,\"weight\":2.396,\"location\":[-122.670778,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.086,\"turn_weight\":0.75,\"weight\":4.453,\"location\":[-122.670671,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":16,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":6.469,\"turn_duration\":2.008,\"turn_weight\":2,\"duration\":5.732,\"location\":[-122.670443,45.634898],\"bearings\":[1,91,182,270],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":0.248,\"turn_weight\":0.75,\"weight\":1.048,\"location\":[-122.670058,45.634895],\"bearings\":[90,271],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":19,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.49,\"turn_weight\":0.75,\"weight\":2.538,\"location\":[-122.670028,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"location\":[-122.66988,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":21,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"distance\":0.0,\"duration\":0.0,\"geometry\":\"ysi`vAn{c~hF??\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.669512,45.634893],\"bearing_before\":90.0,\"bearing_after\":0.0,\"instruction\":\"You have arrived at your destination.\",\"type\":\"arrive\"},\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.669512,45.634893],\"bearings\":[270],\"entry\":[true],\"in\":0,\"geometry_index\":22,\"admin_index\":0}]}],\"annotation\":{\"distance\":[46.0,48.6,37.3,88.4,46.7,41.1,55.1,38.5,70.9,14.5,54.2,15.6,14.5,13.4,44.8,8.4,17.7,0.7,29.3,2.3,11.5,28.7],\"congestion_numeric\":[0,null,4,4,null,null,null,null,null,null,0,0,0,4,4,4,4,1,1,1,1,1]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6715815,45.6344615;-122.6716338,45.6364896;-122.6726954,45.6364085;-122.672707,45.6348712;-122.6695105,45.6350132\",\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,distance\",\"voice_instructions\":false,\"banner_instructions\":false,\"waypoints\":\"0;4\"},\"requestUuid\":\"mapmatching\"}" + //val routeJson = "{\"country_crossed\":false,\"weight_typical\":373.949,\"routeIndex\":\"0\",\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DAChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\oMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTIWzeA\",\"weight\":373.949,\"weight_name\":\"auto\",\"legs\":[{\"weight_typical\":373.949,\"weight\":373.949,\"via_waypoints\":[],\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"summary\":\"West Fourth Plain Boulevard, Kauffman Avenue\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"weight_typical\":111.941,\"distance\":634.918,\"duration\":86.844,\"duration_typical\":86.844,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DA\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.63447],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":634.918,\"announcement\":\"Drive north on Main Street for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eDrive north on \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eMain Street\\u003c/say-as\\u003e for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West Fourth Plain Boulevard.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest Fourth Plain Boulevard\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":42.667,\"announcement\":\"Turn left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":634.918,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":true,\"active_direction\":\"left\"},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"right\"],\"active\":false}]}}],\"driving_side\":\"right\",\"weight\":111.941,\"intersections\":[{\"duration\":7.315,\"weight\":8.778,\"location\":[-122.671531,45.63447],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.937,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.201,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":9.919,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":12.88,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":4.031,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.914,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.832,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.945,\"location\":[-122.671487,45.63679],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.844,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.186,\"location\":[-122.671483,45.637018],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.874,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.998,\"location\":[-122.671477,45.637323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.254,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.237,\"location\":[-122.671473,45.637532],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":2.918,\"turn_duration\":2.019,\"turn_weight\":0.5,\"duration\":3.993,\"location\":[-122.67147,45.63769],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":2.779,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.881,\"location\":[-122.671468,45.63784],\"bearings\":[1,181,267],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":12,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.619,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.41,\"location\":[-122.671464,45.638047],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":7.363,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":9.496,\"location\":[-122.671459,45.638323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":14,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":10.819,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":14.23,\"location\":[-122.67145,45.638782],\"bearings\":[1,75,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.75,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":4.346,\"location\":[-122.671438,45.63946],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671435,45.639654],\"bearings\":[1,90,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":18,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":104.434,\"distance\":744.28,\"duration\":79.063,\"duration_typical\":79.063,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"y}s`vAdsg~hFChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\\",\"name\":\"West Fourth Plain Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671427,45.640173],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West Fourth Plain Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":730.946,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":66.667,\"announcement\":\"Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":744.28,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\",\"right\"],\"active\":true,\"active_direction\":\"right\"}]}}],\"driving_side\":\"right\",\"weight\":104.434,\"intersections\":[{\"weight\":12.272,\"turn_duration\":7.622,\"turn_weight\":10,\"duration\":9.476,\"location\":[-122.671427,45.640173],\"bearings\":[15,90,181,271],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"right\"]}],\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":4.93,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":6.514,\"location\":[-122.671647,45.640175],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":22,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.821,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":3.93,\"location\":[-122.67223,45.64018],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":24,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.672503,45.640182],\"bearings\":[91,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":25,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.673074,45.640185],\"bearings\":[90,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":26,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":5.138,\"turn_duration\":2.021,\"turn_weight\":1.5,\"duration\":4.991,\"location\":[-122.673636,45.640188],\"bearings\":[91,179,271,359],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":28,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":6.75,\"turn_weight\":0.5,\"weight\":8.769,\"location\":[-122.674055,45.640192],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":30,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.784,\"turn_weight\":1,\"turn_duration\":0.021,\"weight\":5.61,\"location\":[-122.675017,45.640202],\"bearings\":[1,91,191,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":31,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":8.007,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":10.1,\"location\":[-122.675603,45.640202],\"bearings\":[0,90,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":32,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.455,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":9.221,\"location\":[-122.676886,45.640215],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":33,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.844,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":2.704,\"location\":[-122.677966,45.64022],\"bearings\":[90,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":34,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.246,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":7.97,\"location\":[-122.678293,45.640224],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":35,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.971,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.84,\"location\":[-122.679353,45.640231],\"bearings\":[91,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":36,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.301,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":4.436,\"location\":[-122.679682,45.640235],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":37,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":0.548,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":1.132,\"location\":[-122.680211,45.640242],\"bearings\":[91,180,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":38,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.046,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.93,\"location\":[-122.680286,45.640243],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":39,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":0.5,\"location\":[-122.680518,45.640246],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":40,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":131.023,\"distance\":877.516,\"duration\":91.718,\"duration_typical\":91.718,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"wbt`vAxhz~hFoMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTI\",\"name\":\"Kauffman Avenue\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680989,45.640252],\"bearing_before\":271.0,\"bearing_after\":1.0,\"instruction\":\"Turn right onto Kauffman Avenue.\",\"type\":\"turn\",\"modifier\":\"right\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":864.182,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West 36th Street.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":91.111,\"announcement\":\"Turn left onto West 36th Street. Then Your destination will be on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e. Then Your destination will be on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":877.516,\"primary\":{\"text\":\"West 36th Street\",\"components\":[{\"text\":\"West 36th Street\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":131.023,\"intersections\":[{\"weight\":19.48,\"turn_duration\":4.005,\"turn_weight\":7,\"duration\":14.405,\"location\":[-122.680989,45.640252],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"right\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":41,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":5.119,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.87,\"location\":[-122.680982,45.640484],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":42,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.276,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.059,\"location\":[-122.680974,45.64079],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":43,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":7.069,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":9.21,\"location\":[-122.680973,45.640821],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":44,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.467,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":4.886,\"location\":[-122.680949,45.641665],\"bearings\":[0,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":45,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.059,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.798,\"location\":[-122.680943,45.642072],\"bearings\":[1,89,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":47,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.752,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":5.98,\"location\":[-122.680937,45.642508],\"bearings\":[1,92,181,267],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":48,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.019,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.35,\"location\":[-122.680933,45.64276],\"bearings\":[1,181,270],\"entry\":[true,false,false],\"in\":1,\"out\":0,\"geometry_index\":49,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":6.869,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":8.969,\"location\":[-122.680929,45.643071],\"bearings\":[0,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":50,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.294,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.88,\"location\":[-122.68092,45.643769],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":52,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.619,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":2.67,\"location\":[-122.680909,45.644285],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":53,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.866,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.166,\"location\":[-122.680905,45.644465],\"bearings\":[1,181,276],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":54,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.795,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":6.031,\"location\":[-122.680898,45.64477],\"bearings\":[1,90,181,269],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":56,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.804,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.197,\"location\":[-122.680892,45.645153],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":57,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.204,\"turn_weight\":2,\"turn_duration\":0.021,\"weight\":6.916,\"location\":[-122.680885,45.645518],\"bearings\":[0,90,181,265],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":58,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.71,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":1.575,\"location\":[-122.680881,45.645902],\"bearings\":[1,90,180],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":59,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.062,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":3.151,\"location\":[-122.68088,45.645973],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":60,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.149,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.778,\"location\":[-122.680877,45.646162],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":62,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.533,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.354,\"location\":[-122.680868,45.646675],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":63,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.118,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":5.14,\"location\":[-122.680867,45.646729],\"bearings\":[0,92,181,284],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":64,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.579,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":3.771,\"location\":[-122.680864,45.647059],\"bearings\":[1,180,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":65,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.819,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.39,\"location\":[-122.680858,45.647327],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":66,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"turn_duration\":0.019,\"location\":[-122.680842,45.647797],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":68,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"weight_typical\":26.551,\"distance\":88.242,\"duration\":17.84,\"duration_typical\":17.84,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kocavAh_z~hFWzeA\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680837,45.648134],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West 36th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":44.444,\"announcement\":\"Your destination is on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eYour destination is on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":88.242,\"primary\":{\"text\":\"Your destination will be on the left\",\"components\":[{\"text\":\"Your destination will be on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":44.444,\"primary\":{\"text\":\"Your destination is on the left\",\"components\":[{\"text\":\"Your destination is on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":26.551,\"intersections\":[{\"turn_weight\":12.5,\"turn_duration\":5.622,\"location\":[-122.680837,45.648134],\"bearings\":[0,181,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":69,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"weight_typical\":0,\"distance\":0.0,\"duration\":0.0,\"duration_typical\":0.0,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"cpcavAdf|~hF??\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.681971,45.648146],\"bearing_before\":271.0,\"bearing_after\":0.0,\"instruction\":\"Your destination is on the left.\",\"type\":\"arrive\",\"modifier\":\"left\"},\"voiceInstructions\":[],\"bannerInstructions\":[],\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.681971,45.648146],\"bearings\":[91],\"entry\":[true],\"in\":0,\"geometry_index\":70,\"admin_index\":0}]}],\"annotation\":{\"distance\":[45.0,48.6,37.3,88.4,39.0,25.4,33.9,23.3,9.7,7.9,7.8,8.9,23.0,30.8,51.1,10.8,64.6,21.6,48.9,8.9,9.1,8.0,39.0,6.4,21.3,44.4,35.2,8.6,7.7,24.9,74.9,45.6,99.8,84.1,25.4,82.5,25.7,41.1,5.9,18.0,36.7,25.8,34.1,3.5,93.9,9.9,35.4,48.6,28.0,34.6,18.5,59.3,57.4,20.0,20.9,13.1,42.6,40.7,42.7,7.9,10.6,10.5,57.1,6.0,36.7,29.9,24.6,27.7,37.5,88.3],\"duration\":[7.315,8.552,3.937,9.919,4.031,2.832,3.844,2.874,1.249,1.004,2.94,1.053,2.779,3.619,7.363,1.564,9.255,2.75,8.429,1.533,8.608,0.868,4.239,0.69,2.821,5.867,4.718,1.148,2.73,2.261,6.75,3.784,8.007,6.455,1.844,6.246,1.971,3.301,0.547,2.046,4.163,14.405,5.119,0.276,7.069,0.774,2.693,5.059,3.752,3.019,1.649,5.22,4.294,1.619,1.764,1.101,3.795,3.804,4.204,0.71,1.046,1.016,5.149,0.533,3.118,2.579,2.276,2.543,3.128,17.84],\"speed\":[6.1,7.4,9.5,8.9,9.7,9.0,8.9,8.1,7.9,7.9,8.5,8.5,8.3,8.5,7.0,7.0,7.0,7.9,5.8,5.8,9.2,9.2,9.2,9.2,7.6,7.6,7.5,7.5,11.0,11.0,11.1,12.1,12.5,13.1,13.9,13.3,13.1,12.6,11.1,8.9,8.8,2.5,6.7,13.4,13.3,13.1,13.1,9.6,7.5,11.5,11.3,11.3,13.4,12.5,11.9,11.9,11.3,10.7,10.2,11.3,10.3,10.3,11.1,11.7,11.9,11.6,10.9,10.9,12.1,7.2],\"maxspeed\":[{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"}],\"congestion_numeric\":[0,24,9,9,0,0,0,null,null,null,0,0,0,null,6,9,9,14,null,null,9,9,9,9,30,30,30,30,12,12,12,4,3,1,0,0,null,3,null,0,0,null,null,null,0,null,null,null,null,null,null,null,null,null,null,null,0,null,null,null,0,0,null,null,null,null,null,null,0,null]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6716938,45.6344717;-122.681974,45.6479927\",\"alternatives\":true,\"language\":\"en\",\"layers\":\";\",\"continue_straight\":true,\"roundabout_exits\":true,\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,maxspeed,closure,speed,duration,distance\",\"voice_instructions\":true,\"banner_instructions\":true,\"voice_units\":\"imperial\",\"enable_refresh\":true},\"voiceLocale\":\"en-US\",\"requestUuid\":\"VA6i2dqAyEvoC4gS25Y14Z6gAE6c2fe_Tpq4H9voaY7FjLb-IUIcYQ\\u003d\\u003d\"}" + return DirectionsRoute.fromJson(routeJson) + } } diff --git a/examples/src/main/res/layout/layout_activity_routeline_example.xml b/examples/src/main/res/layout/layout_activity_routeline_example.xml index 99d198708e7..79b2e3ffd95 100644 --- a/examples/src/main/res/layout/layout_activity_routeline_example.xml +++ b/examples/src/main/res/layout/layout_activity_routeline_example.xml @@ -64,4 +64,11 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:visibility="invisible"/> + + \ No newline at end of file diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt index 723876eb560..02cb263acc1 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt @@ -488,7 +488,7 @@ object MapboxRouteLineUtils { * @return a list of items representing the distance offset of each route leg and the color * used to represent the traffic congestion. */ - fun calculateRouteLineSegments( + internal fun calculateRouteLineSegments( route: NavigationRoute, trafficBackfillRoadClasses: List, isPrimaryRoute: Boolean, @@ -969,7 +969,7 @@ object MapboxRouteLineUtils { //todo the variable names below should be named better fun getFillerPoints(startPoint: RouteLineDistancesIndex, endPoint: RouteLineDistancesIndex): List { - val gapDist = 1.0 // meters + val gapDist = 2.0 // meters val turfDistance = TurfMeasurement.distance(startPoint.point, endPoint.point, TurfConstants.UNIT_METERS) val fillerPoints = mutableListOf() val bearing = TurfMeasurement.bearing(startPoint.point, endPoint.point) diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt index 571db812850..05830bfd99b 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt @@ -226,6 +226,7 @@ class MapboxRouteLineApi( trafficBackfillRoadClasses.addAll( routeLineOptions.resourceProvider.trafficBackfillRoadClasses ) + routeLineOptions.vanishingRouteLine?.setScope(jobControl.scope) } /** @@ -545,7 +546,7 @@ class MapboxRouteLineApi( ) { jobControl.scope.launch(Dispatchers.Main) { mutex.withLock { - routeLineOptions.vanishingRouteLine?.vanishPointOffset = 0.0 + //routeLineOptions.vanishingRouteLine?.vanishPointOffset = 0.0 //todo remove this? activeLegIndex = INVALID_ACTIVE_LEG_INDEX routes.clear() routeFeatureData.clear() @@ -581,7 +582,7 @@ class MapboxRouteLineApi( fun setVanishingOffset( offset: Double ): Expected { - routeLineOptions.vanishingRouteLine?.vanishPointOffset = offset + //routeLineOptions.vanishingRouteLine?.vanishPointOffset = offset return if (offset >= 0) { val workingExpressionData = if (routeLineOptions.styleInactiveRouteLegsIndependently) { alternativelyStyleSegmentsNotInLeg(activeLegIndex, routeLineExpressionData) @@ -1074,72 +1075,6 @@ class MapboxRouteLineApi( } } - //todo remove this - internal fun updateUpcomingRoutePointIndex(routeProgress: RouteProgress) { - ifNonNull( - routeProgress.currentLegProgress, - routeProgress.currentLegProgress?.currentStepProgress, - routePointsProvider(routeProgress.navigationRoute) - ) { currentLegProgress, currentStepProgress, completeRoutePoints -> - var allRemainingPoints = 0 - - /** - * Finds the count of remaining points in the current step. - * - * TurfMisc.lineSliceAlong places an additional point at index 0 to mark the precise - * cut-off point which we can safely ignore. - * We'll add the distance from the upcoming point to the current's puck position later. - */ - allRemainingPoints += try { - TurfMisc.lineSliceAlong( - LineString.fromLngLats(currentStepProgress.stepPoints ?: emptyList()), - currentStepProgress.distanceTraveled.toDouble(), - currentStepProgress.step?.distance() ?: 0.0, - TurfConstants.UNIT_METERS - ).coordinates().drop(1).size - } catch (e: TurfException) { - 0 - } - - /** - * Add to the count of remaining points all of the remaining points on the current leg, - * after the current step. - */ - if (currentLegProgress.legIndex < completeRoutePoints.stepPoints.size) { - val currentLegSteps = completeRoutePoints.stepPoints[currentLegProgress.legIndex] - allRemainingPoints += if (currentStepProgress.stepIndex < currentLegSteps.size) { - currentLegSteps.slice( - currentStepProgress.stepIndex + 1 until currentLegSteps.size - 1 - ).flatten().size - } else { - 0 - } - } - - /** - * Add to the count of remaining points all of the remaining legs. - */ - for (i in currentLegProgress.legIndex + 1 until completeRoutePoints.stepPoints.size) { - allRemainingPoints += completeRoutePoints.stepPoints[i].flatten().size - } - - /** - * When we know the number of remaining points and the number of all points, - * calculate the index of the upcoming point. - */ - val allPoints = completeRoutePoints.flatList.size - routeLineOptions.vanishingRouteLine?.primaryRouteRemainingDistancesIndex = - allPoints - allRemainingPoints - 1 - } ?: run { routeLineOptions.vanishingRouteLine?.primaryRouteRemainingDistancesIndex = null } - - lastIndexUpdateTimeNano = System.nanoTime() - } - - // todo remove this - internal fun updateVanishingPointState(routeProgressState: RouteProgressState) { - routeLineOptions.vanishingRouteLine?.updateVanishingPointState(routeProgressState) - } - private suspend fun setNewRouteData( newRoutes: List, featureDataProvider: () -> List, @@ -1157,11 +1092,11 @@ class MapboxRouteLineApi( distinctNewRoutes.find { it.id == metadata.navigationRoute.id } != null } - ifNonNull(distinctNewRoutes.firstOrNull()) { primaryRouteCandidate -> - if (!primaryRouteCandidate.directionsRoute.isSameRoute(primaryRoute?.directionsRoute)) { - routeLineOptions.vanishingRouteLine?.vanishPointOffset = 0.0 - } - } + // ifNonNull(distinctNewRoutes.firstOrNull()) { primaryRouteCandidate -> + // if (!primaryRouteCandidate.directionsRoute.isSameRoute(primaryRoute?.directionsRoute)) { + // routeLineOptions.vanishingRouteLine?.vanishPointOffset = 0.0 + // } + // } routes.clear() routes.addAll(distinctNewRoutes) @@ -1189,7 +1124,7 @@ class MapboxRouteLineApi( if (routes.isEmpty()) return withContext(jobControl.scope.coroutineContext) { if (vanishingRouteLineEnabled) { - granularDistancesProvider(routes.first())?.let { + granularDistancesProvider(routes.first())?.also { routeLineOptions.vanishingRouteLine?.setGranularDistances(it) } } @@ -1595,4 +1530,8 @@ class MapboxRouteLineApi( jobControl.scope ) }.cacheResult(alternativelyStyleSegmentsNotInLegCache) + + fun deleteMeGetTreePoints(): List { + return routeLineOptions.vanishingRouteLine!!.deleteMeGetTreePoints() + } } diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt index c46f6665864..cf3a9c344b5 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt @@ -1,24 +1,25 @@ package com.mapbox.navigation.ui.maps.route.line.api import android.graphics.Color +import android.util.Log import com.mapbox.geojson.Point import com.mapbox.maps.extension.style.expressions.dsl.generated.literal -import com.mapbox.navigation.base.trip.model.RouteProgressState import com.mapbox.navigation.ui.maps.internal.route.line.LocationSearchTree import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils -import com.mapbox.navigation.ui.maps.route.RouteLayerConstants +import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.ROUTE_LINE_UPDATE_MAX_DISTANCE_THRESHOLD_IN_METERS import com.mapbox.navigation.ui.maps.route.line.model.ExtractedRouteRestrictionData import com.mapbox.navigation.ui.maps.route.line.model.RouteLineDistancesIndex import com.mapbox.navigation.ui.maps.route.line.model.RouteLineExpressionData import com.mapbox.navigation.ui.maps.route.line.model.RouteLineGranularDistances import com.mapbox.navigation.ui.maps.route.line.model.RouteLineResources import com.mapbox.navigation.ui.maps.route.line.model.RouteLineTrimExpressionProvider -import com.mapbox.navigation.ui.maps.route.line.model.VanishingPointState import com.mapbox.navigation.ui.maps.route.line.model.VanishingRouteLineExpressions import com.mapbox.navigation.ui.utils.internal.ifNonNull -import com.mapbox.navigation.utils.internal.logD import com.mapbox.turf.TurfConstants import com.mapbox.turf.TurfMeasurement +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch /** * This class implements a feature that can change the appearance of the route line behind the puck. @@ -32,35 +33,16 @@ import com.mapbox.turf.TurfMeasurement */ internal class VanishingRouteLine { - /** - * the distance index used for calculating the point at which the primary route line - * should change its appearance - */ - var primaryRouteRemainingDistancesIndex: Int? = null - /** * a value representing the percentage distance traveled */ var vanishPointOffset: Double = 0.0 - - /** - * the vanishing point state which influences the behavior of the vanishing point - * calculation - */ - var vanishingPointState = VanishingPointState.DISABLED private set - /** - * Updates this instance with a route progress state from a route progress. - * - * @param routeProgressState a state from a route progress - */ - fun updateVanishingPointState(routeProgressState: RouteProgressState) { - vanishingPointState = when (routeProgressState) { - RouteProgressState.TRACKING -> VanishingPointState.ENABLED - RouteProgressState.COMPLETE -> VanishingPointState.ONLY_INCREASE_PROGRESS - else -> VanishingPointState.DISABLED - } + private var scope: CoroutineScope? = null + + fun setScope(scope: CoroutineScope) { + this.scope = scope } fun getTraveledRouteLineExpressions( @@ -72,7 +54,7 @@ internal class VanishingRouteLine { } fun getTraveledRouteLineExpressions(offset: Double): VanishingRouteLineExpressions { - vanishPointOffset = offset + this.vanishPointOffset = offset val trimmedOffsetExpression = literal(listOf(0.0, offset)) val trafficLineExpressionProvider = RouteLineTrimExpressionProvider { trimmedOffsetExpression @@ -176,53 +158,84 @@ internal class VanishingRouteLine { private var granularDistances: RouteLineGranularDistances? = null private val locationSearchTree = LocationSearchTree() private var stepsPoints: List> = emptyList() - private val stepPointsInTree = mutableListOf>() + private val fillerPointsInTree = mutableListOf>() private var indexOfLastStepPointsLoadedInTree = 0 + private val distanceToLastStepPointInMeters = 20.0 fun setGranularDistances(distances: RouteLineGranularDistances) { - granularDistances = distances - stepsPoints = granularDistances!!.stepsDistances.flatten() // todo test for multileg routes - locationSearchTree.clear() - stepPointsInTree.clear() - indexOfLastStepPointsLoadedInTree = 0 - - if (stepsPoints.isNotEmpty()) { - val firstSteps = stepsPoints.first() - val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(firstSteps) - locationSearchTree.addAll(fillerPoints) - stepPointsInTree.add(firstSteps) + if (distances != granularDistances) { + granularDistances = distances + stepsPoints = + granularDistances!!.stepsDistances.flatten() // todo test for multileg routes + locationSearchTree.clear() + fillerPointsInTree.clear() + indexOfLastStepPointsLoadedInTree = 0 + vanishPointOffset = 0.0 + Log.e("foobar", "everything got cleared, starting fresh") + + if (stepsPoints.isNotEmpty()) { + val firstSteps = stepsPoints.first() + val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(firstSteps) + locationSearchTree.addAll(fillerPoints) + fillerPointsInTree.add(fillerPoints) + } } } fun getOffset(point: Point): Double? { - val offset = ifNonNull(locationSearchTree.getNearestNeighbor(point), granularDistances) { closestPoint, distances -> - //todo check max distance threshold - (1.0 - closestPoint.distanceRemaining / distances.completeDistance) + val offset = ifNonNull(locationSearchTree.getNearestNeighbor(point), granularDistances) + { closestPoint, distances -> + val distanceBetweenPoints = TurfMeasurement.distance(point, closestPoint.point) + if (distanceBetweenPoints <= ROUTE_LINE_UPDATE_MAX_DISTANCE_THRESHOLD_IN_METERS ) { + (1.0 - closestPoint.distanceRemaining / distances.completeDistance) + } else { + Log.e("foobar", "distance of $distanceBetweenPoints beyond distance threshold") + Log.e("foobar", "incoming point $point nearest neighbor ${closestPoint.point}") + null + } } trimTree(point) return offset } - // todo put this on background thread private fun trimTree(point: Point) { //if getting close to the last step point, load the points for the next step //and remove the points long since passed. - if (stepPointsInTree.isNotEmpty()) { - val nearEndStepPoint = stepPointsInTree.last()[stepPointsInTree.last().lastIndex] - val distanceToNearEndStepPoint = TurfMeasurement.distance(point, nearEndStepPoint.point, TurfConstants.UNIT_METERS) - if (distanceToNearEndStepPoint <= 10.0) { - if (indexOfLastStepPointsLoadedInTree < stepsPoints.size) { - val nextSteps = stepsPoints[indexOfLastStepPointsLoadedInTree + 1] - val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(nextSteps) - locationSearchTree.addAll(fillerPoints) - stepPointsInTree.add(nextSteps) - indexOfLastStepPointsLoadedInTree++ - if (stepPointsInTree.size == 3) { - val pointsToDrop = stepPointsInTree.removeAt(0) - locationSearchTree.removeAll(pointsToDrop.toList()) + scope?.launch(Dispatchers.Main) { + if (fillerPointsInTree.isNotEmpty()) { + val nearEndStepPoint = fillerPointsInTree.last()[fillerPointsInTree.last().lastIndex] + val distanceToNearEndStepPoint = + TurfMeasurement.distance(point, nearEndStepPoint.point, TurfConstants.UNIT_METERS) + if (distanceToNearEndStepPoint <= distanceToLastStepPointInMeters) { + if (indexOfLastStepPointsLoadedInTree + 1 < stepsPoints.size) { + val nextSteps = stepsPoints[indexOfLastStepPointsLoadedInTree + 1] + val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(nextSteps) + + val startAdd = System.currentTimeMillis() + locationSearchTree.addAll(fillerPoints) + Log.e("foobar", "time to add ${fillerPoints.size} is ${System.currentTimeMillis() - startAdd}") + + fillerPointsInTree.add(fillerPoints) + indexOfLastStepPointsLoadedInTree++ + if (fillerPointsInTree.size == 3) { + val pointsToDrop = fillerPointsInTree.drop(1).flatten() + val startRemove = System.currentTimeMillis() + locationSearchTree.removeAll(pointsToDrop) + Log.e("foobar", "time to remove ${pointsToDrop.size} is ${System.currentTimeMillis() - startRemove}") + } } } } } } + + fun deleteMeGetTreePoints(): List { + val allPoints = mutableListOf() + fillerPointsInTree.forEach { distanceIndexes -> + distanceIndexes.map { it.point }.forEach { + allPoints.add(it) + } + } + return allPoints + } } From 77f8708f9c24af60051e2368ad9b43046a0e4738 Mon Sep 17 00:00:00 2001 From: Seth Bourget Date: Sat, 15 Oct 2022 07:30:28 -0700 Subject: [PATCH 3/7] modified calculation and fixed bugs. --- .../core/MapboxRouteLineAndArrowActivity.kt | 21 +- .../route/line/MapboxRouteLineUtils.kt | 2 +- .../maps/route/line/api/MapboxRouteLineApi.kt | 8 + .../maps/route/line/api/VanishingRouteLine.kt | 115 +++-- .../line/MapboxRouteLineUtilsRoboTest.kt | 21 +- .../line/api/MapboxRouteLineApiRoboTest.kt | 430 +++++++++--------- .../route/line/api/MapboxRouteLineApiTest.kt | 2 +- .../route/line/api/VanishingRouteLineTest.kt | 5 + 8 files changed, 351 insertions(+), 253 deletions(-) diff --git a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt index fe1f7fd2e0f..74a91500032 100644 --- a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt +++ b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt @@ -124,6 +124,7 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe RouteLineColorResources.Builder() .routeLineTraveledColor(Color.LTGRAY) .routeLineTraveledCasingColor(Color.GRAY) + .inActiveRouteLegsColor(Color.YELLOW) .build() } @@ -161,6 +162,7 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe .withRouteLineBelowLayerId("road-label-navigation") .withVanishingRouteLineEnabled(true) .displaySoftGradientForTraffic(trafficGradientSoft) + //.styleInactiveRouteLegsIndependently(true) .build() } @@ -414,13 +416,14 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe return false } + //Point.fromLngLat(-122.66743711143083, 45.637156363108105), Point.fromLngLat(-122.67117999435773, 45.63660582500783), Point.fromLngLat(-122.67147361785446, 45.63566210717601), Point.fromLngLat(-122.66713095440821, 45.63561846681017), Point.fromLngLat(-122.66742461493801, 45.63709082769017), Point.fromLngLat(-122.66928668721683, 45.63676751447727) fun findRoute(origin: Point?, destination: Point?) { val routeOptions = RouteOptions.builder() .applyDefaultNavigationOptions() .applyLanguageAndVoiceUnitOptions(this) .coordinatesList(listOf(origin, destination)) - .layersList(listOf(mapboxNavigation.getZLevel(), null)) - .alternatives(true) + //.layersList(listOf(mapboxNavigation.getZLevel(), null)) + .alternatives(false) .build() mapboxNavigation.requestRoutes( routeOptions, @@ -430,8 +433,8 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe private val routesReqCallback: RouterCallback = object : RouterCallback { override fun onRoutesReady(routes: List, routerOrigin: RouterOrigin) { - mapboxNavigation.setRoutes(listOf(getRoute())) - //mapboxNavigation.setRoutes(routes) + //mapboxNavigation.setRoutes(listOf(getRoute())) + mapboxNavigation.setRoutes(routes) if (routes.isNotEmpty()) { viewBinding.routeLoadingProgressBar.visibility = View.INVISIBLE viewBinding.startNavigation.visibility = View.VISIBLE @@ -597,9 +600,9 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe } } - fun getRoute(): DirectionsRoute { - val routeJson = "{\"routeIndex\":\"0\",\"distance\":728.195,\"duration\":178.495,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@YEnd@I|_@|]HrTJxf@B~FgAPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"weight\":241.413,\"weight_name\":\"auto\",\"legs\":[{\"weight\":241.413,\"via_waypoints\":[],\"distance\":728.195,\"duration\":178.495,\"summary\":\"Main Street, West McLoughlin Boulevard\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"distance\":220.325,\"duration\":29.108,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@Y\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.634461],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"driving_side\":\"right\",\"weight\":35.461,\"intersections\":[{\"duration\":7.5,\"weight\":9,\"location\":[-122.671531,45.634461],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.719,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.94,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"distance\":87.726,\"duration\":31.082,\"geometry\":\"otl`vAlwg~hFEnd@I|_@\",\"name\":\"West 20th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671495,45.63644],\"bearing_before\":1.0,\"bearing_after\":270.0,\"instruction\":\"Turn left onto West 20th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":45.681,\"intersections\":[{\"duration\":19.722,\"turn_weight\":12.5,\"turn_duration\":5.622,\"weight\":29.773,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.007,\"location\":[-122.672095,45.636443],\"bearings\":[1,90,182,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":179.057,\"duration\":68.349,\"geometry\":\"_ul`vAz}i~hF|]HrTJxf@B~FgA\",\"name\":\"Washington Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672622,45.636448],\"bearing_before\":271.0,\"bearing_after\":180.0,\"instruction\":\"Turn left onto Washington Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":88.24,\"intersections\":[{\"duration\":30.372,\"turn_weight\":10,\"turn_duration\":5.622,\"weight\":39.7,\"location\":[-122.672622,45.636448],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":2,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"duration\":17.558,\"turn_weight\":1,\"turn_duration\":0.008,\"weight\":22.06,\"location\":[-122.672627,45.635953],\"bearings\":[0,92,181],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.019,\"location\":[-122.672633,45.635607],\"bearings\":[1,92,180,270],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":241.086,\"duration\":49.955,\"geometry\":\"spi`vAl|i~hFPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672599,45.634842],\"bearing_before\":169.0,\"bearing_after\":91.0,\"instruction\":\"Turn left onto West McLoughlin Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":72.031,\"intersections\":[{\"duration\":22.522,\"turn_weight\":12.5,\"turn_duration\":3.622,\"weight\":35.18,\"location\":[-122.672599,45.634842],\"bearings\":[91,182,270,349],\"entry\":[true,true,true,false],\"in\":3,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":14.931,\"turn_duration\":2.008,\"turn_weight\":3,\"duration\":11.951,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,182,259],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":1.371,\"turn_weight\":0.75,\"weight\":2.396,\"location\":[-122.670778,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.086,\"turn_weight\":0.75,\"weight\":4.453,\"location\":[-122.670671,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":16,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":6.469,\"turn_duration\":2.008,\"turn_weight\":2,\"duration\":5.732,\"location\":[-122.670443,45.634898],\"bearings\":[1,91,182,270],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":0.248,\"turn_weight\":0.75,\"weight\":1.048,\"location\":[-122.670058,45.634895],\"bearings\":[90,271],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":19,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.49,\"turn_weight\":0.75,\"weight\":2.538,\"location\":[-122.670028,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"location\":[-122.66988,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":21,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"distance\":0.0,\"duration\":0.0,\"geometry\":\"ysi`vAn{c~hF??\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.669512,45.634893],\"bearing_before\":90.0,\"bearing_after\":0.0,\"instruction\":\"You have arrived at your destination.\",\"type\":\"arrive\"},\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.669512,45.634893],\"bearings\":[270],\"entry\":[true],\"in\":0,\"geometry_index\":22,\"admin_index\":0}]}],\"annotation\":{\"distance\":[46.0,48.6,37.3,88.4,46.7,41.1,55.1,38.5,70.9,14.5,54.2,15.6,14.5,13.4,44.8,8.4,17.7,0.7,29.3,2.3,11.5,28.7],\"congestion_numeric\":[0,null,4,4,null,null,null,null,null,null,0,0,0,4,4,4,4,1,1,1,1,1]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6715815,45.6344615;-122.6716338,45.6364896;-122.6726954,45.6364085;-122.672707,45.6348712;-122.6695105,45.6350132\",\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,distance\",\"voice_instructions\":false,\"banner_instructions\":false,\"waypoints\":\"0;4\"},\"requestUuid\":\"mapmatching\"}" - //val routeJson = "{\"country_crossed\":false,\"weight_typical\":373.949,\"routeIndex\":\"0\",\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DAChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\oMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTIWzeA\",\"weight\":373.949,\"weight_name\":\"auto\",\"legs\":[{\"weight_typical\":373.949,\"weight\":373.949,\"via_waypoints\":[],\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"summary\":\"West Fourth Plain Boulevard, Kauffman Avenue\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"weight_typical\":111.941,\"distance\":634.918,\"duration\":86.844,\"duration_typical\":86.844,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DA\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.63447],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":634.918,\"announcement\":\"Drive north on Main Street for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eDrive north on \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eMain Street\\u003c/say-as\\u003e for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West Fourth Plain Boulevard.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest Fourth Plain Boulevard\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":42.667,\"announcement\":\"Turn left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":634.918,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":true,\"active_direction\":\"left\"},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"right\"],\"active\":false}]}}],\"driving_side\":\"right\",\"weight\":111.941,\"intersections\":[{\"duration\":7.315,\"weight\":8.778,\"location\":[-122.671531,45.63447],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.937,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.201,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":9.919,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":12.88,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":4.031,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.914,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.832,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.945,\"location\":[-122.671487,45.63679],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.844,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.186,\"location\":[-122.671483,45.637018],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.874,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.998,\"location\":[-122.671477,45.637323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.254,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.237,\"location\":[-122.671473,45.637532],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":2.918,\"turn_duration\":2.019,\"turn_weight\":0.5,\"duration\":3.993,\"location\":[-122.67147,45.63769],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":2.779,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.881,\"location\":[-122.671468,45.63784],\"bearings\":[1,181,267],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":12,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.619,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.41,\"location\":[-122.671464,45.638047],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":7.363,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":9.496,\"location\":[-122.671459,45.638323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":14,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":10.819,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":14.23,\"location\":[-122.67145,45.638782],\"bearings\":[1,75,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.75,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":4.346,\"location\":[-122.671438,45.63946],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671435,45.639654],\"bearings\":[1,90,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":18,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":104.434,\"distance\":744.28,\"duration\":79.063,\"duration_typical\":79.063,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"y}s`vAdsg~hFChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\\",\"name\":\"West Fourth Plain Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671427,45.640173],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West Fourth Plain Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":730.946,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":66.667,\"announcement\":\"Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":744.28,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\",\"right\"],\"active\":true,\"active_direction\":\"right\"}]}}],\"driving_side\":\"right\",\"weight\":104.434,\"intersections\":[{\"weight\":12.272,\"turn_duration\":7.622,\"turn_weight\":10,\"duration\":9.476,\"location\":[-122.671427,45.640173],\"bearings\":[15,90,181,271],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"right\"]}],\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":4.93,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":6.514,\"location\":[-122.671647,45.640175],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":22,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.821,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":3.93,\"location\":[-122.67223,45.64018],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":24,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.672503,45.640182],\"bearings\":[91,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":25,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.673074,45.640185],\"bearings\":[90,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":26,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":5.138,\"turn_duration\":2.021,\"turn_weight\":1.5,\"duration\":4.991,\"location\":[-122.673636,45.640188],\"bearings\":[91,179,271,359],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":28,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":6.75,\"turn_weight\":0.5,\"weight\":8.769,\"location\":[-122.674055,45.640192],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":30,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.784,\"turn_weight\":1,\"turn_duration\":0.021,\"weight\":5.61,\"location\":[-122.675017,45.640202],\"bearings\":[1,91,191,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":31,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":8.007,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":10.1,\"location\":[-122.675603,45.640202],\"bearings\":[0,90,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":32,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.455,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":9.221,\"location\":[-122.676886,45.640215],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":33,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.844,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":2.704,\"location\":[-122.677966,45.64022],\"bearings\":[90,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":34,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.246,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":7.97,\"location\":[-122.678293,45.640224],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":35,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.971,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.84,\"location\":[-122.679353,45.640231],\"bearings\":[91,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":36,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.301,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":4.436,\"location\":[-122.679682,45.640235],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":37,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":0.548,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":1.132,\"location\":[-122.680211,45.640242],\"bearings\":[91,180,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":38,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.046,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.93,\"location\":[-122.680286,45.640243],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":39,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":0.5,\"location\":[-122.680518,45.640246],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":40,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":131.023,\"distance\":877.516,\"duration\":91.718,\"duration_typical\":91.718,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"wbt`vAxhz~hFoMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTI\",\"name\":\"Kauffman Avenue\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680989,45.640252],\"bearing_before\":271.0,\"bearing_after\":1.0,\"instruction\":\"Turn right onto Kauffman Avenue.\",\"type\":\"turn\",\"modifier\":\"right\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":864.182,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West 36th Street.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":91.111,\"announcement\":\"Turn left onto West 36th Street. Then Your destination will be on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e. Then Your destination will be on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":877.516,\"primary\":{\"text\":\"West 36th Street\",\"components\":[{\"text\":\"West 36th Street\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":131.023,\"intersections\":[{\"weight\":19.48,\"turn_duration\":4.005,\"turn_weight\":7,\"duration\":14.405,\"location\":[-122.680989,45.640252],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"right\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":41,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":5.119,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.87,\"location\":[-122.680982,45.640484],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":42,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.276,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.059,\"location\":[-122.680974,45.64079],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":43,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":7.069,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":9.21,\"location\":[-122.680973,45.640821],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":44,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.467,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":4.886,\"location\":[-122.680949,45.641665],\"bearings\":[0,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":45,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.059,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.798,\"location\":[-122.680943,45.642072],\"bearings\":[1,89,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":47,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.752,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":5.98,\"location\":[-122.680937,45.642508],\"bearings\":[1,92,181,267],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":48,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.019,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.35,\"location\":[-122.680933,45.64276],\"bearings\":[1,181,270],\"entry\":[true,false,false],\"in\":1,\"out\":0,\"geometry_index\":49,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":6.869,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":8.969,\"location\":[-122.680929,45.643071],\"bearings\":[0,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":50,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.294,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.88,\"location\":[-122.68092,45.643769],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":52,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.619,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":2.67,\"location\":[-122.680909,45.644285],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":53,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.866,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.166,\"location\":[-122.680905,45.644465],\"bearings\":[1,181,276],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":54,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.795,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":6.031,\"location\":[-122.680898,45.64477],\"bearings\":[1,90,181,269],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":56,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.804,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.197,\"location\":[-122.680892,45.645153],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":57,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.204,\"turn_weight\":2,\"turn_duration\":0.021,\"weight\":6.916,\"location\":[-122.680885,45.645518],\"bearings\":[0,90,181,265],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":58,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.71,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":1.575,\"location\":[-122.680881,45.645902],\"bearings\":[1,90,180],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":59,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.062,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":3.151,\"location\":[-122.68088,45.645973],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":60,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.149,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.778,\"location\":[-122.680877,45.646162],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":62,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.533,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.354,\"location\":[-122.680868,45.646675],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":63,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.118,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":5.14,\"location\":[-122.680867,45.646729],\"bearings\":[0,92,181,284],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":64,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.579,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":3.771,\"location\":[-122.680864,45.647059],\"bearings\":[1,180,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":65,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.819,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.39,\"location\":[-122.680858,45.647327],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":66,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"turn_duration\":0.019,\"location\":[-122.680842,45.647797],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":68,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"weight_typical\":26.551,\"distance\":88.242,\"duration\":17.84,\"duration_typical\":17.84,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kocavAh_z~hFWzeA\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680837,45.648134],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West 36th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":44.444,\"announcement\":\"Your destination is on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eYour destination is on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":88.242,\"primary\":{\"text\":\"Your destination will be on the left\",\"components\":[{\"text\":\"Your destination will be on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":44.444,\"primary\":{\"text\":\"Your destination is on the left\",\"components\":[{\"text\":\"Your destination is on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":26.551,\"intersections\":[{\"turn_weight\":12.5,\"turn_duration\":5.622,\"location\":[-122.680837,45.648134],\"bearings\":[0,181,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":69,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"weight_typical\":0,\"distance\":0.0,\"duration\":0.0,\"duration_typical\":0.0,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"cpcavAdf|~hF??\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.681971,45.648146],\"bearing_before\":271.0,\"bearing_after\":0.0,\"instruction\":\"Your destination is on the left.\",\"type\":\"arrive\",\"modifier\":\"left\"},\"voiceInstructions\":[],\"bannerInstructions\":[],\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.681971,45.648146],\"bearings\":[91],\"entry\":[true],\"in\":0,\"geometry_index\":70,\"admin_index\":0}]}],\"annotation\":{\"distance\":[45.0,48.6,37.3,88.4,39.0,25.4,33.9,23.3,9.7,7.9,7.8,8.9,23.0,30.8,51.1,10.8,64.6,21.6,48.9,8.9,9.1,8.0,39.0,6.4,21.3,44.4,35.2,8.6,7.7,24.9,74.9,45.6,99.8,84.1,25.4,82.5,25.7,41.1,5.9,18.0,36.7,25.8,34.1,3.5,93.9,9.9,35.4,48.6,28.0,34.6,18.5,59.3,57.4,20.0,20.9,13.1,42.6,40.7,42.7,7.9,10.6,10.5,57.1,6.0,36.7,29.9,24.6,27.7,37.5,88.3],\"duration\":[7.315,8.552,3.937,9.919,4.031,2.832,3.844,2.874,1.249,1.004,2.94,1.053,2.779,3.619,7.363,1.564,9.255,2.75,8.429,1.533,8.608,0.868,4.239,0.69,2.821,5.867,4.718,1.148,2.73,2.261,6.75,3.784,8.007,6.455,1.844,6.246,1.971,3.301,0.547,2.046,4.163,14.405,5.119,0.276,7.069,0.774,2.693,5.059,3.752,3.019,1.649,5.22,4.294,1.619,1.764,1.101,3.795,3.804,4.204,0.71,1.046,1.016,5.149,0.533,3.118,2.579,2.276,2.543,3.128,17.84],\"speed\":[6.1,7.4,9.5,8.9,9.7,9.0,8.9,8.1,7.9,7.9,8.5,8.5,8.3,8.5,7.0,7.0,7.0,7.9,5.8,5.8,9.2,9.2,9.2,9.2,7.6,7.6,7.5,7.5,11.0,11.0,11.1,12.1,12.5,13.1,13.9,13.3,13.1,12.6,11.1,8.9,8.8,2.5,6.7,13.4,13.3,13.1,13.1,9.6,7.5,11.5,11.3,11.3,13.4,12.5,11.9,11.9,11.3,10.7,10.2,11.3,10.3,10.3,11.1,11.7,11.9,11.6,10.9,10.9,12.1,7.2],\"maxspeed\":[{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"}],\"congestion_numeric\":[0,24,9,9,0,0,0,null,null,null,0,0,0,null,6,9,9,14,null,null,9,9,9,9,30,30,30,30,12,12,12,4,3,1,0,0,null,3,null,0,0,null,null,null,0,null,null,null,null,null,null,null,null,null,null,null,0,null,null,null,0,0,null,null,null,null,null,null,0,null]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6716938,45.6344717;-122.681974,45.6479927\",\"alternatives\":true,\"language\":\"en\",\"layers\":\";\",\"continue_straight\":true,\"roundabout_exits\":true,\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,maxspeed,closure,speed,duration,distance\",\"voice_instructions\":true,\"banner_instructions\":true,\"voice_units\":\"imperial\",\"enable_refresh\":true},\"voiceLocale\":\"en-US\",\"requestUuid\":\"VA6i2dqAyEvoC4gS25Y14Z6gAE6c2fe_Tpq4H9voaY7FjLb-IUIcYQ\\u003d\\u003d\"}" - return DirectionsRoute.fromJson(routeJson) - } + // fun getRoute(): DirectionsRoute { + // //val routeJson = "{\"routeIndex\":\"0\",\"distance\":728.195,\"duration\":178.495,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@YEnd@I|_@|]HrTJxf@B~FgAPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"weight\":241.413,\"weight_name\":\"auto\",\"legs\":[{\"weight\":241.413,\"via_waypoints\":[],\"distance\":728.195,\"duration\":178.495,\"summary\":\"Main Street, West McLoughlin Boulevard\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"distance\":220.325,\"duration\":29.108,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@Y\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.634461],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"driving_side\":\"right\",\"weight\":35.461,\"intersections\":[{\"duration\":7.5,\"weight\":9,\"location\":[-122.671531,45.634461],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.719,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.94,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"distance\":87.726,\"duration\":31.082,\"geometry\":\"otl`vAlwg~hFEnd@I|_@\",\"name\":\"West 20th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671495,45.63644],\"bearing_before\":1.0,\"bearing_after\":270.0,\"instruction\":\"Turn left onto West 20th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":45.681,\"intersections\":[{\"duration\":19.722,\"turn_weight\":12.5,\"turn_duration\":5.622,\"weight\":29.773,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.007,\"location\":[-122.672095,45.636443],\"bearings\":[1,90,182,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":179.057,\"duration\":68.349,\"geometry\":\"_ul`vAz}i~hF|]HrTJxf@B~FgA\",\"name\":\"Washington Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672622,45.636448],\"bearing_before\":271.0,\"bearing_after\":180.0,\"instruction\":\"Turn left onto Washington Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":88.24,\"intersections\":[{\"duration\":30.372,\"turn_weight\":10,\"turn_duration\":5.622,\"weight\":39.7,\"location\":[-122.672622,45.636448],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":2,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"duration\":17.558,\"turn_weight\":1,\"turn_duration\":0.008,\"weight\":22.06,\"location\":[-122.672627,45.635953],\"bearings\":[0,92,181],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.019,\"location\":[-122.672633,45.635607],\"bearings\":[1,92,180,270],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":241.086,\"duration\":49.955,\"geometry\":\"spi`vAl|i~hFPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672599,45.634842],\"bearing_before\":169.0,\"bearing_after\":91.0,\"instruction\":\"Turn left onto West McLoughlin Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":72.031,\"intersections\":[{\"duration\":22.522,\"turn_weight\":12.5,\"turn_duration\":3.622,\"weight\":35.18,\"location\":[-122.672599,45.634842],\"bearings\":[91,182,270,349],\"entry\":[true,true,true,false],\"in\":3,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":14.931,\"turn_duration\":2.008,\"turn_weight\":3,\"duration\":11.951,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,182,259],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":1.371,\"turn_weight\":0.75,\"weight\":2.396,\"location\":[-122.670778,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.086,\"turn_weight\":0.75,\"weight\":4.453,\"location\":[-122.670671,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":16,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":6.469,\"turn_duration\":2.008,\"turn_weight\":2,\"duration\":5.732,\"location\":[-122.670443,45.634898],\"bearings\":[1,91,182,270],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":0.248,\"turn_weight\":0.75,\"weight\":1.048,\"location\":[-122.670058,45.634895],\"bearings\":[90,271],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":19,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.49,\"turn_weight\":0.75,\"weight\":2.538,\"location\":[-122.670028,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"location\":[-122.66988,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":21,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"distance\":0.0,\"duration\":0.0,\"geometry\":\"ysi`vAn{c~hF??\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.669512,45.634893],\"bearing_before\":90.0,\"bearing_after\":0.0,\"instruction\":\"You have arrived at your destination.\",\"type\":\"arrive\"},\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.669512,45.634893],\"bearings\":[270],\"entry\":[true],\"in\":0,\"geometry_index\":22,\"admin_index\":0}]}],\"annotation\":{\"distance\":[46.0,48.6,37.3,88.4,46.7,41.1,55.1,38.5,70.9,14.5,54.2,15.6,14.5,13.4,44.8,8.4,17.7,0.7,29.3,2.3,11.5,28.7],\"congestion_numeric\":[0,null,4,4,null,null,null,null,null,null,0,0,0,4,4,4,4,1,1,1,1,1]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6715815,45.6344615;-122.6716338,45.6364896;-122.6726954,45.6364085;-122.672707,45.6348712;-122.6695105,45.6350132\",\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,distance\",\"voice_instructions\":false,\"banner_instructions\":false,\"waypoints\":\"0;4\"},\"requestUuid\":\"mapmatching\"}" + // val routeJson = "{\"country_crossed\":false,\"weight_typical\":373.949,\"routeIndex\":\"0\",\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DAChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\oMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTIWzeA\",\"weight\":373.949,\"weight_name\":\"auto\",\"legs\":[{\"weight_typical\":373.949,\"weight\":373.949,\"via_waypoints\":[],\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"summary\":\"West Fourth Plain Boulevard, Kauffman Avenue\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"weight_typical\":111.941,\"distance\":634.918,\"duration\":86.844,\"duration_typical\":86.844,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DA\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.63447],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":634.918,\"announcement\":\"Drive north on Main Street for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eDrive north on \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eMain Street\\u003c/say-as\\u003e for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West Fourth Plain Boulevard.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest Fourth Plain Boulevard\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":42.667,\"announcement\":\"Turn left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":634.918,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":true,\"active_direction\":\"left\"},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"right\"],\"active\":false}]}}],\"driving_side\":\"right\",\"weight\":111.941,\"intersections\":[{\"duration\":7.315,\"weight\":8.778,\"location\":[-122.671531,45.63447],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.937,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.201,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":9.919,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":12.88,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":4.031,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.914,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.832,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.945,\"location\":[-122.671487,45.63679],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.844,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.186,\"location\":[-122.671483,45.637018],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.874,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.998,\"location\":[-122.671477,45.637323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.254,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.237,\"location\":[-122.671473,45.637532],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":2.918,\"turn_duration\":2.019,\"turn_weight\":0.5,\"duration\":3.993,\"location\":[-122.67147,45.63769],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":2.779,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.881,\"location\":[-122.671468,45.63784],\"bearings\":[1,181,267],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":12,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.619,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.41,\"location\":[-122.671464,45.638047],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":7.363,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":9.496,\"location\":[-122.671459,45.638323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":14,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":10.819,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":14.23,\"location\":[-122.67145,45.638782],\"bearings\":[1,75,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.75,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":4.346,\"location\":[-122.671438,45.63946],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671435,45.639654],\"bearings\":[1,90,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":18,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":104.434,\"distance\":744.28,\"duration\":79.063,\"duration_typical\":79.063,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"y}s`vAdsg~hFChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\\",\"name\":\"West Fourth Plain Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671427,45.640173],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West Fourth Plain Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":730.946,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":66.667,\"announcement\":\"Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":744.28,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\",\"right\"],\"active\":true,\"active_direction\":\"right\"}]}}],\"driving_side\":\"right\",\"weight\":104.434,\"intersections\":[{\"weight\":12.272,\"turn_duration\":7.622,\"turn_weight\":10,\"duration\":9.476,\"location\":[-122.671427,45.640173],\"bearings\":[15,90,181,271],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"right\"]}],\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":4.93,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":6.514,\"location\":[-122.671647,45.640175],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":22,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.821,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":3.93,\"location\":[-122.67223,45.64018],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":24,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.672503,45.640182],\"bearings\":[91,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":25,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.673074,45.640185],\"bearings\":[90,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":26,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":5.138,\"turn_duration\":2.021,\"turn_weight\":1.5,\"duration\":4.991,\"location\":[-122.673636,45.640188],\"bearings\":[91,179,271,359],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":28,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":6.75,\"turn_weight\":0.5,\"weight\":8.769,\"location\":[-122.674055,45.640192],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":30,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.784,\"turn_weight\":1,\"turn_duration\":0.021,\"weight\":5.61,\"location\":[-122.675017,45.640202],\"bearings\":[1,91,191,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":31,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":8.007,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":10.1,\"location\":[-122.675603,45.640202],\"bearings\":[0,90,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":32,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.455,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":9.221,\"location\":[-122.676886,45.640215],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":33,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.844,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":2.704,\"location\":[-122.677966,45.64022],\"bearings\":[90,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":34,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.246,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":7.97,\"location\":[-122.678293,45.640224],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":35,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.971,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.84,\"location\":[-122.679353,45.640231],\"bearings\":[91,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":36,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.301,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":4.436,\"location\":[-122.679682,45.640235],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":37,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":0.548,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":1.132,\"location\":[-122.680211,45.640242],\"bearings\":[91,180,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":38,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.046,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.93,\"location\":[-122.680286,45.640243],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":39,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":0.5,\"location\":[-122.680518,45.640246],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":40,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":131.023,\"distance\":877.516,\"duration\":91.718,\"duration_typical\":91.718,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"wbt`vAxhz~hFoMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTI\",\"name\":\"Kauffman Avenue\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680989,45.640252],\"bearing_before\":271.0,\"bearing_after\":1.0,\"instruction\":\"Turn right onto Kauffman Avenue.\",\"type\":\"turn\",\"modifier\":\"right\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":864.182,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West 36th Street.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":91.111,\"announcement\":\"Turn left onto West 36th Street. Then Your destination will be on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e. Then Your destination will be on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":877.516,\"primary\":{\"text\":\"West 36th Street\",\"components\":[{\"text\":\"West 36th Street\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":131.023,\"intersections\":[{\"weight\":19.48,\"turn_duration\":4.005,\"turn_weight\":7,\"duration\":14.405,\"location\":[-122.680989,45.640252],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"right\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":41,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":5.119,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.87,\"location\":[-122.680982,45.640484],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":42,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.276,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.059,\"location\":[-122.680974,45.64079],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":43,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":7.069,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":9.21,\"location\":[-122.680973,45.640821],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":44,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.467,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":4.886,\"location\":[-122.680949,45.641665],\"bearings\":[0,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":45,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.059,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.798,\"location\":[-122.680943,45.642072],\"bearings\":[1,89,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":47,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.752,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":5.98,\"location\":[-122.680937,45.642508],\"bearings\":[1,92,181,267],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":48,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.019,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.35,\"location\":[-122.680933,45.64276],\"bearings\":[1,181,270],\"entry\":[true,false,false],\"in\":1,\"out\":0,\"geometry_index\":49,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":6.869,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":8.969,\"location\":[-122.680929,45.643071],\"bearings\":[0,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":50,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.294,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.88,\"location\":[-122.68092,45.643769],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":52,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.619,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":2.67,\"location\":[-122.680909,45.644285],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":53,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.866,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.166,\"location\":[-122.680905,45.644465],\"bearings\":[1,181,276],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":54,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.795,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":6.031,\"location\":[-122.680898,45.64477],\"bearings\":[1,90,181,269],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":56,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.804,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.197,\"location\":[-122.680892,45.645153],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":57,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.204,\"turn_weight\":2,\"turn_duration\":0.021,\"weight\":6.916,\"location\":[-122.680885,45.645518],\"bearings\":[0,90,181,265],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":58,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.71,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":1.575,\"location\":[-122.680881,45.645902],\"bearings\":[1,90,180],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":59,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.062,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":3.151,\"location\":[-122.68088,45.645973],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":60,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.149,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.778,\"location\":[-122.680877,45.646162],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":62,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.533,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.354,\"location\":[-122.680868,45.646675],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":63,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.118,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":5.14,\"location\":[-122.680867,45.646729],\"bearings\":[0,92,181,284],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":64,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.579,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":3.771,\"location\":[-122.680864,45.647059],\"bearings\":[1,180,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":65,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.819,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.39,\"location\":[-122.680858,45.647327],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":66,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"turn_duration\":0.019,\"location\":[-122.680842,45.647797],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":68,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"weight_typical\":26.551,\"distance\":88.242,\"duration\":17.84,\"duration_typical\":17.84,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kocavAh_z~hFWzeA\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680837,45.648134],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West 36th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":44.444,\"announcement\":\"Your destination is on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eYour destination is on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":88.242,\"primary\":{\"text\":\"Your destination will be on the left\",\"components\":[{\"text\":\"Your destination will be on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":44.444,\"primary\":{\"text\":\"Your destination is on the left\",\"components\":[{\"text\":\"Your destination is on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":26.551,\"intersections\":[{\"turn_weight\":12.5,\"turn_duration\":5.622,\"location\":[-122.680837,45.648134],\"bearings\":[0,181,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":69,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"weight_typical\":0,\"distance\":0.0,\"duration\":0.0,\"duration_typical\":0.0,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"cpcavAdf|~hF??\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.681971,45.648146],\"bearing_before\":271.0,\"bearing_after\":0.0,\"instruction\":\"Your destination is on the left.\",\"type\":\"arrive\",\"modifier\":\"left\"},\"voiceInstructions\":[],\"bannerInstructions\":[],\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.681971,45.648146],\"bearings\":[91],\"entry\":[true],\"in\":0,\"geometry_index\":70,\"admin_index\":0}]}],\"annotation\":{\"distance\":[45.0,48.6,37.3,88.4,39.0,25.4,33.9,23.3,9.7,7.9,7.8,8.9,23.0,30.8,51.1,10.8,64.6,21.6,48.9,8.9,9.1,8.0,39.0,6.4,21.3,44.4,35.2,8.6,7.7,24.9,74.9,45.6,99.8,84.1,25.4,82.5,25.7,41.1,5.9,18.0,36.7,25.8,34.1,3.5,93.9,9.9,35.4,48.6,28.0,34.6,18.5,59.3,57.4,20.0,20.9,13.1,42.6,40.7,42.7,7.9,10.6,10.5,57.1,6.0,36.7,29.9,24.6,27.7,37.5,88.3],\"duration\":[7.315,8.552,3.937,9.919,4.031,2.832,3.844,2.874,1.249,1.004,2.94,1.053,2.779,3.619,7.363,1.564,9.255,2.75,8.429,1.533,8.608,0.868,4.239,0.69,2.821,5.867,4.718,1.148,2.73,2.261,6.75,3.784,8.007,6.455,1.844,6.246,1.971,3.301,0.547,2.046,4.163,14.405,5.119,0.276,7.069,0.774,2.693,5.059,3.752,3.019,1.649,5.22,4.294,1.619,1.764,1.101,3.795,3.804,4.204,0.71,1.046,1.016,5.149,0.533,3.118,2.579,2.276,2.543,3.128,17.84],\"speed\":[6.1,7.4,9.5,8.9,9.7,9.0,8.9,8.1,7.9,7.9,8.5,8.5,8.3,8.5,7.0,7.0,7.0,7.9,5.8,5.8,9.2,9.2,9.2,9.2,7.6,7.6,7.5,7.5,11.0,11.0,11.1,12.1,12.5,13.1,13.9,13.3,13.1,12.6,11.1,8.9,8.8,2.5,6.7,13.4,13.3,13.1,13.1,9.6,7.5,11.5,11.3,11.3,13.4,12.5,11.9,11.9,11.3,10.7,10.2,11.3,10.3,10.3,11.1,11.7,11.9,11.6,10.9,10.9,12.1,7.2],\"maxspeed\":[{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"}],\"congestion_numeric\":[0,24,9,9,0,0,0,null,null,null,0,0,0,null,6,9,9,14,null,null,9,9,9,9,30,30,30,30,12,12,12,4,3,1,0,0,null,3,null,0,0,null,null,null,0,null,null,null,null,null,null,null,null,null,null,null,0,null,null,null,0,0,null,null,null,null,null,null,0,null]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6716938,45.6344717;-122.681974,45.6479927\",\"alternatives\":true,\"language\":\"en\",\"layers\":\";\",\"continue_straight\":true,\"roundabout_exits\":true,\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,maxspeed,closure,speed,duration,distance\",\"voice_instructions\":true,\"banner_instructions\":true,\"voice_units\":\"imperial\",\"enable_refresh\":true},\"voiceLocale\":\"en-US\",\"requestUuid\":\"VA6i2dqAyEvoC4gS25Y14Z6gAE6c2fe_Tpq4H9voaY7FjLb-IUIcYQ\\u003d\\u003d\"}" + // return DirectionsRoute.fromJson(routeJson) + // } } diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt index 02cb263acc1..4a8ffc4977e 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt @@ -969,7 +969,7 @@ object MapboxRouteLineUtils { //todo the variable names below should be named better fun getFillerPoints(startPoint: RouteLineDistancesIndex, endPoint: RouteLineDistancesIndex): List { - val gapDist = 2.0 // meters + val gapDist = 1.0 // meters val turfDistance = TurfMeasurement.distance(startPoint.point, endPoint.point, TurfConstants.UNIT_METERS) val fillerPoints = mutableListOf() val bearing = TurfMeasurement.bearing(startPoint.point, endPoint.point) diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt index 05830bfd99b..7afcb8bf234 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt @@ -750,6 +750,14 @@ class MapboxRouteLineApi( } } + fun updateUpcomingRoutePointIndex(routeProgress: RouteProgress) { + // del me + } + + fun updateVanishingPointState(state: RouteProgressState) { + // del me + } + /** * Adjusts the route line visibility so that only the current route leg is visible. This is * intended to be used with routes that have multiple waypoints. diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt index cf3a9c344b5..56d0ff60676 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt @@ -2,8 +2,10 @@ package com.mapbox.navigation.ui.maps.route.line.api import android.graphics.Color import android.util.Log +import android.util.Range import com.mapbox.geojson.Point import com.mapbox.maps.extension.style.expressions.dsl.generated.literal +import com.mapbox.navigation.base.trip.model.RouteProgressState import com.mapbox.navigation.ui.maps.internal.route.line.LocationSearchTree import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.ROUTE_LINE_UPDATE_MAX_DISTANCE_THRESHOLD_IN_METERS @@ -20,6 +22,7 @@ import com.mapbox.turf.TurfMeasurement import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.util.concurrent.CopyOnWriteArrayList /** * This class implements a feature that can change the appearance of the route line behind the puck. @@ -37,7 +40,15 @@ internal class VanishingRouteLine { * a value representing the percentage distance traveled */ var vanishPointOffset: Double = 0.0 - private set + //private set todo + + var primaryRouteRemainingDistancesIndex: Int? = null //todo delme + + var vanishingPointState: RouteProgressState? = null //todo delme + + fun updateVanishingPointState(state: RouteProgressState) { + //todo delme + } private var scope: CoroutineScope? = null @@ -160,7 +171,10 @@ internal class VanishingRouteLine { private var stepsPoints: List> = emptyList() private val fillerPointsInTree = mutableListOf>() private var indexOfLastStepPointsLoadedInTree = 0 - private val distanceToLastStepPointInMeters = 20.0 + private val distanceToLastStepPointInMeters = 30.0 + private var stepPointRange: Range? = null + private val stepPointRangeSize = 5 + private val maxAllowedFillerPointListsInTree = 3 fun setGranularDistances(distances: RouteLineGranularDistances) { if (distances != granularDistances) { @@ -173,15 +187,34 @@ internal class VanishingRouteLine { vanishPointOffset = 0.0 Log.e("foobar", "everything got cleared, starting fresh") - if (stepsPoints.isNotEmpty()) { - val firstSteps = stepsPoints.first() - val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(firstSteps) - locationSearchTree.addAll(fillerPoints) - fillerPointsInTree.add(fillerPoints) + // if (stepsPoints.isNotEmpty()) { + // val firstSteps = stepsPoints.first() + // val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(firstSteps) + // locationSearchTree.addAll(fillerPoints) + // fillerPointsInTree.add(fillerPoints) + // } + + if (distances.flatStepDistances.isNotEmpty()) { + val endRange = if (distances.flatStepDistances.size > stepPointRangeSize) { + stepPointRangeSize + } else { + distances.flatStepDistances.lastIndex + } + stepPointRange = Range(0, endRange).also { + val fillerPoints = getFillerPointsForRange(it, distances.flatStepDistances) + locationSearchTree.addAll(fillerPoints) + fillerPointsInTree.add(fillerPoints) + } } } } + private fun getFillerPointsForRange(range: Range, flatStepDistances: Array): List { + val fillerSteps = flatStepDistances.copyOfRange(range.lower, range.upper) + return MapboxRouteLineUtils.getFillerPointsForStepPoints(fillerSteps) + } + + fun getOffset(point: Point): Double? { val offset = ifNonNull(locationSearchTree.getNearestNeighbor(point), granularDistances) { closestPoint, distances -> @@ -198,34 +231,64 @@ internal class VanishingRouteLine { return offset } - private fun trimTree(point: Point) { + //todo make private + fun trimTree(point: Point) { //if getting close to the last step point, load the points for the next step //and remove the points long since passed. - scope?.launch(Dispatchers.Main) { - if (fillerPointsInTree.isNotEmpty()) { - val nearEndStepPoint = fillerPointsInTree.last()[fillerPointsInTree.last().lastIndex] + scope?.launch(Dispatchers.Main.immediate) { + val trimStart = System.currentTimeMillis() + if (fillerPointsInTree.isNotEmpty() && fillerPointsInTree.last().isNotEmpty()) { + val nearEndStepPoint = fillerPointsInTree.last().last() val distanceToNearEndStepPoint = TurfMeasurement.distance(point, nearEndStepPoint.point, TurfConstants.UNIT_METERS) if (distanceToNearEndStepPoint <= distanceToLastStepPointInMeters) { - if (indexOfLastStepPointsLoadedInTree + 1 < stepsPoints.size) { - val nextSteps = stepsPoints[indexOfLastStepPointsLoadedInTree + 1] - val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(nextSteps) - - val startAdd = System.currentTimeMillis() - locationSearchTree.addAll(fillerPoints) - Log.e("foobar", "time to add ${fillerPoints.size} is ${System.currentTimeMillis() - startAdd}") - - fillerPointsInTree.add(fillerPoints) - indexOfLastStepPointsLoadedInTree++ - if (fillerPointsInTree.size == 3) { - val pointsToDrop = fillerPointsInTree.drop(1).flatten() - val startRemove = System.currentTimeMillis() - locationSearchTree.removeAll(pointsToDrop) - Log.e("foobar", "time to remove ${pointsToDrop.size} is ${System.currentTimeMillis() - startRemove}") + stepPointRange = ifNonNull(stepPointRange, granularDistances) { currentStepPointRange, distances -> + val endOfRange = if (currentStepPointRange.upper + stepPointRangeSize < distances.flatStepDistances.lastIndex) { + currentStepPointRange.upper + stepPointRangeSize + } else { + distances.flatStepDistances.lastIndex + } + Range(currentStepPointRange.upper - 1, endOfRange).also { + val fillerPoints = getFillerPointsForRange(it, distances.flatStepDistances) + if (fillerPoints.isNotEmpty()) { + locationSearchTree.addAll(fillerPoints) + fillerPointsInTree.add(fillerPoints) + } } } + if (fillerPointsInTree.size == maxAllowedFillerPointListsInTree) { + val pointsToDrop = fillerPointsInTree.removeFirst() + val startRemove = System.currentTimeMillis() + locationSearchTree.removeAll(pointsToDrop) + Log.e("foobar", "time to remove ${pointsToDrop.size} is ${System.currentTimeMillis() - startRemove}") + } + + + + // if (indexOfLastStepPointsLoadedInTree + 1 < stepsPoints.size) { + // val nextSteps = stepsPoints[indexOfLastStepPointsLoadedInTree + 1] + // val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(nextSteps) + // + // val startAdd = System.currentTimeMillis() + // locationSearchTree.addAll(fillerPoints) + // Log.e("foobar", "time to add ${fillerPoints.size} is ${System.currentTimeMillis() - startAdd}") + // + // fillerPointsInTree.add(fillerPoints) + // indexOfLastStepPointsLoadedInTree++ + // if (fillerPointsInTree.size == 3) { + // val pointsToDrop = fillerPointsInTree.removeFirst() + // val startRemove = System.currentTimeMillis() + // locationSearchTree.removeAll(pointsToDrop) + // Log.e("foobar", "time to remove ${pointsToDrop.size} is ${System.currentTimeMillis() - startRemove}") + // } + // } } } + val trimTotal = System.currentTimeMillis() - trimStart + if (trimTotal > 5) { + Log.e("foobar", "time to trim tree is ${System.currentTimeMillis() - trimStart}") + } + } } diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt index 7d10625fd27..e9de6c05bf9 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt @@ -4,6 +4,7 @@ import android.content.Context import android.graphics.Bitmap import android.graphics.Color import androidx.test.core.app.ApplicationProvider +import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.api.directions.v5.models.RouteOptions import com.mapbox.bindgen.ExpectedFactory import com.mapbox.bindgen.Value @@ -20,6 +21,7 @@ import com.mapbox.maps.plugin.locationcomponent.LocationComponentConstants import com.mapbox.navigation.base.internal.NativeRouteParserWrapper import com.mapbox.navigation.base.route.NavigationRoute import com.mapbox.navigation.base.route.RouterOrigin +import com.mapbox.navigation.base.route.toNavigationRoute import com.mapbox.navigation.testing.FileUtils.loadJsonFixture import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.ARROW_HEAD_ICON import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.ARROW_HEAD_ICON_CASING @@ -58,7 +60,9 @@ import com.mapbox.navigation.ui.maps.route.line.model.RouteLineColorResources import com.mapbox.navigation.ui.maps.route.line.model.RouteLineDistancesIndex import com.mapbox.navigation.ui.maps.route.line.model.RouteLineGranularDistances import com.mapbox.navigation.ui.maps.route.line.model.RoutePoints +import com.mapbox.navigation.ui.maps.testing.TestingUtil import com.mapbox.navigation.ui.maps.testing.TestingUtil.loadNavigationRoute +import com.mapbox.navigation.utils.internal.InternalJobControlFactory import com.mapbox.navigator.RouteInterface import com.mapbox.turf.TurfConstants import com.mapbox.turf.TurfMeasurement @@ -78,7 +82,6 @@ import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import java.util.UUID -import kotlin.math.abs @RunWith(RobolectricTestRunner::class) class MapboxRouteLineUtilsRoboTest { @@ -1204,4 +1207,20 @@ class MapboxRouteLineUtilsRoboTest { verify(exactly = 3) { route1.directionsRoute } verify(exactly = 2) { route2.directionsRoute } } + + @Test + fun scratch() { + val routeJson = "{\"routeIndex\":\"0\",\"distance\":728.195,\"duration\":178.495,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@YEnd@I|_@|]HrTJxf@B~FgAPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"weight\":241.413,\"weight_name\":\"auto\",\"legs\":[{\"weight\":241.413,\"via_waypoints\":[],\"distance\":728.195,\"duration\":178.495,\"summary\":\"Main Street, West McLoughlin Boulevard\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"distance\":220.325,\"duration\":29.108,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@Y\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.634461],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"driving_side\":\"right\",\"weight\":35.461,\"intersections\":[{\"duration\":7.5,\"weight\":9,\"location\":[-122.671531,45.634461],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.719,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.94,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"distance\":87.726,\"duration\":31.082,\"geometry\":\"otl`vAlwg~hFEnd@I|_@\",\"name\":\"West 20th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671495,45.63644],\"bearing_before\":1.0,\"bearing_after\":270.0,\"instruction\":\"Turn left onto West 20th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":45.681,\"intersections\":[{\"duration\":19.722,\"turn_weight\":12.5,\"turn_duration\":5.622,\"weight\":29.773,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.007,\"location\":[-122.672095,45.636443],\"bearings\":[1,90,182,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":179.057,\"duration\":68.349,\"geometry\":\"_ul`vAz}i~hF|]HrTJxf@B~FgA\",\"name\":\"Washington Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672622,45.636448],\"bearing_before\":271.0,\"bearing_after\":180.0,\"instruction\":\"Turn left onto Washington Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":88.24,\"intersections\":[{\"duration\":30.372,\"turn_weight\":10,\"turn_duration\":5.622,\"weight\":39.7,\"location\":[-122.672622,45.636448],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":2,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"duration\":17.558,\"turn_weight\":1,\"turn_duration\":0.008,\"weight\":22.06,\"location\":[-122.672627,45.635953],\"bearings\":[0,92,181],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.019,\"location\":[-122.672633,45.635607],\"bearings\":[1,92,180,270],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":241.086,\"duration\":49.955,\"geometry\":\"spi`vAl|i~hFPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672599,45.634842],\"bearing_before\":169.0,\"bearing_after\":91.0,\"instruction\":\"Turn left onto West McLoughlin Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":72.031,\"intersections\":[{\"duration\":22.522,\"turn_weight\":12.5,\"turn_duration\":3.622,\"weight\":35.18,\"location\":[-122.672599,45.634842],\"bearings\":[91,182,270,349],\"entry\":[true,true,true,false],\"in\":3,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":14.931,\"turn_duration\":2.008,\"turn_weight\":3,\"duration\":11.951,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,182,259],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":1.371,\"turn_weight\":0.75,\"weight\":2.396,\"location\":[-122.670778,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.086,\"turn_weight\":0.75,\"weight\":4.453,\"location\":[-122.670671,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":16,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":6.469,\"turn_duration\":2.008,\"turn_weight\":2,\"duration\":5.732,\"location\":[-122.670443,45.634898],\"bearings\":[1,91,182,270],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":0.248,\"turn_weight\":0.75,\"weight\":1.048,\"location\":[-122.670058,45.634895],\"bearings\":[90,271],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":19,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.49,\"turn_weight\":0.75,\"weight\":2.538,\"location\":[-122.670028,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"location\":[-122.66988,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":21,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"distance\":0.0,\"duration\":0.0,\"geometry\":\"ysi`vAn{c~hF??\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.669512,45.634893],\"bearing_before\":90.0,\"bearing_after\":0.0,\"instruction\":\"You have arrived at your destination.\",\"type\":\"arrive\"},\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.669512,45.634893],\"bearings\":[270],\"entry\":[true],\"in\":0,\"geometry_index\":22,\"admin_index\":0}]}],\"annotation\":{\"distance\":[46.0,48.6,37.3,88.4,46.7,41.1,55.1,38.5,70.9,14.5,54.2,15.6,14.5,13.4,44.8,8.4,17.7,0.7,29.3,2.3,11.5,28.7],\"congestion_numeric\":[0,null,4,4,null,null,null,null,null,null,0,0,0,4,4,4,4,1,1,1,1,1]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6715815,45.6344615;-122.6716338,45.6364896;-122.6726954,45.6364085;-122.672707,45.6348712;-122.6695105,45.6350132\",\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,distance\",\"voice_instructions\":false,\"banner_instructions\":false,\"waypoints\":\"0;4\"},\"requestUuid\":\"mapmatching\"}" + //val route = DirectionsRoute.fromJson(routeJson).toNavigationRoute(RouterOrigin.Offboard) + val route = TestingUtil.loadNavigationRoute("short_route.json", "xyz") + val granularDistances = MapboxRouteLineUtils.granularDistancesProvider(route) + val vanishingRouteLine = VanishingRouteLine().also { + it.setScope(InternalJobControlFactory.createMainScopeJobControl().scope) + } + vanishingRouteLine.setGranularDistances(granularDistances!!) + + granularDistances.flatStepDistances.forEach { + vanishingRouteLine.trimTree(it.point) + } + } } diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt index 2e45b6379d6..ffb629574f0 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiRoboTest.kt @@ -329,221 +329,221 @@ class MapboxRouteLineApiRoboTest { ) } - @Test - fun updateTraveledRouteLine() = coroutineRule.runBlockingTest { - val options = MapboxRouteLineOptions.Builder(ctx) - .withVanishingRouteLineEnabled(true) - .displayRestrictedRoadSections(false) - .vanishingRouteLineUpdateInterval(0) - .build() - val api = MapboxRouteLineApi(options) - val expectedCasingExpression = "[literal, [0.0, 0.3240769449298392]]" - val expectedRouteExpression = "[literal, [0.0, 0.3240769449298392]]" - val expectedTrafficExpression = "[literal, [0.0, 0.3240769449298392]]" - val expectedRestrictedExpression = "[literal, [0.0, 0.3240769449298392]]" - val route = loadNavigationRoute("short_route.json") - val lineString = LineString.fromPolyline( - route.directionsRoute.geometry() ?: "", - Constants.PRECISION_6 - ) - val routeProgress = mockRouteProgress(route, stepIndexValue = 2) - - api.updateVanishingPointState(RouteProgressState.TRACKING) - api.setNavigationRoutes(listOf(route)) - api.updateUpcomingRoutePointIndex(routeProgress) - - val result = api.updateTraveledRouteLine(lineString.coordinates()[1]) - - assertEquals( - expectedCasingExpression, - result.value!!.primaryRouteLineDynamicData - .casingExpressionProvider.generateExpression().toString() - ) - assertEquals( - expectedRouteExpression, - result.value!!.primaryRouteLineDynamicData - .baseExpressionProvider.generateExpression().toString() - ) - assertEquals( - expectedTrafficExpression, - result.value!! - .primaryRouteLineDynamicData.trafficExpressionProvider!! - .generateExpression().toString() - ) - assertEquals( - expectedRestrictedExpression, - result.value!! - .primaryRouteLineDynamicData.restrictedSectionExpressionProvider!! - .generateExpression().toString() - ) - } - - @Test - fun updateTraveledRouteLine_pointUpdateIntervalRespected() = - coroutineRule.runBlockingTest { - val options = MapboxRouteLineOptions.Builder(ctx) - .withVanishingRouteLineEnabled(true) - .displayRestrictedRoadSections(false) - .vanishingRouteLineUpdateInterval(TimeUnit.MILLISECONDS.toNanos(1200)) - .build() - val api = MapboxRouteLineApi(options) - val route = loadNavigationRoute("short_route.json") - val lineString = LineString.fromPolyline( - route.directionsRoute.geometry() ?: "", - Constants.PRECISION_6 - ) - val routeProgress = mockRouteProgress(route, stepIndexValue = 2) - - api.updateVanishingPointState(RouteProgressState.TRACKING) - api.setNavigationRoutes(listOf(route)) - api.updateUpcomingRoutePointIndex(routeProgress) - - pauseDispatcher { - val result1 = api.updateTraveledRouteLine(lineString.coordinates()[1]) - assertTrue(result1.isValue) - - Thread.sleep(1000L) - api.updateUpcomingRoutePointIndex(routeProgress) // only update the progress - Thread.sleep(300L) // in summary we've waited for 1.3s since last point update - val result2 = api.updateTraveledRouteLine(lineString.coordinates()[1]) - assertTrue(result2.isValue) // should succeed because threshold was 1.2s - - Thread.sleep(500L) // wait less than threshold - val result3 = api.updateTraveledRouteLine(lineString.coordinates()[1]) - assertTrue(result3.isError) - } - } - - @Test - fun `updateTraveledRouteLine when route has restrictions and legs not styled independently`() = - coroutineRule.runBlockingTest { - val options = MapboxRouteLineOptions.Builder(ctx) - .withVanishingRouteLineEnabled(true) - .displayRestrictedRoadSections(true) - .vanishingRouteLineUpdateInterval(0) - .build() - val api = MapboxRouteLineApi(options) - val expectedRestrictedExpression = "[literal, [0.0, 0.05416168943228483]]" - val route = loadNavigationRoute("route-with-restrictions.json") - val lineString = LineString.fromPolyline( - route.directionsRoute.geometry() ?: "", - Constants.PRECISION_6 - ) - val routeProgress = mockRouteProgress(route, stepIndexValue = 2) - - api.updateVanishingPointState(RouteProgressState.TRACKING) - api.setNavigationRoutes(listOf(route)) - api.updateUpcomingRoutePointIndex(routeProgress) - - mockkObject(MapboxRouteLineUtils) - val result = api.updateTraveledRouteLine(lineString.coordinates()[1]) - - assertEquals( - expectedRestrictedExpression, - result.value!!.primaryRouteLineDynamicData.restrictedSectionExpressionProvider!! - .generateExpression().toString() - ) - - verify(exactly = 0) { - // the cache key is based on the full hash of the Directions Route - // and is not suited to be used as frequently as the vanishing route line needs it - MapboxRouteLineUtils.extractRouteData(any(), any()) - } - unmockkObject(MapboxRouteLineUtils) - } - - @Test - fun updateTraveledRouteLine_whenRouteRestrictionsEnabledButHasNone() = - coroutineRule.runBlockingTest { - val expectedCasingExpression = "[literal, [0.0, 0.3240769449298392]]" - val expectedRouteExpression = "[literal, [0.0, 0.3240769449298392]]" - val expectedTrafficExpression = "[literal, [0.0, 0.3240769449298392]]" - val restrictedTrafficExpression = "[literal, [0.0, 0.3240769449298392]]" - val options = MapboxRouteLineOptions.Builder(ctx) - .withVanishingRouteLineEnabled(true) - .displayRestrictedRoadSections(true) - .vanishingRouteLineUpdateInterval(0) - .build() - val api = MapboxRouteLineApi(options) - val route = loadNavigationRoute("short_route.json") - val lineString = LineString.fromPolyline( - route.directionsRoute.geometry() ?: "", - Constants.PRECISION_6 - ) - val routeProgress = mockRouteProgress(route, stepIndexValue = 2) - - api.updateVanishingPointState(RouteProgressState.TRACKING) - api.setNavigationRoutes(listOf(route)) - api.updateUpcomingRoutePointIndex(routeProgress) - - val result = api.updateTraveledRouteLine(lineString.coordinates()[1]) - - assertEquals( - expectedCasingExpression, - result.value!!.primaryRouteLineDynamicData - .casingExpressionProvider.generateExpression().toString() - ) - assertEquals( - expectedRouteExpression, - result.value!!.primaryRouteLineDynamicData - .baseExpressionProvider.generateExpression() - .toString() - ) - assertEquals( - expectedTrafficExpression, - result.value!! - .primaryRouteLineDynamicData.trafficExpressionProvider!! - .generateExpression().toString() - ) - assertEquals( - restrictedTrafficExpression, - result.value!! - .primaryRouteLineDynamicData.restrictedSectionExpressionProvider!! - .generateExpression().toString() - ) - } - - @Test - fun updateWithRouteProgress_whenDeEmphasizeInactiveLegSegments() = - coroutineRule.runBlockingTest { - val expectedTrafficExp = "[step, [line-progress], [rgba, 0.0, 0.0, 0.0, 0.0], 0.0, " + - "[rgba, 86.0, 168.0, 251.0, 1.0], 0.10373821458415478, " + - "[rgba, 255.0, 149.0, 0.0, 1.0], 0.1240124365711821, " + - "[rgba, 86.0, 168.0, 251.0, 1.0], 0.2718982903427929, " + - "[rgba, 255.0, 149.0, 0.0, 1.0], 0.32264099467350016, " + - "[rgba, 86.0, 168.0, 251.0, 1.0], 0.4897719974699625, [rgba, 0.0, 0.0, 0.0, 0.0]]" - val realOptions = MapboxRouteLineOptions.Builder(ctx) - .styleInactiveRouteLegsIndependently(true) - .build() - val route = loadNavigationRoute("multileg-route-two-legs.json") - val mockVanishingRouteLine = mockk(relaxUnitFun = true) { - every { vanishPointOffset } returns 0.0 - } - val options = mockk { - every { vanishingRouteLine } returns mockVanishingRouteLine - every { resourceProvider } returns realOptions.resourceProvider - every { - styleInactiveRouteLegsIndependently - } returns realOptions.styleInactiveRouteLegsIndependently - every { displayRestrictedRoadSections } returns false - every { displaySoftGradientForTraffic } returns false - every { softGradientTransition } returns 30.0 - every { routeStyleDescriptors } returns listOf() - } - val api = MapboxRouteLineApi(options) - val routeProgress = mockRouteProgress(route) - api.updateVanishingPointState(RouteProgressState.TRACKING) - api.setNavigationRoutes(listOf(route)) - api.updateWithRouteProgress(routeProgress) {} - - val result = api.setVanishingOffset(0.0).value!! - - assertEquals( - expectedTrafficExp, - result.primaryRouteLineDynamicData - .trafficExpressionProvider!!.generateExpression().toString() - ) - } + // @Test //todo is this relevant? + // fun updateTraveledRouteLine() = coroutineRule.runBlockingTest { + // val options = MapboxRouteLineOptions.Builder(ctx) + // .withVanishingRouteLineEnabled(true) + // .displayRestrictedRoadSections(false) + // .vanishingRouteLineUpdateInterval(0) + // .build() + // val api = MapboxRouteLineApi(options) + // val expectedCasingExpression = "[literal, [0.0, 0.3240769449298392]]" + // val expectedRouteExpression = "[literal, [0.0, 0.3240769449298392]]" + // val expectedTrafficExpression = "[literal, [0.0, 0.3240769449298392]]" + // val expectedRestrictedExpression = "[literal, [0.0, 0.3240769449298392]]" + // val route = loadNavigationRoute("short_route.json") + // val lineString = LineString.fromPolyline( + // route.directionsRoute.geometry() ?: "", + // Constants.PRECISION_6 + // ) + // val routeProgress = mockRouteProgress(route, stepIndexValue = 2) + // + // api.updateVanishingPointState(RouteProgressState.TRACKING) + // api.setNavigationRoutes(listOf(route)) + // api.updateUpcomingRoutePointIndex(routeProgress) + // + // val result = api.updateTraveledRouteLine(lineString.coordinates()[1]) + // + // assertEquals( + // expectedCasingExpression, + // result.value!!.primaryRouteLineDynamicData + // .casingExpressionProvider.generateExpression().toString() + // ) + // assertEquals( + // expectedRouteExpression, + // result.value!!.primaryRouteLineDynamicData + // .baseExpressionProvider.generateExpression().toString() + // ) + // assertEquals( + // expectedTrafficExpression, + // result.value!! + // .primaryRouteLineDynamicData.trafficExpressionProvider!! + // .generateExpression().toString() + // ) + // assertEquals( + // expectedRestrictedExpression, + // result.value!! + // .primaryRouteLineDynamicData.restrictedSectionExpressionProvider!! + // .generateExpression().toString() + // ) + // } + + // @Test //todo + // fun updateTraveledRouteLine_pointUpdateIntervalRespected() = + // coroutineRule.runBlockingTest { + // val options = MapboxRouteLineOptions.Builder(ctx) + // .withVanishingRouteLineEnabled(true) + // .displayRestrictedRoadSections(false) + // .vanishingRouteLineUpdateInterval(TimeUnit.MILLISECONDS.toNanos(1200)) + // .build() + // val api = MapboxRouteLineApi(options) + // val route = loadNavigationRoute("short_route.json") + // val lineString = LineString.fromPolyline( + // route.directionsRoute.geometry() ?: "", + // Constants.PRECISION_6 + // ) + // val routeProgress = mockRouteProgress(route, stepIndexValue = 2) + // + // api.updateVanishingPointState(RouteProgressState.TRACKING) + // api.setNavigationRoutes(listOf(route)) + // api.updateUpcomingRoutePointIndex(routeProgress) + // + // pauseDispatcher { + // val result1 = api.updateTraveledRouteLine(lineString.coordinates()[1]) + // assertTrue(result1.isValue) + // + // Thread.sleep(1000L) + // api.updateUpcomingRoutePointIndex(routeProgress) // only update the progress + // Thread.sleep(300L) // in summary we've waited for 1.3s since last point update + // val result2 = api.updateTraveledRouteLine(lineString.coordinates()[1]) + // assertTrue(result2.isValue) // should succeed because threshold was 1.2s + // + // Thread.sleep(500L) // wait less than threshold + // val result3 = api.updateTraveledRouteLine(lineString.coordinates()[1]) + // assertTrue(result3.isError) + // } + // } + + // @Test //todo + // fun `updateTraveledRouteLine when route has restrictions and legs not styled independently`() = + // coroutineRule.runBlockingTest { + // val options = MapboxRouteLineOptions.Builder(ctx) + // .withVanishingRouteLineEnabled(true) + // .displayRestrictedRoadSections(true) + // .vanishingRouteLineUpdateInterval(0) + // .build() + // val api = MapboxRouteLineApi(options) + // val expectedRestrictedExpression = "[literal, [0.0, 0.05416168943228483]]" + // val route = loadNavigationRoute("route-with-restrictions.json") + // val lineString = LineString.fromPolyline( + // route.directionsRoute.geometry() ?: "", + // Constants.PRECISION_6 + // ) + // val routeProgress = mockRouteProgress(route, stepIndexValue = 2) + // + // api.updateVanishingPointState(RouteProgressState.TRACKING) + // api.setNavigationRoutes(listOf(route)) + // api.updateUpcomingRoutePointIndex(routeProgress) + // + // mockkObject(MapboxRouteLineUtils) + // val result = api.updateTraveledRouteLine(lineString.coordinates()[1]) + // + // assertEquals( + // expectedRestrictedExpression, + // result.value!!.primaryRouteLineDynamicData.restrictedSectionExpressionProvider!! + // .generateExpression().toString() + // ) + // + // verify(exactly = 0) { + // // the cache key is based on the full hash of the Directions Route + // // and is not suited to be used as frequently as the vanishing route line needs it + // MapboxRouteLineUtils.extractRouteData(any(), any()) + // } + // unmockkObject(MapboxRouteLineUtils) + // } + + // @Test //todo is this relevant? + // fun updateTraveledRouteLine_whenRouteRestrictionsEnabledButHasNone() = + // coroutineRule.runBlockingTest { + // val expectedCasingExpression = "[literal, [0.0, 0.3240769449298392]]" + // val expectedRouteExpression = "[literal, [0.0, 0.3240769449298392]]" + // val expectedTrafficExpression = "[literal, [0.0, 0.3240769449298392]]" + // val restrictedTrafficExpression = "[literal, [0.0, 0.3240769449298392]]" + // val options = MapboxRouteLineOptions.Builder(ctx) + // .withVanishingRouteLineEnabled(true) + // .displayRestrictedRoadSections(true) + // .vanishingRouteLineUpdateInterval(0) + // .build() + // val api = MapboxRouteLineApi(options) + // val route = loadNavigationRoute("short_route.json") + // val lineString = LineString.fromPolyline( + // route.directionsRoute.geometry() ?: "", + // Constants.PRECISION_6 + // ) + // val routeProgress = mockRouteProgress(route, stepIndexValue = 2) + // + // api.updateVanishingPointState(RouteProgressState.TRACKING) + // api.setNavigationRoutes(listOf(route)) + // api.updateUpcomingRoutePointIndex(routeProgress) + // + // val result = api.updateTraveledRouteLine(lineString.coordinates()[1]) + // + // assertEquals( + // expectedCasingExpression, + // result.value!!.primaryRouteLineDynamicData + // .casingExpressionProvider.generateExpression().toString() + // ) + // assertEquals( + // expectedRouteExpression, + // result.value!!.primaryRouteLineDynamicData + // .baseExpressionProvider.generateExpression() + // .toString() + // ) + // assertEquals( + // expectedTrafficExpression, + // result.value!! + // .primaryRouteLineDynamicData.trafficExpressionProvider!! + // .generateExpression().toString() + // ) + // assertEquals( + // restrictedTrafficExpression, + // result.value!! + // .primaryRouteLineDynamicData.restrictedSectionExpressionProvider!! + // .generateExpression().toString() + // ) + // } + + // @Test //todo + // fun updateWithRouteProgress_whenDeEmphasizeInactiveLegSegments() = + // coroutineRule.runBlockingTest { + // val expectedTrafficExp = "[step, [line-progress], [rgba, 0.0, 0.0, 0.0, 0.0], 0.0, " + + // "[rgba, 86.0, 168.0, 251.0, 1.0], 0.10373821458415478, " + + // "[rgba, 255.0, 149.0, 0.0, 1.0], 0.1240124365711821, " + + // "[rgba, 86.0, 168.0, 251.0, 1.0], 0.2718982903427929, " + + // "[rgba, 255.0, 149.0, 0.0, 1.0], 0.32264099467350016, " + + // "[rgba, 86.0, 168.0, 251.0, 1.0], 0.4897719974699625, [rgba, 0.0, 0.0, 0.0, 0.0]]" + // val realOptions = MapboxRouteLineOptions.Builder(ctx) + // .styleInactiveRouteLegsIndependently(true) + // .build() + // val route = loadNavigationRoute("multileg-route-two-legs.json") + // val mockVanishingRouteLine = mockk(relaxUnitFun = true) { + // every { vanishPointOffset } returns 0.0 + // } + // val options = mockk { + // every { vanishingRouteLine } returns mockVanishingRouteLine + // every { resourceProvider } returns realOptions.resourceProvider + // every { + // styleInactiveRouteLegsIndependently + // } returns realOptions.styleInactiveRouteLegsIndependently + // every { displayRestrictedRoadSections } returns false + // every { displaySoftGradientForTraffic } returns false + // every { softGradientTransition } returns 30.0 + // every { routeStyleDescriptors } returns listOf() + // } + // val api = MapboxRouteLineApi(options) + // val routeProgress = mockRouteProgress(route) + // api.updateVanishingPointState(RouteProgressState.TRACKING) + // api.setNavigationRoutes(listOf(route)) + // api.updateWithRouteProgress(routeProgress) {} + // + // val result = api.setVanishingOffset(0.0).value!! + // + // assertEquals( + // expectedTrafficExp, + // result.primaryRouteLineDynamicData + // .trafficExpressionProvider!!.generateExpression().toString() + // ) + // } @Test fun highlightActiveLeg() = coroutineRule.runBlockingTest { diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiTest.kt index 16c599bc2c3..5e782dde744 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApiTest.kt @@ -151,7 +151,7 @@ class MapboxRouteLineApiTest { ) } - @Test + @Test //todo fun getVanishPointOffset() { val options = MapboxRouteLineOptions.Builder(ctx) .withVanishingRouteLineEnabled(true) diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLineTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLineTest.kt index 69ea971fa7e..89bdc6f6fa4 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLineTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLineTest.kt @@ -1,8 +1,13 @@ package com.mapbox.navigation.ui.maps.route.line.api +import com.mapbox.api.directions.v5.models.DirectionsRoute +import com.mapbox.navigation.base.route.RouterOrigin +import com.mapbox.navigation.base.route.toNavigationRoute import com.mapbox.navigation.base.trip.model.RouteProgressState import com.mapbox.navigation.testing.MainCoroutineRule +import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils import com.mapbox.navigation.ui.maps.route.line.model.VanishingPointState +import com.mapbox.navigation.ui.maps.testing.TestingUtil import com.mapbox.navigation.utils.internal.InternalJobControlFactory import com.mapbox.navigation.utils.internal.JobControl import io.mockk.every From 0088e4d0e50c4800239c548e690c9ea929788e04 Mon Sep 17 00:00:00 2001 From: Seth Bourget Date: Sat, 15 Oct 2022 18:59:12 -0700 Subject: [PATCH 4/7] wip code cleanup and fixes. --- .../maps/route/line/api/MapboxRouteLineApi.kt | 108 +++++++----------- .../maps/route/line/api/VanishingRouteLine.kt | 41 ++----- 2 files changed, 48 insertions(+), 101 deletions(-) diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt index 7afcb8bf234..838863eb398 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt @@ -1,6 +1,7 @@ package com.mapbox.navigation.ui.maps.route.line.api import android.graphics.Color +import android.util.Log import android.util.LruCache import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.api.directions.v5.models.RouteOptions @@ -438,52 +439,44 @@ class MapboxRouteLineApi( point: Point ): Expected { val currentNanoTime = System.nanoTime() - - //todo does the VanishingPointState matter anymore? - //todo is the nano time still needed? - - // if (routeLineOptions.vanishingRouteLine?.vanishingPointState == - // VanishingPointState.DISABLED || currentNanoTime - lastIndexUpdateTimeNano > - // RouteLayerConstants.MAX_ELAPSED_SINCE_INDEX_UPDATE_NANO || - // currentNanoTime - lastPointUpdateTimeNano < - // routeLineOptions.vanishingRouteLineUpdateIntervalNano - // ) { - // return ExpectedFactory.createError( - // RouteLineError( - // "Vanishing point state is disabled or the update doesn't fall" + - // "within the configured interval window.", - // null - // ) - // ) - // } + if ( + currentNanoTime - lastPointUpdateTimeNano < + routeLineOptions.vanishingRouteLineUpdateIntervalNano + ) { + return ExpectedFactory.createError( + RouteLineError( + "Vanishing point state is disabled or the update doesn't fall" + + "within the configured interval window.", + null + ) + ) + } val routeLineExpressionProviders = ifNonNull(primaryRoute) { route -> - val stopGap: Double = RouteLayerConstants.SOFT_GRADIENT_STOP_GAP_METERS / route.directionsRoute.distance() - ifNonNull(granularDistancesProvider(route)) { granularDistances -> - if (routeLineOptions.styleInactiveRouteLegsIndependently) { - val workingRouteLineExpressionData = - alternativelyStyleSegmentsNotInLeg(activeLegIndex, routeLineExpressionData) - - val restrictedExpressionData: List? = - if (routeLineOptions.displayRestrictedRoadSections && - MapboxRouteLineUtils.routeHasRestrictions(primaryRoute) - ) { - extractRouteRestrictionData(route) - } else { - null - } - routeLineOptions.vanishingRouteLine?.getTraveledRouteLineExpressions( - point, - workingRouteLineExpressionData, - restrictedExpressionData, - routeLineOptions.resourceProvider, - activeLegIndex, - stopGap, - routeLineOptions.displaySoftGradientForTraffic, - ) - } else { - routeLineOptions.vanishingRouteLine?.getTraveledRouteLineExpressions(point) - } + if (routeLineOptions.styleInactiveRouteLegsIndependently) { + val stopGap: Double = + RouteLayerConstants.SOFT_GRADIENT_STOP_GAP_METERS / route.directionsRoute.distance() + val workingRouteLineExpressionData = + alternativelyStyleSegmentsNotInLeg(activeLegIndex, routeLineExpressionData) + val restrictedExpressionData: List? = + if (routeLineOptions.displayRestrictedRoadSections && + MapboxRouteLineUtils.routeHasRestrictions(primaryRoute) + ) { + extractRouteRestrictionData(route) + } else { + null + } + routeLineOptions.vanishingRouteLine?.getTraveledRouteLineExpressions( + point, + workingRouteLineExpressionData, + restrictedExpressionData, + routeLineOptions.resourceProvider, + activeLegIndex, + stopGap, + routeLineOptions.displaySoftGradientForTraffic, + ) + } else { + routeLineOptions.vanishingRouteLine?.getTraveledRouteLineExpressions(point) } } @@ -679,6 +672,7 @@ class MapboxRouteLineApi( } } + // todo adjust doc /** * Updates the state of the route line based on data in the [RouteProgress] passing a result * to the consumer that should be rendered by the [MapboxRouteLineView]. @@ -697,28 +691,6 @@ class MapboxRouteLineApi( routeProgress: RouteProgress, consumer: MapboxNavigationConsumer> ) { - // val currentPrimaryRoute = primaryRoute - // if (currentPrimaryRoute == null) { - // val msg = "You're calling #updateWithRouteProgress without any routes being set." - // consumer.accept( - // ExpectedFactory.createError(RouteLineError(msg, throwable = null)) - // ) - // logW(msg, LOG_CATEGORY) - // return - // } else if (currentPrimaryRoute.id != routeProgress.navigationRoute.id) { - // val msg = "Provided primary route (#setNavigationRoutes, ID: " + - // "${currentPrimaryRoute.id}) and navigated route (#updateWithRouteProgress, ID: " + - // "${routeProgress.navigationRoute.id}) are not the same. Aborting the update." - // consumer.accept( - // ExpectedFactory.createError(RouteLineError(msg, throwable = null)) - // ) - // logE(msg, LOG_CATEGORY) - // return - // } - // - // updateUpcomingRoutePointIndex(routeProgress) - // updateVanishingPointState(routeProgress.currentState) - // If the de-emphasize inactive route legs feature is enabled and the vanishing route line // feature is enabled and the active leg index has changed, then calling the // alternativelyStyleSegmentsNotInLeg() method here will get the resulting calculation cached so @@ -751,11 +723,11 @@ class MapboxRouteLineApi( } fun updateUpcomingRoutePointIndex(routeProgress: RouteProgress) { - // del me + // todo del me } fun updateVanishingPointState(state: RouteProgressState) { - // del me + // todo del me } /** diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt index 56d0ff60676..3829a75526a 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt @@ -24,6 +24,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.util.concurrent.CopyOnWriteArrayList +// todo adjust doc /** * This class implements a feature that can change the appearance of the route line behind the puck. * The route line behind the puck can be configured to be transparent or a specified color and @@ -179,20 +180,14 @@ internal class VanishingRouteLine { fun setGranularDistances(distances: RouteLineGranularDistances) { if (distances != granularDistances) { granularDistances = distances - stepsPoints = - granularDistances!!.stepsDistances.flatten() // todo test for multileg routes + stepsPoints = distances.stepsDistances.flatten() locationSearchTree.clear() fillerPointsInTree.clear() indexOfLastStepPointsLoadedInTree = 0 vanishPointOffset = 0.0 - Log.e("foobar", "everything got cleared, starting fresh") - // if (stepsPoints.isNotEmpty()) { - // val firstSteps = stepsPoints.first() - // val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(firstSteps) - // locationSearchTree.addAll(fillerPoints) - // fillerPointsInTree.add(fillerPoints) - // } + // todo remove logging + Log.e("foobar", "everything got cleared, starting fresh") if (distances.flatStepDistances.isNotEmpty()) { val endRange = if (distances.flatStepDistances.size > stepPointRangeSize) { @@ -222,6 +217,7 @@ internal class VanishingRouteLine { if (distanceBetweenPoints <= ROUTE_LINE_UPDATE_MAX_DISTANCE_THRESHOLD_IN_METERS ) { (1.0 - closestPoint.distanceRemaining / distances.completeDistance) } else { + // todo remove logging Log.e("foobar", "distance of $distanceBetweenPoints beyond distance threshold") Log.e("foobar", "incoming point $point nearest neighbor ${closestPoint.point}") null @@ -233,7 +229,7 @@ internal class VanishingRouteLine { //todo make private fun trimTree(point: Point) { - //if getting close to the last step point, load the points for the next step + //if getting close to the last step point, load the points for the next step range //and remove the points long since passed. scope?.launch(Dispatchers.Main.immediate) { val trimStart = System.currentTimeMillis() @@ -258,34 +254,13 @@ internal class VanishingRouteLine { } if (fillerPointsInTree.size == maxAllowedFillerPointListsInTree) { val pointsToDrop = fillerPointsInTree.removeFirst() - val startRemove = System.currentTimeMillis() locationSearchTree.removeAll(pointsToDrop) - Log.e("foobar", "time to remove ${pointsToDrop.size} is ${System.currentTimeMillis() - startRemove}") } - - - - // if (indexOfLastStepPointsLoadedInTree + 1 < stepsPoints.size) { - // val nextSteps = stepsPoints[indexOfLastStepPointsLoadedInTree + 1] - // val fillerPoints = MapboxRouteLineUtils.getFillerPointsForStepPoints(nextSteps) - // - // val startAdd = System.currentTimeMillis() - // locationSearchTree.addAll(fillerPoints) - // Log.e("foobar", "time to add ${fillerPoints.size} is ${System.currentTimeMillis() - startAdd}") - // - // fillerPointsInTree.add(fillerPoints) - // indexOfLastStepPointsLoadedInTree++ - // if (fillerPointsInTree.size == 3) { - // val pointsToDrop = fillerPointsInTree.removeFirst() - // val startRemove = System.currentTimeMillis() - // locationSearchTree.removeAll(pointsToDrop) - // Log.e("foobar", "time to remove ${pointsToDrop.size} is ${System.currentTimeMillis() - startRemove}") - // } - // } } } val trimTotal = System.currentTimeMillis() - trimStart - if (trimTotal > 5) { + if (trimTotal > 10) { + // todo remove logging Log.e("foobar", "time to trim tree is ${System.currentTimeMillis() - trimStart}") } From 069ccc81205105271549aff07602456a0498c3ad Mon Sep 17 00:00:00 2001 From: Seth Bourget Date: Mon, 17 Oct 2022 17:10:42 -0700 Subject: [PATCH 5/7] fix to recalculate the step point range. --- .../maps/route/line/api/VanishingRouteLine.kt | 76 +++++++++++++------ .../line/MapboxRouteLineUtilsRoboTest.kt | 48 ++++++++++-- .../view/AlternativeRouteActivity.kt | 42 +++++++++- 3 files changed, 137 insertions(+), 29 deletions(-) diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt index 3829a75526a..766a0f9f1f5 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt @@ -178,27 +178,29 @@ internal class VanishingRouteLine { private val maxAllowedFillerPointListsInTree = 3 fun setGranularDistances(distances: RouteLineGranularDistances) { - if (distances != granularDistances) { - granularDistances = distances - stepsPoints = distances.stepsDistances.flatten() - locationSearchTree.clear() - fillerPointsInTree.clear() - indexOfLastStepPointsLoadedInTree = 0 - vanishPointOffset = 0.0 + scope?.launch(Dispatchers.Main.immediate) { + if (distances != granularDistances) { + granularDistances = distances + stepsPoints = distances.stepsDistances.flatten() + locationSearchTree.clear() + fillerPointsInTree.clear() + indexOfLastStepPointsLoadedInTree = 0 + vanishPointOffset = 0.0 - // todo remove logging - Log.e("foobar", "everything got cleared, starting fresh") + // todo remove logging + Log.e("foobar", "everything got cleared, starting fresh") - if (distances.flatStepDistances.isNotEmpty()) { - val endRange = if (distances.flatStepDistances.size > stepPointRangeSize) { - stepPointRangeSize - } else { - distances.flatStepDistances.lastIndex - } - stepPointRange = Range(0, endRange).also { - val fillerPoints = getFillerPointsForRange(it, distances.flatStepDistances) - locationSearchTree.addAll(fillerPoints) - fillerPointsInTree.add(fillerPoints) + if (distances.flatStepDistances.isNotEmpty()) { + val endRange = if (distances.flatStepDistances.size > stepPointRangeSize) { + stepPointRangeSize + } else { + distances.flatStepDistances.lastIndex + } + stepPointRange = Range(0, endRange).also { + val fillerPoints = getFillerPointsForRange(it, distances.flatStepDistances) + locationSearchTree.addAll(fillerPoints) + fillerPointsInTree.add(fillerPoints) + } } } } @@ -213,13 +215,16 @@ internal class VanishingRouteLine { fun getOffset(point: Point): Double? { val offset = ifNonNull(locationSearchTree.getNearestNeighbor(point), granularDistances) { closestPoint, distances -> - val distanceBetweenPoints = TurfMeasurement.distance(point, closestPoint.point) + val distanceBetweenPoints = TurfMeasurement.distance(point, closestPoint.point, TurfConstants.UNIT_METERS) if (distanceBetweenPoints <= ROUTE_LINE_UPDATE_MAX_DISTANCE_THRESHOLD_IN_METERS ) { (1.0 - closestPoint.distanceRemaining / distances.completeDistance) } else { // todo remove logging - Log.e("foobar", "distance of $distanceBetweenPoints beyond distance threshold") - Log.e("foobar", "incoming point $point nearest neighbor ${closestPoint.point}") + //Log.e("foobar", "distance of $distanceBetweenPoints beyond distance threshold") + //Log.e("foobar", "incoming point $point nearest neighbor ${closestPoint.point}") + if (distanceBetweenPoints >= distanceToLastStepPointInMeters) { + recalculateRange(point) + } null } } @@ -227,6 +232,33 @@ internal class VanishingRouteLine { return offset } + fun recalculateRange(point: Point) { + scope?.launch(Dispatchers.Main.immediate) { + ifNonNull(granularDistances) { distances -> + val indexOfClosestStepPoint = distances.flatStepDistances.mapIndexed { index, routeLineDistancesIndex -> + val dist = TurfMeasurement.distance(point, routeLineDistancesIndex.point, TurfConstants.UNIT_METERS) + Pair(index, dist) + }.minByOrNull { it.second } + ifNonNull(indexOfClosestStepPoint) { + val endOfRange = if (it.first + stepPointRangeSize < distances.flatStepDistances.lastIndex) { + it.first + stepPointRangeSize + } else { + distances.flatStepDistances.lastIndex + } + stepPointRange = Range(it.first - 1, endOfRange).also { range -> + val fillerPoints = getFillerPointsForRange(range, distances.flatStepDistances) + if (fillerPoints.isNotEmpty()) { + locationSearchTree.clear() + locationSearchTree.addAll(fillerPoints) + fillerPointsInTree.clear() + fillerPointsInTree.add(fillerPoints) + } + } + } + } + } + } + //todo make private fun trimTree(point: Point) { //if getting close to the last step point, load the points for the next step range diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt index e9de6c05bf9..3b6d5059753 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt @@ -1210,17 +1210,55 @@ class MapboxRouteLineUtilsRoboTest { @Test fun scratch() { - val routeJson = "{\"routeIndex\":\"0\",\"distance\":728.195,\"duration\":178.495,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@YEnd@I|_@|]HrTJxf@B~FgAPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"weight\":241.413,\"weight_name\":\"auto\",\"legs\":[{\"weight\":241.413,\"via_waypoints\":[],\"distance\":728.195,\"duration\":178.495,\"summary\":\"Main Street, West McLoughlin Boulevard\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"distance\":220.325,\"duration\":29.108,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@Y\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.634461],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"driving_side\":\"right\",\"weight\":35.461,\"intersections\":[{\"duration\":7.5,\"weight\":9,\"location\":[-122.671531,45.634461],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.719,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.94,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"distance\":87.726,\"duration\":31.082,\"geometry\":\"otl`vAlwg~hFEnd@I|_@\",\"name\":\"West 20th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671495,45.63644],\"bearing_before\":1.0,\"bearing_after\":270.0,\"instruction\":\"Turn left onto West 20th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":45.681,\"intersections\":[{\"duration\":19.722,\"turn_weight\":12.5,\"turn_duration\":5.622,\"weight\":29.773,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.007,\"location\":[-122.672095,45.636443],\"bearings\":[1,90,182,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":179.057,\"duration\":68.349,\"geometry\":\"_ul`vAz}i~hF|]HrTJxf@B~FgA\",\"name\":\"Washington Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672622,45.636448],\"bearing_before\":271.0,\"bearing_after\":180.0,\"instruction\":\"Turn left onto Washington Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":88.24,\"intersections\":[{\"duration\":30.372,\"turn_weight\":10,\"turn_duration\":5.622,\"weight\":39.7,\"location\":[-122.672622,45.636448],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":2,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"duration\":17.558,\"turn_weight\":1,\"turn_duration\":0.008,\"weight\":22.06,\"location\":[-122.672627,45.635953],\"bearings\":[0,92,181],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.019,\"location\":[-122.672633,45.635607],\"bearings\":[1,92,180,270],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":241.086,\"duration\":49.955,\"geometry\":\"spi`vAl|i~hFPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672599,45.634842],\"bearing_before\":169.0,\"bearing_after\":91.0,\"instruction\":\"Turn left onto West McLoughlin Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":72.031,\"intersections\":[{\"duration\":22.522,\"turn_weight\":12.5,\"turn_duration\":3.622,\"weight\":35.18,\"location\":[-122.672599,45.634842],\"bearings\":[91,182,270,349],\"entry\":[true,true,true,false],\"in\":3,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":14.931,\"turn_duration\":2.008,\"turn_weight\":3,\"duration\":11.951,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,182,259],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":1.371,\"turn_weight\":0.75,\"weight\":2.396,\"location\":[-122.670778,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.086,\"turn_weight\":0.75,\"weight\":4.453,\"location\":[-122.670671,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":16,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":6.469,\"turn_duration\":2.008,\"turn_weight\":2,\"duration\":5.732,\"location\":[-122.670443,45.634898],\"bearings\":[1,91,182,270],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":0.248,\"turn_weight\":0.75,\"weight\":1.048,\"location\":[-122.670058,45.634895],\"bearings\":[90,271],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":19,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.49,\"turn_weight\":0.75,\"weight\":2.538,\"location\":[-122.670028,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"location\":[-122.66988,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":21,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"distance\":0.0,\"duration\":0.0,\"geometry\":\"ysi`vAn{c~hF??\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.669512,45.634893],\"bearing_before\":90.0,\"bearing_after\":0.0,\"instruction\":\"You have arrived at your destination.\",\"type\":\"arrive\"},\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.669512,45.634893],\"bearings\":[270],\"entry\":[true],\"in\":0,\"geometry_index\":22,\"admin_index\":0}]}],\"annotation\":{\"distance\":[46.0,48.6,37.3,88.4,46.7,41.1,55.1,38.5,70.9,14.5,54.2,15.6,14.5,13.4,44.8,8.4,17.7,0.7,29.3,2.3,11.5,28.7],\"congestion_numeric\":[0,null,4,4,null,null,null,null,null,null,0,0,0,4,4,4,4,1,1,1,1,1]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6715815,45.6344615;-122.6716338,45.6364896;-122.6726954,45.6364085;-122.672707,45.6348712;-122.6695105,45.6350132\",\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,distance\",\"voice_instructions\":false,\"banner_instructions\":false,\"waypoints\":\"0;4\"},\"requestUuid\":\"mapmatching\"}" - //val route = DirectionsRoute.fromJson(routeJson).toNavigationRoute(RouterOrigin.Offboard) - val route = TestingUtil.loadNavigationRoute("short_route.json", "xyz") + val routeJson = "{\"country_crossed\":false,\"weight_typical\":305.822,\"routeIndex\":\"1\",\"distance\":1752.465,\"duration\":225.213,\"duration_typical\":225.213,\"geometry\":\"axh`vAtyg~hFqYQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DAcEq@mIwD_Bs@oCoA}FaCkCiAuD{AsB{@yCmAoQiHsGiCcFsBmDuAkBu@yVaJ}EaBwOiFiCgAkFyBuJ_E}ViKiWgKwUoJ}UqJuUmJoHgC{OsFiDmACA{CgA_EuAmC}@_@fFEfN?j@Oz|@CdLCfN?tA?zwAIp^Opq@?tDCrDg@zoAC`R\",\"weight\":305.822,\"weight_name\":\"auto\",\"legs\":[{\"weight_typical\":305.822,\"weight\":305.822,\"via_waypoints\":[],\"distance\":1752.465,\"duration\":225.213,\"duration_typical\":225.213,\"summary\":\"Main Street, East 33rd Street\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"weight_typical\":212.389,\"distance\":1255.235,\"duration\":157.679,\"duration_typical\":157.679,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"axh`vAtyg~hFqYQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DAcEq@mIwD_Bs@oCoA}FaCkCiAuD{AsB{@yCmAoQiHsGiCcFsBmDuAkBu@yVaJ}EaBwOiFiCgAkFyBuJ_E}ViKiWgKwUoJ}UqJuUmJoHgC{OsFiDmACA{CgA_EuAmC}@\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.634449],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":1255.235,\"announcement\":\"Drive north on Main Street for 1 mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eDrive north on \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eMain Street\\u003c/say-as\\u003e for 1 mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto East 33rd Street.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eEast 33rd Street\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":85.333,\"announcement\":\"Turn left onto East 33rd Street.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eEast 33rd Street\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":1255.235,\"primary\":{\"text\":\"East 33rd Street\",\"components\":[{\"text\":\"East 33rd Street\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"East 33rd Street\",\"components\":[{\"text\":\"East 33rd Street\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":true,\"active_direction\":\"left\"},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\",\"right\"],\"active\":false}]}}],\"driving_side\":\"right\",\"weight\":212.389,\"intersections\":[{\"duration\":7.364,\"weight\":8.836,\"location\":[-122.671531,45.634449],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.937,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.201,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":9.337,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":12.181,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":4.274,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":6.212,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.746,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.841,\"location\":[-122.671487,45.63679],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.728,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.044,\"location\":[-122.671483,45.637018],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.874,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.998,\"location\":[-122.671477,45.637323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.965,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.108,\"location\":[-122.671473,45.637532],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":2.999,\"turn_duration\":2.019,\"turn_weight\":0.5,\"duration\":4.059,\"location\":[-122.67147,45.63769],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":2.779,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.881,\"location\":[-122.671468,45.63784],\"bearings\":[1,181,267],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":12,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":4.005,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.882,\"location\":[-122.671464,45.638047],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.819,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":8.83,\"location\":[-122.671459,45.638323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":14,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":9.662,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":12.812,\"location\":[-122.67145,45.638782],\"bearings\":[1,75,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.659,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":4.234,\"location\":[-122.671438,45.63946],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":11.009,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":14.462,\"location\":[-122.671435,45.639654],\"bearings\":[1,90,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":18,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":17.19,\"turn_duration\":2.017,\"turn_weight\":2,\"duration\":14.417,\"location\":[-122.671427,45.640173],\"bearings\":[15,90,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"right\"]}],\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":2.4,\"turn_weight\":0.5,\"weight\":3.44,\"location\":[-122.67131,45.640438],\"bearings\":[21,201],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":22,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.607,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":4.91,\"location\":[-122.671284,45.640486],\"bearings\":[21,201,258],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":23,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.019,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":2.95,\"location\":[-122.671244,45.640558],\"bearings\":[20,201,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":24,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.067,\"turn_weight\":0.5,\"weight\":1.807,\"location\":[-122.671179,45.640685],\"bearings\":[20,200],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":25,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":2.835,\"turn_duration\":0.007,\"turn_weight\":0.5,\"duration\":1.913,\"location\":[-122.671142,45.640755],\"bearings\":[20,111,200],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":26,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":6.106,\"turn_duration\":0.021,\"turn_weight\":1,\"duration\":4.189,\"location\":[-122.671066,45.640904],\"bearings\":[19,101,200,283],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":28,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.535,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":2.357,\"location\":[-122.670878,45.641277],\"bearings\":[19,108,199],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":30,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.177,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":1.933,\"location\":[-122.670809,45.641415],\"bearings\":[20,108,199],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":31,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":1.602,\"turn_duration\":0.021,\"turn_weight\":0.5,\"duration\":0.921,\"location\":[-122.670751,45.641529],\"bearings\":[19,90,200],\"entry\":[true,false,false],\"in\":2,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":32,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":1.101,\"turn_duration\":0.019,\"turn_weight\":0.5,\"duration\":0.51,\"location\":[-122.670708,45.641616],\"bearings\":[19,76,199],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":33,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":4.722,\"turn_duration\":0.019,\"turn_weight\":0.5,\"duration\":3.466,\"location\":[-122.670681,45.64167],\"bearings\":[18,199,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\"]}],\"geometry_index\":34,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.084,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":1.803,\"location\":[-122.670504,45.642051],\"bearings\":[17,198,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":35,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.536,\"turn_weight\":0.5,\"weight\":3.607,\"location\":[-122.670455,45.642162],\"bearings\":[17,197],\"entry\":[true,false],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\"]}],\"geometry_index\":36,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":3.609,\"turn_duration\":0.008,\"turn_weight\":1.5,\"duration\":1.73,\"location\":[-122.670338,45.64243],\"bearings\":[20,92,173,197,270],\"entry\":[true,true,false,false,true],\"in\":3,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\"]}],\"geometry_index\":37,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.722,\"turn_weight\":0.5,\"weight\":2.609,\"location\":[-122.670241,45.642617],\"bearings\":[20,200],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":39,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.247,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":4.469,\"location\":[-122.670145,45.642804],\"bearings\":[20,200,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":40,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.268,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":4.478,\"location\":[-122.669948,45.643187],\"bearings\":[19,200,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":41,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.996,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.147,\"location\":[-122.669752,45.643576],\"bearings\":[19,199,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":42,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.115,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.293,\"location\":[-122.669568,45.64394],\"bearings\":[19,199,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":43,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.244,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.451,\"location\":[-122.669383,45.644307],\"bearings\":[19,199,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":44,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.528,\"turn_weight\":1,\"turn_duration\":0.021,\"weight\":2.846,\"location\":[-122.6692,45.64467],\"bearings\":[17,99,199,277],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":45,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.686,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":3.782,\"location\":[-122.669132,45.644822],\"bearings\":[18,197,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":46,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.733,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":2.6,\"location\":[-122.66901,45.645092],\"bearings\":[18,198,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":47,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.543,\"turn_weight\":0.5,\"weight\":2.39,\"location\":[-122.668971,45.645177],\"bearings\":[18,198],\"entry\":[true,false],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":48,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":0.5,\"location\":[-122.668934,45.645257],\"bearings\":[17,198],\"entry\":[true,false],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":50,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":93.433,\"distance\":497.229,\"duration\":67.534,\"duration_typical\":67.534,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"_f~`vAvrb~hF_@fFEfN?j@Oz|@CdLCfN?tA?zwAIp^Opq@?tDCrDg@zoAC`R\",\"name\":\"East 33rd Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.66886,45.645424],\"bearing_before\":17.0,\"bearing_after\":275.0,\"instruction\":\"Turn left onto East 33rd Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":483.896,\"announcement\":\"In a quarter mile, Your destination will be on the right.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Your destination will be on the right.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":55.556,\"announcement\":\"Your destination is on the right.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eYour destination is on the right.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":497.229,\"primary\":{\"text\":\"Your destination will be on the right\",\"components\":[{\"text\":\"Your destination will be on the right\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"right\"}},{\"distanceAlongGeometry\":55.556,\"primary\":{\"text\":\"Your destination is on the right\",\"components\":[{\"text\":\"Your destination is on the right\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"right\"}}],\"driving_side\":\"right\",\"weight\":93.433,\"intersections\":[{\"weight\":19.562,\"turn_duration\":8.501,\"turn_weight\":15,\"duration\":12.225,\"location\":[-122.66886,45.645424],\"bearings\":[15,103,197,275],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":52,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":9.559,\"turn_weight\":0.75,\"weight\":12.459,\"location\":[-122.669242,45.645443],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":55,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.426,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":2.471,\"location\":[-122.670232,45.645451],\"bearings\":[0,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":56,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.689,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":2.794,\"location\":[-122.670443,45.645453],\"bearings\":[0,91,271],\"entry\":[false,false,true],\"in\":1,\"out\":2,\"geometry_index\":57,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.284,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":1.073,\"location\":[-122.670687,45.645455],\"bearings\":[91,182,270],\"entry\":[false,false,true],\"in\":0,\"out\":2,\"geometry_index\":58,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":9.746,\"turn_weight\":0.75,\"weight\":12.689,\"location\":[-122.67073,45.645455],\"bearings\":[90,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":59,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":15.703,\"turn_weight\":1.5,\"turn_duration\":0.007,\"weight\":20.728,\"location\":[-122.672152,45.645455],\"bearings\":[1,90,180,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":60,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":17.876,\"turn_duration\":2.021,\"turn_weight\":2,\"duration\":14.981,\"location\":[-122.673557,45.645468],\"bearings\":[0,91,182,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":63,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"turn_weight\":1.5,\"turn_duration\":0.021,\"location\":[-122.674941,45.64549],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":65,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"weight_typical\":0,\"distance\":0.0,\"duration\":0.0,\"duration_typical\":0.0,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"gj~`vAzao~hF??\",\"name\":\"East 33rd Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.675246,45.645492],\"bearing_before\":270.0,\"bearing_after\":0.0,\"instruction\":\"Your destination is on the right.\",\"type\":\"arrive\",\"modifier\":\"right\"},\"voiceInstructions\":[],\"bannerInstructions\":[],\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.675246,45.645492],\"bearings\":[90],\"entry\":[true],\"in\":0,\"geometry_index\":66,\"admin_index\":0}]}],\"annotation\":{\"distance\":[47.3,48.7,37.3,88.4,38.9,25.4,34.0,23.2,9.7,7.9,7.8,8.9,23.1,30.7,51.1,10.8,64.7,21.6,48.9,8.9,11.0,20.0,5.7,8.6,15.0,8.3,10.7,6.9,9.1,34.9,16.3,13.5,10.2,6.4,44.6,12.9,31.2,8.2,14.0,22.1,45.3,45.9,43.0,43.3,42.8,17.8,31.5,9.9,0.2,9.2,11.2,8.2,9.2,19.0,1.7,77.1,16.4,19.0,3.3,110.7,39.3,63.0,7.1,7.0,100.7,23.8],\"duration\":[7.364,8.552,3.937,9.337,4.274,2.746,3.728,2.874,1.641,1.324,2.971,1.088,2.779,4.005,6.819,1.399,8.263,2.659,9.315,1.694,6.449,7.968,2.4,3.607,2.019,1.067,1.17,0.743,0.882,3.307,1.535,1.177,0.921,0.51,3.466,1.084,2.536,0.644,1.086,1.722,3.247,3.268,2.996,3.115,3.244,1.528,2.686,1.733,0.039,1.504,1.874,1.383,9.647,2.365,0.213,9.559,1.426,1.689,0.284,9.746,5.649,9.038,1.017,2.864,12.117,1.922],\"speed\":[6.4,7.4,9.5,9.5,9.2,9.3,9.2,8.1,6.0,6.0,8.2,8.2,8.3,7.7,7.5,7.8,7.8,8.2,5.3,5.3,2.5,2.5,2.4,2.4,7.5,7.8,9.2,9.2,10.6,10.6,10.7,11.5,11.4,13.0,12.9,12.2,12.3,12.9,12.9,12.8,14.0,14.1,14.4,14.0,13.3,11.8,11.8,5.8,6.1,6.1,6.0,6.0,8.0,8.0,8.0,8.1,11.7,11.4,12.7,11.4,7.0,7.0,7.0,8.3,8.3,12.5],\"maxspeed\":[{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"}],\"congestion_numeric\":[0,24,9,4,4,0,0,null,6,6,0,0,null,null,0,0,0,11,0,0,null,null,null,null,null,null,null,null,6,6,null,null,null,null,8,1,1,1,1,1,0,0,0,0,1,6,6,0,0,0,0,0,20,20,20,20,null,0,0,0,0,0,0,8,8,6]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6717523,45.6344513;-122.6752454,45.6455678\",\"alternatives\":true,\"language\":\"en\",\"layers\":\";\",\"continue_straight\":true,\"roundabout_exits\":true,\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,maxspeed,closure,speed,duration,distance\",\"voice_instructions\":true,\"banner_instructions\":true,\"voice_units\":\"imperial\",\"enable_refresh\":true},\"voiceLocale\":\"en-US\",\"requestUuid\":\"PuEXN4U6XkX5NOGg6UssKTN-Ipon4nZF7dok-zNkwT-ney88PBFDqA\\u003d\\u003d\"}" + //val routeJson = "{\"routeIndex\":\"0\",\"distance\":728.195,\"duration\":178.495,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@YEnd@I|_@|]HrTJxf@B~FgAPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"weight\":241.413,\"weight_name\":\"auto\",\"legs\":[{\"weight\":241.413,\"via_waypoints\":[],\"distance\":728.195,\"duration\":178.495,\"summary\":\"Main Street, West McLoughlin Boulevard\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"distance\":220.325,\"duration\":29.108,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@Y\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.634461],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"driving_side\":\"right\",\"weight\":35.461,\"intersections\":[{\"duration\":7.5,\"weight\":9,\"location\":[-122.671531,45.634461],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.719,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.94,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"distance\":87.726,\"duration\":31.082,\"geometry\":\"otl`vAlwg~hFEnd@I|_@\",\"name\":\"West 20th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671495,45.63644],\"bearing_before\":1.0,\"bearing_after\":270.0,\"instruction\":\"Turn left onto West 20th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":45.681,\"intersections\":[{\"duration\":19.722,\"turn_weight\":12.5,\"turn_duration\":5.622,\"weight\":29.773,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.007,\"location\":[-122.672095,45.636443],\"bearings\":[1,90,182,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":179.057,\"duration\":68.349,\"geometry\":\"_ul`vAz}i~hF|]HrTJxf@B~FgA\",\"name\":\"Washington Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672622,45.636448],\"bearing_before\":271.0,\"bearing_after\":180.0,\"instruction\":\"Turn left onto Washington Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":88.24,\"intersections\":[{\"duration\":30.372,\"turn_weight\":10,\"turn_duration\":5.622,\"weight\":39.7,\"location\":[-122.672622,45.636448],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":2,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"duration\":17.558,\"turn_weight\":1,\"turn_duration\":0.008,\"weight\":22.06,\"location\":[-122.672627,45.635953],\"bearings\":[0,92,181],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.019,\"location\":[-122.672633,45.635607],\"bearings\":[1,92,180,270],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":241.086,\"duration\":49.955,\"geometry\":\"spi`vAl|i~hFPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672599,45.634842],\"bearing_before\":169.0,\"bearing_after\":91.0,\"instruction\":\"Turn left onto West McLoughlin Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":72.031,\"intersections\":[{\"duration\":22.522,\"turn_weight\":12.5,\"turn_duration\":3.622,\"weight\":35.18,\"location\":[-122.672599,45.634842],\"bearings\":[91,182,270,349],\"entry\":[true,true,true,false],\"in\":3,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":14.931,\"turn_duration\":2.008,\"turn_weight\":3,\"duration\":11.951,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,182,259],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":1.371,\"turn_weight\":0.75,\"weight\":2.396,\"location\":[-122.670778,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.086,\"turn_weight\":0.75,\"weight\":4.453,\"location\":[-122.670671,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":16,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":6.469,\"turn_duration\":2.008,\"turn_weight\":2,\"duration\":5.732,\"location\":[-122.670443,45.634898],\"bearings\":[1,91,182,270],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":0.248,\"turn_weight\":0.75,\"weight\":1.048,\"location\":[-122.670058,45.634895],\"bearings\":[90,271],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":19,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.49,\"turn_weight\":0.75,\"weight\":2.538,\"location\":[-122.670028,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"location\":[-122.66988,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":21,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"distance\":0.0,\"duration\":0.0,\"geometry\":\"ysi`vAn{c~hF??\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.669512,45.634893],\"bearing_before\":90.0,\"bearing_after\":0.0,\"instruction\":\"You have arrived at your destination.\",\"type\":\"arrive\"},\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.669512,45.634893],\"bearings\":[270],\"entry\":[true],\"in\":0,\"geometry_index\":22,\"admin_index\":0}]}],\"annotation\":{\"distance\":[46.0,48.6,37.3,88.4,46.7,41.1,55.1,38.5,70.9,14.5,54.2,15.6,14.5,13.4,44.8,8.4,17.7,0.7,29.3,2.3,11.5,28.7],\"congestion_numeric\":[0,null,4,4,null,null,null,null,null,null,0,0,0,4,4,4,4,1,1,1,1,1]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6715815,45.6344615;-122.6716338,45.6364896;-122.6726954,45.6364085;-122.672707,45.6348712;-122.6695105,45.6350132\",\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,distance\",\"voice_instructions\":false,\"banner_instructions\":false,\"waypoints\":\"0;4\"},\"requestUuid\":\"mapmatching\"}" + val route = DirectionsRoute.fromJson(routeJson).toNavigationRoute(RouterOrigin.Offboard) + //val route = TestingUtil.loadNavigationRoute("short_route.json", "xyz") val granularDistances = MapboxRouteLineUtils.granularDistancesProvider(route) val vanishingRouteLine = VanishingRouteLine().also { it.setScope(InternalJobControlFactory.createMainScopeJobControl().scope) } vanishingRouteLine.setGranularDistances(granularDistances!!) - granularDistances.flatStepDistances.forEach { - vanishingRouteLine.trimTree(it.point) + // granularDistances.flatStepDistances.forEach { + // vanishingRouteLine.trimTree(it.point) + // } + //point Point{type=Point, bbox=null, coordinates=[-122.67146157204115, 45.638172892050875]} offset 0.11118330619475914 + val point = Point.fromLngLat(-122.67146157204115, 45.638172892050875) + //val point = granularDistances.flatStepDistances.get(granularDistances.flatStepDistances.size / 2) + + //vanishingRouteLine.foobar(point.point) + + //vanishingRouteLine.checkPointInCurrentRange(Point.fromLngLat(-122.67147824336483, 45.63726680626696)) + + listOf( + //Point.fromLngLat(-122.67147824336483, 45.63726680626696), + Point.fromLngLat(-122.67147742508963, 45.63731108636806), + Point.fromLngLat(-122.67147676267612, 45.63734693217765), + Point.fromLngLat(-122.67147611000415, 45.6373822508342), + Point.fromLngLat(-122.67147545733246, 45.63741756947505), + Point.fromLngLat(-122.67147493129485, 45.63744639668131), + Point.fromLngLat(-122.67147436374492, 45.63747816134145), + Point.fromLngLat(-122.671473796195, 45.637509926000696) + ).forEach { + val offset = vanishingRouteLine.getOffset(it) + println(offset) } + + + } + +//0.12647115633449757 +/* +point Point{type=Point, bbox=null, coordinates=[-122.67147824336483, 45.63726680626696]} offset 0.1264711563343266 +point Point{type=Point, bbox=null, coordinates=[-122.67147742508963, 45.63731108636806]} offset 0.1264711563343266 +point Point{type=Point, bbox=null, coordinates=[-122.67147676267612, 45.63734693217765]} offset 0.1264711563343266 +point Point{type=Point, bbox=null, coordinates=[-122.67147611000415, 45.6373822508342]} offset 0.1264711563343266 +point Point{type=Point, bbox=null, coordinates=[-122.67147545733246, 45.63741756947505]} offset 0.1264711563343266 +point Point{type=Point, bbox=null, coordinates=[-122.67147493129485, 45.63744639668131]} offset 0.1264711563343266 +point Point{type=Point, bbox=null, coordinates=[-122.67147436374492, 45.63747816134145]} offset 0.1264711563343266 +point Point{type=Point, bbox=null, coordinates=[-122.671473796195, 45.637509926000696]} offset 0.1264711563343266 +point Point{type=Point, bbox=null, coordinates=[-122.6714732286451, 45.63754169065995]} offset 0.1264711563343266 + */ } diff --git a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt index 312d96b50ac..076d6c6cedf 100644 --- a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt +++ b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt @@ -1,6 +1,7 @@ package com.mapbox.navigation.qa_test_app.view import android.annotation.SuppressLint +import android.graphics.Color import android.location.Location import android.os.Build import android.os.Bundle @@ -15,9 +16,16 @@ import com.mapbox.android.core.location.LocationEngineResult import com.mapbox.android.gestures.Utils import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.api.directions.v5.models.RouteOptions +import com.mapbox.geojson.Feature +import com.mapbox.geojson.FeatureCollection import com.mapbox.geojson.Point import com.mapbox.maps.CameraOptions import com.mapbox.maps.EdgeInsets +import com.mapbox.maps.Style +import com.mapbox.maps.extension.style.layers.generated.CircleLayer +import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource +import com.mapbox.maps.extension.style.sources.generated.geoJsonSource +import com.mapbox.maps.extension.style.sources.getSource import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin import com.mapbox.maps.plugin.animation.MapAnimationOptions import com.mapbox.maps.plugin.animation.camera @@ -154,7 +162,7 @@ class AlternativeRouteActivity : AppCompatActivity(), OnMapLongClickListener { enabled = true } mapboxReplayer.pushRealLocation(this, 0.0) - mapboxReplayer.playbackSpeed(1.5) + mapboxReplayer.playbackSpeed(1.0) mapboxReplayer.play() } @@ -182,7 +190,7 @@ class AlternativeRouteActivity : AppCompatActivity(), OnMapLongClickListener { CameraOptions.Builder() .center(Point.fromLngLat(location.longitude, location.latitude)) .bearing(location.bearing.toDouble()) - .zoom(13.0) + .zoom(15.0) .padding(EdgeInsets(1000.0, 0.0, 0.0, 0.0)) .build(), mapAnimationOptionsBuilder.build() @@ -209,6 +217,7 @@ class AlternativeRouteActivity : AppCompatActivity(), OnMapLongClickListener { } ) binding.mapView.gestures.addOnMapLongClickListener(this) + initTreePointLayer(it) } } @@ -267,6 +276,10 @@ class AlternativeRouteActivity : AppCompatActivity(), OnMapLongClickListener { routeLineView.renderRouteLineUpdate(this, result) } } + + routeLineApi.deleteMeGetTreePoints().apply { + addTreePoints(this) + } } private fun findRoute(origin: Point?, destination: Point?) { @@ -367,4 +380,29 @@ class AlternativeRouteActivity : AppCompatActivity(), OnMapLongClickListener { } false } + + //todo delete below + private val TREE_LINE_LAYER_ID = "TREE_LINE_LAYER_ID" + private val TREE_LINE_SOURCE_ID = "TREE_LINE_SOURCE_ID" + private fun initTreePointLayer(style: Style) { + if (!style.styleSourceExists(TREE_LINE_SOURCE_ID)) { + geoJsonSource(TREE_LINE_SOURCE_ID) {}.bindTo(style) + } + + if (!style.styleLayerExists(TREE_LINE_LAYER_ID)) { + CircleLayer(TREE_LINE_LAYER_ID, TREE_LINE_SOURCE_ID) + .circleRadius(2.0) + .circleOpacity(.75) + .circleColor(Color.MAGENTA) + .bindTo(style) + } + } + + private fun addTreePoints(points: List) { + val features = points.map { Feature.fromGeometry(it) } + + (binding.mapView.getMapboxMap().getStyle()!!.getSource(TREE_LINE_SOURCE_ID) as GeoJsonSource).apply { + this.featureCollection(FeatureCollection.fromFeatures(features)) + } + } } From 8865baf40fc4eb64b0bbed124a764a3bb67cf397 Mon Sep 17 00:00:00 2001 From: Seth Bourget Date: Tue, 18 Oct 2022 13:39:18 -0700 Subject: [PATCH 6/7] wip code cleanup and docs updates. --- .../core/MapboxRouteLineAndArrowActivity.kt | 125 ++---------- .../layout_activity_routeline_example.xml | 7 - .../route/line/MapboxRouteLineUtils.kt | 61 ++++-- .../maps/internal/route/line/PointProvider.kt | 10 - .../line/MapboxRouteLineApiExtensions.kt | 2 - .../maps/route/line/api/MapboxRouteLineApi.kt | 17 +- .../maps/route/line/api/VanishingRouteLine.kt | 181 +++++++++--------- .../maps/route/line/model/RouteFeatureData.kt | 2 +- .../line/model/RouteLineGranularDistances.kt | 2 +- .../route/line/model/RouteLineSourceKey.kt | 2 +- .../route/line => util}/LocationSearchTree.kt | 4 +- .../route/line => util}/LocationTreeNode.kt | 8 +- .../line => util}/NearestNeighborCollector.kt | 23 ++- .../line/MapboxRouteLineUtilsRoboTest.kt | 66 ------- .../view/AlternativeRouteActivity.kt | 40 +--- 15 files changed, 179 insertions(+), 371 deletions(-) delete mode 100644 libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/PointProvider.kt rename libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/{internal/route/line => util}/LocationSearchTree.kt (92%) rename libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/{internal/route/line => util}/LocationTreeNode.kt (97%) rename libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/{internal/route/line => util}/NearestNeighborCollector.kt (68%) diff --git a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt index 74a91500032..b2ccb64b1a7 100644 --- a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt +++ b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt @@ -16,19 +16,13 @@ import com.mapbox.android.core.location.LocationEngineResult import com.mapbox.android.gestures.Utils import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.api.directions.v5.models.RouteOptions -import com.mapbox.geojson.Feature -import com.mapbox.geojson.FeatureCollection import com.mapbox.geojson.Point import com.mapbox.maps.CameraOptions import com.mapbox.maps.EdgeInsets import com.mapbox.maps.MapboxMap import com.mapbox.maps.Style import com.mapbox.maps.extension.observable.eventdata.MapLoadingErrorEventData -import com.mapbox.maps.extension.style.layers.generated.CircleLayer import com.mapbox.maps.extension.style.layers.properties.generated.Visibility -import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource -import com.mapbox.maps.extension.style.sources.generated.geoJsonSource -import com.mapbox.maps.extension.style.sources.getSource import com.mapbox.maps.plugin.LocationPuck2D import com.mapbox.maps.plugin.animation.MapAnimationOptions import com.mapbox.maps.plugin.animation.camera @@ -41,11 +35,9 @@ import com.mapbox.maps.plugin.locationcomponent.location import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions import com.mapbox.navigation.base.extensions.applyLanguageAndVoiceUnitOptions import com.mapbox.navigation.base.options.NavigationOptions -import com.mapbox.navigation.base.route.RouteRefreshOptions import com.mapbox.navigation.base.route.RouterCallback import com.mapbox.navigation.base.route.RouterFailure import com.mapbox.navigation.base.route.RouterOrigin -import com.mapbox.navigation.base.utils.DecodeUtils.stepGeometryToPoints import com.mapbox.navigation.core.MapboxNavigationProvider import com.mapbox.navigation.core.directions.session.RoutesObserver import com.mapbox.navigation.core.replay.MapboxReplayer @@ -69,8 +61,6 @@ import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions import com.mapbox.navigation.ui.maps.route.line.model.RouteLine import com.mapbox.navigation.ui.maps.route.line.model.RouteLineColorResources import com.mapbox.navigation.ui.maps.route.line.model.RouteLineResources -import com.mapbox.navigation.utils.internal.InternalJobControlFactory -import kotlinx.coroutines.cancelChildren import java.lang.ref.WeakReference /** @@ -85,7 +75,6 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe private val replayRouteMapper = ReplayRouteMapper() private val replayProgressObserver = ReplayProgressObserver(mapboxReplayer) private var trafficGradientSoft = false - private val jobControl = InternalJobControlFactory.createDefaultScopeJobControl() private val viewBinding: LayoutActivityRoutelineExampleBinding by lazy { LayoutActivityRoutelineExampleBinding.inflate(layoutInflater) @@ -124,7 +113,6 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe RouteLineColorResources.Builder() .routeLineTraveledColor(Color.LTGRAY) .routeLineTraveledCasingColor(Color.GRAY) - .inActiveRouteLegsColor(Color.YELLOW) .build() } @@ -162,7 +150,6 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe .withRouteLineBelowLayerId("road-label-navigation") .withVanishingRouteLineEnabled(true) .displaySoftGradientForTraffic(trafficGradientSoft) - //.styleInactiveRouteLegsIndependently(true) .build() } @@ -265,25 +252,6 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe } private val routeProgressObserver = RouteProgressObserver { routeProgress -> - - //todo remove this - // RouteLine: This line is only necessary if the vanishing route line feature - // is enabled. - // routeLineApi.updateWithRouteProgress(routeProgress) { result -> - // mapboxMap.getStyle()?.apply { - // routeLineView.renderRouteLineUpdate(this, result) - // } - // } - - routeProgress.currentLegProgress?.currentStepProgress?.step?.apply { - val points = routeProgress.route.stepGeometryToPoints(this) - addPointToPixelMapPoints(points) - } - - routeLineApi.deleteMeGetTreePoints().apply { - addTreePoints(this) - } - // RouteArrow: The next maneuver arrows are driven by route progress events. // Generate the next maneuver arrow update data and pass it to the view class // to visualize the updates on the map. @@ -339,7 +307,7 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe // The lines below are related to the navigation simulator. mapboxReplayer.pushRealLocation(this, 0.0) - //mapboxReplayer.playbackSpeed(1.5) + mapboxReplayer.playbackSpeed(1.5) mapboxReplayer.play() } @@ -355,19 +323,17 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe } private fun updateCamera(location: Location) { - if (cameraUpdatesAllowed) { - val mapAnimationOptionsBuilder = MapAnimationOptions.Builder() - mapCamera.easeTo( - CameraOptions.Builder() - .center(Point.fromLngLat(location.longitude, location.latitude)) - .bearing(location.bearing.toDouble()) - .pitch(45.0) - .zoom(17.0) - .padding(EdgeInsets(1000.0, 0.0, 0.0, 0.0)) - .build(), - mapAnimationOptionsBuilder.build() - ) - } + val mapAnimationOptionsBuilder = MapAnimationOptions.Builder() + mapCamera.easeTo( + CameraOptions.Builder() + .center(Point.fromLngLat(location.longitude, location.latitude)) + .bearing(location.bearing.toDouble()) + .pitch(45.0) + .zoom(17.0) + .padding(EdgeInsets(1000.0, 0.0, 0.0, 0.0)) + .build(), + mapAnimationOptionsBuilder.build() + ) } private fun getMapboxAccessTokenFromResources(): String { @@ -384,9 +350,6 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe locationEngineCallback ) viewBinding.mapView.gestures.addOnMapLongClickListener(this) - - initPointLayer(style) - initTreePointLayer(style) }, object : OnMapLoadErrorListener { override fun onMapLoadError(eventData: MapLoadingErrorEventData) { @@ -416,13 +379,12 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe return false } - //Point.fromLngLat(-122.66743711143083, 45.637156363108105), Point.fromLngLat(-122.67117999435773, 45.63660582500783), Point.fromLngLat(-122.67147361785446, 45.63566210717601), Point.fromLngLat(-122.66713095440821, 45.63561846681017), Point.fromLngLat(-122.66742461493801, 45.63709082769017), Point.fromLngLat(-122.66928668721683, 45.63676751447727) fun findRoute(origin: Point?, destination: Point?) { val routeOptions = RouteOptions.builder() .applyDefaultNavigationOptions() .applyLanguageAndVoiceUnitOptions(this) .coordinatesList(listOf(origin, destination)) - //.layersList(listOf(mapboxNavigation.getZLevel(), null)) + .layersList(listOf(mapboxNavigation.getZLevel(), null)) .alternatives(false) .build() mapboxNavigation.requestRoutes( @@ -433,7 +395,6 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe private val routesReqCallback: RouterCallback = object : RouterCallback { override fun onRoutesReady(routes: List, routerOrigin: RouterOrigin) { - //mapboxNavigation.setRoutes(listOf(getRoute())) mapboxNavigation.setRoutes(routes) if (routes.isNotEmpty()) { viewBinding.routeLoadingProgressBar.visibility = View.INVISIBLE @@ -484,12 +445,8 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe } } - viewBinding.btnTemp.setOnClickListener { - cameraUpdatesAllowed = !cameraUpdatesAllowed - } viewBinding.mapView.gestures.addOnMapClickListener(mapClickListener) } - var cameraUpdatesAllowed = true // Starts the navigation simulator private fun startSimulation(route: DirectionsRoute) { @@ -511,7 +468,6 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe override fun onStop() { super.onStop() - jobControl.job.cancelChildren() locationComponent.removeOnIndicatorPositionChangedListener(onPositionChangedListener) mapboxNavigation.unregisterRouteProgressObserver(replayProgressObserver) mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver) @@ -550,59 +506,4 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe override fun onFailure(exception: Exception) { } } - - private val LINE_END_LAYER_ID = "DRAW_UTIL_LINE_END_LAYER_ID" - private val LINE_END_SOURCE_ID = "DRAW_UTIL_LINE_END_SOURCE_ID" - private fun initPointLayer(style: Style) { - if (!style.styleSourceExists(LINE_END_SOURCE_ID)) { - geoJsonSource(LINE_END_SOURCE_ID) {}.bindTo(style) - } - - if (!style.styleLayerExists(LINE_END_LAYER_ID)) { - CircleLayer(LINE_END_LAYER_ID, LINE_END_SOURCE_ID) - .circleRadius(5.0) - .circleOpacity(1.0) - .circleColor(Color.BLACK) - .bindTo(style) - } - } - - private val TREE_LINE_LAYER_ID = "TREE_LINE_LAYER_ID" - private val TREE_LINE_SOURCE_ID = "TREE_LINE_SOURCE_ID" - private fun initTreePointLayer(style: Style) { - if (!style.styleSourceExists(TREE_LINE_SOURCE_ID)) { - geoJsonSource(TREE_LINE_SOURCE_ID) {}.bindTo(style) - } - - if (!style.styleLayerExists(TREE_LINE_LAYER_ID)) { - CircleLayer(TREE_LINE_LAYER_ID, TREE_LINE_SOURCE_ID) - .circleRadius(2.0) - .circleOpacity(.75) - .circleColor(Color.MAGENTA) - .bindTo(style) - } - } - - // todo remove this - private fun addPointToPixelMapPoints(points: List) { - val features = points.map { Feature.fromGeometry(it) } - - (mapboxMap.getStyle()!!.getSource(LINE_END_SOURCE_ID) as GeoJsonSource).apply { - this.featureCollection(FeatureCollection.fromFeatures(features)) - } - } - - private fun addTreePoints(points: List) { - val features = points.map { Feature.fromGeometry(it) } - - (mapboxMap.getStyle()!!.getSource(TREE_LINE_SOURCE_ID) as GeoJsonSource).apply { - this.featureCollection(FeatureCollection.fromFeatures(features)) - } - } - - // fun getRoute(): DirectionsRoute { - // //val routeJson = "{\"routeIndex\":\"0\",\"distance\":728.195,\"duration\":178.495,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@YEnd@I|_@|]HrTJxf@B~FgAPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"weight\":241.413,\"weight_name\":\"auto\",\"legs\":[{\"weight\":241.413,\"via_waypoints\":[],\"distance\":728.195,\"duration\":178.495,\"summary\":\"Main Street, West McLoughlin Boulevard\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"distance\":220.325,\"duration\":29.108,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@Y\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.634461],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"driving_side\":\"right\",\"weight\":35.461,\"intersections\":[{\"duration\":7.5,\"weight\":9,\"location\":[-122.671531,45.634461],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.719,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.94,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"distance\":87.726,\"duration\":31.082,\"geometry\":\"otl`vAlwg~hFEnd@I|_@\",\"name\":\"West 20th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671495,45.63644],\"bearing_before\":1.0,\"bearing_after\":270.0,\"instruction\":\"Turn left onto West 20th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":45.681,\"intersections\":[{\"duration\":19.722,\"turn_weight\":12.5,\"turn_duration\":5.622,\"weight\":29.773,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.007,\"location\":[-122.672095,45.636443],\"bearings\":[1,90,182,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":179.057,\"duration\":68.349,\"geometry\":\"_ul`vAz}i~hF|]HrTJxf@B~FgA\",\"name\":\"Washington Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672622,45.636448],\"bearing_before\":271.0,\"bearing_after\":180.0,\"instruction\":\"Turn left onto Washington Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":88.24,\"intersections\":[{\"duration\":30.372,\"turn_weight\":10,\"turn_duration\":5.622,\"weight\":39.7,\"location\":[-122.672622,45.636448],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":2,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"duration\":17.558,\"turn_weight\":1,\"turn_duration\":0.008,\"weight\":22.06,\"location\":[-122.672627,45.635953],\"bearings\":[0,92,181],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.019,\"location\":[-122.672633,45.635607],\"bearings\":[1,92,180,270],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":241.086,\"duration\":49.955,\"geometry\":\"spi`vAl|i~hFPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672599,45.634842],\"bearing_before\":169.0,\"bearing_after\":91.0,\"instruction\":\"Turn left onto West McLoughlin Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":72.031,\"intersections\":[{\"duration\":22.522,\"turn_weight\":12.5,\"turn_duration\":3.622,\"weight\":35.18,\"location\":[-122.672599,45.634842],\"bearings\":[91,182,270,349],\"entry\":[true,true,true,false],\"in\":3,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":14.931,\"turn_duration\":2.008,\"turn_weight\":3,\"duration\":11.951,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,182,259],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":1.371,\"turn_weight\":0.75,\"weight\":2.396,\"location\":[-122.670778,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.086,\"turn_weight\":0.75,\"weight\":4.453,\"location\":[-122.670671,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":16,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":6.469,\"turn_duration\":2.008,\"turn_weight\":2,\"duration\":5.732,\"location\":[-122.670443,45.634898],\"bearings\":[1,91,182,270],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":0.248,\"turn_weight\":0.75,\"weight\":1.048,\"location\":[-122.670058,45.634895],\"bearings\":[90,271],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":19,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.49,\"turn_weight\":0.75,\"weight\":2.538,\"location\":[-122.670028,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"location\":[-122.66988,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":21,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"distance\":0.0,\"duration\":0.0,\"geometry\":\"ysi`vAn{c~hF??\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.669512,45.634893],\"bearing_before\":90.0,\"bearing_after\":0.0,\"instruction\":\"You have arrived at your destination.\",\"type\":\"arrive\"},\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.669512,45.634893],\"bearings\":[270],\"entry\":[true],\"in\":0,\"geometry_index\":22,\"admin_index\":0}]}],\"annotation\":{\"distance\":[46.0,48.6,37.3,88.4,46.7,41.1,55.1,38.5,70.9,14.5,54.2,15.6,14.5,13.4,44.8,8.4,17.7,0.7,29.3,2.3,11.5,28.7],\"congestion_numeric\":[0,null,4,4,null,null,null,null,null,null,0,0,0,4,4,4,4,1,1,1,1,1]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6715815,45.6344615;-122.6716338,45.6364896;-122.6726954,45.6364085;-122.672707,45.6348712;-122.6695105,45.6350132\",\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,distance\",\"voice_instructions\":false,\"banner_instructions\":false,\"waypoints\":\"0;4\"},\"requestUuid\":\"mapmatching\"}" - // val routeJson = "{\"country_crossed\":false,\"weight_typical\":373.949,\"routeIndex\":\"0\",\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DAChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\oMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTIWzeA\",\"weight\":373.949,\"weight_name\":\"auto\",\"legs\":[{\"weight_typical\":373.949,\"weight\":373.949,\"via_waypoints\":[],\"distance\":2344.955,\"duration\":275.465,\"duration_typical\":275.465,\"summary\":\"West Fourth Plain Boulevard, Kauffman Avenue\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"weight_typical\":111.941,\"distance\":634.918,\"duration\":86.844,\"duration_typical\":86.844,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kyh`vAtyg~hFgXQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DA\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.63447],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":634.918,\"announcement\":\"Drive north on Main Street for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eDrive north on \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eMain Street\\u003c/say-as\\u003e for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West Fourth Plain Boulevard.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest Fourth Plain Boulevard\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":42.667,\"announcement\":\"Turn left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":634.918,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"West Fourth Plain Boulevard\",\"components\":[{\"text\":\"West Fourth Plain Boulevard\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":true,\"active_direction\":\"left\"},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"right\"],\"active\":false}]}}],\"driving_side\":\"right\",\"weight\":111.941,\"intersections\":[{\"duration\":7.315,\"weight\":8.778,\"location\":[-122.671531,45.63447],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.937,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.201,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":9.919,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":12.88,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":4.031,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.914,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.832,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.945,\"location\":[-122.671487,45.63679],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.844,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.186,\"location\":[-122.671483,45.637018],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.874,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.998,\"location\":[-122.671477,45.637323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.254,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.237,\"location\":[-122.671473,45.637532],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":2.918,\"turn_duration\":2.019,\"turn_weight\":0.5,\"duration\":3.993,\"location\":[-122.67147,45.63769],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":2.779,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.881,\"location\":[-122.671468,45.63784],\"bearings\":[1,181,267],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":12,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.619,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.41,\"location\":[-122.671464,45.638047],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":7.363,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":9.496,\"location\":[-122.671459,45.638323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":14,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":10.819,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":14.23,\"location\":[-122.67145,45.638782],\"bearings\":[1,75,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.75,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":4.346,\"location\":[-122.671438,45.63946],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671435,45.639654],\"bearings\":[1,90,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":18,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":104.434,\"distance\":744.28,\"duration\":79.063,\"duration_typical\":79.063,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"y}s`vAdsg~hFChF?lEIh^?bDC`PEtb@Cf[AzEAfEE|RSb{@?rc@YdoAInbAGlSMfaAGpSM``@AtCEnMKl\\\\\",\"name\":\"West Fourth Plain Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671427,45.640173],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West Fourth Plain Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":730.946,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":66.667,\"announcement\":\"Turn right onto Kauffman Avenue.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn right onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eKauffman Avenue\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":744.28,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"Kauffman Avenue\",\"components\":[{\"text\":\"Kauffman Avenue\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"right\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\",\"right\"],\"active\":true,\"active_direction\":\"right\"}]}}],\"driving_side\":\"right\",\"weight\":104.434,\"intersections\":[{\"weight\":12.272,\"turn_duration\":7.622,\"turn_weight\":10,\"duration\":9.476,\"location\":[-122.671427,45.640173],\"bearings\":[15,90,181,271],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"right\"]}],\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":4.93,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":6.514,\"location\":[-122.671647,45.640175],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":22,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.821,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":3.93,\"location\":[-122.67223,45.64018],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":24,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.672503,45.640182],\"bearings\":[91,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":25,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":5.867,\"turn_weight\":0.5,\"weight\":7.687,\"location\":[-122.673074,45.640185],\"bearings\":[90,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":26,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":5.138,\"turn_duration\":2.021,\"turn_weight\":1.5,\"duration\":4.991,\"location\":[-122.673636,45.640188],\"bearings\":[91,179,271,359],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":28,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":6.75,\"turn_weight\":0.5,\"weight\":8.769,\"location\":[-122.674055,45.640192],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":30,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.784,\"turn_weight\":1,\"turn_duration\":0.021,\"weight\":5.61,\"location\":[-122.675017,45.640202],\"bearings\":[1,91,191,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":31,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":8.007,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":10.1,\"location\":[-122.675603,45.640202],\"bearings\":[0,90,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":32,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.455,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":9.221,\"location\":[-122.676886,45.640215],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":33,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.844,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":2.704,\"location\":[-122.677966,45.64022],\"bearings\":[90,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":34,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.246,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":7.97,\"location\":[-122.678293,45.640224],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":35,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.971,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.84,\"location\":[-122.679353,45.640231],\"bearings\":[91,182,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":36,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.301,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":4.436,\"location\":[-122.679682,45.640235],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":37,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":0.548,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":1.132,\"location\":[-122.680211,45.640242],\"bearings\":[91,180,271],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":38,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.046,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":2.93,\"location\":[-122.680286,45.640243],\"bearings\":[1,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":39,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":0.5,\"location\":[-122.680518,45.640246],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":40,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":131.023,\"distance\":877.516,\"duration\":91.718,\"duration_typical\":91.718,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"wbt`vAxhz~hFoMMcRO}@Aws@o@qD?{RKgZKwNGmRGkICg`@Mg_@UgJGuJGkFE}VKyUM_WGmCA}D?{DEa_@QkBAsSEwOKyLMqNQaTI\",\"name\":\"Kauffman Avenue\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680989,45.640252],\"bearing_before\":271.0,\"bearing_after\":1.0,\"instruction\":\"Turn right onto Kauffman Avenue.\",\"type\":\"turn\",\"modifier\":\"right\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":864.182,\"announcement\":\"Continue for a half mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eContinue for a half mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto West 36th Street.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":91.111,\"announcement\":\"Turn left onto West 36th Street. Then Your destination will be on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eWest 36th Street\\u003c/say-as\\u003e. Then Your destination will be on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":877.516,\"primary\":{\"text\":\"West 36th Street\",\"components\":[{\"text\":\"West 36th Street\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":131.023,\"intersections\":[{\"weight\":19.48,\"turn_duration\":4.005,\"turn_weight\":7,\"duration\":14.405,\"location\":[-122.680989,45.640252],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"right\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":41,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":5.119,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.87,\"location\":[-122.680982,45.640484],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":42,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.276,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.059,\"location\":[-122.680974,45.64079],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":43,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":7.069,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":9.21,\"location\":[-122.680973,45.640821],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":44,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.467,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":4.886,\"location\":[-122.680949,45.641665],\"bearings\":[0,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":45,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.059,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.798,\"location\":[-122.680943,45.642072],\"bearings\":[1,89,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":47,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.752,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":5.98,\"location\":[-122.680937,45.642508],\"bearings\":[1,92,181,267],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":48,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.019,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.35,\"location\":[-122.680933,45.64276],\"bearings\":[1,181,270],\"entry\":[true,false,false],\"in\":1,\"out\":0,\"geometry_index\":49,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":6.869,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":8.969,\"location\":[-122.680929,45.643071],\"bearings\":[0,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":50,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.294,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.88,\"location\":[-122.68092,45.643769],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":52,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.619,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":2.67,\"location\":[-122.680909,45.644285],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":53,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.866,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":4.166,\"location\":[-122.680905,45.644465],\"bearings\":[1,181,276],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":54,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.795,\"turn_weight\":1.5,\"turn_duration\":0.019,\"weight\":6.031,\"location\":[-122.680898,45.64477],\"bearings\":[1,90,181,269],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":56,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.804,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":5.197,\"location\":[-122.680892,45.645153],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":57,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.204,\"turn_weight\":2,\"turn_duration\":0.021,\"weight\":6.916,\"location\":[-122.680885,45.645518],\"bearings\":[0,90,181,265],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":58,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.71,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":1.575,\"location\":[-122.680881,45.645902],\"bearings\":[1,90,180],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":59,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.062,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":3.151,\"location\":[-122.68088,45.645973],\"bearings\":[1,181,269],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":60,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":5.149,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.778,\"location\":[-122.680877,45.646162],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":62,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.533,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":1.354,\"location\":[-122.680868,45.646675],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":63,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.118,\"turn_weight\":1.5,\"turn_duration\":0.021,\"weight\":5.14,\"location\":[-122.680867,45.646729],\"bearings\":[0,92,181,284],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":64,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":2.579,\"turn_weight\":0.75,\"turn_duration\":0.007,\"weight\":3.771,\"location\":[-122.680864,45.647059],\"bearings\":[1,180,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":65,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":4.819,\"turn_weight\":0.75,\"turn_duration\":0.019,\"weight\":6.39,\"location\":[-122.680858,45.647327],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":66,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"turn_duration\":0.019,\"location\":[-122.680842,45.647797],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":68,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"weight_typical\":26.551,\"distance\":88.242,\"duration\":17.84,\"duration_typical\":17.84,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"kocavAh_z~hFWzeA\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.680837,45.648134],\"bearing_before\":1.0,\"bearing_after\":271.0,\"instruction\":\"Turn left onto West 36th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":44.444,\"announcement\":\"Your destination is on the left.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eYour destination is on the left.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":88.242,\"primary\":{\"text\":\"Your destination will be on the left\",\"components\":[{\"text\":\"Your destination will be on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":44.444,\"primary\":{\"text\":\"Your destination is on the left\",\"components\":[{\"text\":\"Your destination is on the left\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"left\"}}],\"driving_side\":\"right\",\"weight\":26.551,\"intersections\":[{\"turn_weight\":12.5,\"turn_duration\":5.622,\"location\":[-122.680837,45.648134],\"bearings\":[0,181,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":69,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"weight_typical\":0,\"distance\":0.0,\"duration\":0.0,\"duration_typical\":0.0,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"cpcavAdf|~hF??\",\"name\":\"West 36th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.681971,45.648146],\"bearing_before\":271.0,\"bearing_after\":0.0,\"instruction\":\"Your destination is on the left.\",\"type\":\"arrive\",\"modifier\":\"left\"},\"voiceInstructions\":[],\"bannerInstructions\":[],\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.681971,45.648146],\"bearings\":[91],\"entry\":[true],\"in\":0,\"geometry_index\":70,\"admin_index\":0}]}],\"annotation\":{\"distance\":[45.0,48.6,37.3,88.4,39.0,25.4,33.9,23.3,9.7,7.9,7.8,8.9,23.0,30.8,51.1,10.8,64.6,21.6,48.9,8.9,9.1,8.0,39.0,6.4,21.3,44.4,35.2,8.6,7.7,24.9,74.9,45.6,99.8,84.1,25.4,82.5,25.7,41.1,5.9,18.0,36.7,25.8,34.1,3.5,93.9,9.9,35.4,48.6,28.0,34.6,18.5,59.3,57.4,20.0,20.9,13.1,42.6,40.7,42.7,7.9,10.6,10.5,57.1,6.0,36.7,29.9,24.6,27.7,37.5,88.3],\"duration\":[7.315,8.552,3.937,9.919,4.031,2.832,3.844,2.874,1.249,1.004,2.94,1.053,2.779,3.619,7.363,1.564,9.255,2.75,8.429,1.533,8.608,0.868,4.239,0.69,2.821,5.867,4.718,1.148,2.73,2.261,6.75,3.784,8.007,6.455,1.844,6.246,1.971,3.301,0.547,2.046,4.163,14.405,5.119,0.276,7.069,0.774,2.693,5.059,3.752,3.019,1.649,5.22,4.294,1.619,1.764,1.101,3.795,3.804,4.204,0.71,1.046,1.016,5.149,0.533,3.118,2.579,2.276,2.543,3.128,17.84],\"speed\":[6.1,7.4,9.5,8.9,9.7,9.0,8.9,8.1,7.9,7.9,8.5,8.5,8.3,8.5,7.0,7.0,7.0,7.9,5.8,5.8,9.2,9.2,9.2,9.2,7.6,7.6,7.5,7.5,11.0,11.0,11.1,12.1,12.5,13.1,13.9,13.3,13.1,12.6,11.1,8.9,8.8,2.5,6.7,13.4,13.3,13.1,13.1,9.6,7.5,11.5,11.3,11.3,13.4,12.5,11.9,11.9,11.3,10.7,10.2,11.3,10.3,10.3,11.1,11.7,11.9,11.6,10.9,10.9,12.1,7.2],\"maxspeed\":[{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"}],\"congestion_numeric\":[0,24,9,9,0,0,0,null,null,null,0,0,0,null,6,9,9,14,null,null,9,9,9,9,30,30,30,30,12,12,12,4,3,1,0,0,null,3,null,0,0,null,null,null,0,null,null,null,null,null,null,null,null,null,null,null,0,null,null,null,0,0,null,null,null,null,null,null,0,null]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6716938,45.6344717;-122.681974,45.6479927\",\"alternatives\":true,\"language\":\"en\",\"layers\":\";\",\"continue_straight\":true,\"roundabout_exits\":true,\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,maxspeed,closure,speed,duration,distance\",\"voice_instructions\":true,\"banner_instructions\":true,\"voice_units\":\"imperial\",\"enable_refresh\":true},\"voiceLocale\":\"en-US\",\"requestUuid\":\"VA6i2dqAyEvoC4gS25Y14Z6gAE6c2fe_Tpq4H9voaY7FjLb-IUIcYQ\\u003d\\u003d\"}" - // return DirectionsRoute.fromJson(routeJson) - // } } diff --git a/examples/src/main/res/layout/layout_activity_routeline_example.xml b/examples/src/main/res/layout/layout_activity_routeline_example.xml index 79b2e3ffd95..99d198708e7 100644 --- a/examples/src/main/res/layout/layout_activity_routeline_example.xml +++ b/examples/src/main/res/layout/layout_activity_routeline_example.xml @@ -64,11 +64,4 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:visibility="invisible"/> - - \ No newline at end of file diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt index 4a8ffc4977e..d4e98e16ab9 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtils.kt @@ -64,7 +64,7 @@ import kotlin.math.max import kotlin.math.sin import kotlin.math.sqrt -object MapboxRouteLineUtils { +internal object MapboxRouteLineUtils { private const val LOG_CATEGORY = "MapboxRouteLineUtils" internal const val VANISH_POINT_STOP_GAP = .00000000001 @@ -488,7 +488,7 @@ object MapboxRouteLineUtils { * @return a list of items representing the distance offset of each route leg and the color * used to represent the traffic congestion. */ - internal fun calculateRouteLineSegments( + fun calculateRouteLineSegments( route: NavigationRoute, trafficBackfillRoadClasses: List, isPrimaryRoute: Boolean, @@ -877,7 +877,7 @@ object MapboxRouteLineUtils { private fun generateFeatureCollection(route: NavigationRouteLine): RouteFeatureData = generateRouteFeatureData(route.route, route.identifier) - private fun calculateGranularDistances( + private fun calculateGranularDistances( stepsPoints: List>> ): RouteLineGranularDistances { var distance = 0.0 @@ -955,11 +955,19 @@ object MapboxRouteLineUtils { ) } - fun getFillerPointsForStepPoints(nextSteps: Array): List { + /** + * Adds equally spaced [RouteLineDistancesIndex] points between each of the inputted steps and + * returns a collection of the original [RouteLineDistancesIndex] points with the newly created + * points between them. + * + * @param steps a collection of [RouteLineDistancesIndex] representing step points + * @return a collection of RouteLineDistancesIndex + */ + fun getFillerPointsForStepPoints(steps: Array): List { val fillerPoints = mutableListOf() - nextSteps.forEachIndexed { index, routeLineDistancesIndex -> - if (index < nextSteps.lastIndex) { - getFillerPoints(routeLineDistancesIndex, nextSteps[index + 1]).apply { + steps.forEachIndexed { index, routeLineDistancesIndex -> + if (index < steps.lastIndex) { + getFillerPoints(routeLineDistancesIndex, steps[index + 1]).apply { fillerPoints.addAll(this) } } @@ -967,29 +975,44 @@ object MapboxRouteLineUtils { return fillerPoints } - //todo the variable names below should be named better - fun getFillerPoints(startPoint: RouteLineDistancesIndex, endPoint: RouteLineDistancesIndex): List { - val gapDist = 1.0 // meters - val turfDistance = TurfMeasurement.distance(startPoint.point, endPoint.point, TurfConstants.UNIT_METERS) + /** + * Creates equally spaced [RouteLineDistancesIndex] points between the start point and end points + * and returns a collection with the start point and end point with the newly created + * points between them. + * + * @param startPoint the starting RouteLineDistancesIndex + * @param endPoint the ending RouteLineDistancesIndex + * @return a collection of the start and end points and the points generated here + */ + private fun getFillerPoints( + startPoint: RouteLineDistancesIndex, + endPoint: RouteLineDistancesIndex + ): List { + val gapDistanceInMeters = 1.0 + val turfDistance = TurfMeasurement.distance( + startPoint.point, + endPoint.point, + TurfConstants.UNIT_METERS + ) val fillerPoints = mutableListOf() val bearing = TurfMeasurement.bearing(startPoint.point, endPoint.point) - var lastCalculatedPoint = startPoint - val count = (turfDistance / gapDist).toInt() + val numPointsToCreate = (turfDistance / gapDistanceInMeters).toInt() val delta = startPoint.distanceRemaining - endPoint.distanceRemaining - val itemDist = delta / count + val itemDistance = delta / numPointsToCreate + var lastCalculatedPoint = startPoint + var distanceRemaining = startPoint.distanceRemaining fillerPoints.add(startPoint) - var dist = startPoint.distanceRemaining - repeat(count) { + repeat(numPointsToCreate) { val fillerPoint = TurfMeasurement.destination( lastCalculatedPoint.point, - gapDist, + gapDistanceInMeters, bearing, TurfConstants.UNIT_METERS ) - dist -= itemDist - fillerPoints.add(RouteLineDistancesIndex(fillerPoint, dist)) + distanceRemaining -= itemDistance + fillerPoints.add(RouteLineDistancesIndex(fillerPoint, distanceRemaining)) lastCalculatedPoint = fillerPoints.last() } return fillerPoints diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/PointProvider.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/PointProvider.kt deleted file mode 100644 index bc3dd7c0990..00000000000 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/PointProvider.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.mapbox.navigation.ui.maps.internal.route.line - -import com.mapbox.geojson.Point -import java.util.function.Supplier - -class PointProvider(private val p: Point): Supplier { - override fun get(): Point { - return p - } -} diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt index e8cbb6c8ef6..5cd0dcd6dec 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/MapboxRouteLineApiExtensions.kt @@ -4,8 +4,6 @@ import androidx.annotation.ColorInt import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.bindgen.Expected import com.mapbox.bindgen.ExpectedFactory -import com.mapbox.geojson.Feature -import com.mapbox.geojson.FeatureCollection import com.mapbox.geojson.Point import com.mapbox.maps.MapboxMap import com.mapbox.maps.extension.style.expressions.generated.Expression diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt index 838863eb398..d7cb56a3953 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/MapboxRouteLineApi.kt @@ -1,14 +1,12 @@ package com.mapbox.navigation.ui.maps.route.line.api import android.graphics.Color -import android.util.Log import android.util.LruCache import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.api.directions.v5.models.RouteOptions import com.mapbox.bindgen.Expected import com.mapbox.bindgen.ExpectedFactory import com.mapbox.geojson.FeatureCollection -import com.mapbox.geojson.LineString import com.mapbox.geojson.Point import com.mapbox.maps.MapboxMap import com.mapbox.maps.QueriedFeature @@ -19,7 +17,6 @@ import com.mapbox.maps.Style import com.mapbox.maps.extension.style.layers.Layer import com.mapbox.maps.plugin.locationcomponent.LocationComponentPluginImpl import com.mapbox.maps.plugin.locationcomponent.OnIndicatorPositionChangedListener -import com.mapbox.navigation.base.internal.utils.isSameRoute import com.mapbox.navigation.base.route.NavigationRoute import com.mapbox.navigation.base.route.toDirectionsRoutes import com.mapbox.navigation.base.trip.model.RouteProgress @@ -36,7 +33,6 @@ import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils.gr import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils.layerGroup1SourceLayerIds import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils.layerGroup2SourceLayerIds import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils.layerGroup3SourceLayerIds -import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils.routePointsProvider import com.mapbox.navigation.ui.maps.route.RouteLayerConstants import com.mapbox.navigation.ui.maps.route.line.model.ClosestRouteValue import com.mapbox.navigation.ui.maps.route.line.model.ExtractedRouteRestrictionData @@ -62,9 +58,6 @@ import com.mapbox.navigation.ui.utils.internal.ifNonNull import com.mapbox.navigation.utils.internal.InternalJobControlFactory import com.mapbox.navigation.utils.internal.logW import com.mapbox.navigation.utils.internal.parallelMap -import com.mapbox.turf.TurfConstants -import com.mapbox.turf.TurfException -import com.mapbox.turf.TurfMisc import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.cancelChildren @@ -539,7 +532,6 @@ class MapboxRouteLineApi( ) { jobControl.scope.launch(Dispatchers.Main) { mutex.withLock { - //routeLineOptions.vanishingRouteLine?.vanishPointOffset = 0.0 //todo remove this? activeLegIndex = INVALID_ACTIVE_LEG_INDEX routes.clear() routeFeatureData.clear() @@ -723,11 +715,11 @@ class MapboxRouteLineApi( } fun updateUpcomingRoutePointIndex(routeProgress: RouteProgress) { - // todo del me + // todo delete me } fun updateVanishingPointState(state: RouteProgressState) { - // todo del me + // todo delete me } /** @@ -1072,6 +1064,7 @@ class MapboxRouteLineApi( distinctNewRoutes.find { it.id == metadata.navigationRoute.id } != null } + // todo is this still needed? // ifNonNull(distinctNewRoutes.firstOrNull()) { primaryRouteCandidate -> // if (!primaryRouteCandidate.directionsRoute.isSameRoute(primaryRoute?.directionsRoute)) { // routeLineOptions.vanishingRouteLine?.vanishPointOffset = 0.0 @@ -1510,8 +1503,4 @@ class MapboxRouteLineApi( jobControl.scope ) }.cacheResult(alternativelyStyleSegmentsNotInLegCache) - - fun deleteMeGetTreePoints(): List { - return routeLineOptions.vanishingRouteLine!!.deleteMeGetTreePoints() - } } diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt index 766a0f9f1f5..e6136d7eb33 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/api/VanishingRouteLine.kt @@ -1,12 +1,10 @@ package com.mapbox.navigation.ui.maps.route.line.api import android.graphics.Color -import android.util.Log import android.util.Range import com.mapbox.geojson.Point import com.mapbox.maps.extension.style.expressions.dsl.generated.literal -import com.mapbox.navigation.base.trip.model.RouteProgressState -import com.mapbox.navigation.ui.maps.internal.route.line.LocationSearchTree +import com.mapbox.navigation.ui.maps.util.LocationSearchTree import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.ROUTE_LINE_UPDATE_MAX_DISTANCE_THRESHOLD_IN_METERS import com.mapbox.navigation.ui.maps.route.line.model.ExtractedRouteRestrictionData @@ -22,18 +20,16 @@ import com.mapbox.turf.TurfMeasurement import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import java.util.concurrent.CopyOnWriteArrayList -// todo adjust doc /** * This class implements a feature that can change the appearance of the route line behind the puck. * The route line behind the puck can be configured to be transparent or a specified color and * will update during navigation. * - * To enable this feature add an instance of this class to the constructor of the MapboxRouteLineApi - * class. Be sure to send route progress updates and location updates from a - * OnIndicatorPositionChangedListener to the MapboxRouteLineApi. See the documentation for more - * information. + * Enable this feature with the [MapboxRouteLineOptions] class. Be sure to create a + * [OnIndicatorPositionChangedListener] and pass the values generated to the [MapboxRouteLineApi] instance. + * + * See the documentation for more information. */ internal class VanishingRouteLine { @@ -41,17 +37,17 @@ internal class VanishingRouteLine { * a value representing the percentage distance traveled */ var vanishPointOffset: Double = 0.0 - //private set todo - - var primaryRouteRemainingDistancesIndex: Int? = null //todo delme - - var vanishingPointState: RouteProgressState? = null //todo delme - - fun updateVanishingPointState(state: RouteProgressState) { - //todo delme - } + private set private var scope: CoroutineScope? = null + private var granularDistances: RouteLineGranularDistances? = null + private val locationSearchTree = LocationSearchTree() + private val fillerPointsInTree = mutableListOf>() + private var indexOfLastStepPointsLoadedInTree = 0 + private val distanceToLastStepPointInMeters = 30.0 + private var stepPointRange: Range? = null + private val stepPointRangeSize = 5 + private val maxAllowedFillerPointListsInTree = 3 fun setScope(scope: CoroutineScope) { this.scope = scope @@ -164,32 +160,28 @@ internal class VanishingRouteLine { } } - - //////////// - - private var granularDistances: RouteLineGranularDistances? = null - private val locationSearchTree = LocationSearchTree() - private var stepsPoints: List> = emptyList() - private val fillerPointsInTree = mutableListOf>() - private var indexOfLastStepPointsLoadedInTree = 0 - private val distanceToLastStepPointInMeters = 30.0 - private var stepPointRange: Range? = null - private val stepPointRangeSize = 5 - private val maxAllowedFillerPointListsInTree = 3 - + /** + * When the granular distances are received the flatStepDistances are used to generate + * a range of very granular points along the route. These granular points are added + * to a search tree. When a call is made to get the offset for a specific point a + * nearest neighbor search of the granular points generated is performed. If a neighbor is + * found within the distance threshold it is used to determine the offset. + * + * The range of granular points adjusts at runtime according to the point coming in for the + * offset calculation. The range begins with the first step points in flatStepDistances. + * As the route is navigated the range is adjusted to include upcoming step points and + * the points that have been passed are removed. This constantly adjusting range keeps the + * number of points to search low to optimize performance. + */ fun setGranularDistances(distances: RouteLineGranularDistances) { scope?.launch(Dispatchers.Main.immediate) { if (distances != granularDistances) { granularDistances = distances - stepsPoints = distances.stepsDistances.flatten() locationSearchTree.clear() fillerPointsInTree.clear() indexOfLastStepPointsLoadedInTree = 0 vanishPointOffset = 0.0 - // todo remove logging - Log.e("foobar", "everything got cleared, starting fresh") - if (distances.flatStepDistances.isNotEmpty()) { val endRange = if (distances.flatStepDistances.size > stepPointRangeSize) { stepPointRangeSize @@ -206,22 +198,17 @@ internal class VanishingRouteLine { } } - private fun getFillerPointsForRange(range: Range, flatStepDistances: Array): List { - val fillerSteps = flatStepDistances.copyOfRange(range.lower, range.upper) - return MapboxRouteLineUtils.getFillerPointsForStepPoints(fillerSteps) - } - - fun getOffset(point: Point): Double? { val offset = ifNonNull(locationSearchTree.getNearestNeighbor(point), granularDistances) { closestPoint, distances -> - val distanceBetweenPoints = TurfMeasurement.distance(point, closestPoint.point, TurfConstants.UNIT_METERS) + val distanceBetweenPoints = TurfMeasurement.distance( + point, + closestPoint.point, + TurfConstants.UNIT_METERS + ) if (distanceBetweenPoints <= ROUTE_LINE_UPDATE_MAX_DISTANCE_THRESHOLD_IN_METERS ) { (1.0 - closestPoint.distanceRemaining / distances.completeDistance) } else { - // todo remove logging - //Log.e("foobar", "distance of $distanceBetweenPoints beyond distance threshold") - //Log.e("foobar", "incoming point $point nearest neighbor ${closestPoint.point}") if (distanceBetweenPoints >= distanceToLastStepPointInMeters) { recalculateRange(point) } @@ -232,25 +219,39 @@ internal class VanishingRouteLine { return offset } - fun recalculateRange(point: Point) { + /** + * It's possible the incoming point is not at the beginning of the route. This method + * searches the route for the closest step point and creates a point range around it + * so that the correct offset can be determined. Any/All points in the search tree + * are removed and the points falling withing the range defined here are added. + */ + private fun recalculateRange(point: Point) { scope?.launch(Dispatchers.Main.immediate) { ifNonNull(granularDistances) { distances -> - val indexOfClosestStepPoint = distances.flatStepDistances.mapIndexed { index, routeLineDistancesIndex -> - val dist = TurfMeasurement.distance(point, routeLineDistancesIndex.point, TurfConstants.UNIT_METERS) + val indexOfClosestStepPoint = + distances.flatStepDistances.mapIndexed { index, routeLineDistancesIndex -> + val dist = TurfMeasurement.distance( + point, routeLineDistancesIndex.point, + TurfConstants.UNIT_METERS + ) Pair(index, dist) }.minByOrNull { it.second } ifNonNull(indexOfClosestStepPoint) { - val endOfRange = if (it.first + stepPointRangeSize < distances.flatStepDistances.lastIndex) { - it.first + stepPointRangeSize - } else { - distances.flatStepDistances.lastIndex - } - stepPointRange = Range(it.first - 1, endOfRange).also { range -> - val fillerPoints = getFillerPointsForRange(range, distances.flatStepDistances) + val endOfRange = + if (it.first + stepPointRangeSize < distances.flatStepDistances.lastIndex) { + it.first + stepPointRangeSize + } else { + distances.flatStepDistances.lastIndex + } + stepPointRange = Range(it.first, endOfRange).also { range -> + val fillerPoints = getFillerPointsForRange( + range, + distances.flatStepDistances + ) if (fillerPoints.isNotEmpty()) { locationSearchTree.clear() - locationSearchTree.addAll(fillerPoints) fillerPointsInTree.clear() + locationSearchTree.addAll(fillerPoints) fillerPointsInTree.add(fillerPoints) } } @@ -259,25 +260,49 @@ internal class VanishingRouteLine { } } - //todo make private - fun trimTree(point: Point) { - //if getting close to the last step point, load the points for the next step range - //and remove the points long since passed. + /** + * Gets the generated points between the points in the range so they can be added to the + * search tree. + */ + private fun getFillerPointsForRange( + range: Range, + flatStepDistances: Array + ): List { + val fillerSteps = flatStepDistances.copyOfRange(range.lower, range.upper) + return MapboxRouteLineUtils.getFillerPointsForStepPoints(fillerSteps) + } + + /** + * When the incoming point gets close to the last point in the currently defined range + * the range is redefined with the upcoming points. The points in the newly defined + * range are added to the search tree and the points passed are removed. + */ + private fun trimTree(point: Point) { scope?.launch(Dispatchers.Main.immediate) { - val trimStart = System.currentTimeMillis() if (fillerPointsInTree.isNotEmpty() && fillerPointsInTree.last().isNotEmpty()) { val nearEndStepPoint = fillerPointsInTree.last().last() - val distanceToNearEndStepPoint = - TurfMeasurement.distance(point, nearEndStepPoint.point, TurfConstants.UNIT_METERS) + val distanceToNearEndStepPoint = TurfMeasurement.distance( + point, + nearEndStepPoint.point, + TurfConstants.UNIT_METERS + ) if (distanceToNearEndStepPoint <= distanceToLastStepPointInMeters) { - stepPointRange = ifNonNull(stepPointRange, granularDistances) { currentStepPointRange, distances -> - val endOfRange = if (currentStepPointRange.upper + stepPointRangeSize < distances.flatStepDistances.lastIndex) { - currentStepPointRange.upper + stepPointRangeSize - } else { - distances.flatStepDistances.lastIndex - } + stepPointRange = ifNonNull(stepPointRange, granularDistances) + { currentStepPointRange, distances -> + val endOfRange = + if ( + currentStepPointRange.upper + stepPointRangeSize + < distances.flatStepDistances.lastIndex + ) { + currentStepPointRange.upper + stepPointRangeSize + } else { + distances.flatStepDistances.lastIndex + } Range(currentStepPointRange.upper - 1, endOfRange).also { - val fillerPoints = getFillerPointsForRange(it, distances.flatStepDistances) + val fillerPoints = getFillerPointsForRange( + it, + distances.flatStepDistances + ) if (fillerPoints.isNotEmpty()) { locationSearchTree.addAll(fillerPoints) fillerPointsInTree.add(fillerPoints) @@ -290,22 +315,6 @@ internal class VanishingRouteLine { } } } - val trimTotal = System.currentTimeMillis() - trimStart - if (trimTotal > 10) { - // todo remove logging - Log.e("foobar", "time to trim tree is ${System.currentTimeMillis() - trimStart}") - } - - } - } - - fun deleteMeGetTreePoints(): List { - val allPoints = mutableListOf() - fillerPointsInTree.forEach { distanceIndexes -> - distanceIndexes.map { it.point }.forEach { - allPoints.add(it) - } } - return allPoints } } diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteFeatureData.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteFeatureData.kt index 39f0afc762e..a99c007b275 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteFeatureData.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteFeatureData.kt @@ -12,7 +12,7 @@ import com.mapbox.navigation.base.route.NavigationRoute * @param featureCollection a FeatureCollection created using the route * @param lineString a LineString derived from the route's geometry. */ -data class RouteFeatureData constructor( // fixme make internal +internal data class RouteFeatureData constructor( val route: NavigationRoute, val featureCollection: FeatureCollection, val lineString: LineString diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineGranularDistances.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineGranularDistances.kt index f79d9acac08..2bb760907d6 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineGranularDistances.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineGranularDistances.kt @@ -14,7 +14,7 @@ import com.mapbox.navigation.ui.maps.internal.route.line.MapboxRouteLineUtils * @param flatStepDistances values in this array are matching indices a flattened [stepsDistances]. * This means that **duplicate start/end points of adjacent steps are not filtered out**. */ -data class RouteLineGranularDistances constructor( +internal data class RouteLineGranularDistances constructor( val completeDistance: Double, val routeDistances: Array, val legsDistances: Array>, diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineSourceKey.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineSourceKey.kt index 74c6be317c6..604f085fb41 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineSourceKey.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/route/line/model/RouteLineSourceKey.kt @@ -1,4 +1,4 @@ package com.mapbox.navigation.ui.maps.route.line.model @JvmInline -value class RouteLineSourceKey(val sourceId: String) //fixme me make internal +internal value class RouteLineSourceKey(val sourceId: String) diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationSearchTree.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/LocationSearchTree.kt similarity index 92% rename from libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationSearchTree.kt rename to libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/LocationSearchTree.kt index 7c3bba9ef22..613b8d13ec5 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationSearchTree.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/LocationSearchTree.kt @@ -1,11 +1,11 @@ -package com.mapbox.navigation.ui.maps.internal.route.line +package com.mapbox.navigation.ui.maps.util import com.mapbox.geojson.Point import com.mapbox.turf.TurfConstants import com.mapbox.turf.TurfMeasurement import java.util.function.Supplier -class LocationSearchTree>(private val capacity: Int = 10) { +internal class LocationSearchTree>(private val capacity: Int = 10) { private var rootNode: LocationTreeNode? = null fun size() = rootNode?.size() ?: 0 diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationTreeNode.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/LocationTreeNode.kt similarity index 97% rename from libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationTreeNode.kt rename to libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/LocationTreeNode.kt index 9097a209f52..00b06a4db65 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/LocationTreeNode.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/LocationTreeNode.kt @@ -1,20 +1,18 @@ -package com.mapbox.navigation.ui.maps.internal.route.line +package com.mapbox.navigation.ui.maps.util import com.mapbox.geojson.Point import java.util.function.Supplier -class LocationTreeNode>( +internal class LocationTreeNode>( private val points: MutableList, - private val capacity: Int = 32, + private val capacity: Int = 10, private val distanceCalcFunction: (Point, Point) -> Double ) { private val vantagePoint: Point by lazy { points.random().get() } - private var threshold = 0.0 - private var closer: LocationTreeNode? = null private var farther: LocationTreeNode? = null diff --git a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/NearestNeighborCollector.kt b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/NearestNeighborCollector.kt similarity index 68% rename from libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/NearestNeighborCollector.kt rename to libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/NearestNeighborCollector.kt index 8f0d1d6e169..4592691fcd9 100644 --- a/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/route/line/NearestNeighborCollector.kt +++ b/libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/util/NearestNeighborCollector.kt @@ -1,7 +1,6 @@ -package com.mapbox.navigation.ui.maps.internal.route.line +package com.mapbox.navigation.ui.maps.util import com.mapbox.geojson.Point -import com.mapbox.navigation.ui.maps.util.DistanceComparator import com.mapbox.navigation.ui.utils.internal.ifNonNull import com.mapbox.turf.TurfConstants import com.mapbox.turf.TurfMeasurement @@ -9,7 +8,10 @@ import java.util.Collections import java.util.PriorityQueue import java.util.function.Supplier -class NearestNeighborCollector>(val queryPoint: Point, private val capacity: Int) { +internal class NearestNeighborCollector>( + val queryPoint: Point, + private val capacity: Int +) { private val distanceComparator by lazy { DistanceComparator(queryPoint) @@ -26,7 +28,11 @@ class NearestNeighborCollector>(val queryPoint: Point, privat priorityQueue.add(offeredPoint) } else { if (priorityQueue.isNotEmpty()) { - val distanceToNewPoint = TurfMeasurement.distance(queryPoint, offeredPoint.get(), TurfConstants.UNIT_METERS) + val distanceToNewPoint = TurfMeasurement.distance( + queryPoint, + offeredPoint.get(), + TurfConstants.UNIT_METERS + ) if (distanceToNewPoint < distanceToFarthestPoint) { priorityQueue.poll() priorityQueue.add(offeredPoint) @@ -40,8 +46,13 @@ class NearestNeighborCollector>(val queryPoint: Point, privat } if (pointAdded && priorityQueue.isNotEmpty()) { - distanceToFarthestPoint = ifNonNull(priorityQueue.peek()) { pointSupplier: Supplier -> - TurfMeasurement.distance(queryPoint, pointSupplier.get(), TurfConstants.UNIT_METERS) + distanceToFarthestPoint = + ifNonNull(priorityQueue.peek()) { pointSupplier: Supplier -> + TurfMeasurement.distance( + queryPoint, + pointSupplier.get(), + TurfConstants.UNIT_METERS + ) } ?: Double.MAX_VALUE } } diff --git a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt index 3b6d5059753..f5e2809063d 100644 --- a/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt +++ b/libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/route/line/MapboxRouteLineUtilsRoboTest.kt @@ -4,7 +4,6 @@ import android.content.Context import android.graphics.Bitmap import android.graphics.Color import androidx.test.core.app.ApplicationProvider -import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.api.directions.v5.models.RouteOptions import com.mapbox.bindgen.ExpectedFactory import com.mapbox.bindgen.Value @@ -21,7 +20,6 @@ import com.mapbox.maps.plugin.locationcomponent.LocationComponentConstants import com.mapbox.navigation.base.internal.NativeRouteParserWrapper import com.mapbox.navigation.base.route.NavigationRoute import com.mapbox.navigation.base.route.RouterOrigin -import com.mapbox.navigation.base.route.toNavigationRoute import com.mapbox.navigation.testing.FileUtils.loadJsonFixture import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.ARROW_HEAD_ICON import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.ARROW_HEAD_ICON_CASING @@ -53,20 +51,10 @@ import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.ORIGIN_MARKER_NAM import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.TOP_LEVEL_ROUTE_LINE_LAYER_ID import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.WAYPOINT_LAYER_ID import com.mapbox.navigation.ui.maps.route.RouteLayerConstants.WAYPOINT_SOURCE_ID -import com.mapbox.navigation.ui.maps.route.line.api.VanishingRouteLine -import com.mapbox.navigation.ui.maps.route.line.model.ExtractedRouteData import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineOptions import com.mapbox.navigation.ui.maps.route.line.model.RouteLineColorResources -import com.mapbox.navigation.ui.maps.route.line.model.RouteLineDistancesIndex -import com.mapbox.navigation.ui.maps.route.line.model.RouteLineGranularDistances -import com.mapbox.navigation.ui.maps.route.line.model.RoutePoints -import com.mapbox.navigation.ui.maps.testing.TestingUtil import com.mapbox.navigation.ui.maps.testing.TestingUtil.loadNavigationRoute -import com.mapbox.navigation.utils.internal.InternalJobControlFactory import com.mapbox.navigator.RouteInterface -import com.mapbox.turf.TurfConstants -import com.mapbox.turf.TurfMeasurement -import com.mapbox.turf.TurfMisc import io.mockk.every import io.mockk.mockk import io.mockk.mockkObject @@ -1207,58 +1195,4 @@ class MapboxRouteLineUtilsRoboTest { verify(exactly = 3) { route1.directionsRoute } verify(exactly = 2) { route2.directionsRoute } } - - @Test - fun scratch() { - val routeJson = "{\"country_crossed\":false,\"weight_typical\":305.822,\"routeIndex\":\"1\",\"distance\":1752.465,\"duration\":225.213,\"duration_typical\":225.213,\"geometry\":\"axh`vAtyg~hFqYQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DAcEq@mIwD_Bs@oCoA}FaCkCiAuD{AsB{@yCmAoQiHsGiCcFsBmDuAkBu@yVaJ}EaBwOiFiCgAkFyBuJ_E}ViKiWgKwUoJ}UqJuUmJoHgC{OsFiDmACA{CgA_EuAmC}@_@fFEfN?j@Oz|@CdLCfN?tA?zwAIp^Opq@?tDCrDg@zoAC`R\",\"weight\":305.822,\"weight_name\":\"auto\",\"legs\":[{\"weight_typical\":305.822,\"weight\":305.822,\"via_waypoints\":[],\"distance\":1752.465,\"duration\":225.213,\"duration_typical\":225.213,\"summary\":\"Main Street, East 33rd Street\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"weight_typical\":212.389,\"distance\":1255.235,\"duration\":157.679,\"duration_typical\":157.679,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"axh`vAtyg~hFqYQiZO}SKsp@Y{TOgMGaRKaLGmDAmCCkCA_DA}KGgPIu[QaEAic@UcKEmZM_DAcEq@mIwD_Bs@oCoA}FaCkCiAuD{AsB{@yCmAoQiHsGiCcFsBmDuAkBu@yVaJ}EaBwOiFiCgAkFyBuJ_E}ViKiWgKwUoJ}UqJuUmJoHgC{OsFiDmACA{CgA_EuAmC}@\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.634449],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":1255.235,\"announcement\":\"Drive north on Main Street for 1 mile.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eDrive north on \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eMain Street\\u003c/say-as\\u003e for 1 mile.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":402.336,\"announcement\":\"In a quarter mile, Turn left onto East 33rd Street.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Turn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eEast 33rd Street\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":85.333,\"announcement\":\"Turn left onto East 33rd Street.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eTurn left onto \\u003csay-as interpret-as\\u003d\\\"address\\\"\\u003eEast 33rd Street\\u003c/say-as\\u003e.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":1255.235,\"primary\":{\"text\":\"East 33rd Street\",\"components\":[{\"text\":\"East 33rd Street\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"}},{\"distanceAlongGeometry\":402.336,\"primary\":{\"text\":\"East 33rd Street\",\"components\":[{\"text\":\"East 33rd Street\",\"type\":\"text\"}],\"type\":\"turn\",\"modifier\":\"left\"},\"sub\":{\"text\":\"\",\"components\":[{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"left\"],\"active\":true,\"active_direction\":\"left\"},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\"],\"active\":false},{\"text\":\"\",\"type\":\"lane\",\"directions\":[\"straight\",\"right\"],\"active\":false}]}}],\"driving_side\":\"right\",\"weight\":212.389,\"intersections\":[{\"duration\":7.364,\"weight\":8.836,\"location\":[-122.671531,45.634449],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.937,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.201,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":9.337,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":12.181,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":4.274,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":6.212,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.746,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.841,\"location\":[-122.671487,45.63679],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.728,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":5.044,\"location\":[-122.671483,45.637018],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.874,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.998,\"location\":[-122.671477,45.637323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.965,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.108,\"location\":[-122.671473,45.637532],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":2.999,\"turn_duration\":2.019,\"turn_weight\":0.5,\"duration\":4.059,\"location\":[-122.67147,45.63769],\"bearings\":[1,92,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":2.779,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":3.881,\"location\":[-122.671468,45.63784],\"bearings\":[1,181,267],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":12,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":4.005,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":5.882,\"location\":[-122.671464,45.638047],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":6.819,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":8.83,\"location\":[-122.671459,45.638323],\"bearings\":[1,181,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":14,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":9.662,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":12.812,\"location\":[-122.67145,45.638782],\"bearings\":[1,75,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.659,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":4.234,\"location\":[-122.671438,45.63946],\"bearings\":[1,92,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":11.009,\"turn_weight\":1,\"turn_duration\":0.019,\"weight\":14.462,\"location\":[-122.671435,45.639654],\"bearings\":[1,90,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":18,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":17.19,\"turn_duration\":2.017,\"turn_weight\":2,\"duration\":14.417,\"location\":[-122.671427,45.640173],\"bearings\":[15,90,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"right\"]}],\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":2.4,\"turn_weight\":0.5,\"weight\":3.44,\"location\":[-122.67131,45.640438],\"bearings\":[21,201],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":22,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.607,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":4.91,\"location\":[-122.671284,45.640486],\"bearings\":[21,201,258],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":23,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.019,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":2.95,\"location\":[-122.671244,45.640558],\"bearings\":[20,201,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":24,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.067,\"turn_weight\":0.5,\"weight\":1.807,\"location\":[-122.671179,45.640685],\"bearings\":[20,200],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":25,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":2.835,\"turn_duration\":0.007,\"turn_weight\":0.5,\"duration\":1.913,\"location\":[-122.671142,45.640755],\"bearings\":[20,111,200],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":26,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":6.106,\"turn_duration\":0.021,\"turn_weight\":1,\"duration\":4.189,\"location\":[-122.671066,45.640904],\"bearings\":[19,101,200,283],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":28,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.535,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":2.357,\"location\":[-122.670878,45.641277],\"bearings\":[19,108,199],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":30,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.177,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":1.933,\"location\":[-122.670809,45.641415],\"bearings\":[20,108,199],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":31,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":1.602,\"turn_duration\":0.021,\"turn_weight\":0.5,\"duration\":0.921,\"location\":[-122.670751,45.641529],\"bearings\":[19,90,200],\"entry\":[true,false,false],\"in\":2,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":32,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":1.101,\"turn_duration\":0.019,\"turn_weight\":0.5,\"duration\":0.51,\"location\":[-122.670708,45.641616],\"bearings\":[19,76,199],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":33,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":4.722,\"turn_duration\":0.019,\"turn_weight\":0.5,\"duration\":3.466,\"location\":[-122.670681,45.64167],\"bearings\":[18,199,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\"]}],\"geometry_index\":34,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.084,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":1.803,\"location\":[-122.670504,45.642051],\"bearings\":[17,198,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":35,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.536,\"turn_weight\":0.5,\"weight\":3.607,\"location\":[-122.670455,45.642162],\"bearings\":[17,197],\"entry\":[true,false],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\"]}],\"geometry_index\":36,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":3.609,\"turn_duration\":0.008,\"turn_weight\":1.5,\"duration\":1.73,\"location\":[-122.670338,45.64243],\"bearings\":[20,92,173,197,270],\"entry\":[true,true,false,false,true],\"in\":3,\"out\":0,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\"]}],\"geometry_index\":37,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.722,\"turn_weight\":0.5,\"weight\":2.609,\"location\":[-122.670241,45.642617],\"bearings\":[20,200],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":39,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.247,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":4.469,\"location\":[-122.670145,45.642804],\"bearings\":[20,200,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":40,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.268,\"turn_weight\":0.5,\"turn_duration\":0.021,\"weight\":4.478,\"location\":[-122.669948,45.643187],\"bearings\":[19,200,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":41,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.996,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.147,\"location\":[-122.669752,45.643576],\"bearings\":[19,199,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":42,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.115,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.293,\"location\":[-122.669568,45.64394],\"bearings\":[19,199,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":43,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":3.244,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.451,\"location\":[-122.669383,45.644307],\"bearings\":[19,199,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":44,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.528,\"turn_weight\":1,\"turn_duration\":0.021,\"weight\":2.846,\"location\":[-122.6692,45.64467],\"bearings\":[17,99,199,277],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":45,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":2.686,\"turn_weight\":0.5,\"turn_duration\":0.007,\"weight\":3.782,\"location\":[-122.669132,45.644822],\"bearings\":[18,197,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":46,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.733,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":2.6,\"location\":[-122.66901,45.645092],\"bearings\":[18,198,270],\"entry\":[true,false,true],\"in\":1,\"out\":0,\"geometry_index\":47,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"duration\":1.543,\"turn_weight\":0.5,\"weight\":2.39,\"location\":[-122.668971,45.645177],\"bearings\":[18,198],\"entry\":[true,false],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":48,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":0.5,\"location\":[-122.668934,45.645257],\"bearings\":[17,198],\"entry\":[true,false],\"in\":1,\"out\":0,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":50,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"weight_typical\":93.433,\"distance\":497.229,\"duration\":67.534,\"duration_typical\":67.534,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"_f~`vAvrb~hF_@fFEfN?j@Oz|@CdLCfN?tA?zwAIp^Opq@?tDCrDg@zoAC`R\",\"name\":\"East 33rd Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.66886,45.645424],\"bearing_before\":17.0,\"bearing_after\":275.0,\"instruction\":\"Turn left onto East 33rd Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"voiceInstructions\":[{\"distanceAlongGeometry\":483.896,\"announcement\":\"In a quarter mile, Your destination will be on the right.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eIn a quarter mile, Your destination will be on the right.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"},{\"distanceAlongGeometry\":55.556,\"announcement\":\"Your destination is on the right.\",\"ssmlAnnouncement\":\"\\u003cspeak\\u003e\\u003camazon:effect name\\u003d\\\"drc\\\"\\u003e\\u003cprosody rate\\u003d\\\"1.08\\\"\\u003eYour destination is on the right.\\u003c/prosody\\u003e\\u003c/amazon:effect\\u003e\\u003c/speak\\u003e\"}],\"bannerInstructions\":[{\"distanceAlongGeometry\":497.229,\"primary\":{\"text\":\"Your destination will be on the right\",\"components\":[{\"text\":\"Your destination will be on the right\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"right\"}},{\"distanceAlongGeometry\":55.556,\"primary\":{\"text\":\"Your destination is on the right\",\"components\":[{\"text\":\"Your destination is on the right\",\"type\":\"text\"}],\"type\":\"arrive\",\"modifier\":\"right\"}}],\"driving_side\":\"right\",\"weight\":93.433,\"intersections\":[{\"weight\":19.562,\"turn_duration\":8.501,\"turn_weight\":15,\"duration\":12.225,\"location\":[-122.66886,45.645424],\"bearings\":[15,103,197,275],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"lanes\":[{\"valid\":true,\"active\":true,\"valid_indication\":\"left\",\"indications\":[\"left\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\"]},{\"valid\":false,\"active\":false,\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":52,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":9.559,\"turn_weight\":0.75,\"weight\":12.459,\"location\":[-122.669242,45.645443],\"bearings\":[91,271],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":55,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.426,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":2.471,\"location\":[-122.670232,45.645451],\"bearings\":[0,91,271],\"entry\":[true,false,true],\"in\":1,\"out\":2,\"geometry_index\":56,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.689,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":2.794,\"location\":[-122.670443,45.645453],\"bearings\":[0,91,271],\"entry\":[false,false,true],\"in\":1,\"out\":2,\"geometry_index\":57,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":0.284,\"turn_weight\":0.75,\"turn_duration\":0.021,\"weight\":1.073,\"location\":[-122.670687,45.645455],\"bearings\":[91,182,270],\"entry\":[false,false,true],\"in\":0,\"out\":2,\"geometry_index\":58,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":9.746,\"turn_weight\":0.75,\"weight\":12.689,\"location\":[-122.67073,45.645455],\"bearings\":[90,270],\"entry\":[false,true],\"in\":0,\"out\":1,\"geometry_index\":59,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":15.703,\"turn_weight\":1.5,\"turn_duration\":0.007,\"weight\":20.728,\"location\":[-122.672152,45.645455],\"bearings\":[1,90,180,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":60,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":17.876,\"turn_duration\":2.021,\"turn_weight\":2,\"duration\":14.981,\"location\":[-122.673557,45.645468],\"bearings\":[0,91,182,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":63,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"turn_weight\":1.5,\"turn_duration\":0.021,\"location\":[-122.674941,45.64549],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":65,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"weight_typical\":0,\"distance\":0.0,\"duration\":0.0,\"duration_typical\":0.0,\"speedLimitUnit\":\"mph\",\"speedLimitSign\":\"mutcd\",\"geometry\":\"gj~`vAzao~hF??\",\"name\":\"East 33rd Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.675246,45.645492],\"bearing_before\":270.0,\"bearing_after\":0.0,\"instruction\":\"Your destination is on the right.\",\"type\":\"arrive\",\"modifier\":\"right\"},\"voiceInstructions\":[],\"bannerInstructions\":[],\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.675246,45.645492],\"bearings\":[90],\"entry\":[true],\"in\":0,\"geometry_index\":66,\"admin_index\":0}]}],\"annotation\":{\"distance\":[47.3,48.7,37.3,88.4,38.9,25.4,34.0,23.2,9.7,7.9,7.8,8.9,23.1,30.7,51.1,10.8,64.7,21.6,48.9,8.9,11.0,20.0,5.7,8.6,15.0,8.3,10.7,6.9,9.1,34.9,16.3,13.5,10.2,6.4,44.6,12.9,31.2,8.2,14.0,22.1,45.3,45.9,43.0,43.3,42.8,17.8,31.5,9.9,0.2,9.2,11.2,8.2,9.2,19.0,1.7,77.1,16.4,19.0,3.3,110.7,39.3,63.0,7.1,7.0,100.7,23.8],\"duration\":[7.364,8.552,3.937,9.337,4.274,2.746,3.728,2.874,1.641,1.324,2.971,1.088,2.779,4.005,6.819,1.399,8.263,2.659,9.315,1.694,6.449,7.968,2.4,3.607,2.019,1.067,1.17,0.743,0.882,3.307,1.535,1.177,0.921,0.51,3.466,1.084,2.536,0.644,1.086,1.722,3.247,3.268,2.996,3.115,3.244,1.528,2.686,1.733,0.039,1.504,1.874,1.383,9.647,2.365,0.213,9.559,1.426,1.689,0.284,9.746,5.649,9.038,1.017,2.864,12.117,1.922],\"speed\":[6.4,7.4,9.5,9.5,9.2,9.3,9.2,8.1,6.0,6.0,8.2,8.2,8.3,7.7,7.5,7.8,7.8,8.2,5.3,5.3,2.5,2.5,2.4,2.4,7.5,7.8,9.2,9.2,10.6,10.6,10.7,11.5,11.4,13.0,12.9,12.2,12.3,12.9,12.9,12.8,14.0,14.1,14.4,14.0,13.3,11.8,11.8,5.8,6.1,6.1,6.0,6.0,8.0,8.0,8.0,8.1,11.7,11.4,12.7,11.4,7.0,7.0,7.0,8.3,8.3,12.5],\"maxspeed\":[{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":32,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":48,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"},{\"speed\":40,\"unit\":\"km/h\"}],\"congestion_numeric\":[0,24,9,4,4,0,0,null,6,6,0,0,null,null,0,0,0,11,0,0,null,null,null,null,null,null,null,null,6,6,null,null,null,null,8,1,1,1,1,1,0,0,0,0,1,6,6,0,0,0,0,0,20,20,20,20,null,0,0,0,0,0,0,8,8,6]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6717523,45.6344513;-122.6752454,45.6455678\",\"alternatives\":true,\"language\":\"en\",\"layers\":\";\",\"continue_straight\":true,\"roundabout_exits\":true,\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,maxspeed,closure,speed,duration,distance\",\"voice_instructions\":true,\"banner_instructions\":true,\"voice_units\":\"imperial\",\"enable_refresh\":true},\"voiceLocale\":\"en-US\",\"requestUuid\":\"PuEXN4U6XkX5NOGg6UssKTN-Ipon4nZF7dok-zNkwT-ney88PBFDqA\\u003d\\u003d\"}" - //val routeJson = "{\"routeIndex\":\"0\",\"distance\":728.195,\"duration\":178.495,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@YEnd@I|_@|]HrTJxf@B~FgAPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"weight\":241.413,\"weight_name\":\"auto\",\"legs\":[{\"weight\":241.413,\"via_waypoints\":[],\"distance\":728.195,\"duration\":178.495,\"summary\":\"Main Street, West McLoughlin Boulevard\",\"admins\":[{\"iso_3166_1\":\"US\",\"iso_3166_1_alpha3\":\"USA\"}],\"steps\":[{\"distance\":220.325,\"duration\":29.108,\"geometry\":\"yxh`vAtyg~hFyXQiZO}SKsp@Y\",\"name\":\"Main Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671531,45.634461],\"bearing_before\":0.0,\"bearing_after\":1.0,\"instruction\":\"Drive north on Main Street.\",\"type\":\"depart\"},\"driving_side\":\"right\",\"weight\":35.461,\"intersections\":[{\"duration\":7.5,\"weight\":9,\"location\":[-122.671531,45.634461],\"bearings\":[1],\"entry\":[true],\"out\":0,\"geometry_index\":0,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"weight\":9.34,\"turn_duration\":2.019,\"turn_weight\":1.5,\"duration\":8.552,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,181,259],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":1,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"},\"traffic_signal\":true},{\"duration\":3.719,\"turn_weight\":0.5,\"turn_duration\":0.019,\"weight\":4.94,\"location\":[-122.671514,45.635311],\"bearings\":[1,90,181],\"entry\":[true,true,false],\"in\":2,\"out\":0,\"geometry_index\":2,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}},{\"turn_weight\":1,\"turn_duration\":0.019,\"location\":[-122.671508,45.635646],\"bearings\":[1,92,181,249],\"entry\":[true,true,false,true],\"in\":2,\"out\":0,\"geometry_index\":3,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"secondary\"}}]},{\"distance\":87.726,\"duration\":31.082,\"geometry\":\"otl`vAlwg~hFEnd@I|_@\",\"name\":\"West 20th Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.671495,45.63644],\"bearing_before\":1.0,\"bearing_after\":270.0,\"instruction\":\"Turn left onto West 20th Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":45.681,\"intersections\":[{\"duration\":19.722,\"turn_weight\":12.5,\"turn_duration\":5.622,\"weight\":29.773,\"location\":[-122.671495,45.63644],\"bearings\":[1,104,181,270],\"entry\":[true,true,false,true],\"in\":2,\"out\":3,\"geometry_index\":4,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.007,\"location\":[-122.672095,45.636443],\"bearings\":[1,90,182,271],\"entry\":[true,false,true,true],\"in\":1,\"out\":3,\"geometry_index\":5,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":179.057,\"duration\":68.349,\"geometry\":\"_ul`vAz}i~hF|]HrTJxf@B~FgA\",\"name\":\"Washington Street\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672622,45.636448],\"bearing_before\":271.0,\"bearing_after\":180.0,\"instruction\":\"Turn left onto Washington Street.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":88.24,\"intersections\":[{\"duration\":30.372,\"turn_weight\":10,\"turn_duration\":5.622,\"weight\":39.7,\"location\":[-122.672622,45.636448],\"bearings\":[1,91,180,270],\"entry\":[true,false,true,true],\"in\":1,\"out\":2,\"geometry_index\":6,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"duration\":17.558,\"turn_weight\":1,\"turn_duration\":0.008,\"weight\":22.06,\"location\":[-122.672627,45.635953],\"bearings\":[0,92,181],\"entry\":[false,true,true],\"in\":0,\"out\":2,\"geometry_index\":7,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}},{\"turn_weight\":2,\"turn_duration\":0.019,\"location\":[-122.672633,45.635607],\"bearings\":[1,92,180,270],\"entry\":[false,true,true,true],\"in\":0,\"out\":2,\"geometry_index\":8,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"street\"}}]},{\"distance\":241.086,\"duration\":49.955,\"geometry\":\"spi`vAl|i~hFPoj@UoK{@iJu@oIB_c@?uE@gM?QDoV?{@?gHB_V\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.672599,45.634842],\"bearing_before\":169.0,\"bearing_after\":91.0,\"instruction\":\"Turn left onto West McLoughlin Boulevard.\",\"type\":\"turn\",\"modifier\":\"left\"},\"driving_side\":\"right\",\"weight\":72.031,\"intersections\":[{\"duration\":22.522,\"turn_weight\":12.5,\"turn_duration\":3.622,\"weight\":35.18,\"location\":[-122.672599,45.634842],\"bearings\":[91,182,270,349],\"entry\":[true,true,true,false],\"in\":3,\"out\":0,\"geometry_index\":10,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":14.931,\"turn_duration\":2.008,\"turn_weight\":3,\"duration\":11.951,\"location\":[-122.671522,45.634874],\"bearings\":[1,82,182,259],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"geometry_index\":13,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":1.371,\"turn_weight\":0.75,\"weight\":2.396,\"location\":[-122.670778,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":15,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":3.086,\"turn_weight\":0.75,\"weight\":4.453,\"location\":[-122.670671,45.634899],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":16,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"weight\":6.469,\"turn_duration\":2.008,\"turn_weight\":2,\"duration\":5.732,\"location\":[-122.670443,45.634898],\"bearings\":[1,91,182,270],\"entry\":[true,true,true,false],\"in\":3,\"out\":1,\"lanes\":[{\"valid\":false,\"active\":false,\"indications\":[\"left\"]},{\"valid\":true,\"active\":true,\"valid_indication\":\"straight\",\"indications\":[\"straight\",\"right\"]}],\"geometry_index\":17,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"},\"traffic_signal\":true},{\"duration\":0.248,\"turn_weight\":0.75,\"weight\":1.048,\"location\":[-122.670058,45.634895],\"bearings\":[90,271],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":19,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"duration\":1.49,\"turn_weight\":0.75,\"weight\":2.538,\"location\":[-122.670028,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":20,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}},{\"turn_weight\":0.75,\"location\":[-122.66988,45.634895],\"bearings\":[90,270],\"entry\":[true,false],\"in\":1,\"out\":0,\"geometry_index\":21,\"is_urban\":true,\"admin_index\":0,\"mapbox_streets_v8\":{\"class\":\"tertiary\"}}]},{\"distance\":0.0,\"duration\":0.0,\"geometry\":\"ysi`vAn{c~hF??\",\"name\":\"West McLoughlin Boulevard\",\"mode\":\"driving\",\"maneuver\":{\"location\":[-122.669512,45.634893],\"bearing_before\":90.0,\"bearing_after\":0.0,\"instruction\":\"You have arrived at your destination.\",\"type\":\"arrive\"},\"driving_side\":\"right\",\"weight\":0.0,\"intersections\":[{\"location\":[-122.669512,45.634893],\"bearings\":[270],\"entry\":[true],\"in\":0,\"geometry_index\":22,\"admin_index\":0}]}],\"annotation\":{\"distance\":[46.0,48.6,37.3,88.4,46.7,41.1,55.1,38.5,70.9,14.5,54.2,15.6,14.5,13.4,44.8,8.4,17.7,0.7,29.3,2.3,11.5,28.7],\"congestion_numeric\":[0,null,4,4,null,null,null,null,null,null,0,0,0,4,4,4,4,1,1,1,1,1]}}],\"routeOptions\":{\"baseUrl\":\"https://api.mapbox.com\",\"user\":\"mapbox\",\"profile\":\"driving-traffic\",\"coordinates\":\"-122.6715815,45.6344615;-122.6716338,45.6364896;-122.6726954,45.6364085;-122.672707,45.6348712;-122.6695105,45.6350132\",\"geometries\":\"polyline6\",\"overview\":\"full\",\"steps\":true,\"annotations\":\"congestion_numeric,distance\",\"voice_instructions\":false,\"banner_instructions\":false,\"waypoints\":\"0;4\"},\"requestUuid\":\"mapmatching\"}" - val route = DirectionsRoute.fromJson(routeJson).toNavigationRoute(RouterOrigin.Offboard) - //val route = TestingUtil.loadNavigationRoute("short_route.json", "xyz") - val granularDistances = MapboxRouteLineUtils.granularDistancesProvider(route) - val vanishingRouteLine = VanishingRouteLine().also { - it.setScope(InternalJobControlFactory.createMainScopeJobControl().scope) - } - vanishingRouteLine.setGranularDistances(granularDistances!!) - - // granularDistances.flatStepDistances.forEach { - // vanishingRouteLine.trimTree(it.point) - // } - //point Point{type=Point, bbox=null, coordinates=[-122.67146157204115, 45.638172892050875]} offset 0.11118330619475914 - val point = Point.fromLngLat(-122.67146157204115, 45.638172892050875) - //val point = granularDistances.flatStepDistances.get(granularDistances.flatStepDistances.size / 2) - - //vanishingRouteLine.foobar(point.point) - - //vanishingRouteLine.checkPointInCurrentRange(Point.fromLngLat(-122.67147824336483, 45.63726680626696)) - - listOf( - //Point.fromLngLat(-122.67147824336483, 45.63726680626696), - Point.fromLngLat(-122.67147742508963, 45.63731108636806), - Point.fromLngLat(-122.67147676267612, 45.63734693217765), - Point.fromLngLat(-122.67147611000415, 45.6373822508342), - Point.fromLngLat(-122.67147545733246, 45.63741756947505), - Point.fromLngLat(-122.67147493129485, 45.63744639668131), - Point.fromLngLat(-122.67147436374492, 45.63747816134145), - Point.fromLngLat(-122.671473796195, 45.637509926000696) - ).forEach { - val offset = vanishingRouteLine.getOffset(it) - println(offset) - } - - - - } - -//0.12647115633449757 -/* -point Point{type=Point, bbox=null, coordinates=[-122.67147824336483, 45.63726680626696]} offset 0.1264711563343266 -point Point{type=Point, bbox=null, coordinates=[-122.67147742508963, 45.63731108636806]} offset 0.1264711563343266 -point Point{type=Point, bbox=null, coordinates=[-122.67147676267612, 45.63734693217765]} offset 0.1264711563343266 -point Point{type=Point, bbox=null, coordinates=[-122.67147611000415, 45.6373822508342]} offset 0.1264711563343266 -point Point{type=Point, bbox=null, coordinates=[-122.67147545733246, 45.63741756947505]} offset 0.1264711563343266 -point Point{type=Point, bbox=null, coordinates=[-122.67147493129485, 45.63744639668131]} offset 0.1264711563343266 -point Point{type=Point, bbox=null, coordinates=[-122.67147436374492, 45.63747816134145]} offset 0.1264711563343266 -point Point{type=Point, bbox=null, coordinates=[-122.671473796195, 45.637509926000696]} offset 0.1264711563343266 -point Point{type=Point, bbox=null, coordinates=[-122.6714732286451, 45.63754169065995]} offset 0.1264711563343266 - */ } diff --git a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt index 076d6c6cedf..3818dee822f 100644 --- a/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt +++ b/qa-test-app/src/main/java/com/mapbox/navigation/qa_test_app/view/AlternativeRouteActivity.kt @@ -1,7 +1,6 @@ package com.mapbox.navigation.qa_test_app.view import android.annotation.SuppressLint -import android.graphics.Color import android.location.Location import android.os.Build import android.os.Bundle @@ -16,16 +15,9 @@ import com.mapbox.android.core.location.LocationEngineResult import com.mapbox.android.gestures.Utils import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.api.directions.v5.models.RouteOptions -import com.mapbox.geojson.Feature -import com.mapbox.geojson.FeatureCollection import com.mapbox.geojson.Point import com.mapbox.maps.CameraOptions import com.mapbox.maps.EdgeInsets -import com.mapbox.maps.Style -import com.mapbox.maps.extension.style.layers.generated.CircleLayer -import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource -import com.mapbox.maps.extension.style.sources.generated.geoJsonSource -import com.mapbox.maps.extension.style.sources.getSource import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin import com.mapbox.maps.plugin.animation.MapAnimationOptions import com.mapbox.maps.plugin.animation.camera @@ -162,7 +154,7 @@ class AlternativeRouteActivity : AppCompatActivity(), OnMapLongClickListener { enabled = true } mapboxReplayer.pushRealLocation(this, 0.0) - mapboxReplayer.playbackSpeed(1.0) + mapboxReplayer.playbackSpeed(1.5) mapboxReplayer.play() } @@ -217,7 +209,6 @@ class AlternativeRouteActivity : AppCompatActivity(), OnMapLongClickListener { } ) binding.mapView.gestures.addOnMapLongClickListener(this) - initTreePointLayer(it) } } @@ -276,10 +267,6 @@ class AlternativeRouteActivity : AppCompatActivity(), OnMapLongClickListener { routeLineView.renderRouteLineUpdate(this, result) } } - - routeLineApi.deleteMeGetTreePoints().apply { - addTreePoints(this) - } } private fun findRoute(origin: Point?, destination: Point?) { @@ -380,29 +367,4 @@ class AlternativeRouteActivity : AppCompatActivity(), OnMapLongClickListener { } false } - - //todo delete below - private val TREE_LINE_LAYER_ID = "TREE_LINE_LAYER_ID" - private val TREE_LINE_SOURCE_ID = "TREE_LINE_SOURCE_ID" - private fun initTreePointLayer(style: Style) { - if (!style.styleSourceExists(TREE_LINE_SOURCE_ID)) { - geoJsonSource(TREE_LINE_SOURCE_ID) {}.bindTo(style) - } - - if (!style.styleLayerExists(TREE_LINE_LAYER_ID)) { - CircleLayer(TREE_LINE_LAYER_ID, TREE_LINE_SOURCE_ID) - .circleRadius(2.0) - .circleOpacity(.75) - .circleColor(Color.MAGENTA) - .bindTo(style) - } - } - - private fun addTreePoints(points: List) { - val features = points.map { Feature.fromGeometry(it) } - - (binding.mapView.getMapboxMap().getStyle()!!.getSource(TREE_LINE_SOURCE_ID) as GeoJsonSource).apply { - this.featureCollection(FeatureCollection.fromFeatures(features)) - } - } } From c06dcb35f14cfa319b0418cd2a6ff5c62652a12b Mon Sep 17 00:00:00 2001 From: Seth Bourget Date: Mon, 31 Oct 2022 13:30:40 -0700 Subject: [PATCH 7/7] wip testing edge case --- .../examples/core/MapboxNavigationActivity.kt | 21 ++++++++++++++++++- .../core/MapboxRouteLineAndArrowActivity.kt | 6 ++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxNavigationActivity.kt b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxNavigationActivity.kt index 7f4b5aac9fc..c1fe72ffbd2 100644 --- a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxNavigationActivity.kt +++ b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxNavigationActivity.kt @@ -20,6 +20,7 @@ import com.mapbox.maps.Style.Companion.MAPBOX_STREETS import com.mapbox.maps.plugin.LocationPuck2D import com.mapbox.maps.plugin.animation.camera import com.mapbox.maps.plugin.gestures.gestures +import com.mapbox.maps.plugin.locationcomponent.OnIndicatorPositionChangedListener import com.mapbox.maps.plugin.locationcomponent.location import com.mapbox.navigation.base.TimeFormat import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions @@ -141,6 +142,13 @@ class MapboxNavigationActivity : AppCompatActivity() { private lateinit var routeArrowView: MapboxRouteArrowView private val routeArrowAPI: MapboxRouteArrowApi = MapboxRouteArrowApi() + private val locationComponent by lazy { + binding.mapView.location.apply { + setLocationProvider(navigationLocationProvider) + enabled = true + } + } + /* ----- Voice instruction callbacks ----- */ private val voiceInstructionsObserver = VoiceInstructionsObserver { voiceInstructions -> @@ -388,6 +396,7 @@ class MapboxNavigationActivity : AppCompatActivity() { // initialize route line val mapboxRouteLineOptions = MapboxRouteLineOptions.Builder(this) .withRouteLineBelowLayerId("road-label") + .withVanishingRouteLineEnabled(true) .build() routeLineAPI = MapboxRouteLineApi(mapboxRouteLineOptions) routeLineView = MapboxRouteLineView(mapboxRouteLineOptions) @@ -434,6 +443,7 @@ class MapboxNavigationActivity : AppCompatActivity() { override fun onStart() { super.onStart() + locationComponent.addOnIndicatorPositionChangedListener(onPositionChangedListener) mapboxNavigation.registerRoutesObserver(routesObserver) mapboxNavigation.registerNavigationSessionStateObserver(navigationSessionStateObserver) mapboxNavigation.registerRouteProgressObserver(routeProgressObserver) @@ -443,6 +453,7 @@ class MapboxNavigationActivity : AppCompatActivity() { override fun onStop() { super.onStop() + locationComponent.removeOnIndicatorPositionChangedListener(onPositionChangedListener) mapboxNavigation.unregisterRoutesObserver(routesObserver) mapboxNavigation.unregisterNavigationSessionStateObserver(navigationSessionStateObserver) mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver) @@ -469,7 +480,7 @@ class MapboxNavigationActivity : AppCompatActivity() { RouteOptions.builder() .applyDefaultNavigationOptions() .applyLanguageAndVoiceUnitOptions(this) - .coordinatesList(listOf(origin, destination)) + .coordinatesList(listOf(Point.fromLngLat(-122.37033971197376, 45.5794559098664), Point.fromLngLat(-122.37006184362927, 45.57944922334681))) // fixme .layersList(listOf(mapboxNavigation.getZLevel(), null)) .build(), object : NavigationRouterCallback { @@ -527,4 +538,12 @@ class MapboxNavigationActivity : AppCompatActivity() { private companion object { private const val LOG_CATEGORY = "MapboxNavigationActivity" } + + private val onPositionChangedListener = OnIndicatorPositionChangedListener { point -> + val result = routeLineAPI.updateTraveledRouteLine(point) + mapboxMap.getStyle()?.apply { + // Render the result to update the map. + routeLineView.renderRouteLineUpdate(this, result) + } + } } diff --git a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt index b2ccb64b1a7..7eadbbf56e1 100644 --- a/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt +++ b/examples/src/main/java/com/mapbox/navigation/examples/core/MapboxRouteLineAndArrowActivity.kt @@ -364,6 +364,7 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe } override fun onMapLongClick(point: Point): Boolean { + Log.e("foobar", "point $point") vibrate() viewBinding.startNavigation.visibility = View.GONE viewBinding.optionTrafficGradient.visibility = View.GONE @@ -378,12 +379,13 @@ class MapboxRouteLineAndArrowActivity : AppCompatActivity(), OnMapLongClickListe } return false } - + //-122.36898496055935, 45.57909397202329 +//-122.37006184362927, 45.57944922334681 fun findRoute(origin: Point?, destination: Point?) { val routeOptions = RouteOptions.builder() .applyDefaultNavigationOptions() .applyLanguageAndVoiceUnitOptions(this) - .coordinatesList(listOf(origin, destination)) + .coordinatesList(listOf(Point.fromLngLat(-122.37033971197376, 45.5794559098664), Point.fromLngLat(-122.37006184362927, 45.57944922334681))) //fixme .layersList(listOf(mapboxNavigation.getZLevel(), null)) .alternatives(false) .build()