diff --git a/.screenshots/Screenshot_20221122_195412.png b/.screenshots/Screenshot_20221122_195412.png new file mode 100644 index 00000000..d29c5deb Binary files /dev/null and b/.screenshots/Screenshot_20221122_195412.png differ diff --git a/.screenshots/Screenshot_20221122_195701.png b/.screenshots/Screenshot_20221122_195701.png new file mode 100644 index 00000000..c1f342c5 Binary files /dev/null and b/.screenshots/Screenshot_20221122_195701.png differ diff --git a/.screenshots/Screenshot_20221122_200055.png b/.screenshots/Screenshot_20221122_200055.png new file mode 100644 index 00000000..394f466c Binary files /dev/null and b/.screenshots/Screenshot_20221122_200055.png differ diff --git a/.screenshots/Screenshot_20221122_200606.png b/.screenshots/Screenshot_20221122_200606.png new file mode 100644 index 00000000..af0b9578 Binary files /dev/null and b/.screenshots/Screenshot_20221122_200606.png differ diff --git a/.screenshots/Screenshot_20221122_200812.png b/.screenshots/Screenshot_20221122_200812.png new file mode 100644 index 00000000..eb178c19 Binary files /dev/null and b/.screenshots/Screenshot_20221122_200812.png differ diff --git a/TRAFFIC.MD b/TRAFFIC.MD new file mode 100644 index 00000000..a3bf0286 --- /dev/null +++ b/TRAFFIC.MD @@ -0,0 +1,245 @@ +![F](/.screenshots/Screenshot_20221122_195412.png?raw=true) +``` +19:53:24.134 6623-6623 com.here.android...rafficRepository com.here.android.example.routing V fetchTrafficEventList [Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [Tempelhofer Ufer] + Affected Length: 1055 + From Streets: [Schöneberger Ufer] + To Streets: [Mehringdamm] + Speed Limit: 6 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [] + Affected Length: 779 + From Streets: [] + To Streets: [] + Speed Limit: 29 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: HIGH + Affected Streets: [Potsdamer Straße] + Affected Length: 982 + From Streets: [Bülowstraße] + To Streets: [Schöneberger Ufer] + Speed Limit: 14 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + ] +19:53:24.149 6623-6623 MapFragmentView com.here.android.example.routing D loadTrafficForRoute [RouteTrafficInfo(startPercent=0.0, endPercent=0.012536162, trafficSeverity=HIGH), RouteTrafficInfo(startPercent=0.012536162, endPercent=0.36885247, trafficSeverity=NORMAL), RouteTrafficInfo(startPercent=0.36885247, endPercent=0.9165863, trafficSeverity=VERY_HIGH), RouteTrafficInfo(startPercent=0.9165863, endPercent=0.9975892, trafficSeverity=NORMAL)] +19:53:24.154 6623-6623 MapFragmentView com.here.android.example.routing D loadTrafficForRoute s:0 e:0.01 l:0.01 level: HIGH + s:0.37 e:0.92 l:0.55 level: VERY_HIGH +``` + +![S](/.screenshots/Screenshot_20221122_195701.png?raw=true) +``` +19:55:48.394 6623-6623 com.here.android...rafficRepository com.here.android.example.routing V fetchTrafficEventList [Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [Tempelhofer Ufer] + Affected Length: 1055 + From Streets: [Schöneberger Ufer] + To Streets: [Mehringdamm] + Speed Limit: 6 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [Schöneberger Ufer] + Affected Length: 474 + From Streets: [George-C.-Marshall-Brücke] + To Streets: [Tempelhofer Ufer] + Speed Limit: 22 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [] + Affected Length: 779 + From Streets: [] + To Streets: [] + Speed Limit: 31 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: HIGH + Affected Streets: [Potsdamer Straße] + Affected Length: 982 + From Streets: [Bülowstraße] + To Streets: [Schöneberger Ufer] + Speed Limit: 13 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + ] +19:55:48.407 6623-6623 MapFragmentView com.here.android.example.routing D loadTrafficForRoute [RouteTrafficInfo(startPercent=0.0, endPercent=0.012536162, trafficSeverity=HIGH), RouteTrafficInfo(startPercent=0.012536162, endPercent=0.14079075, trafficSeverity=NORMAL), RouteTrafficInfo(startPercent=0.14079075, endPercent=0.9165863, trafficSeverity=VERY_HIGH), RouteTrafficInfo(startPercent=0.9165863, endPercent=0.9975892, trafficSeverity=NORMAL)] +19:55:48.410 6623-6623 MapFragmentView com.here.android.example.routing D loadTrafficForRoute s:0 e:0.01 l:0.01 level: HIGH + s:0.14 e:0.92 l:0.78 level: VERY_HIGH +``` + +![T](/.screenshots/Screenshot_20221122_195701.png?raw=true) +``` +20:01:01.970 6623-6623 com.here.android...rafficRepository com.here.android.example.routing V fetchTrafficEventList [Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [Tempelhofer Ufer] + Affected Length: 1055 + From Streets: [Schöneberger Ufer] + To Streets: [Mehringdamm] + Speed Limit: 6 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [Schöneberger Ufer] + Affected Length: 474 + From Streets: [George-C.-Marshall-Brücke] + To Streets: [Tempelhofer Ufer] + Speed Limit: 6 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [] + Affected Length: 779 + From Streets: [] + To Streets: [] + Speed Limit: 30 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + ] +20:01:01.983 6623-6623 MapFragmentView com.here.android.example.routing D loadTrafficForRoute [RouteTrafficInfo(startPercent=0.0, endPercent=0.14079075, trafficSeverity=NORMAL), RouteTrafficInfo(startPercent=0.14079075, endPercent=0.9165863, trafficSeverity=VERY_HIGH), RouteTrafficInfo(startPercent=0.9165863, endPercent=0.9975892, trafficSeverity=NORMAL)] +20:01:01.985 6623-6623 MapFragmentView com.here.android.example.routing D loadTrafficForRoute s:0.14 e:0.92 l:0.78 level: VERY_HIGH +``` + +![F](/.screenshots/Screenshot_20221122_200606.png?raw=true) + +``` +20:06:11.461 6623-6623 com.here.android...rafficRepository com.here.android.example.routing V fetchTrafficEventList [Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [Tempelhofer Ufer] + Affected Length: 1055 + From Streets: [Schöneberger Ufer] + To Streets: [Mehringdamm] + Speed Limit: 6 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [Schöneberger Ufer] + Affected Length: 474 + From Streets: [George-C.-Marshall-Brücke] + To Streets: [Tempelhofer Ufer] + Speed Limit: 14 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [] + Affected Length: 779 + From Streets: [] + To Streets: [] + Speed Limit: 28 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + ] +20:06:11.521 6623-6623 MapFragmentView com.here.android.example.routing D loadTrafficForRoute [RouteTrafficInfo(startPercent=0.0, endPercent=0.14079075, trafficSeverity=NORMAL), RouteTrafficInfo(startPercent=0.14079075, endPercent=0.9165863, trafficSeverity=VERY_HIGH), RouteTrafficInfo(startPercent=0.9165863, endPercent=0.9975892, trafficSeverity=NORMAL)] +20:06:11.534 6623-6623 MapFragmentView com.here.android.example.routing D loadTrafficForRoute s:0.14 e:0.92 l:0.78 level: VERY_HIGH +``` + +![Fi](/.screenshots/Screenshot_20221122_200812.png?raw=true) +``` +20:08:16.679 6623-6623 com.here.android...rafficRepository com.here.android.example.routing V fetchTrafficEventList [Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [Tempelhofer Ufer] + Affected Length: 1055 + From Streets: [Schöneberger Ufer] + To Streets: [Mehringdamm] + Speed Limit: 6 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [Schöneberger Ufer] + Affected Length: 474 + From Streets: [George-C.-Marshall-Brücke] + To Streets: [Tempelhofer Ufer] + Speed Limit: 17 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + , Event Text: Traffic flow message. + Short Text: FLOW + Severity: VERY_HIGH + Affected Streets: [] + Affected Length: 779 + From Streets: [] + To Streets: [] + Speed Limit: 28 + Flow: True + Incident: False + Visible: True + Hazard Warning: False + Penalty: 0 + ] +20:08:16.718 6623-6623 MapFragmentView com.here.android.example.routing D loadTrafficForRoute [RouteTrafficInfo(startPercent=0.0, endPercent=0.14079075, trafficSeverity=NORMAL), RouteTrafficInfo(startPercent=0.14079075, endPercent=0.9165863, trafficSeverity=VERY_HIGH), RouteTrafficInfo(startPercent=0.9165863, endPercent=0.9975892, trafficSeverity=NORMAL)] +20:08:16.722 6623-6623 MapFragmentView com.here.android.example.routing D loadTrafficForRoute s:0.14 e:0.92 l:0.78 level: VERY_HIGH +``` diff --git a/routing/app/build.gradle b/routing/app/build.gradle index 7ecc186f..e967feb2 100644 --- a/routing/app/build.gradle +++ b/routing/app/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' android { compileSdkVersion 33 @@ -24,4 +25,16 @@ dependencies { implementation files('libs/HERE-sdk.aar') implementation 'com.google.code.gson:gson:2.8.2' implementation 'androidx.appcompat:appcompat:1.2.0' + + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation "androidx.core:core-ktx:1.9.0" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.1" + + + annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.4.1" + implementation "androidx.lifecycle:lifecycle-common-java8:2.4.1" + implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1" } diff --git a/routing/app/src/main/java/com/here/android/example/routing/MapFragmentView.java b/routing/app/src/main/java/com/here/android/example/routing/MapFragmentView.java index a610c9b2..0e75d93a 100644 --- a/routing/app/src/main/java/com/here/android/example/routing/MapFragmentView.java +++ b/routing/app/src/main/java/com/here/android/example/routing/MapFragmentView.java @@ -18,14 +18,19 @@ import android.app.AlertDialog; import android.content.DialogInterface; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; +import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; +import com.arrival.vehiclenavigation.R; +import com.here.android.example.routing.traffic.RouteTrafficInfo; +import com.here.android.example.routing.traffic.TrafficRepository; import com.here.android.mpa.common.GeoCoordinate; import com.here.android.mpa.common.GeoPolygon; import com.here.android.mpa.common.OnEngineInitListener; @@ -33,6 +38,8 @@ import com.here.android.mpa.mapping.AndroidXMapFragment; import com.here.android.mpa.mapping.Map; import com.here.android.mpa.mapping.MapRoute; +import com.here.android.mpa.mapping.MapTrafficLayer; +import com.here.android.mpa.mapping.TrafficEvent; import com.here.android.mpa.routing.CoreRouter; import com.here.android.mpa.routing.DrivingDirection; import com.here.android.mpa.routing.DynamicPenalty; @@ -45,12 +52,18 @@ import com.here.android.mpa.routing.RoutingError; import com.here.android.mpa.routing.RoutingZone; +import java.text.DecimalFormat; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; +import java.util.Iterator; import java.util.List; +import kotlin.Unit; +import kotlin.jvm.functions.Function1; + /** * This class encapsulates the properties and functionality of the Map view.A route calculation from * south of Berlin to the north of Berlin. @@ -64,8 +77,10 @@ public class MapFragmentView { private AppCompatActivity m_activity; private Map m_map; private MapRoute m_mapRoute; + private TextView m_trafficReport; private boolean m_isExcludeRoutingZones; private boolean m_addAvoidedAreas; + private NumberFormat decimalFormat = DecimalFormat.getInstance(); public MapFragmentView(AppCompatActivity activity) { m_activity = activity; @@ -74,6 +89,8 @@ public MapFragmentView(AppCompatActivity activity) { * We use a button in this example to control the route calculation */ initCreateRouteButton(); + m_trafficReport = m_activity.findViewById(R.id.trafficReport); + decimalFormat.setMaximumFractionDigits(2); } private AndroidXMapFragment getMapFragment() { @@ -93,6 +110,11 @@ public void onEngineInitializationCompleted(OnEngineInitListener.Error error) { if (error == Error.NONE) { /* get the map object */ m_map = m_mapFragment.getMap(); + m_map.getMapTrafficLayer().setEnabled(MapTrafficLayer.RenderLayer.FLOW, true); + m_map.getMapTrafficLayer().setEnabled(MapTrafficLayer.RenderLayer.INCIDENT, true); + m_map.getMapTrafficLayer().setEnabled(MapTrafficLayer.RenderLayer.ONROUTE, true); + + m_map.setTrafficInfoVisible(true); /* * Set the map center to the south of Berlin. @@ -187,9 +209,9 @@ private void createRoute(final List excludedRoutingZones) { /* Define waypoints for the route */ /* START: South of Berlin */ - RouteWaypoint startPoint = new RouteWaypoint(new GeoCoordinate(52.406425, 13.193975)); + RouteWaypoint startPoint = new RouteWaypoint(new GeoCoordinate(52.505326, 13.368087)); /* END: North of Berlin */ - RouteWaypoint destination = new RouteWaypoint(new GeoCoordinate(52.638623, 13.441998)); + RouteWaypoint destination = new RouteWaypoint(new GeoCoordinate(52.491863, 13.377296)); /* Add both waypoints to the route plan */ routePlan.addWaypoint(startPoint); @@ -218,6 +240,8 @@ public void onCalculateRouteFinished(List routeResults, } else { /* Create a MapRoute so that it can be placed on the map */ m_mapRoute = new MapRoute(route); + m_mapRoute.setTrafficEnabled(true); + loadTrafficForRoute(route); /* Show the maneuver number on top of the route */ m_mapRoute.setManeuverNumberVisible(true); @@ -241,6 +265,34 @@ public void onCalculateRouteFinished(List routeResults, }); } + public void loadTrafficForRoute(Route route) { + TrafficRepository.INSTANCE.loadTrafficForRoute(m_activity, route, new Function1, Unit>() { + @Override + public Unit invoke(List routeTrafficInfos) { + Log.d("MapFragmentView", "loadTrafficForRoute " + routeTrafficInfos.toString()); + + StringBuilder builder = new StringBuilder(); + Iterator i = routeTrafficInfos.iterator(); + while (i.hasNext()) { + RouteTrafficInfo v = i.next(); + if(v.getTrafficSeverity() == TrafficEvent.Severity.NORMAL) continue; + builder.append("s:"); + builder.append(decimalFormat.format(v.getStartPercent())); + builder.append(" e:"); + builder.append(decimalFormat.format(v.getEndPercent())); + builder.append(" l:"); + builder.append(decimalFormat.format(v.getEndPercent() - v.getStartPercent())); + builder.append(" level: "); + builder.append(v.getTrafficSeverity()); + builder.append("\n"); + } + m_trafficReport.setText(builder); + Log.d("MapFragmentView", "loadTrafficForRoute " + builder.toString()); + return Unit.INSTANCE; + } + }); + } + public boolean onOptionsItemSelected(MenuItem item) { item.setChecked(!item.isChecked()); if (item.getItemId() == ITEM_ID_SHOW_ZONES) { diff --git a/routing/app/src/main/java/com/here/android/example/routing/traffic/TrafficRepository.kt b/routing/app/src/main/java/com/here/android/example/routing/traffic/TrafficRepository.kt new file mode 100644 index 00000000..0c959a04 --- /dev/null +++ b/routing/app/src/main/java/com/here/android/example/routing/traffic/TrafficRepository.kt @@ -0,0 +1,217 @@ +package com.here.android.example.routing.traffic + +import android.util.Log +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope +import com.here.android.mpa.common.Identifier +import com.here.android.mpa.common.RoadElement +import com.here.android.mpa.guidance.TrafficUpdater +import com.here.android.mpa.mapping.TrafficEvent +import com.here.android.mpa.mapping.TrafficEvent.Severity +import com.here.android.mpa.routing.Route +import com.here.android.mpa.routing.RouteElement +import com.here.android.mpa.routing.RouteElements +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine +import kotlin.math.roundToLong + +data class RouteTrafficInfo( + val startPercent: Float, + val endPercent: Float, + val trafficSeverity: Severity +) + +data class RelativeTrafficInfoMeters( + val roadElement: RoadElement, + val start: Long, + val length: Long, + val trafficSeverity: Severity, +) + +object TrafficRepository { + + + private val trafficUpdater by lazy { TrafficUpdater.getInstance() } + private var job: Job? = null + + fun loadTrafficForRoute(activity: AppCompatActivity, route: Route, block: (List) -> Unit) { + job?.cancel() + job = activity.lifecycleScope.launch { + var routeTrafficInfoList = getTrafficForRoute(route, false) + + withContext(Dispatchers.Main) { + block(routeTrafficInfoList) + } + + while (isActive) { + delay(15_000L) + routeTrafficInfoList = getTrafficForRoute(route, true) + + withContext(Dispatchers.Main) { + block(routeTrafficInfoList) + } + } + } + } + + fun cancelRequest() { + job?.cancel() + } + + private suspend fun getTrafficForRoute( + route: Route, + forceRequest: Boolean + ): List = try { + if (forceRequest) { + route.routeElements?.let { + requestTrafficUpdate(it) + } + } + val trafficEventList = fetchTrafficEventList(route) + val routeElements = route.routeElements + if (routeElements != null ) { + val affectedRouteElements = routeElements.elements + .getRouteRangesTraffic() + .applyTrafficEvents(trafficEventList.filter { it.isOnRoute(route) }) + + val packedTrafficInfo = affectedRouteElements.values.toList() + .pack() + .toInterval(route.length.toLong()) + + packedTrafficInfo + } else { + emptyList() + } + } catch (ex: CancellationException) { + throw ex + } catch (ex: Exception) { + Log.e(this.javaClass.name, "getTrafficForRoute", ex) + emptyList() + } + + private suspend fun fetchTrafficEventList(route: Route): List = + suspendCoroutine { continuation -> + val listener = TrafficUpdater.GetEventsListener { eventsList, error -> + if (error != TrafficUpdater.Error.NONE) { + Log.e(this.javaClass.name, "fetchTrafficEventList $error") + continuation.resumeWith(Result.success(emptyList())) + } else { + Log.v(this.javaClass.name, "fetchTrafficEventList ${eventsList.filter { it.severity != TrafficEvent.Severity.NORMAL }}") + continuation.resumeWith(Result.success(eventsList)) + } + } + trafficUpdater.getEvents(route, listener) + } + + private suspend fun requestTrafficUpdate(routeElements: RouteElements): TrafficUpdater.RequestState = + suspendCancellableCoroutine { continuation -> + val listener = TrafficUpdater.Listener { requestState -> + continuation.resume(requestState) + } + + val requestInfo = trafficUpdater.request(routeElements, listener) + + if (requestInfo.error != TrafficUpdater.Error.NONE) + continuation.resumeWithException( + IllegalStateException("an error occurred while requesting ${requestInfo.error}}") + ) + continuation.invokeOnCancellation { + trafficUpdater.cancelRequest(requestInfo.requestId) + } + } + + /** + * Maps ALL current route RoadElements to RelativeTrafficInfoMeters + */ + private fun List.getRouteRangesTraffic(): MutableMap { + val internalRoadElements = this.mapNotNull { it.roadElement } + + val map: MutableMap = HashMap() + var lastFinish = 0L + internalRoadElements + .map { Triple(it, it.identifier, it.geometryLength.roundToLong()) } + .forEach { (routeElement, id, length) -> + id?.let { itemId -> + map[itemId] = + RelativeTrafficInfoMeters( + routeElement, + lastFinish, + length, + TrafficEvent.Severity.NORMAL + ) + lastFinish += length + } + } + return map + } + + /** + * Applies traffic severity info to route road elements + */ + private fun MutableMap.applyTrafficEvents(eventsList: List): Map { + eventsList.filter { it.severity != TrafficEvent.Severity.NORMAL } + .flatMap { event -> + event.affectedRoadElements.map { roadElement -> + Pair( + roadElement.identifier, + event.severity + ) + } + } + .forEach { (id, severity) -> + id?.let { itemId -> + this[itemId]?.copy(trafficSeverity = severity)?.let { + this[itemId] = it + } + } + } + return this.toMap() + } + + /** + * Merge sibling [RelativeTrafficInfoMeters] elements anc calculate merged length. + */ + private fun List.pack(): List { + val packedTrafficList = emptyList().toMutableList() + this.sortedBy { it.start } + .forEach { + if (packedTrafficList.isEmpty()) + packedTrafficList.add(it) + else { + val last = packedTrafficList.last() + if (last.trafficSeverity == it.trafficSeverity) { + packedTrafficList.removeLast() + // merge lengths + packedTrafficList.add(last.copy(length = last.length + it.length)) + } else { + packedTrafficList.add(it) + } + } + } + + return packedTrafficList + } + + private fun List.toInterval(routeLength: Long): List { + return this.map { + RouteTrafficInfo( + it.start.fractionForRange(0, routeLength), + (it.start + it.length).fractionForRange(0, routeLength), + it.trafficSeverity + ) + } + } + + fun Long.fractionForRange(start: Long, end: Long): Float = + coerceIn(start, end).let { (it - start) / (end - start).toFloat() } +} + diff --git a/routing/app/src/main/res/layout/activity_main.xml b/routing/app/src/main/res/layout/activity_main.xml index 4610ad3c..7b4da39f 100644 --- a/routing/app/src/main/res/layout/activity_main.xml +++ b/routing/app/src/main/res/layout/activity_main.xml @@ -17,4 +17,11 @@ android:layout_height="wrap_content" android:text="Create Route" android:id="@+id/button" /> + + diff --git a/routing/build.gradle b/routing/build.gradle index ecdbfd77..755258a1 100644 --- a/routing/build.gradle +++ b/routing/build.gradle @@ -1,6 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.6.20' repositories { google() jcenter() @@ -8,6 +9,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:7.2.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files