Refactoring Route, Speed

This commit is contained in:
Dimitris
2025-12-29 15:44:52 +01:00
parent 1b8abbd4eb
commit 82027dce76
32 changed files with 350 additions and 134 deletions

View File

@@ -24,11 +24,15 @@ import com.kouros.navigation.car.screen.RequestPermissionScreen
import com.kouros.navigation.car.screen.SearchScreen
import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION
import com.kouros.navigation.data.Constants.MAXIMAL_SNAP_CORRECTION
import com.kouros.navigation.data.Constants.ROUTE_ENGINE
import com.kouros.navigation.data.Constants.TAG
import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.osrm.OsrmRepository
import com.kouros.navigation.data.valhalla.ValhallaRepository
import com.kouros.navigation.model.ViewModel
import com.kouros.navigation.utils.GeoUtils.snapLocation
import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue
import com.kouros.navigation.utils.NavigationUtils.getRouteEngine
class NavigationSession : Session(), NavigationScreen.Listener {
@@ -69,7 +73,7 @@ class NavigationSession : Session(), NavigationScreen.Listener {
}
}
val navigationViewModel = ViewModel(ValhallaRepository())
lateinit var navigationViewModel : ViewModel
init {
val lifecycle: Lifecycle = lifecycle
@@ -77,6 +81,8 @@ class NavigationSession : Session(), NavigationScreen.Listener {
}
override fun onCreateScreen(intent: Intent): Screen {
navigationViewModel = getRouteEngine(carContext)
routeModel = RouteCarModel()
surfaceRenderer = SurfaceRenderer(carContext, lifecycle, routeModel)

View File

@@ -34,6 +34,7 @@ import com.kouros.navigation.car.map.cameraState
import com.kouros.navigation.car.map.getPaddingValues
import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.homeLocation
import com.kouros.navigation.data.ObjectBox
import com.kouros.navigation.model.RouteModel
import com.kouros.navigation.utils.bearing
@@ -57,7 +58,7 @@ class SurfaceRenderer(
private val cameraPosition = MutableLiveData(
CameraPosition(
zoom = 15.0,
target = Position(latitude = 48.1857475, longitude = 11.5793627)
target = Position(latitude = homeLocation.latitude, longitude = homeLocation.longitude)
)
)
private var visibleArea = MutableLiveData(
@@ -68,6 +69,7 @@ class SurfaceRenderer(
var height = 0
var lastBearing = 0.0
val routeData = MutableLiveData("")
val speedCamerasData = MutableLiveData("")
val speed = MutableLiveData(0F)
lateinit var centerLocation: Location
var viewStyle = ViewStyle.VIEW
@@ -165,11 +167,11 @@ class SurfaceRenderer(
}
}
@Composable
fun MapView() {
val position: CameraPosition? by cameraPosition.observeAsState()
val route: String? by routeData.observeAsState()
val speedCameras: String? by speedCamerasData.observeAsState()
val paddingValues = getPaddingValues(height, viewStyle)
val cameraState = cameraState(paddingValues, position, tilt)
@@ -177,7 +179,7 @@ class SurfaceRenderer(
mutableStateOf(BaseStyle.Uri(Constants.STYLE))
}
DarkMode(carContext, baseStyle)
MapLibre(carContext, cameraState, baseStyle, route, viewStyle)
MapLibre(carContext, cameraState, baseStyle, route, viewStyle, speedCameras)
ShowPosition(cameraState, position, paddingValues)
}
@@ -189,9 +191,15 @@ class SurfaceRenderer(
) {
val cameraDuration =
duration(viewStyle == ViewStyle.PREVIEW, position!!.bearing, lastBearing)
val currentSpeed: Float? by speed.observeAsState()
val currentSpeed: Float? by speed.observeAsState()
if (viewStyle == ViewStyle.VIEW) {
DrawNavigationImages(paddingValues, currentSpeed, routeModel.routeState.maxSpeed, width, height)
DrawNavigationImages(
paddingValues,
currentSpeed,
routeModel.routeState.maxSpeed,
width,
height
)
}
LaunchedEffect(position, viewStyle) {
cameraState.animateTo(
@@ -237,7 +245,11 @@ class SurfaceRenderer(
fun updateLocation(location: Location) {
synchronized(this) {
if (viewStyle == ViewStyle.VIEW || viewStyle == ViewStyle.PAN_VIEW) {
val bearing = bearing(lastLocation, location, cameraPosition.value!!.bearing)
val bearing = bearing(
lastLocation,
location,
cameraPosition.value!!.bearing
)
val zoom = if (viewStyle == ViewStyle.VIEW) {
calculateZoom(location.speed.toDouble())
} else {

View File

@@ -47,6 +47,7 @@ import org.maplibre.spatialk.geojson.Feature
import org.maplibre.spatialk.geojson.FeatureCollection
import org.maplibre.spatialk.geojson.Point
import kotlin.math.PI
import kotlin.math.absoluteValue
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.sqrt
@@ -244,8 +245,8 @@ private fun rememberLocationSource(locationState: Location): GeoJsonSource {
buildJsonObject {
put("accuracy", location.accuracy)
put("bearing", location.bearing)
//put("bearingAccuracy", location.bearingAccuracy)
//put("age", location.timestamp.elapsedNow().inWholeNanoseconds)
put("bearingAccuracy", location.hasBearingAccuracy())
put("age", location.time.absoluteValue)
},
)
)

View File

@@ -1,6 +1,5 @@
package com.kouros.navigation.car.map
import android.annotation.SuppressLint
import android.location.Location
import android.content.Context
import androidx.compose.foundation.Canvas
@@ -36,6 +35,7 @@ import com.kouros.navigation.data.RouteColor
import com.kouros.navigation.data.SpeedColor
import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue
import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue
import com.kouros.navigation.utils.location
import org.maplibre.compose.camera.CameraPosition
import org.maplibre.compose.camera.CameraState
import org.maplibre.compose.camera.rememberCameraState
@@ -89,7 +89,8 @@ fun MapLibre(
cameraState: CameraState,
baseStyle: MutableState<BaseStyle.Uri>,
route: String?,
viewStyle: ViewStyle
viewStyle: ViewStyle,
speedCameras: String? = ""
) {
MaplibreMap(
options = MapOptions(
@@ -108,11 +109,12 @@ fun MapLibre(
} else {
RouteLayer(route)
}
SpeedCameraLayer(speedCameras)
}
//val lastLocation = location(cameraState.position.target.longitude, cameraState.position.target.latitude)
//Puck(cameraState, lastLocation)
}
}
@Composable
fun RouteLayer(routeData: String?) {
if (routeData != null && routeData.isNotEmpty()) {
@@ -167,6 +169,28 @@ fun AmenityLayer(routeData: String?) {
}
}
@Composable
fun SpeedCameraLayer(speedCameras: String?) {
if (speedCameras != null && speedCameras.isNotEmpty()) {
val color = const(Color.DarkGray)
val cameraSource = rememberGeoJsonSource(GeoJsonData.JsonString(speedCameras))
SymbolLayer(
id = "speed-camera-layer",
source = cameraSource,
iconImage = image(painterResource(R.drawable.speed_camera_48px), drawAsSdf = true),
iconColor = color,
iconSize =
interpolate(
type = exponential(1.2f),
input = zoom(),
5 to const(0.4f),
6 to const(0.7f),
7 to const(1.75f),
20 to const(3f),
),
)
}
}
@Composable
fun BuildingLayer(tiles: Source) {
Anchor.Replace("building-3d") {
@@ -188,7 +212,9 @@ fun DrawNavigationImages(
height: Int
) {
NavigationImage(padding, width, height)
CurrentSpeed(width, height, speed)
if (speed != null) {
CurrentSpeed(width, height, speed, maxSpeed)
}
if (speed != null && maxSpeed > 0 && (speed * 3.6) > maxSpeed) {
MaxSpeed(width, height, maxSpeed)
}
@@ -211,7 +237,8 @@ fun NavigationImage(padding: PaddingValues, width: Int, height: Int) {
painter = painterResource(id = R.drawable.navigation_48px),
"Navigation",
tint = color.copy(alpha = 0.7f),
modifier = Modifier.size(imageSize.dp, imageSize.dp)
modifier = Modifier
.size(imageSize.dp, imageSize.dp)
.scale(scaleX = 1f, scaleY = 0.7f),
)
}
@@ -221,7 +248,8 @@ fun NavigationImage(padding: PaddingValues, width: Int, height: Int) {
private fun CurrentSpeed(
width: Int,
height: Int,
speed: Float?
curSpeed: Float,
maxSpeed: Int
) {
val radius = 32
Box(
@@ -234,7 +262,8 @@ private fun CurrentSpeed(
) {
val textMeasurerSpeed = rememberTextMeasurer()
val textMeasurerKm = rememberTextMeasurer()
val speed = (speed!! * 3.6).toInt().toString()
val speed = (curSpeed * 3.6).toInt().toString()
val kmh = "km/h"
val styleSpeed = TextStyle(
fontSize = 22.sp,
@@ -245,10 +274,10 @@ private fun CurrentSpeed(
fontSize = 12.sp,
color = Color.White,
)
val textLayoutSpeed = remember(speed) {
val textLayoutSpeed = remember(speed, maxSpeed) {
textMeasurerSpeed.measure(speed, styleSpeed)
}
val textLayoutKm = remember(kmh) {
val textLayoutKm = remember(kmh, maxSpeed) {
textMeasurerSpeed.measure(kmh, styleKm)
}
Canvas(modifier = Modifier.fillMaxSize()) {

View File

@@ -34,6 +34,7 @@ import com.kouros.navigation.data.Place
import com.kouros.navigation.data.nominatim.SearchResult
import com.kouros.navigation.data.overpass.Elements
import com.kouros.navigation.model.ViewModel
import com.kouros.navigation.utils.GeoUtils
import com.kouros.navigation.utils.bearing
import com.kouros.navigation.utils.location
import kotlin.math.absoluteValue
@@ -60,7 +61,7 @@ class NavigationScreen(
val observer = Observer<String> { route ->
if (route.isNotEmpty()) {
navigationType = NavigationType.NAVIGATION
routeModel.startNavigation(route)
routeModel.startNavigation(route, carContext)
surfaceRenderer.setRouteData()
invalidate()
}
@@ -92,6 +93,16 @@ class NavigationScreen(
var speedCameras = listOf<Elements>()
val speedObserver = Observer<List<Elements>> { cameras ->
speedCameras = cameras
val coordinates = mutableListOf<List<Double>>()
val loc = location(0.0, 0.0)
cameras.forEach {
val loc =
location(longitude = it.lon!!, latitude = it.lat!!)
coordinates.add(listOf(it.lon!!, it.lat!!))
}
val speedData = GeoUtils.createPointCollection(coordinates, "radar")
surfaceRenderer.speedCamerasData.value =speedData
}
init {
@@ -339,7 +350,7 @@ class NavigationScreen(
private fun settingsAction(): Action {
return Action.Builder()
.setIcon(routeModel.createCarIcon(carContext, R.drawable.settings_applications_48px))
.setIcon(routeModel.createCarIcon(carContext, R.drawable.settings_48px))
.setOnClickListener {
screenManager.push(SettingsScreen(carContext))
}
@@ -472,7 +483,7 @@ class NavigationScreen(
private fun updateSpeedCamera(location: Location) {
if (lastCameraSearch++ % 100 == 0) {
viewModel.getSpeedCameras(location)
viewModel.getSpeedCameras(location, 5.0)
}
if (speedCameras.isNotEmpty()) {
updateDistance(location)

View File

@@ -54,13 +54,13 @@ class PlaceListScreen(
}
init {
if (category == Constants.RECENT) {
if (category == RECENT) {
viewModel.places.observe(this, observer)
}
if (category == Constants.CONTACTS) {
if (category == CONTACTS) {
viewModel.contactAddress.observe(this, observerAddress)
}
if (category == Constants.FAVORITES) {
if (category == FAVORITES) {
viewModel.favorites.observe(this, observer)
}
loadPlaces()
@@ -84,7 +84,7 @@ class PlaceListScreen(
places.forEach {
val row = Row.Builder()
.setImage(contactIcon(it.avatar, it.category))
.setTitle(it.name!!)
.setTitle("${it.street!!} ${it.city}")
.setOnClickListener {
val place = Place(
0,
@@ -152,7 +152,7 @@ class PlaceListScreen(
.setIcon(
RouteCarModel().createCarIcon(
carContext,
R.drawable.ic_pan_24
R.drawable.ic_close_white_24dp
)
)
.setOnClickListener {
@@ -167,7 +167,7 @@ class PlaceListScreen(
.build()
fun contactIcon(avatar: Uri?, category: String?): CarIcon {
if (category == Constants.RECENT || avatar == null) {
if (category == RECENT || avatar == null) {
return CarIcon.Builder(
IconCompat.createWithResource(
carContext, R.drawable.ic_place_white_24dp

View File

@@ -52,7 +52,7 @@ class RoutePreviewScreen(
val navigationMessage = NavigationMessage(carContext)
val observer = Observer<String> { route ->
if (route.isNotEmpty()) {
routeModel.startNavigation(route)
routeModel.startNavigation(route, carContext)
surfaceRenderer.setPreviewRouteData(routeModel)
invalidate()
}

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M190,840L160,810L480,80L800,810L770,840L480,708L190,840Z"/>
</vector>