This commit is contained in:
Dimitris
2026-04-24 12:24:53 +02:00
parent 0fa625d785
commit 17e68de017
18 changed files with 242 additions and 205 deletions
@@ -14,8 +14,6 @@ import org.junit.Test
class OverpassTest {
val location = Location(LocationManager.GPS_PROVIDER)
@Test
fun `maxSpeed Schmalkaldener 30 `() {
val curLocation = location(11.582495, 48.186863)
@@ -31,7 +29,7 @@ class OverpassTest {
@Test
fun `maxSpeed Isarring 50 `() {
val curLocation = location(11.5989114, 48.1694783)
executeSpeedTest( curLocation, "Isarring", listOf("B2R"), 190, 50)
executeSpeedTest( curLocation, "Isarring", listOf("B2R"), 190, 60)
}
@Test
@@ -12,10 +12,13 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.kouros.data.BuildConfig
import com.kouros.navigation.data.Constants.a22
import com.kouros.navigation.data.Constants.a9
import com.kouros.navigation.data.Constants.a94
import com.kouros.navigation.data.Constants.homeHohenwaldeck
import com.kouros.navigation.data.Constants.homeVogelhart
import com.kouros.navigation.data.Constants.ioannina
import com.kouros.navigation.data.Constants.isarring
import com.kouros.navigation.data.Constants.subislawa
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@@ -104,8 +107,8 @@ class DeviceLocationManager(
val lastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if (lastLocation != null) {
if (setIndividualLocation) {
onInitialLocation(homeVogelhart)
onLocationUpdate(homeVogelhart)
onInitialLocation(a22)
onLocationUpdate(a22)
} else {
onInitialLocation(lastLocation)
onLocationUpdate(lastLocation)
@@ -54,6 +54,7 @@ import com.kouros.navigation.repository.SettingsRepository
import com.kouros.navigation.utils.GeoUtils
import com.kouros.navigation.utils.GeoUtils.snapLocation
import com.kouros.navigation.utils.NavigationUtils.getViewModel
import com.kouros.navigation.utils.bearingPositive
import com.kouros.navigation.utils.getSettingsRepository
import com.kouros.navigation.utils.getSettingsViewModel
import com.kouros.navigation.utils.location
@@ -464,23 +465,25 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
*/
private fun handleNavigationLocation(location: Location) {
val startTime = System.currentTimeMillis()
routeModel.updateLocation(location, navigationViewModel)
val snappedLocation = snapLocation(location, routeModel.route.maneuverLocations())
routeModel.updateLocation(location, navigationViewModel) // 30 ms
val snappedLocation = snapLocation(location, routeModel.route.maneuverLocations()) // 160 ms
val streetName = routeModel.currentStep().street
if (checkLocationDeviation(location, snappedLocation, streetName)) {
if (checkLocationDeviation(location, snappedLocation, streetName)) { // 1 ms
if (routeModel.navState.arrived) return
if (guidanceAudio == 1) {
handleGuidanceAudio()
}
val currentDate = LocalDateTime.now(ZoneOffset.UTC)
checkTraffic(currentDate, snappedLocation)
updateSpeedCamera(snappedLocation)
checkRoute(currentDate, snappedLocation)
updateNavigationScreen()
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")
checkArrival()
}
val endTime = System.currentTimeMillis() - startTime
Log.d(TAG, "handleNavigationLocation: $endTime")
}
/**
@@ -498,9 +501,9 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
distance < MAXIMAL_SNAP_CORRECTION -> {
surfaceRenderer.updateLocation(snappedLocation, streetName)
}
else -> {
surfaceRenderer.updateLocation(location, streetName)
}
}
return true
@@ -516,15 +519,14 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
return
}
val currentStep = routeModel.route.currentStep()
val stepData = routeModel.currentStep()
val stepData = routeModel.currentStep() // 121 ms
navigationScreen.updateTrip(
navigationScreen.updateTrip( // 277 ms
isNavigating = routeModel.isNavigating(),
isRerouting = false,
hasArrived = routeModel.isArrival(),
destinationTravelEstimate = routeModel.getTravelEstimateTrip(carContext),
stepTravelEstimate = routeModel.getTravelEstimateStep(carContext),
destinationTravelEstimate = routeModel.getTravelEstimateTrip(carContext), // 60 ms
stepTravelEstimate = routeModel.getTravelEstimateStep(carContext), // 60 ms
destinations = mutableListOf(routeModel.getDestination()),
steps = routeModel.getSteps(carContext),
stepRemainingDistance = routeModel.getDistance(),
@@ -539,7 +541,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
* Updates the trip information and notifies the listener with a new Trip object.
* This includes destination name, address, travel estimate, and loading status.
*/
updateTrip(routeModel.getTrip(carContext))
updateTrip(routeModel.getTrip(carContext)) // 230 ms
}
/**
@@ -594,6 +596,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
lastCameraSearch = 0
surfaceRenderer.viewStyle = ViewStyle.VIEW
navigationScreen.navigationType = NavigationType.VIEW
navigationScreen.invalidate()
}
override fun updateTrip(trip: Trip) {
@@ -781,26 +784,28 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
private fun updateDistance(
location: Location,
) {
val updatedCameras = mutableListOf<Elements>()
speedCameras.forEach {
val plLocation =
location(longitude = it.lon, latitude = it.lat)
val distance = plLocation.distanceTo(location)
it.distance = distance.toDouble()
updatedCameras.add(it)
}
val sortedList = updatedCameras.sortedWith(compareBy { it.distance })
val camera = sortedList.firstOrNull() ?: return
val bearingRoute = surfaceRenderer.lastLocation.bearingTo(location)
val bearingSpeedCamera = try {
camera.tags.direction.toFloat()
} catch (e: Exception) {
0F
}
if (camera.distance < 80 && (System.currentTimeMillis() - lastAlert > 5000)) {
if ((bearingSpeedCamera - bearingRoute.absoluteValue).absoluteValue < 15.0) {
routeModel.showSpeedCamera(carContext, camera.distance, camera.tags.maxspeed)
lastAlert = System.currentTimeMillis()
synchronized(this) {
val updatedCameras = mutableListOf<Elements>()
speedCameras.forEach {
val plLocation =
location(longitude = it.lon, latitude = it.lat)
val distance = plLocation.distanceTo(location)
it.distance = distance.toDouble()
updatedCameras.add(it)
}
val sortedList = updatedCameras.sortedWith(compareBy { it.distance })
val camera = sortedList.firstOrNull() ?: return
val bearingRoute = surfaceRenderer.lastLocation.bearingPositive(location)
val bearingSpeedCamera = try {
camera.tags.direction.toFloat()
} catch (e: Exception) {
0F
}
if (camera.distance < 80 && (System.currentTimeMillis() - lastAlert > 10000)) {
if ((bearingSpeedCamera - bearingRoute).absoluteValue < 15.0) {
routeModel.showSpeedCamera(carContext, camera.distance, camera.tags.maxspeed)
lastAlert = System.currentTimeMillis()
}
}
}
}
@@ -34,7 +34,7 @@ import com.kouros.navigation.data.Constants.TILT
import com.kouros.navigation.data.DarkMode
import com.kouros.navigation.data.ViewStyle
import com.kouros.navigation.model.BaseStyleModel
import com.kouros.navigation.utils.bearing
import com.kouros.navigation.utils.bearingPositive
import com.kouros.navigation.utils.calculateTilt
import com.kouros.navigation.utils.calculateZoom
import com.kouros.navigation.utils.duration
@@ -46,6 +46,7 @@ import org.maplibre.compose.camera.CameraState
import org.maplibre.compose.style.BaseStyle
import org.maplibre.spatialk.geojson.Position
import java.time.LocalDateTime
import kotlin.math.*
/**
@@ -225,15 +226,40 @@ class SurfaceRenderer(
*/
override fun onScroll(distanceX: Float, distanceY: Float) {
synchronized(this@SurfaceRenderer) {
val currentCamera = cameraPosition.value ?: return@synchronized
val zoom = currentCamera.zoom
val bearing = currentCamera.bearing
// MapLibre typically uses 512px tiles.
// At zoom level z, the world (360 degrees) is 512 * 2^z pixels wide.
val pixelsPerDegreeLon = (512.0 * 2.0.pow(zoom)) / 360.0
// Latitude correction: In Mercator, the vertical scale is stretched by 1/cos(lat).
val latRad = lastLocation.latitude * PI / 180.0
val pixelsPerDegreeLat = pixelsPerDegreeLon / cos(latRad)
// Rotation compensation (bearing is degrees clockwise from North)
val bearingRad = bearing * PI / 180.0
val cosB = cos(bearingRad)
val sinB = sin(bearingRad)
// Rotate screen-space scroll to map-space scroll
val rotatedDx = distanceX * cosB - distanceY * sinB
val rotatedDy = distanceX * sinB + distanceY * cosB
viewStyle = ViewStyle.PAN_VIEW
if (distanceX != 0.0F) {
lastLocation.longitude += (distanceX / 1000) / cameraPosition.value!!.zoom
}
if (distanceY != 0.0F) {
lastLocation.latitude += (distanceY / 1000) / cameraPosition.value!!.zoom
}
// Update location based on rotated scroll distances and calculated factors
lastLocation.longitude += (rotatedDx / pixelsPerDegreeLon)
lastLocation.latitude -= (rotatedDy / pixelsPerDegreeLat)
val pos = Position(lastLocation.longitude, lastLocation.latitude)
updateCameraPosition( target = pos)
updateCameraPosition(
bearing = bearing,
zoom = zoom,
target = pos,
tilt = tilt
)
navigationSession.invalidateNavigationScreen()
}
}
@@ -374,7 +400,7 @@ class SurfaceRenderer(
if (location.hasBearing()) {
location.bearing.toDouble()
} else {
bearing(
bearingPositive(
lastLocation,
location,
cameraPosition.value!!.bearing
@@ -330,7 +330,7 @@ fun DrawNavigationImages(
if (speed != null) {
CurrentSpeed(width, height, speed, maxSpeed)
}
if (speed != null && maxSpeed > 0) { // && (speed * 3.6) > maxSpeed) {
if (speed != null && maxSpeed > 0) {
MaxSpeed(width, height, maxSpeed, speed)
}
//DebugInfo(width, height, lat!!)
@@ -507,7 +507,7 @@ private fun MaxSpeed(
val textLayoutSpeed = remember(speed) {
textMeasurerSpeed.measure(speed, styleSpeed)
}
val signColor = if (curSpeed * 3.6 > maxSpeed) {
val signColor = if (curSpeed * 3.6 > (maxSpeed + 3)) {
Color.Red
} else {
Color.Green
@@ -56,14 +56,14 @@ class Simulation {
longitude = point[0]
bearing = curBearing
speedAccuracyMetersPerSecond = 1.0f // ~1 m/s
speed = 10.0f
speed = 9.0f
time = System.currentTimeMillis()
elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
}
// Update your app's state as if a real GPS update occurred
updateLocation(fakeLocation)
// Wait before moving to the next point (e.g., every 1 second)
delay(1000)
delay(500)
lastLocation = fakeLocation
}
}
@@ -100,7 +100,6 @@ open class NavigationScreen(
repository.tripSuggestionFlow.asLiveData().observe(this, Observer {
navigationViewModel.recentPlaces.observe(this, observerRecentPlaces)
//navigationViewModel.recentPlacesFlow(carContext, surfaceRenderer.lastLocation ).asLiveData().observe(this, ::test)
tripSuggestion = it
})
repository.alternativeRoutesFlow.asLiveData().observe(this, Observer {
@@ -142,10 +141,10 @@ open class NavigationScreen(
createAction(
carContext,
R.drawable.ic_close_white_24dp,
0,
{ stopNavigation() })
0
) { stopNavigation() }
)
return NavigationTemplate.Builder()
val navigationTemplate = NavigationTemplate.Builder()
.setNavigationInfo(
getRoutingInfo()
)
@@ -167,6 +166,7 @@ open class NavigationScreen(
)
.setBackgroundColor(backGroundColor)
.build()
return navigationTemplate
}
/**
@@ -490,8 +490,6 @@ open class NavigationScreen(
}
}
/**
* Updates navigation state with the current location, checks for arrival, and traffic updates.
*/
@@ -523,7 +521,6 @@ open class NavigationScreen(
this.junctionImage = junctionImage
this.backGroundColor = backGroundColor
this.message = message
navigationType = NavigationType.NAVIGATION
invalidate()
}