Overpass, Traffic

This commit is contained in:
Dimitris
2026-04-27 15:58:04 +02:00
parent 17e68de017
commit 42b3eabe47
22 changed files with 206 additions and 142 deletions
@@ -4,9 +4,9 @@ import androidx.compose.ui.graphics.Color
val NavigationColorLight = Color(0xFF17A119)
val NavigationColorDark = Color(0xFF03411F)
val NavigationColorDark = Color(0xFF07568C)
val RouteColor = Color(0xFF195D02)
val RouteColor = Color(0xFF5201B4)
val SpeedColor = Color(0xFF262525)
@@ -13,6 +13,7 @@ import com.kouros.navigation.data.tomtom.TomTomRoute
import com.kouros.navigation.data.valhalla.ValhallaResponse
import com.kouros.navigation.data.valhalla.ValhallaRoute
import com.kouros.navigation.utils.location
import kotlinx.coroutines.selects.whileSelect
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.jsonObject
@@ -102,16 +103,22 @@ data class Route(
return if (isRouteValid()) {
legs().first().steps[currentStepIndex]
} else {
Step(maneuver = Maneuver(waypoints = emptyList(), location = location(0.0, 0.0)))
Step(maneuver = Maneuver(waypoints = emptyList(), location = location(0.0, 0.0), leftDistance = emptyList()))
}
}
/**
* Maneuver locations to snap location
*/
fun maneuverLocations(): List<Point> {
val wayPointIndex = currentStep().waypointIndex
val waypoints = currentStep().maneuver.waypoints
val points = mutableListOf<Point>()
for (loc in waypoints) {
val point = Point.fromLngLat(loc[0], loc[1])
points.add(point)
for ((index,loc) in waypoints.withIndex()) {
if (index >= wayPointIndex && points.size < 20) {
val point = Point.fromLngLat(loc[0], loc[1])
points.add(point)
}
}
return points
}
@@ -12,6 +12,7 @@ import com.kouros.navigation.utils.GeoUtils.createCenterLocation
import com.kouros.navigation.utils.GeoUtils.createLineStringCollection
import com.kouros.navigation.utils.GeoUtils.decodePolyline
import com.kouros.navigation.utils.location
import kotlin.math.absoluteValue
class OsrmRoute {
@@ -27,8 +28,22 @@ class OsrmRoute {
val steps = mutableListOf<Step>()
leg.steps.forEach { step ->
val intersections = mutableListOf<Intersection>()
val leftDistance = mutableListOf<Float>()
var lastLocation = location(0.0,0.0)
val points = decodePolyline(step.geometry, 5)
waypoints.addAll(points)
// calculate left step distance for each point
var leftStepDistance = step.distance
leftDistance.add(leftStepDistance.toFloat())
points.forEach {
if (lastLocation.latitude != 0.0) {
val curLocation = location(it[0], it[1])
val dist = curLocation.distanceTo(lastLocation).absoluteValue
leftStepDistance -= dist
leftDistance.add(leftStepDistance.toFloat())
}
lastLocation = location(it[0], it[1])
}
val maneuver = RouteManeuver(
bearingBefore = step.maneuver.bearingBefore,
bearingAfter = step.maneuver.bearingAfter,
@@ -38,7 +53,8 @@ class OsrmRoute {
location = location(
step.maneuver.location[0],
step.maneuver.location[1]
)
),
leftDistance = leftDistance
)
step.intersections.forEach { it2 ->
if (it2.location[0] != 0.0) {
@@ -56,7 +56,6 @@ class Overpass {
""".trimMargin()
Log.d("OverpassApi", "Overpass Query: $searchQuery")
val connection = (URL(overpassUrl).openConnection() as HttpURLConnection).apply {
requestMethod = "POST"
setRequestProperty("Accept", "application/json")
@@ -9,6 +9,7 @@ data class Tags(
val lanes: String = "",
val lit: String = "",
val maxspeed: String = "0",
@SerializedName("maxspeed:variable") val maxSpeedVariable: String = "",
val name: String = "",
val oneway: String = "",
val ref: String = "",
@@ -12,6 +12,7 @@ data class Maneuver(
val street: String = "",
val message: String = "",
val pointIndex: Int = 0,
val leftDistance: List<Float>
)
enum class ManeuverType(val value: Int) {
@@ -40,8 +40,8 @@ class TomTomRepository : NavigationRepository() {
}
if (useLocal) {
return fetchUrl(
//"http://192.168.1.37/tomtom_routing.json",
"http://192.168.1.37/verona.json",
"http://192.168.1.37/tomtom_routing.json",
//"http://192.168.1.37/verona.json",
false
)
}
@@ -13,7 +13,9 @@ import com.kouros.navigation.data.route.Summary
import com.kouros.navigation.utils.GeoUtils.createCenterLocation
import com.kouros.navigation.utils.GeoUtils.createLineStringCollection
import com.kouros.navigation.utils.GeoUtils.decodePolyline
import com.kouros.navigation.utils.isNumeric
import com.kouros.navigation.utils.location
import kotlin.math.absoluteValue
import com.kouros.navigation.data.route.Maneuver as RouteManeuver
@@ -53,6 +55,27 @@ class TomTomRoute {
val instruction = route.guidance.instructions[index]
val street = lastInstruction.street ?: ""
val maneuverStreet = instruction.street ?: ""
val leftDistance = mutableListOf<Float>()
var lastLocation = location(0.0, 0.0)
stepDistance =
route.guidance.instructions[index].routeOffsetInMeters - stepDistance
stepDuration =
route.guidance.instructions[index].travelTimeInSeconds - stepDuration
// calculate left step distance for each point
var leftStepDistance = stepDistance
leftDistance.add(leftStepDistance.toFloat())
points.subList(
lastPointIndex,
instruction.pointIndex + 1,
).forEach {
if (lastLocation.latitude != 0.0) {
val curLocation = location(it[0], it[1])
val dist = curLocation.distanceTo(lastLocation).absoluteValue
leftStepDistance -= dist
leftDistance.add(leftStepDistance.toFloat())
}
lastLocation = location(it[0], it[1])
}
val maneuver = RouteManeuver(
bearingBefore = 0,
bearingAfter = 0,
@@ -67,9 +90,9 @@ class TomTomRoute {
),
street = maneuverStreet,
message = instruction.message,
pointIndex = instruction.pointIndex
pointIndex = instruction.pointIndex,
leftDistance = leftDistance
)
lastPointIndex = instruction.pointIndex
val intersections = mutableListOf<Intersection>()
route.sections?.forEach { section ->
@@ -95,10 +118,7 @@ class TomTomRoute {
intersections.add(Intersection(waypoints[startIndex], lanes))
}
}
stepDistance =
route.guidance.instructions[index].routeOffsetInMeters - stepDistance
stepDuration =
route.guidance.instructions[index].travelTimeInSeconds - stepDuration
val roadNumbers = if (lastInstruction.roadNumbers != null) {
lastInstruction.roadNumbers
} else {
@@ -212,6 +232,7 @@ class TomTomRoute {
"TAKE_EXIT" -> {
newType = ManeuverType.TYPE_TURN_SLIGHT_RIGHT.value
}
"WAYPOINT_RIGHT" -> {
newType = ManeuverType.TYPE_WAYPOINT_RIGHT.value
}
@@ -227,9 +248,9 @@ private fun exitNumber(
) {
0
} else {
try {
if (isNumeric(instruction.exitNumber)) {
instruction.exitNumber.toInt()
} catch (e: NumberFormatException) {
} else {
0
}
}
@@ -27,7 +27,8 @@ class ValhallaRoute {
type = convertType(it),
waypoints =waypoints.subList(it.beginShapeIndex, it.endShapeIndex+1),
// TODO: calculate from ShapeIndex !
location = location(0.0, 0.0)
location = location(0.0, 0.0),
leftDistance = emptyList()
)
var name = ""
@@ -2,12 +2,14 @@ package com.kouros.navigation.model
import android.content.Context
import android.location.Location
import android.util.Log
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.runtime.toMutableStateList
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.SPEED_BEARING_DEVIATION
@@ -24,6 +26,7 @@ import com.kouros.navigation.data.overpass.Overpass
import com.kouros.navigation.utils.bearingPositive
import com.kouros.navigation.utils.countryCodeSpeedLimit
import com.kouros.navigation.utils.getSettingsRepository
import com.kouros.navigation.utils.isNumeric
import com.kouros.navigation.utils.location
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
@@ -115,7 +118,7 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
MutableLiveData()
}
val gson: com.google.gson.Gson = GsonBuilder().create()
val gson: Gson = GsonBuilder().create()
/**
* Retrieves recent places from Preferences as a Flow.
@@ -432,7 +435,7 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
val search = mutableListOf<ElementSearch>()
speedElements.filter { it.type == "way"}.forEach {
var distance = 0F
var distance: Float
var maxDistance = 1000F
var geometryFirstLocation = location(0.0, 0.0)
var geometryLastLocation = location(0.0, 0.0)
@@ -466,7 +469,11 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
speed = if (element.tags.maxspeed == "none" && element.tags.highway == "motorway") {
countryCodeSpeedLimit(countryCode)
} else {
element.tags.maxspeed.toInt()
if (isNumeric(element.tags.maxspeed)) {
element.tags.maxspeed.toInt()
} else {
0
}
}
}
return speed
@@ -7,6 +7,7 @@ import com.kouros.navigation.data.Constants.NEAREST_LOCATION_DISTANCE
import com.kouros.navigation.data.Constants.SPEED_UPDATE_DISTANCE
import com.kouros.navigation.utils.location
import java.util.concurrent.TimeUnit
import kotlin.math.absoluteValue
class RouteCalculator(var routeModel: RouteModel) {
@@ -17,10 +18,11 @@ class RouteCalculator(var routeModel: RouteModel) {
fun findStep(location: Location) {
var nearestDistance = MAXIMUM_LOCATION_DISTANCE
for ((index, step) in routeModel.curLeg.steps.withIndex()) {
var distance = 0F
if (index >= routeModel.navState.route.currentStepIndex) {
for ((wayIndex, waypoint) in step.maneuver.waypoints.withIndex()) {
if (wayIndex >= step.waypointIndex) {
val distance = location.distanceTo(location(waypoint[0], waypoint[1]))
distance = location.distanceTo(location(waypoint[0], waypoint[1]))
if (distance < nearestDistance) {
nearestDistance = distance
routeModel.navState.route.currentStepIndex = step.index
@@ -28,9 +30,12 @@ class RouteCalculator(var routeModel: RouteModel) {
step.wayPointLocation = location(waypoint[0], waypoint[1])
}
}
if (nearestDistance < NEAREST_LOCATION_DISTANCE && distance > NEAREST_LOCATION_DISTANCE * 10) {
break
}
}
}
if (nearestDistance < NEAREST_LOCATION_DISTANCE) {
if (nearestDistance < NEAREST_LOCATION_DISTANCE && distance > NEAREST_LOCATION_DISTANCE * 10) {
break
}
}
@@ -69,19 +74,15 @@ class RouteCalculator(var routeModel: RouteModel) {
fun leftStepDistance(): Double {
val step = routeModel.route.currentStep()
var leftDistance = 0F
for (i in step.waypointIndex..<step.maneuver.waypoints.size - 1) {
val loc1 = location(step.maneuver.waypoints[i][0], step.maneuver.waypoints[i][1])
val loc2 =
location(step.maneuver.waypoints[i + 1][0], step.maneuver.waypoints[i + 1][1])
val locationDistance = loc1.distanceTo(routeModel.navState.lastLocation)
val distance = loc1.distanceTo(loc2)
leftDistance += if (locationDistance < distance) {
locationDistance
} else {
distance
if (step.waypointIndex < step.maneuver.waypoints.size -1) {
leftDistance = step.maneuver.leftDistance[step.waypointIndex]
val waypointLocation = location(step.maneuver.waypoints[step.waypointIndex][0], step.maneuver.waypoints[step.waypointIndex][1])
if (routeModel.navState.lastLocation.latitude != 0.0) {
val locationDistance = waypointLocation.distanceTo(routeModel.navState.lastLocation)
leftDistance -= locationDistance
}
}
return leftDistance.toDouble()
return leftDistance.absoluteValue.toDouble()
}
/** Returns the left distance in m. */
@@ -139,6 +139,11 @@ fun Double.round(numFractionDigits: Int): Double {
return (this * factor).roundToInt() / factor
}
fun isNumeric(toCheck: String): Boolean {
val regex = "-?[0-9]+(\\.[0-9]+)?".toRegex()
return toCheck.matches(regex)
}
fun duration(
viewStyle: ViewStyle,
bearing: Double,
@@ -44,7 +44,7 @@ class RouteModelTest {
return Step(
index = index,
waypointIndex = waypointIndex,
maneuver = Maneuver(waypoints = waypoints, location = mock()),
maneuver = Maneuver(waypoints = waypoints, location = mock(), leftDistance = mock()),
duration = duration,
distance = distance,
)