TomTom Routing
This commit is contained in:
@@ -87,8 +87,8 @@ class MainActivity : ComponentActivity() {
|
|||||||
|
|
||||||
val routeModel = RouteModel()
|
val routeModel = RouteModel()
|
||||||
var tilt = 50.0
|
var tilt = 50.0
|
||||||
val useMock = false
|
val useMock = true
|
||||||
val type = 1 // simulate 2 test 3 gpx
|
val type = 3 // simulate 2 test 3 gpx
|
||||||
|
|
||||||
var currentIndex = 0
|
var currentIndex = 0
|
||||||
val stepData: MutableLiveData<StepData> by lazy {
|
val stepData: MutableLiveData<StepData> by lazy {
|
||||||
@@ -317,6 +317,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
if (isNavigating()) {
|
if (isNavigating()) {
|
||||||
updateLocation(currentLocation, navigationViewModel)
|
updateLocation(currentLocation, navigationViewModel)
|
||||||
stepData.value = currentStep()
|
stepData.value = currentStep()
|
||||||
|
println("Step: ${stepData.value!!.instruction} ${stepData.value!!.leftStepDistance}")
|
||||||
if (route.currentStepIndex + 1 <= curLeg.steps.size) {
|
if (route.currentStepIndex + 1 <= curLeg.steps.size) {
|
||||||
nextStepData.value = nextStep()
|
nextStepData.value = nextStep()
|
||||||
}
|
}
|
||||||
@@ -390,7 +391,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
for ((index, waypoint) in routeModel.curRoute.waypoints.withIndex()) {
|
for ((index, waypoint) in routeModel.curRoute.waypoints.withIndex()) {
|
||||||
if (routeModel.isNavigating()) {
|
if (routeModel.isNavigating()) {
|
||||||
val deviation = 0.0
|
val deviation = 0.0
|
||||||
if (index in 300..routeModel.curRoute.waypoints.size) {
|
if (index in 0..routeModel.curRoute.waypoints.size) {
|
||||||
mock.setMockLocation(waypoint[1], waypoint[0])
|
mock.setMockLocation(waypoint[1], waypoint[0])
|
||||||
delay(500L) //
|
delay(500L) //
|
||||||
}
|
}
|
||||||
@@ -408,7 +409,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
navigationViewModel
|
navigationViewModel
|
||||||
)
|
)
|
||||||
val step = routeModel.currentStep()
|
val step = routeModel.currentStep()
|
||||||
println("Step: ${step}")
|
println("Step: ${step.instruction} ${step.leftStepDistance}")
|
||||||
if (step.leftStepDistance == 70.0) {
|
if (step.leftStepDistance == 70.0) {
|
||||||
println("")
|
println("")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,12 +33,6 @@ abstract class NavigationRepository {
|
|||||||
|
|
||||||
//private val nominatimUrl = "https://kouros-online.de/nominatim/"
|
//private val nominatimUrl = "https://kouros-online.de/nominatim/"
|
||||||
|
|
||||||
val tomtomApiKey = "678k5v6940cSXXIS5oD92qIrDgW3RBZ3"
|
|
||||||
|
|
||||||
private val tomtomUrl = "https://api.tomtom.com/traffic/services/5/incidentDetails"
|
|
||||||
|
|
||||||
private val tomtomFields =
|
|
||||||
"{incidents{type,geometry{type,coordinates},properties{iconCategory,events{description}}}}"
|
|
||||||
|
|
||||||
abstract fun getRoute(
|
abstract fun getRoute(
|
||||||
context: Context,
|
context: Context,
|
||||||
@@ -48,6 +42,7 @@ abstract class NavigationRepository {
|
|||||||
searchFilter: SearchFilter
|
searchFilter: SearchFilter
|
||||||
): String
|
): String
|
||||||
|
|
||||||
|
abstract fun getTraffic(context: Context, location: Location, carOrientation: Float): String
|
||||||
fun getRouteDistance(
|
fun getRouteDistance(
|
||||||
currentLocation: Location,
|
currentLocation: Location,
|
||||||
location: Location,
|
location: Location,
|
||||||
@@ -78,23 +73,7 @@ abstract class NavigationRepository {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTraffic(context: Context, location: Location, carOrientation: Float): String {
|
|
||||||
val useAsset = false
|
|
||||||
val bbox = calculateSquareRadius(location.latitude, location.longitude, 15.0)
|
|
||||||
return if (useAsset) {
|
|
||||||
val trafficJson = context.resources.openRawResource(R.raw.tomtom_traffic)
|
|
||||||
trafficJson.bufferedReader().use { it.readText() }
|
|
||||||
} else {
|
|
||||||
val trafficResult = fetchUrl(
|
|
||||||
"$tomtomUrl?key=$tomtomApiKey&bbox=$bbox&fields=$tomtomFields&language=en-GB&timeValidityFilter=present",
|
|
||||||
false
|
|
||||||
)
|
|
||||||
trafficResult.replace(
|
|
||||||
"{\"incidents\":",
|
|
||||||
"{\"type\": \"FeatureCollection\", \"features\":"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fetchUrl(url: String, authenticator: Boolean): String {
|
fun fetchUrl(url: String, authenticator: Boolean): String {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -26,4 +26,12 @@ class OsrmRepository : NavigationRepository() {
|
|||||||
val routeLocation = "${currentLocation.longitude},${currentLocation.latitude};${location.longitude},${location.latitude}?steps=true&alternatives=0"
|
val routeLocation = "${currentLocation.longitude},${currentLocation.latitude};${location.longitude},${location.latitude}?steps=true&alternatives=0"
|
||||||
return fetchUrl(routeUrl + routeLocation + exclude, true)
|
return fetchUrl(routeUrl + routeLocation + exclude, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getTraffic(
|
||||||
|
context: Context,
|
||||||
|
location: Location,
|
||||||
|
carOrientation: Float
|
||||||
|
): String {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,10 +5,19 @@ import android.location.Location
|
|||||||
import com.kouros.data.R
|
import com.kouros.data.R
|
||||||
import com.kouros.navigation.data.NavigationRepository
|
import com.kouros.navigation.data.NavigationRepository
|
||||||
import com.kouros.navigation.data.SearchFilter
|
import com.kouros.navigation.data.SearchFilter
|
||||||
|
import com.kouros.navigation.utils.GeoUtils.calculateSquareRadius
|
||||||
|
|
||||||
|
|
||||||
private const val routeUrl = "https://api.tomtom.com/routing/1/calculateRoute/"
|
private const val routeUrl = "https://api.tomtom.com/routing/1/calculateRoute/"
|
||||||
|
|
||||||
|
val tomtomApiKey = "678k5v6940cSXXIS5oD92qIrDgW3RBZ3"
|
||||||
|
|
||||||
|
val tomtomTrafficUrl = "https://api.tomtom.com/traffic/services/5/incidentDetails"
|
||||||
|
|
||||||
|
|
||||||
|
private val tomtomFields =
|
||||||
|
"{incidents{type,geometry{type,coordinates},properties{iconCategory,events{description}}}}"
|
||||||
|
|
||||||
class TomTomRepository : NavigationRepository() {
|
class TomTomRepository : NavigationRepository() {
|
||||||
override fun getRoute(
|
override fun getRoute(
|
||||||
context: Context,
|
context: Context,
|
||||||
@@ -17,9 +26,9 @@ class TomTomRepository : NavigationRepository() {
|
|||||||
carOrientation: Float,
|
carOrientation: Float,
|
||||||
searchFilter: SearchFilter
|
searchFilter: SearchFilter
|
||||||
): String {
|
): String {
|
||||||
//val routeJson = context.resources.openRawResource(R.raw.tomom_routing)
|
val routeJson = context.resources.openRawResource(R.raw.tomom_routing)
|
||||||
//val routeJsonString = routeJson.bufferedReader().use { it.readText() }
|
val routeJsonString = routeJson.bufferedReader().use { it.readText() }
|
||||||
//return routeJsonString
|
return routeJsonString
|
||||||
val url =
|
val url =
|
||||||
routeUrl + "${currentLocation.latitude},${currentLocation.longitude}:${location.latitude},${location.longitude}" +
|
routeUrl + "${currentLocation.latitude},${currentLocation.longitude}:${location.latitude},${location.longitude}" +
|
||||||
"/json?vehicleHeading=90§ionType=traffic&report=effectiveSettings&routeType=eco" +
|
"/json?vehicleHeading=90§ionType=traffic&report=effectiveSettings&routeType=eco" +
|
||||||
@@ -33,4 +42,22 @@ class TomTomRepository : NavigationRepository() {
|
|||||||
false
|
false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getTraffic(context: Context, location: Location, carOrientation: Float): String {
|
||||||
|
val useAsset = true
|
||||||
|
val bbox = calculateSquareRadius(location.latitude, location.longitude, 15.0)
|
||||||
|
return if (useAsset) {
|
||||||
|
val trafficJson = context.resources.openRawResource(R.raw.tomtom_traffic)
|
||||||
|
trafficJson.bufferedReader().use { it.readText() }
|
||||||
|
} else {
|
||||||
|
val trafficResult = fetchUrl(
|
||||||
|
"$tomtomTrafficUrl?key=$tomtomApiKey&bbox=$bbox&fields=$tomtomFields&language=en-GB&timeValidityFilter=present",
|
||||||
|
false
|
||||||
|
)
|
||||||
|
trafficResult.replace(
|
||||||
|
"{\"incidents\":",
|
||||||
|
"{\"type\": \"FeatureCollection\", \"features\":"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -47,4 +47,12 @@ class ValhallaRepository : NavigationRepository() {
|
|||||||
val routeLocation = Json.encodeToString(valhallaLocation)
|
val routeLocation = Json.encodeToString(valhallaLocation)
|
||||||
return fetchUrl(routeUrl + routeLocation, true)
|
return fetchUrl(routeUrl + routeLocation, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getTraffic(
|
||||||
|
context: Context,
|
||||||
|
location: Location,
|
||||||
|
carOrientation: Float
|
||||||
|
): String {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -136,25 +136,25 @@ open class RouteModel() {
|
|||||||
}
|
}
|
||||||
return lanes
|
return lanes
|
||||||
|
|
||||||
var inter = Intersection()
|
// var inter = Intersection()
|
||||||
var nearestDistance = 100000.0f
|
// var nearestDistance = 100000.0f
|
||||||
route.currentStep().intersection.forEach {
|
// route.currentStep().intersection.forEach {
|
||||||
if (it.lane.isNotEmpty()) {
|
// if (it.lane.isNotEmpty()) {
|
||||||
val distance = location.distanceTo(location(it.location[0], it.location[1]))
|
// val distance = location.distanceTo(location(it.location[0], it.location[1]))
|
||||||
val interBearing = location.bearingTo(location(it.location[0], it.location[1]))
|
// val interBearing = location.bearingTo(location(it.location[0], it.location[1]))
|
||||||
if (distance < nearestDistance) {
|
// if (distance < nearestDistance) {
|
||||||
nearestDistance = distance
|
// nearestDistance = distance
|
||||||
if (distance <= NEXT_STEP_THRESHOLD * 3) {
|
// if (distance <= NEXT_STEP_THRESHOLD * 3) {
|
||||||
if (route.routeEngine == RouteEngine.TOMTOM.ordinal
|
// if (route.routeEngine == RouteEngine.TOMTOM.ordinal
|
||||||
|| (interBearing.absoluteValue - route.currentStep().maneuver.bearingAfter.absoluteValue).absoluteValue < 20
|
// || (interBearing.absoluteValue - route.currentStep().maneuver.bearingAfter.absoluteValue).absoluteValue < 20
|
||||||
) {
|
// ) {
|
||||||
inter = it
|
// inter = it
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return inter.lane
|
// return inter.lane
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateSpeedLimit(location: Location, viewModel: ViewModel) = runBlocking {
|
fun updateSpeedLimit(location: Location, viewModel: ViewModel) = runBlocking {
|
||||||
@@ -188,7 +188,7 @@ open class RouteModel() {
|
|||||||
fun currentStep(): StepData {
|
fun currentStep(): StepData {
|
||||||
val distanceToNextStep = leftStepDistance()
|
val distanceToNextStep = leftStepDistance()
|
||||||
// Determine the maneuver type and corresponding icon
|
// Determine the maneuver type and corresponding icon
|
||||||
val currentStep = route.nextStep(1) // This advances the route's state
|
val currentStep = route.nextStep(1)
|
||||||
// Safely get the street name from the maneuver
|
// Safely get the street name from the maneuver
|
||||||
val streetName = currentStep.name
|
val streetName = currentStep.name
|
||||||
val curManeuverType = currentStep.maneuver.type
|
val curManeuverType = currentStep.maneuver.type
|
||||||
@@ -270,7 +270,8 @@ open class RouteModel() {
|
|||||||
/** Returns the current [Step] left distance in m. */
|
/** Returns the current [Step] left distance in m. */
|
||||||
fun leftStepDistance(): Double {
|
fun leftStepDistance(): Double {
|
||||||
val step = route.currentStep()
|
val step = route.currentStep()
|
||||||
var leftDistance = 0.0
|
println(step.index)
|
||||||
|
var leftDistance = 0F
|
||||||
for (i in step.waypointIndex..<step.maneuver.waypoints.size - 1) {
|
for (i in step.waypointIndex..<step.maneuver.waypoints.size - 1) {
|
||||||
val loc1 = location(step.maneuver.waypoints[i][0], step.maneuver.waypoints[i][1])
|
val loc1 = location(step.maneuver.waypoints[i][0], step.maneuver.waypoints[i][1])
|
||||||
val loc2 =
|
val loc2 =
|
||||||
|
|||||||
@@ -135,7 +135,7 @@
|
|||||||
"source": "openmaptiles",
|
"source": "openmaptiles",
|
||||||
"source-layer": "landuse",
|
"source-layer": "landuse",
|
||||||
"filter": ["==", ["get", "class"], "track"],
|
"filter": ["==", ["get", "class"], "track"],
|
||||||
"paint": {"fill-color": "#DEE3CD"}
|
"paint": {"fill-color": "rgba(67, 67, 65, 1)"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "landuse_cemetery",
|
"id": "landuse_cemetery",
|
||||||
@@ -151,7 +151,7 @@
|
|||||||
"source": "openmaptiles",
|
"source": "openmaptiles",
|
||||||
"source-layer": "landuse",
|
"source-layer": "landuse",
|
||||||
"filter": ["==", ["get", "class"], "hospital"],
|
"filter": ["==", ["get", "class"], "hospital"],
|
||||||
"paint": {"fill-color": "#fde"}
|
"paint": {"fill-color": "rgba(51, 45, 48, 1)"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "landuse_school",
|
"id": "landuse_school",
|
||||||
@@ -362,7 +362,7 @@
|
|||||||
["==", ["get", "brunnel"], "tunnel"],
|
["==", ["get", "brunnel"], "tunnel"],
|
||||||
["match", ["get", "class"], ["service", "track"], true, false]
|
["match", ["get", "class"], ["service", "track"], true, false]
|
||||||
],
|
],
|
||||||
"layout": {"line-join": "round"},
|
"layout": {"line-join": "round", "visibility": "none"},
|
||||||
"paint": {
|
"paint": {
|
||||||
"line-color": "#cfcdca",
|
"line-color": "#cfcdca",
|
||||||
"line-dasharray": [0.5, 0.25],
|
"line-dasharray": [0.5, 0.25],
|
||||||
@@ -535,6 +535,7 @@
|
|||||||
["==", ["get", "brunnel"], "tunnel"],
|
["==", ["get", "brunnel"], "tunnel"],
|
||||||
["match", ["get", "class"], ["path", "pedestrian"], true, false]
|
["match", ["get", "class"], ["path", "pedestrian"], true, false]
|
||||||
],
|
],
|
||||||
|
"layout": {"visibility": "none"},
|
||||||
"paint": {
|
"paint": {
|
||||||
"line-color": "hsl(0,0%,100%)",
|
"line-color": "hsl(0,0%,100%)",
|
||||||
"line-dasharray": [1, 0.75],
|
"line-dasharray": [1, 0.75],
|
||||||
@@ -588,7 +589,7 @@
|
|||||||
["==", ["get", "brunnel"], "tunnel"],
|
["==", ["get", "brunnel"], "tunnel"],
|
||||||
["match", ["get", "class"], ["service", "track"], true, false]
|
["match", ["get", "class"], ["service", "track"], true, false]
|
||||||
],
|
],
|
||||||
"layout": {"line-join": "round"},
|
"layout": {"line-join": "round", "visibility": "none"},
|
||||||
"paint": {
|
"paint": {
|
||||||
"line-color": "#fff",
|
"line-color": "#fff",
|
||||||
"line-width": [
|
"line-width": [
|
||||||
@@ -616,7 +617,7 @@
|
|||||||
],
|
],
|
||||||
"layout": {"line-join": "round"},
|
"layout": {"line-join": "round"},
|
||||||
"paint": {
|
"paint": {
|
||||||
"line-color": "#fff4c6",
|
"line-color": "rgba(72, 72, 67, 1)",
|
||||||
"line-width": [
|
"line-width": [
|
||||||
"interpolate",
|
"interpolate",
|
||||||
["exponential", 1.2],
|
["exponential", 1.2],
|
||||||
|
|||||||
@@ -6,39 +6,39 @@ koinAndroid = "4.1.1"
|
|||||||
koinAndroidxCompose = "4.1.1"
|
koinAndroidxCompose = "4.1.1"
|
||||||
koinComposeViewmodel = "4.1.1"
|
koinComposeViewmodel = "4.1.1"
|
||||||
koinCore = "4.1.1"
|
koinCore = "4.1.1"
|
||||||
kotlin = "2.3.0"
|
kotlin = "2.3.10"
|
||||||
coreKtx = "1.17.0"
|
coreKtx = "1.17.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.3.0"
|
junitVersion = "1.3.0"
|
||||||
espressoCore = "3.7.0"
|
espressoCore = "3.7.0"
|
||||||
kotlinxSerializationJson = "1.9.0"
|
kotlinxSerializationJson = "1.10.0"
|
||||||
lifecycleRuntimeKtx = "2.10.0"
|
lifecycleRuntimeKtx = "2.10.0"
|
||||||
composeBom = "2025.12.01"
|
composeBom = "2026.01.01"
|
||||||
appcompat = "1.7.1"
|
appcompat = "1.7.1"
|
||||||
material = "1.13.0"
|
material = "1.13.0"
|
||||||
carApp = "1.7.0"
|
carApp = "1.7.0"
|
||||||
androidx-car = "1.7.0"
|
androidx-car = "1.7.0"
|
||||||
objectboxKotlin = "5.0.1"
|
objectboxKotlin = "5.1.0"
|
||||||
objectboxProcessor = "5.0.1"
|
objectboxProcessor = "5.0.1"
|
||||||
ui = "1.10.0"
|
ui = "1.10.0"
|
||||||
material3 = "1.4.0"
|
material3 = "1.4.0"
|
||||||
runtimeLivedata = "1.10.0"
|
runtimeLivedata = "1.10.2"
|
||||||
foundation = "1.10.0"
|
foundation = "1.10.0"
|
||||||
maplibre-composeMaterial3 = "0.12.2"
|
maplibre-composeMaterial3 = "0.12.2"
|
||||||
maplibre-compose = "0.12.1"
|
maplibre-compose = "0.12.1"
|
||||||
playServicesLocation = "21.3.0"
|
playServicesLocation = "21.3.0"
|
||||||
runtime = "1.10.0"
|
runtime = "1.10.2"
|
||||||
accompanist = "0.37.3"
|
accompanist = "0.37.3"
|
||||||
uiVersion = "1.10.0"
|
uiVersion = "1.10.2"
|
||||||
uiText = "1.10.0"
|
uiText = "1.10.2"
|
||||||
navigationCompose = "2.9.6"
|
navigationCompose = "2.9.7"
|
||||||
uiToolingPreview = "1.10.0"
|
uiToolingPreview = "1.10.2"
|
||||||
uiTooling = "1.10.0"
|
uiTooling = "1.10.2"
|
||||||
material3WindowSizeClass = "1.4.0"
|
material3WindowSizeClass = "1.4.0"
|
||||||
uiGraphics = "1.10.0"
|
uiGraphics = "1.10.2"
|
||||||
window = "1.5.1"
|
window = "1.5.1"
|
||||||
foundationLayout = "1.10.0"
|
foundationLayout = "1.10.2"
|
||||||
foundationLayoutVersion = "1.10.1"
|
foundationLayoutVersion = "1.10.2"
|
||||||
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
|||||||
Reference in New Issue
Block a user