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

@@ -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,61 +15,75 @@ 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>()
var stepIndex = 0
routeJson.routes.first().legs.first().steps.forEach {
val intersections = mutableListOf<Intersection>()
if (it.maneuver != null) {
val points = decodePolyline(it.geometry!!, 5)
waypoints.addAll(points)
val maneuver = RouteManeuver(
bearingBefore = it.maneuver.bearingBefore ?: 0,
bearingAfter = it.maneuver.bearingAfter ?: 0,
type = convertType(it.maneuver),
waypoints = points,
location = location(it.maneuver.location[0], it.maneuver.location[1])
)
it.intersections.forEach { it2 ->
if (it2.location[0] != 0.0) {
val lanes = mutableListOf<Lane>()
it2.lanes.forEach { it3 ->
if (it3.indications.isNotEmpty() && it3.indications.first() != "none") {
val lane = Lane(
location(it2.location[0], it2.location[1]),
it3.valid,
it3.indications
)
lanes.add(lane)
val routes = mutableListOf<com.kouros.navigation.data.route.Routes>()
var stepIndex = 0
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 (step.maneuver != null) {
val points = decodePolyline(step.geometry!!, 5)
waypoints.addAll(points)
val maneuver = RouteManeuver(
bearingBefore = step.maneuver.bearingBefore ?: 0,
bearingAfter = step.maneuver.bearingAfter ?: 0,
type = convertType(step.maneuver),
waypoints = points,
location = location(
step.maneuver.location[0],
step.maneuver.location[1]
)
)
step.intersections.forEach { it2 ->
if (it2.location[0] != 0.0) {
val lanes = mutableListOf<Lane>()
it2.lanes.forEach { it3 ->
if (it3.indications.isNotEmpty() && it3.indications.first() != "none") {
val lane = Lane(
location(it2.location[0], it2.location[1]),
it3.valid,
it3.indications
)
lanes.add(lane)
}
}
intersections.add(Intersection(it2.location, lanes))
}
}
intersections.add(Intersection(it2.location, lanes))
val step = Step(
index = stepIndex,
name = step.name!!,
distance = step.distance!! / 1000,
duration = step.duration!!,
maneuver = maneuver,
intersection = intersections
)
steps.add(step)
stepIndex += 1
}
}
val step = Step(
index = stepIndex,
name = it.name!!,
distance = it.distance!! / 1000,
duration = it.duration!!,
maneuver = maneuver,
intersection = intersections
)
steps.add(step)
stepIndex += 1
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)
}
val leg = Leg(steps)
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
class Routes (
var legs : List<Leg> = arrayListOf()
import android.location.Location
import com.kouros.navigation.utils.location
class Routes(
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>