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
+2 -2
View File
@@ -17,8 +17,8 @@ android {
applicationId = "com.kouros.navigation"
minSdk = 33
targetSdk = 37
versionCode = 98
versionName = "0.2.3.98"
versionCode = 103
versionName = "0.3.0.103"
base.archivesName = "navi-$versionName"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -92,7 +92,7 @@ fun MapView(
duration = 1.seconds
)
}
NavigationImage(paddingValues, width, height / 6, "", dark)
NavigationImage(paddingValues, width, height / 6, "", dark, tilt)
}
}
}
@@ -27,10 +27,24 @@ class OverpassTest {
}
@Test
fun `maxSpeed Isarring 50 `() {
val curLocation = location(11.5989114, 48.1694783)
executeSpeedTest( curLocation, "Isarring", listOf("B2R"), 190, 60)
fun `maxSpeed Isarring `() {
var curLocation = location(11.5999989, 48.1732329)
executeSpeedTest(curLocation, "Isarring", listOf("B2R"), 200, 60)
curLocation = location(11.5995437, 48.1703931)
executeSpeedTest(curLocation, "Isarring", listOf("B2R"), 204, 50)
val locations = listOf(
location( 11.5964253, 48.1658679),
location( 11.5960449, 48.1650396),
location( 11.5959427, 48.1645584),
location( 11.5959714, 48.1641186),
)
locations.forEach {
executeSpeedTest(it, "Biedersteiner", listOf("B2R"), 190, 60)
}
}
@Test
fun `maxSpeed A94 `() {
@@ -36,9 +36,9 @@ class RouteModelTest {
val distance = listOf(
1025.5,
989.8,
963.5,
923.7,
1012.8,
979.5,
972.7,
915.8,
914.6,
871.0,
@@ -130,7 +130,7 @@ class RouteModelTest {
} else {
assertEquals(stepData.currentManeuverType, ManeuverType.TYPE_TURN_NORMAL_LEFT.value)
}
assertEquals(stepData.leftStepDistance, 301.0, 1.0)
assertEquals(stepData.leftStepDistance, 297.0, 1.0)
}
@Test
@@ -142,7 +142,7 @@ class RouteModelTest {
val stepData = routeModel.currentStep()
assertEquals(stepData.currentManeuverType, ManeuverType.TYPE_TURN_NORMAL_LEFT.value)
assertEquals(stepData.instruction, "Schenkendorfstraße")
assertEquals(stepData.leftStepDistance, 170.0, 10.0)
assertEquals(stepData.leftStepDistance, 116.0, 10.0)
assertEquals(stepData.lane.size, 4)
assertEquals(stepData.lane.first().valid, true)
assertEquals(stepData.lane.last().valid, false)
@@ -227,10 +227,15 @@ class RouteModelTest {
@Test
fun `leftStepDistance Inglolstädter `() {
val location: Location = location(11.584578, 48.183653)
var location = location( 11.584352, 48.186771)
routeModel.updateLocation(location, NavigationViewModel(TomTomRepository()))
val step = routeModel.currentStep()
assertEquals(step.leftStepDistance, 645.0, 1.0)
var step = routeModel.currentStep()
assertEquals(step.leftStepDistance, 1019.0, 1.0)
location = location(11.584578, 48.183653)
routeModel.updateLocation(location, NavigationViewModel(TomTomRepository()))
step = routeModel.currentStep()
assertEquals(step.leftStepDistance, 638.0, 1.0)
}
@Test
@@ -107,8 +107,8 @@ class DeviceLocationManager(
val lastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if (lastLocation != null) {
if (setIndividualLocation) {
onInitialLocation(a22)
onLocationUpdate(a22)
onInitialLocation(lastLocation)
onLocationUpdate(lastLocation)
} else {
onInitialLocation(lastLocation)
onLocationUpdate(lastLocation)
@@ -122,16 +122,6 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
*/
private val lifecycleObserver: LifecycleObserver = object : DefaultLifecycleObserver {
override fun onPause(owner: LifecycleOwner) {
Log.d(TAG, "NavigationSession paused")
super.onPause(owner)
}
override fun onResume(owner: LifecycleOwner) {
Log.d(TAG, "NavigationSession resumed")
super.onResume(owner)
}
override fun onDestroy(owner: LifecycleOwner) {
if (::navigationManager.isInitialized) {
navigationManager.clearNavigationManagerCallback()
@@ -465,25 +455,23 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
*/
private fun handleNavigationLocation(location: Location) {
val startTime = System.currentTimeMillis()
routeModel.updateLocation(location, navigationViewModel) // 30 ms
val snappedLocation = snapLocation(location, routeModel.route.maneuverLocations()) // 160 ms
routeModel.updateLocation(location, navigationViewModel)
val snappedLocation = snapLocation(location, routeModel.route.maneuverLocations())
val streetName = routeModel.currentStep().street
if (checkLocationDeviation(location, snappedLocation, streetName)) { // 1 ms
if (checkLocationDeviation(location, snappedLocation, streetName)) {
if (routeModel.navState.arrived) return
if (guidanceAudio == 1) {
handleGuidanceAudio()
}
val currentDate = LocalDateTime.now(ZoneOffset.UTC)
checkTraffic(currentDate, snappedLocation) // 0 ms
updateSpeedCamera(snappedLocation) // 0 ms
checkRoute(currentDate, snappedLocation) // 0 ms
updateNavigationScreen() // 660 ms
val endTime = System.currentTimeMillis() - startTime
// Log.d(TAG, "updateNavigationScreen: $endTime")
checkTraffic(currentDate, snappedLocation)
updateSpeedCamera(snappedLocation)
checkRoute(currentDate, snappedLocation)
updateNavigationScreen()
checkArrival()
}
val endTime = System.currentTimeMillis() - startTime
//Log.d(TAG, "handleNavigationLocation: $endTime")
}
/**
@@ -565,7 +553,6 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
* Called when user starts navigation
*/
override fun startNavigation() {
Log.d(TAG, "startNavigation")
surfaceRenderer.navigation = true
surfaceRenderer.viewStyle = ViewStyle.VIEW
navigationManager.navigationStarted()
@@ -584,7 +571,6 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
* Called when user exits navigation or arrives at destination.
*/
override fun stopNavigation() {
Log.d(TAG, "stopNavigation")
surfaceRenderer.navigation = false
routeModel.stopNavigation()
navigationManager.navigationEnded()
@@ -636,7 +622,6 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
* Starts navigation and invalidates the screen.
*/
override fun onRouteReceived(route: String) {
Log.d(TAG, "onRouteReceived")
if (route.isNotEmpty()) {
this.route = route
if (routeModel.isNavigating()) {
@@ -722,7 +707,6 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
* Loads a route to the specified place and sets it as the destination.
*/
override fun navigateToPlace(place: Place) {
Log.d(TAG, "navigateToPlace ${place.street}")
var prevDestination = Place()
if (surfaceRenderer.navigation) {
prevDestination = routeModel.navState.destination
@@ -340,7 +340,8 @@ class SurfaceRenderer(
width,
height,
streetName,
darkMode
darkMode,
tilt
)
}
LaunchedEffect(position, viewStyle) {
@@ -23,6 +23,7 @@ import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.kouros.data.R
@@ -45,6 +46,7 @@ import org.maplibre.compose.expressions.dsl.image
import org.maplibre.compose.expressions.dsl.interpolate
import org.maplibre.compose.expressions.dsl.zoom
import org.maplibre.compose.expressions.value.ColorValue
import org.maplibre.compose.expressions.value.DpValue
import org.maplibre.compose.layers.Anchor
import org.maplibre.compose.layers.FillLayer
import org.maplibre.compose.layers.LineLayer
@@ -107,11 +109,15 @@ fun MapLibre(
BuildingLayer(tiles)
}
if (viewStyle == ViewStyle.AMENITY_VIEW) {
val lastLocation = location(cameraState.position.target.longitude, cameraState.position.target.latitude)
val lastLocation = location(
cameraState.position.target.longitude,
cameraState.position.target.latitude
)
Puck(cameraState, lastLocation)
AmenityLayer(route)
} else {
RouteLayer(route, traffic!!)
RouteLayer(route)
TrafficLayer(traffic!!)
StartEndLayer(route)
//RouteLayerPoint(route )
}
@@ -146,72 +152,60 @@ fun StartEndLayer(routeData: String?) {
}
@Composable
fun RouteLayer(routeData: String?, trafficData: Map<String, String>) {
fun RouteLayer(routeData: String?) {
if (!routeData.isNullOrEmpty()) {
val routes = rememberGeoJsonSource(GeoJsonData.JsonString(routeData))
LineLayer(
id = "routes-casing",
source = routes,
color = const(Color.White),
width =
interpolate(
type = exponential(1.2f),
input = zoom(),
5 to const(0.4.dp),
6 to const(0.8.dp),
7 to const(2.0.dp),
20 to const(24.dp),
),
color = const(Color.Green),
width = routeLineWidth(base = 1.dp, isCasing = true),
)
LineLayer(
id = "routes",
source = routes,
color = const(RouteColor),
width =
interpolate(
type = exponential(1.2f),
input = zoom(),
5 to const(0.7.dp),
6 to const(1.0.dp),
7 to const(2.4.dp),
20 to const(26.dp),
),
width = routeLineWidth(base = 1.dp, isCasing = false),
)
}
}
@Composable
fun TrafficLayer(trafficData: Map<String, String>) {
trafficData.forEach {
val traffic = rememberGeoJsonSource(GeoJsonData.JsonString(it.value))
LineLayer(
id = "traffic-${it.key}-casing",
source = traffic,
color = const(Color.White),
width =
interpolate(
type = exponential(1.2f),
input = zoom(),
5 to const(0.4.dp),
6 to const(0.6.dp),
7 to const(1.8.dp),
20 to const(20.dp),
),
width = routeLineWidth(base = 2.dp, isCasing = true),
)
LineLayer(
id = "traffic-${it.key}",
source = traffic,
color = trafficColor(it.key),
width =
interpolate(
type = exponential(1.2f),
input = zoom(),
5 to const(0.4.dp),
6 to const(0.5.dp),
7 to const(1.6.dp),
20 to const(18.dp),
),
width = routeLineWidth(base = 2.dp, isCasing = false),
)
}
}
/**
* Reusable helper for consistent line widths across all route layers.
*/
@Composable
private fun routeLineWidth(base: Dp, isCasing: Boolean = false): Expression<DpValue> {
val extra = if (isCasing) 1.dp else 0.dp
val width = base + extra
return interpolate(
type = exponential(1.1f),
input = zoom(),
5 to const(width + 3.dp),
10 to const(width + 8.dp),
15 to const(width + 13.dp),
20 to const(width + 18.dp),
)
}
@Composable
fun RouteLayerPoint(routeData: String?) {
@@ -244,7 +238,7 @@ fun trafficColor(key: String): Expression<ColorValue> {
"slow" -> return const(Color(0xFFC43E3E))
"stationary" -> return const(Color(0xFF910A0A))
"heavy" -> return const(Color(0xFF6B0404))
"roadworks" -> return const(Color(0xFF443506))
"roadworks" -> return const(Color(0xFFDAA707))
}
return const(Color.Blue)
}
@@ -325,8 +319,9 @@ fun DrawNavigationImages(
height: Int,
streetName: String?,
darkMode: Boolean,
tilt: Double,
) {
NavigationImage(padding, width, height, streetName, darkMode)
NavigationImage(padding, width, height, streetName, darkMode, tilt)
if (speed != null) {
CurrentSpeed(width, height, speed, maxSpeed)
}
@@ -342,7 +337,8 @@ fun NavigationImage(
width: Int,
height: Int,
streetName: String?,
darkMode: Boolean
darkMode: Boolean,
tilt: Double
) {
val imageSize = (height / 8)
@@ -362,12 +358,17 @@ fun NavigationImage(
textMeasurerStreet.measure(street, styleStreet, overflow = TextOverflow.Ellipsis)
}
val scaleY = if (tilt == 0.0) {
1F
} else {
0.7F
}
Box(contentAlignment = Alignment.Center, modifier = Modifier.padding(padding)) {
Canvas(
modifier = Modifier
.size(imageSize.dp, imageSize.dp)
) {
scale(scaleX = 1f, scaleY = 0.7f) {
scale(scaleX = 1f, scaleY = scaleY) {
drawCircle(navigationColor.copy(alpha = 0.3f))
}
}
@@ -377,7 +378,7 @@ fun NavigationImage(
tint = navigationColor.copy(alpha = 0.7f),
modifier = Modifier
.size(imageSize.dp, imageSize.dp)
.scale(scaleX = 1f, scaleY = 0.7f),
.scale(scaleX = 1f, scaleY = scaleY),
)
Canvas(
@@ -431,7 +432,8 @@ private fun CurrentSpeed(
val textMeasurerSpeed = rememberTextMeasurer()
val textMeasurerKm = rememberTextMeasurer()
val speed = if (isMetricSystem()) (curSpeed * 3.6).toInt().toString() else (curSpeed * 3.6 * 0.6214).toInt().toString()
val speed = if (isMetricSystem()) (curSpeed * 3.6).toInt()
.toString() else (curSpeed * 3.6 * 0.6214).toInt().toString()
val kmh = if (isMetricSystem()) "km/h" else "mph"
@@ -126,10 +126,9 @@ class RouteCarModel : RouteModel() {
.setRemainingTimeColor(CarColor.GREEN)
.setRemainingDistanceColor(CarColor.BLUE)
if (traffic > 0) {
travelBuilder.setTripText(createDelay(traffic))
travelBuilder.setTripIcon(createCarIcon(carContext, R.drawable.traffic_jam_48px))
travelBuilder.setTripText(createDelay(traffic))
}
if (navState.travelMessage.isNotEmpty()) {
travelBuilder.setTripIcon(createCarIcon(carContext, R.drawable.warning_24px))
travelBuilder.setTripText(CarText.create(navState.travelMessage))
@@ -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,17 +103,23 @@ 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) {
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 {
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,
)