This commit is contained in:
Dimitris
2026-01-20 13:21:58 +01:00
parent e22865bd73
commit 7db7cba4fb
21 changed files with 3595 additions and 1218 deletions

View File

@@ -14,8 +14,8 @@ android {
applicationId = "com.kouros.navigation"
minSdk = 33
targetSdk = 36
versionCode = 23
versionName = "0.1.3.23"
versionCode = 28
versionName = "0.1.3.28"
base.archivesName = "navi-$versionName"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

View File

@@ -43,8 +43,8 @@ import com.kouros.data.R
import com.kouros.navigation.MainApplication.Companion.navigationViewModel
import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE
import com.kouros.navigation.data.Constants.home2Location
import com.kouros.navigation.data.Constants.homeLocation
import com.kouros.navigation.data.Constants.homeHohenwaldeck
import com.kouros.navigation.data.Constants.homeVogelhart
import com.kouros.navigation.data.StepData
import com.kouros.navigation.model.BaseStyleModel
import com.kouros.navigation.model.MockLocation
@@ -62,7 +62,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.joda.time.DateTime
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.maplibre.compose.camera.CameraPosition
import org.maplibre.compose.location.DesiredAccuracy
import org.maplibre.compose.location.Location
@@ -89,12 +88,14 @@ class MainActivity : ComponentActivity() {
val observer = Observer<String> { newRoute ->
if (newRoute.isNotEmpty()) {
routeModel.startNavigation(newRoute, applicationContext)
routeData.value = routeModel.route.routeGeoJson
routeData.value = routeModel.curRoute.routeGeoJson
if (useMock) {
simulate()
//test()
///gpx(applicationContext)
}
}
}
val cameraPosition = MutableLiveData(
CameraPosition(
zoom = 15.0,
@@ -109,8 +110,6 @@ class MainActivity : ComponentActivity() {
private var loadRecentPlaces = false
private var overpass = false
lateinit var baseStyle: BaseStyle.Json
init {
@@ -132,8 +131,8 @@ class MainActivity : ComponentActivity() {
if (useMock) {
mock = MockLocation(locationManager)
mock.setMockLocation(
home2Location.latitude,
home2Location.longitude
homeHohenwaldeck.latitude,
homeHohenwaldeck.longitude
)
}
}
@@ -157,7 +156,7 @@ class MainActivity : ComponentActivity() {
Content()
// auto navigate
if (useMock) {
//navigationViewModel.loadRoute(applicationContext, homeLocation, home2Location, 0F)
navigationViewModel.loadRoute(applicationContext, homeHohenwaldeck, homeVogelhart, 0F)
}
},
)
@@ -255,7 +254,7 @@ class MainActivity : ComponentActivity() {
if (isNavigating()) {
updateLocation(currentLocation, navigationViewModel)
stepData.value = currentStep()
if (route.currentStep + 1 <= legs.steps.size) {
if (route.currentStep + 1 <= curLeg.steps.size) {
nextStepData.value = nextStep()
}
if (maneuverType in 39..42
@@ -284,8 +283,8 @@ class MainActivity : ComponentActivity() {
}
fun stopNavigation(closeSheet: () -> Unit) {
val latitude = routeModel.route.waypoints!![0][1]
val longitude = routeModel.route.waypoints!![0][0]
val latitude = routeModel.curRoute.waypoints[0][1]
val longitude = routeModel.curRoute.waypoints[0][0]
closeSheet()
routeModel.stopNavigation()
if (useMock) {
@@ -325,10 +324,10 @@ class MainActivity : ComponentActivity() {
fun simulate() {
CoroutineScope(Dispatchers.IO).launch {
for ((index, waypoint) in routeModel.route.waypoints!!.withIndex()) {
for ((index, waypoint) in routeModel.curRoute.waypoints.withIndex()) {
if (routeModel.isNavigating()) {
var deviation = 0.0
if (index in 0..routeModel.route.waypoints!!.size) {
if (index in 0..routeModel.curRoute.waypoints.size) {
mock.setMockLocation(waypoint[1] + deviation, waypoint[0])
delay(500L) //
}
@@ -338,7 +337,7 @@ class MainActivity : ComponentActivity() {
}
fun test() {
for ((index, step) in routeModel.legs.steps.withIndex()) {
for ((index, step) in routeModel.curLeg.steps.withIndex()) {
if (index in 3..3) {
for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) {
routeModel.updateLocation(
@@ -349,7 +348,7 @@ class MainActivity : ComponentActivity() {
if (step.leftStepDistance == 70.0) {
println("")
}
if (index + 1 <= routeModel.legs.steps.size) {
if (index + 1 <= routeModel.curLeg.steps.size) {
//nextStepData.value = routeModel.nextStep()
}
}

View File

@@ -115,7 +115,6 @@ class NavigationSession : Session(), NavigationScreen.Listener {
}
}
val carSpeedListener = OnCarDataAvailableListener<Speed> { data ->
if (data.displaySpeedMetersPerSecond.status == CarValue.STATUS_SUCCESS) {
val speed = data.displaySpeedMetersPerSecond.value
@@ -184,7 +183,7 @@ class NavigationSession : Session(), NavigationScreen.Listener {
val useCarLocation = getBooleanKeyValue(carContext, CAR_LOCATION)
if (useCarLocation) {
val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors
carSensors.addCompassListener(CarSensors.UPDATE_RATE_FASTEST,
carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL,
carContext.mainExecutor,
carCompassListener)
carSensors.addCarHardwareLocationListener(

View File

@@ -30,7 +30,7 @@ import com.kouros.navigation.car.map.getPaddingValues
import com.kouros.navigation.car.map.rememberBaseStyle
import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.data.Constants.ROUTING_ENGINE
import com.kouros.navigation.data.Constants.homeLocation
import com.kouros.navigation.data.Constants.homeVogelhart
import com.kouros.navigation.data.ObjectBox
import com.kouros.navigation.data.RouteEngine
import com.kouros.navigation.model.RouteModel
@@ -55,11 +55,11 @@ class SurfaceRenderer(
var lastLocation = location(0.0, 0.0)
var carOrientation = 0F
var carOrientation = 999F
private val cameraPosition = MutableLiveData(
CameraPosition(
zoom = 15.0,
target = Position(latitude = homeLocation.latitude, longitude = homeLocation.longitude)
target = Position(latitude = homeVogelhart.latitude, longitude = homeVogelhart.longitude)
)
)
private var visibleArea = MutableLiveData(
@@ -245,11 +245,14 @@ class SurfaceRenderer(
fun updateLocation(location: Location) {
synchronized(this) {
if (viewStyle == ViewStyle.VIEW || viewStyle == ViewStyle.PAN_VIEW) {
val bearing = bearing(
val bearing = if (carOrientation == 999F)
bearing(
lastLocation,
location,
cameraPosition.value!!.bearing
)
) else {
carOrientation.toDouble()
}
val zoom = if (viewStyle == ViewStyle.VIEW) {
calculateZoom(location.speed.toDouble())
} else {
@@ -281,16 +284,16 @@ class SurfaceRenderer(
}
fun setRouteData() {
routeData.value = routeModel.route.routeGeoJson
routeData.value = routeModel.curRoute.routeGeoJson
viewStyle = ViewStyle.VIEW
}
fun setPreviewRouteData(routeModel: RouteModel) {
viewStyle = ViewStyle.PREVIEW
with(routeModel) {
routeData.value = route.routeGeoJson
centerLocation = route.centerLocation
previewDistance = route.summary!!.distance
routeData.value = curRoute.routeGeoJson
centerLocation = curRoute.centerLocation
previewDistance = curRoute.summary.distance
}
updateCameraPosition(
0.0,

View File

@@ -158,21 +158,31 @@ fun RouteLayer(routeData: String?) {
@Composable
fun AmenityLayer(routeData: String?) {
if (routeData != null && routeData.isNotEmpty()) {
val color = if (routeData.contains(Constants.PHARMACY)) {
const(Color.Red)
} else if (routeData.contains(Constants.CHARGING_STATION)) {
const(Color.Blue)
} else {
const(Color.Black)
var color = const(Color.Red)
var img = image(painterResource(R.drawable.local_pharmacy_48px), drawAsSdf = true)
if (routeData.contains(Constants.CHARGING_STATION)) {
color = const(Color.Green)
img = image(painterResource(R.drawable.ev_station_48px), drawAsSdf = true)
} else if (routeData.contains(Constants.FUEL_STATION)){
color = const(Color.Black)
img = image(painterResource(R.drawable.local_gas_station_48px), drawAsSdf = true)
}
val routes = rememberGeoJsonSource(GeoJsonData.JsonString(routeData))
SymbolLayer(
id = "amenity-layer",
source = routes,
iconImage = image(painterResource(R.drawable.ev_station_48px), drawAsSdf = true),
iconImage = img,
iconColor = color,
iconOpacity = const(2.0f),
iconSize = const(3.0f),
iconSize =
interpolate(
type = exponential(1.2f),
input = zoom(),
5 to const(0.7f),
6 to const(1.0f),
7 to const(2.0f),
20 to const(4f),
),
)
}
}

View File

@@ -450,7 +450,7 @@ class NavigationScreen(
invalidate()
val mainThreadHandler = Handler(carContext.mainLooper)
mainThreadHandler.post {
object : CountDownTimer(3000, 1000) {
object : CountDownTimer(2000, 1000) {
override fun onTick(millisUntilFinished: Long) {}
override fun onFinish() {
navigationType = NavigationType.NAVIGATION

View File

@@ -6,11 +6,10 @@ import androidx.annotation.DrawableRes
import androidx.car.app.CarContext
import androidx.car.app.CarToast
import androidx.car.app.Screen
import androidx.car.app.constraints.ConstraintManager
import androidx.car.app.model.Action
import androidx.car.app.model.Action.FLAG_DEFAULT
import androidx.car.app.model.Action.FLAG_PRIMARY
import androidx.car.app.model.ActionStrip
import androidx.car.app.model.CarColor
import androidx.car.app.model.CarIcon
import androidx.car.app.model.CarText
import androidx.car.app.model.DurationSpan
@@ -18,19 +17,17 @@ import androidx.car.app.model.Header
import androidx.car.app.model.ItemList
import androidx.car.app.model.ListTemplate
import androidx.car.app.model.MessageTemplate
import androidx.car.app.model.OnClickListener
import androidx.car.app.model.Row
import androidx.car.app.model.Template
import androidx.car.app.navigation.model.MapController
import androidx.car.app.navigation.model.MapWithContentTemplate
import androidx.car.app.navigation.model.NavigationTemplate
import androidx.car.app.navigation.model.RoutingInfo
import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.Observer
import com.kouros.data.R
import com.kouros.navigation.car.SurfaceRenderer
import com.kouros.navigation.car.navigation.NavigationMessage
import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.Place
import com.kouros.navigation.model.ViewModel
import com.kouros.navigation.utils.location
@@ -79,9 +76,14 @@ class RoutePreviewScreen(
.setFlags(FLAG_DEFAULT)
.setIcon(navigateActionIcon)
.setOnClickListener { this.onNavigate() }
.build()
val itemListBuilder = ItemList.Builder()
var i = 0
routeModel.route.routes.forEach { it ->
itemListBuilder.addItem(createRow(i++, navigateAction))
}
val header = Header.Builder()
.setStartHeaderAction(Action.BACK)
.setTitle(carContext.getString(R.string.route_preview))
@@ -93,13 +95,30 @@ class RoutePreviewScreen(
)
.build()
val message = if (routeModel.isNavigating() && routeModel.route.waypoints!!.isNotEmpty()) {
createRouteText()
val message =
if (routeModel.isNavigating() && routeModel.curRoute.waypoints!!.isNotEmpty()) {
createRouteText(0)
} else {
CarText.Builder("Wait")
.build()
}
val messageTemplate = MessageTemplate.Builder(
if (routeModel.route.routes.size == 1) {
val timer = object : CountDownTimer(5000, 1000) {
override fun onTick(millisUntilFinished: Long) {}
override fun onFinish() {
onNavigate()
}
}
timer.start()
}
val content = if (routeModel.route.routes.size > 1) {
ListTemplate.Builder()
.setHeader(header)
.setSingleList(itemListBuilder.build())
.build()
} else {
MessageTemplate.Builder(
message
)
.setHeader(header)
@@ -107,16 +126,9 @@ class RoutePreviewScreen(
.setLoading(message.toString() == "Wait")
.build()
val timer = object : CountDownTimer(5000, 1000) {
override fun onTick(millisUntilFinished: Long) {}
override fun onFinish() {
//onNavigate()
}
}
timer.start()
return MapWithContentTemplate.Builder()
.setContentTemplate(messageTemplate)
.setContentTemplate(content)
.setMapController(
MapController.Builder().setMapActionStrip(
getMapActionStrip()
@@ -176,10 +188,14 @@ class RoutePreviewScreen(
)
.build()
private fun createRouteText(): CarText {
val time = routeModel.route.summary!!.duration
private fun createRouteText(index: Int): CarText {
val time = routeModel.route.routes[index].summary.duration
println("Duration $time")
val length =
BigDecimal(routeModel.route.summary!!.distance).setScale(1, RoundingMode.HALF_EVEN)
BigDecimal(routeModel.route.routes[index].summary.distance).setScale(
1,
RoundingMode.HALF_EVEN
)
val firstRoute = SpannableString(" \u00b7 $length km")
firstRoute.setSpan(
DurationSpan.create(time.toLong()), 0, 1, 0
@@ -188,14 +204,27 @@ class RoutePreviewScreen(
.build()
}
private fun createRow(index: Int, action: Action): Row {
val route = createRouteText(index)
val titleText = "$index"
return Row.Builder()
.setTitle(route)
.setOnClickListener(OnClickListener { onRouteSelected(index) })
.addText(titleText)
.addAction(action)
.build()
}
private fun onNavigate() {
setResult(destination)
finish()
}
private fun onRouteSelected(index: Int) {
setResult(destination)
finish()
routeModel.currentRouteIndex = index
surfaceRenderer.setPreviewRouteData(routeModel)
//setResult(destination)
//finish()
}
fun getMapActionStrip(): ActionStrip {

View File

@@ -122,17 +122,8 @@ object Constants {
val categories = listOf("Tankstelle", "Apotheke", "Ladestationen")
/** The initial location to use as an anchor for searches. */
val homeLocation: Location = Location(LocationManager.GPS_PROVIDER)
val home2Location: Location = Location(LocationManager.GPS_PROVIDER)
init {
// Vogelhartstr. 17
homeLocation.latitude = 48.185749
homeLocation.longitude = 11.5793748
// Hohenwaldeckstr. 27
home2Location.latitude = 48.1164817
home2Location.longitude = 11.594322
}
val homeVogelhart = location(11.5793748, 48.185749)
val homeHohenwaldeck = location( 11.594322, 48.1164817)
const val SHARED_PREF_KEY = "NavigationPrefs"
@@ -151,7 +142,7 @@ object Constants {
const val MAXIMAL_SNAP_CORRECTION = 50.0
const val MAXIMAL_ROUTE_DEVIATION = 100.0
const val MAXIMAL_ROUTE_DEVIATION = 80.0
const val DESTINATION_ARRIVAL_DISTANCE = 40.0

View File

@@ -43,7 +43,7 @@ abstract class NavigationRepository {
val route = getRoute(currentLocation, location, carOrientation, searchFilter)
val routeModel = RouteModel()
routeModel.startNavigation(route, context)
return routeModel.route.summary!!.distance
return routeModel.curRoute.summary.distance
}
fun searchPlaces(search: String, location: Location) : String {

View File

@@ -21,33 +21,23 @@ import org.maplibre.geojson.Point
data class Route(
val routeEngine: Int,
val summary: Summary?,
val legs: List<Leg>?,
val routeGeoJson: String = "",
val centerLocation: Location = location(0.0, 0.0),
val routes: List<com.kouros.navigation.data.route.Routes>,
var currentStep: Int = 0,
val waypoints: List<List<Double>>?,
) {
data class Builder(
var routeEngine: Int = 0,
var summary: Summary? = null,
var legs: List<Leg>? = null,
var routeGeoJson: String = "",
var centerLocation: Location = location(0.0, 0.0),
var waypoints: List<List<Double>>? = null,
var summary: Summary = Summary(),
var routes: List<com.kouros.navigation.data.route.Routes> = emptyList(),
) {
fun routeType(routeEngine: Int) = apply { this.routeEngine = routeEngine }
fun summary(summary: Summary) = apply { this.summary = summary }
fun legs(legs: List<Leg>) = apply { this.legs = legs }
fun routeGeoJson(routeGeoJson: String) = apply {
this.routeGeoJson = routeGeoJson
centerLocation = createCenterLocation(routeGeoJson)
fun routes(routes: List<com.kouros.navigation.data.route.Routes>) = apply {
this.routes = routes
}
fun routeEngine(routeEngine: Int) = apply { this.routeEngine = routeEngine }
fun waypoints(waypoints: List<List<Double>>) = apply { this.waypoints = waypoints }
fun route(route: String) = apply {
if (route.isNotEmpty() && route != "[]") {
val gson = GsonBuilder().serializeNulls().create()
@@ -74,26 +64,30 @@ data class Route(
fun build(): Route {
return Route(
routeEngine = this.routeEngine,
summary = this.summary,
legs = this.legs,
waypoints = this.waypoints,
routeGeoJson = this.routeGeoJson,
routes = this.routes,
)
}
fun buildEmpty(): Route {
return Route(
routeEngine = 0,
summary = Summary(0.0, 0.0),
legs = emptyList(),
waypoints = emptyList(),
routeGeoJson = "",
//summary = Summary(0.0, 0.0),
routes = emptyList(),
// legs = emptyList(),
//waypoints = emptyList(),
//routeGeoJson = "",
)
}
}
val legs: List<Leg>
get() = routes.first().legs
fun currentStep(): Step {
return if (legs != null && legs.isNotEmpty()) {
return if (legs.isNotEmpty()) {
legs.first().steps[currentStep]
} else {
Step(maneuver = Maneuver(waypoints = emptyList(), location = location(0.0, 0.0)))
@@ -102,7 +96,7 @@ data class Route(
fun nextStep(): Step {
val nextIndex = currentStep + 1
return if (nextIndex < legs!!.first().steps.size) {
return if (nextIndex < legs.first().steps.size) {
legs.first().steps[nextIndex]
} else {
throw IndexOutOfBoundsException("No next maneuver available.")

View File

@@ -21,7 +21,7 @@ class OsrmRepository : NavigationRepository() {
if (searchFilter.avoidTollway) {
exclude = "$exclude&exclude=toll"
}
val routeLocation = "${currentLocation.longitude},${currentLocation.latitude};${location.longitude},${location.latitude}?steps=true&alternatives=2"
val routeLocation = "${currentLocation.longitude},${currentLocation.latitude};${location.longitude},${location.latitude}?steps=true&alternatives=0"
return fetchUrl(routeUrl + routeLocation + exclude, true)
}
}

View File

@@ -7,6 +7,7 @@ import com.kouros.navigation.data.route.Leg
import com.kouros.navigation.data.route.Maneuver as RouteManeuver
import com.kouros.navigation.data.route.Step
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.location
@@ -14,26 +15,32 @@ import com.kouros.navigation.utils.location
class OsrmRoute {
fun mapToOsrm(routeJson: OsrmResponse, builder: Route.Builder) {
val waypoints = mutableListOf<List<Double>>()
val summary = Summary()
summary.distance = routeJson.routes.first().distance!! / 1000
summary.duration = routeJson.routes.first().duration!! / 1000
val steps = mutableListOf<Step>()
val routes = mutableListOf<com.kouros.navigation.data.route.Routes>()
var stepIndex = 0
routeJson.routes.first().legs.first().steps.forEach {
routeJson.routes.forEach { route ->
val legs = mutableListOf<Leg>()
val waypoints = mutableListOf<List<Double>>()
val summary = Summary(route.duration!!, route.distance!! / 1000)
route.legs.forEach { leg ->
val steps = mutableListOf<Step>()
leg.steps.forEach { step ->
val intersections = mutableListOf<Intersection>()
if (it.maneuver != null) {
val points = decodePolyline(it.geometry!!, 5)
if (step.maneuver != null) {
val points = decodePolyline(step.geometry!!, 5)
waypoints.addAll(points)
val maneuver = RouteManeuver(
bearingBefore = it.maneuver.bearingBefore ?: 0,
bearingAfter = it.maneuver.bearingAfter ?: 0,
type = convertType(it.maneuver),
bearingBefore = step.maneuver.bearingBefore ?: 0,
bearingAfter = step.maneuver.bearingAfter ?: 0,
type = convertType(step.maneuver),
waypoints = points,
location = location(it.maneuver.location[0], it.maneuver.location[1])
location = location(
step.maneuver.location[0],
step.maneuver.location[1]
)
it.intersections.forEach { it2 ->
)
step.intersections.forEach { it2 ->
if (it2.location[0] != 0.0) {
val lanes = mutableListOf<Lane>()
it2.lanes.forEach { it3 ->
@@ -51,9 +58,9 @@ class OsrmRoute {
}
val step = Step(
index = stepIndex,
name = it.name!!,
distance = it.distance!! / 1000,
duration = it.duration!!,
name = step.name!!,
distance = step.distance!! / 1000,
duration = step.duration!!,
maneuver = maneuver,
intersection = intersections
)
@@ -61,14 +68,22 @@ class OsrmRoute {
stepIndex += 1
}
}
val leg = Leg(steps)
legs.add(Leg(steps))
}
val routeGeoJson = createLineStringCollection(waypoints)
val centerLocation = createCenterLocation(createLineStringCollection(waypoints))
val newRoute = com.kouros.navigation.data.route.Routes(
legs,
summary,
routeGeoJson,
centerLocation = centerLocation,
waypoints = waypoints
)
routes.add(newRoute)
}
builder
.routeType(1)
.summary(summary)
.routeGeoJson(createLineStringCollection(waypoints))
.legs(listOf(leg))
.waypoints(waypoints.toList())
.routes(routes)
}
fun convertType(maneuver: Maneuver): Int {
@@ -93,12 +108,24 @@ class OsrmRoute {
ManeuverType.continue_.value -> {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_STRAIGHT
if (maneuver.modifier == "right") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_RIGHT
}
if (maneuver.modifier == "left") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_LEFT
}
}
ManeuverType.newName.value -> {
if (maneuver.modifier == "straight") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_STRAIGHT
}
if (maneuver.modifier == "slight right") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT
}
if (maneuver.modifier == "slight left") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_LEFT
}
}
ManeuverType.turn.value,
@@ -110,7 +137,7 @@ class OsrmRoute {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_LEFT
}
if (maneuver.modifier == "straight") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT
newType = androidx.car.app.navigation.model.Maneuver.TYPE_STRAIGHT
}
}
@@ -120,6 +147,12 @@ class OsrmRoute {
if (maneuver.modifier == "left") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_LEFT
}
if (maneuver.modifier == "slight right") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT
}
if (maneuver.modifier == "slight left") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_LEFT
}
}
ManeuverType.offRamp.value
@@ -127,6 +160,15 @@ class OsrmRoute {
if (maneuver.modifier == "slight right") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT
}
if (maneuver.modifier == "right") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_RIGHT
}
if (maneuver.modifier == "slight left") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_LEFT
}
if (maneuver.modifier == "left") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_NORMAL_LEFT
}
}
ManeuverType.fork.value
@@ -134,10 +176,6 @@ class OsrmRoute {
if (maneuver.modifier == "slight left") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_LEFT
}
}
ManeuverType.fork.value
-> {
if (maneuver.modifier == "slight right") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT
}
@@ -148,6 +186,21 @@ class OsrmRoute {
if (maneuver.modifier == "slight left") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_LEFT
}
if (maneuver.modifier == "slight right") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT
}
}
ManeuverType.roundAbout.value
-> {
if (maneuver.modifier == "right") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW
}
}
ManeuverType.exitRoundabout.value
-> {
if (maneuver.modifier == "right") {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_ROUNDABOUT_EXIT_CCW
}
}
}
return newType

View File

@@ -1,5 +1,12 @@
package com.kouros.navigation.data.route
import android.location.Location
import com.kouros.navigation.utils.location
class Routes(
var legs : List<Leg> = arrayListOf()
val legs: List<Leg> = arrayListOf(),
val summary: Summary,
val routeGeoJson: String,
val centerLocation: Location = location(0.0, 0.0),
val waypoints: List<List<Double>>,
)

View File

@@ -1,6 +1,8 @@
package com.kouros.navigation.data.route
data class Summary(
// sec
var duration : Double = 0.0,
// km
var distance : Double = 0.0,
)

View File

@@ -15,9 +15,7 @@ class ValhallaRoute {
fun mapJsonToValhalla(routeJson: ValhallaResponse, builder: Route.Builder) {
val waypoints = decodePolyline(routeJson.legs[0].shape)
val summary = Summary()
summary.distance = routeJson.summaryValhalla.length
summary.duration = routeJson.summaryValhalla.time
val summary = Summary(routeJson.summaryValhalla.time, routeJson.summaryValhalla.length)
val steps = mutableListOf<Step>()
var stepIndex = 0
routeJson.legs[0].maneuvers.forEach {
@@ -39,13 +37,13 @@ class ValhallaRoute {
steps.add(step)
stepIndex += 1
}
val leg = Leg(steps)
builder
.routeType(1)
.summary(summary)
.routeGeoJson(createLineStringCollection(waypoints))
.legs(listOf(leg))
.waypoints(waypoints)
// TODO
.routes(emptyList())
//.summary(summary)
//.routeGeoJson(createLineStringCollection(waypoints))
//.waypoints(waypoints)
}
fun convertType(maneuver: Maneuvers): Int {

View File

@@ -19,8 +19,8 @@ import com.kouros.navigation.data.StepData
import com.kouros.navigation.data.route.Intersection
import com.kouros.navigation.data.route.Lane
import com.kouros.navigation.data.route.Leg
import com.kouros.navigation.data.route.Routes
import com.kouros.navigation.data.valhalla.ManeuverType
import com.kouros.navigation.utils.GeoUtils.createCenterLocation
import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue
import com.kouros.navigation.utils.location
import kotlinx.coroutines.CoroutineScope
@@ -48,9 +48,12 @@ open class RouteModel() {
var lastLocation: Location = location(0.0, 0.0)
var bearing: Float = 0F
var currentRouteIndex = 0
val curRoute: Routes
get() = route.routes[currentRouteIndex]
val legs: Leg
get() = route.legs!!.first()
val curLeg: Leg
get() = route.routes[currentRouteIndex].legs.first()
fun startNavigation(routeString: String, context: Context) {
val routeEngine = getIntKeyValue(context = context, ROUTING_ENGINE)
@@ -58,8 +61,6 @@ open class RouteModel() {
.routeEngine(routeEngine)
.route(routeString)
.build()
// TODO:
route = route.copy(centerLocation = createCenterLocation(route.routeGeoJson))
navigating = true
}
@@ -67,7 +68,7 @@ open class RouteModel() {
route = Route.Builder().buildEmpty()
navigating = false
arrived = false
maneuverType = 0
maneuverType = Maneuver.TYPE_UNKNOWN
}
@@ -80,7 +81,7 @@ open class RouteModel() {
private fun findStep(location: Location) {
var nearestDistance = 100000.0f
for ((index, step) in legs.steps.withIndex()) {
for ((index, step) in curLeg.steps.withIndex()) {
if (index >= route.currentStep) {
for ((wayIndex, waypoint) in step.maneuver.waypoints.withIndex()) {
if (wayIndex >= step.waypointIndex) {
@@ -149,7 +150,7 @@ open class RouteModel() {
val distanceToNextStep = leftStepDistance()
val isNearNextManeuver = distanceToNextStep in 0.0..NEXT_STEP_THRESHOLD
val shouldAdvance =
isNearNextManeuver && route.currentStep < (route.legs!!.first().steps.size)
isNearNextManeuver && route.currentStep < (route.legs.first().steps.size)
// Determine the maneuver type and corresponding icon
var curManeuverType = if (hasArrived(currentStep.maneuver.type)) {
@@ -221,8 +222,8 @@ open class RouteModel() {
fun travelLeftTime(): Double {
var timeLeft = 0.0
// time for next step until end step
for (i in route.currentStep + 1..<legs.steps.size) {
val step = legs.steps[i]
for (i in route.currentStep + 1..<curLeg.steps.size) {
val step = curLeg.steps[i]
timeLeft += step.duration
}
// time for current step
@@ -261,7 +262,7 @@ open class RouteModel() {
/** Returns the left distance in km. */
fun travelLeftDistance(): Double {
var leftDistance = 0.0
for (i in route.currentStep + 1..<legs.steps.size) {
for (i in route.currentStep + 1..<curLeg.steps.size) {
val step = route.legs!![0].steps[i]
leftDistance += step.distance
}

View File

@@ -302,6 +302,11 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
}
fun saveRecent(place: Place) {
if (place.category == Constants.FUEL_STATION
|| place.category == Constants.CHARGING_STATION
|| place.category == Constants.PHARMACY) {
return
}
place.category = Constants.RECENT
savePlace(place)
}

View File

@@ -92,16 +92,16 @@ fun calculateZoom(speed: Double?): Double {
in 61..70 -> 16.5
else -> 16.0
}
return zoom.toDouble()
return zoom
}
fun previewZoom(previewDistance: Double): Double {
when (previewDistance) {
in 0.0..10.0 -> return 13.0
in 10.0..20.0 -> return 11.0
in 20.0..30.0 -> return 10.0
in 0.0..10.0 -> return 13.5
in 10.0..20.0 -> return 11.5
in 20.0..30.0 -> return 10.5
}
return 9.0
return 9.5
}
fun calculateTilt(newZoom: Double, tilt: Double): Double =

View File

@@ -47,6 +47,6 @@
<string name="pharmacy">Apotheke</string>
<string name="charging_station">Ladestation</string>
<string name="speed_camera">Speed camera</string>
<string name="use_car_location">Auto Location verwenden</string>
<string name="use_car_location">Auto GPS verwenden</string>
</resources>

View File

@@ -1,7 +1,7 @@
[versions]
agp = "8.13.2"
agp = "9.0.0"
androidSdkTurf = "6.0.1"
gradle = "8.13.2"
gradle = "9.0.0"
koinAndroid = "4.1.1"
koinAndroidxCompose = "4.1.1"
koinComposeViewmodel = "4.1.1"