This commit is contained in:
Dimitris
2026-03-15 17:18:02 +01:00
parent 619ceb9f83
commit 5198725879
46 changed files with 840 additions and 1326 deletions

View File

@@ -62,7 +62,7 @@ data class StepData (
var icon: Int,
var arrivalTime : Long,
var leftDistance: Double,
var lane: List<Lane> = listOf(Lane(location(0.0, 0.0), valid = false, indications = emptyList())),
var lane: List<Lane> = listOf(Lane(location(0.0, 0.0), valid = false, indications = emptyList(), 0, 0)),
var exitNumber: Int = 0,
var message: String = "",
)
@@ -116,7 +116,7 @@ object Constants {
val homeVogelhart = location(11.5793748, 48.185749)
val homeHohenwaldeck = location( 11.594322, 48.1164817)
const val NEXT_STEP_THRESHOLD = 1000.0
const val NEXT_STEP_THRESHOLD = 500.0
const val MAXIMAL_SNAP_CORRECTION = 50.0

View File

@@ -15,6 +15,7 @@ data class NavigationState (
val lastLocation: Location = location(0.0, 0.0),
val currentLocation: Location = location(0.0, 0.0),
val routeBearing: Float = 0F,
// index of current route in the list of routes
val currentRouteIndex: Int = 0,
val destination: Place = Place(),
val carConnection: Int = 0,

View File

@@ -48,7 +48,9 @@ class OsrmRoute {
val lane = Lane(
location(it2.location[0], it2.location[1]),
it3.valid,
it3.indications
it3.indications,
0,
0
)
lanes.add(lane)
}

View File

@@ -4,5 +4,5 @@ import java.util.Collections
data class Intersection(
val location: List<Double> = listOf(0.0, 0.0),
val lane : List<Lane> = Collections.emptyList<Lane>(),
val lane : List<Lane> = Collections.emptyList(),
)

View File

@@ -6,4 +6,6 @@ data class Lane (
val location: Location,
val valid: Boolean,
var indications: List<String>,
val startIndex: Int,
val endIndex: Int,
)

View File

@@ -2,5 +2,4 @@ package com.kouros.navigation.data.route
data class Leg(
var steps : List<Step> = arrayListOf(),
var intersection: List<Intersection> = arrayListOf()
)

View File

@@ -10,5 +10,6 @@ data class Maneuver(
val location: Location,
val exit: Int = 0,
val street: String = "",
val message: String = ""
val message: String = "",
val pointIndex : Int = 0,
)

View File

@@ -35,7 +35,6 @@ class TomTomRoute {
}
var stepDistance = 0.0
var stepDuration = 0.0
val allIntersections = mutableListOf<Intersection>()
val steps = mutableListOf<Step>()
var lastPointIndex = 0
for (index in 1..<route.guidance.instructions.size) {
@@ -56,46 +55,59 @@ class TomTomRoute {
instruction.point.longitude, instruction.point.latitude
),
street = maneuverStreet,
message = instruction.message
message = instruction.message,
pointIndex = instruction.pointIndex
)
lastPointIndex = instruction.pointIndex
val intersections = mutableListOf<Intersection>()
route.sections?.forEach { section ->
val lanes = mutableListOf<Lane>()
var startIndex = 0
section.lanes?.forEach { itLane ->
val lane = Lane(
location(
waypoints[section.startPointIndex][0],
waypoints[section.startPointIndex][1]
),
itLane.directions.first() == itLane.follow,
itLane.directions
)
startIndex = section.startPointIndex
lanes.add(lane)
}
intersections.add(Intersection(waypoints[startIndex], lanes))
if (section.sectionType == "LANES" && section.startPointIndex <= lastPointIndex && section.endPointIndex >= lastPointIndex) {
val lanes = mutableListOf<Lane>()
var startIndex = 0
var lastLane: Lane? = null
section.lanes?.forEach { itLane ->
val lane = Lane(
location = location(
waypoints[section.startPointIndex][0],
waypoints[section.startPointIndex][1]
),
valid = itLane.directions.first() == itLane.follow,
indications = itLane.directions,
startIndex = startIndex,
endIndex = section.endPointIndex
)
startIndex = section.startPointIndex
if (lastLane == null
|| (!(lastLane.valid && lane.valid
&& lastLane.indications == lane.indications))
) {
lanes.add(lane)
}
lastLane = lane
}
intersections.add(Intersection(waypoints[startIndex], lanes))
}
stepDistance =
route.guidance.instructions[index].routeOffsetInMeters - stepDistance
stepDuration =
route.guidance.instructions[index].travelTimeInSeconds - stepDuration
val step = Step(
index = stepIndex,
street = street,
distance = stepDistance,
duration = stepDuration,
maneuver = maneuver,
intersection = intersections
)
stepDistance = route.guidance.instructions[index].routeOffsetInMeters.toDouble()
stepDuration = route.guidance.instructions[index].travelTimeInSeconds.toDouble()
steps.add(step)
stepIndex += 1
}
allIntersections.addAll(intersections)
stepDistance = route.guidance.instructions[index].routeOffsetInMeters - stepDistance
stepDuration = route.guidance.instructions[index].travelTimeInSeconds - stepDuration
val step = Step(
index = stepIndex,
street = street,
distance = stepDistance,
duration = stepDuration,
maneuver = maneuver,
intersection = intersections
)
stepDistance = route.guidance.instructions[index].routeOffsetInMeters.toDouble()
stepDuration = route.guidance.instructions[index].travelTimeInSeconds.toDouble()
steps.add(step)
stepIndex += 1
}
legs.add(Leg(steps, allIntersections))
legs.add(Leg(steps))
val routeGeoJson = createLineStringCollection(waypoints)
val centerLocation = createCenterLocation(createLineStringCollection(waypoints))
val newRoute = com.kouros.navigation.data.route.Routes(
@@ -184,8 +196,7 @@ class TomTomRoute {
}
"TAKE_EXIT" -> {
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SHARP_RIGHT
newType = androidx.car.app.navigation.model.Maneuver.TYPE_TURN_SLIGHT_RIGHT
}
}
return newType
@@ -195,8 +206,7 @@ class TomTomRoute {
private fun exitNumber(
instruction: Instruction
): Int {
return if (instruction.exitNumber == null
|| instruction.exitNumber.isEmpty()
return if (instruction.exitNumber.isNullOrEmpty()
) {
0
} else {

View File

@@ -65,12 +65,15 @@ class IconMapper() {
currentTurnIcon = R.drawable.ic_roundabout_ccw
}
Maneuver.TYPE_U_TURN_LEFT -> {
currentTurnIcon = R.drawable.ic_turn_u_turn_left
}
Maneuver.TYPE_U_TURN_RIGHT -> {
currentTurnIcon = R.drawable.ic_turn_u_turn_right
}
Maneuver.TYPE_MERGE_LEFT -> {
currentTurnIcon = R.drawable.ic_turn_merge_symmetrical
}
@@ -136,10 +139,12 @@ class IconMapper() {
"right_slight", "slight_right" -> {
when (stepData.currentManeuverType) {
Maneuver.TYPE_TURN_SLIGHT_RIGHT -> LaneDirection.SHAPE_NORMAL_RIGHT
Maneuver.TYPE_KEEP_RIGHT -> LaneDirection.SHAPE_SLIGHT_RIGHT
else
-> LaneDirection.SHAPE_UNKNOWN
}
}
else -> {
LaneDirection.SHAPE_UNKNOWN
}
@@ -151,8 +156,7 @@ class IconMapper() {
val bitmaps = mutableListOf<Bitmap>()
stepData.lane.forEach { lane ->
if (lane.indications.isNotEmpty()) {
Collections.sort<String>(lane.indications)
val resource = laneToResource(lane.indications, stepData)
val resource = laneToResource(lane.indications.sorted(), stepData)
if (resource.isNotEmpty()) {
val id = resourceId(resource)
val bitMap = BitmapFactory.decodeResource(context.resources, id)
@@ -222,11 +226,21 @@ class IconMapper() {
"right" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT) "${direction}_o" else "${direction}_x"
"left" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_LEFT) "${direction}_o" else "${direction}_x"
"straight" -> if (stepData.currentManeuverType == Maneuver.TYPE_STRAIGHT) "${direction}_o" else "${direction}_x"
"straight" -> if (stepData.currentManeuverType == Maneuver.TYPE_STRAIGHT
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_LEFT
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_RIGHT
) "${direction}_o" else "${direction}_x"
"right_slight", "slight_right" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_RIGHT
|| stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT) "slight_right_o" else "slight_right_x"
|| stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_RIGHT
) "slight_right_o" else "slight_right_x"
"left_slight", "slight_left" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_LEFT
|| stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_LEFT) "slight_left_o" else "slight_left_x"
|| stepData.currentManeuverType == Maneuver.TYPE_TURN_NORMAL_LEFT
|| stepData.currentManeuverType == Maneuver.TYPE_KEEP_LEFT
) "slight_left_o" else "slight_left_x"
else -> {
""
}

View File

@@ -550,14 +550,15 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
val rp = settingsRepository.recentPlacesFlow.first()
val places = mutableListOf<Place>()
if (rp.isNotEmpty()) {
val recentPlaces =
val rPlaces =
gson.fromJson(rp, Places::class.java).places.sortedBy { it.lastDate }
for (curPlace in recentPlaces) {
for (curPlace in rPlaces) {
if (curPlace.name != place.name || curPlace.category != place.category) {
places.add(curPlace)
}
}
settingsRepository.setRecentPlaces(gson.toJson(Places(places)))
recentPlaces.value = places
}
} catch (e: Exception) {
e.printStackTrace()

View File

@@ -31,7 +31,7 @@ class RouteCalculator(var routeModel: RouteModel) {
}
}
if (nearestDistance < NEAREST_LOCATION_DISTANCE) {
break;
break
}
}
}

View File

@@ -11,6 +11,7 @@ import com.kouros.navigation.data.StepData
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.route.Step
import com.kouros.navigation.utils.location
import kotlin.math.absoluteValue
@@ -29,6 +30,9 @@ open class RouteModel {
val curLeg: Leg
get() = navState.route.routes[navState.currentRouteIndex].legs.first()
val currentStep: Step
get() = navState.route.nextStep(0)
fun startNavigation(routeString: String) {
navState = navState.copy(
route = Route.Builder()
@@ -69,42 +73,11 @@ open class RouteModel {
navState = navState.copy(lastLocation = navState.currentLocation)
}
fun currentStep(): StepData {
val distanceToNextStep = routeCalculator.leftStepDistance()
// Determine the maneuver type and corresponding icon
val currentStep = navState.route.nextStep(0)
var streetName = currentStep.maneuver.street
var curManeuverType = currentStep.maneuver.type
if (navState.nextStep) {
if (distanceToNextStep > NEXT_STEP_THRESHOLD) {
streetName = currentStep.street
curManeuverType = Maneuver.TYPE_STRAIGHT
}
}
val exitNumber = currentStep.maneuver.exit
val maneuverIcon = navState.iconMapper.maneuverIcon(curManeuverType)
navState = navState.copy(maneuverType = curManeuverType)
// Construct and return the final StepData object
return StepData(
instruction = streetName,
street = currentStep.street,
leftStepDistance = distanceToNextStep,
currentManeuverType = navState.maneuverType,
icon = maneuverIcon,
arrivalTime = routeCalculator.arrivalTime(),
leftDistance = routeCalculator.travelLeftDistance(),
lane = currentLanes(),
exitNumber = exitNumber,
message = currentStep.maneuver.message
)
}
fun nextStep(): StepData {
val distanceToNextStep = routeCalculator.leftStepDistance()
val currentStep = navState.route.nextStep(0)
val nextStep = navState.route.nextStep(1)
var streetName = nextStep.street
var maneuverType = currentStep.maneuver.type
var maneuverType = currentStep.maneuver.type
if (distanceToNextStep < NEXT_STEP_THRESHOLD) {
streetName = nextStep.maneuver.street
maneuverType = nextStep.maneuver.type
@@ -128,16 +101,13 @@ open class RouteModel {
private fun currentLanes(): List<Lane> {
var lanes = emptyList<Lane>()
if (navState.route.legs().isNotEmpty()) {
navState.route.legs().first().intersection.forEach {
currentStep.intersection.forEach {
if (it.lane.isNotEmpty()) {
val distance =
navState.lastLocation.distanceTo(location(it.location[0], it.location[1]))
val sectionBearing =
navState.lastLocation.bearingTo(location(it.location[0], it.location[1]))
val bearingDeviation =
(navState.routeBearing.absoluteValue - sectionBearing.absoluteValue).absoluteValue
if (distance < NEXT_STEP_THRESHOLD && bearingDeviation < 10) {
if (distance < NEXT_STEP_THRESHOLD) {
lanes = it.lane
return@forEach
}
}
}
@@ -145,6 +115,36 @@ open class RouteModel {
return lanes
}
fun currentStep(): StepData {
val distanceToNextStep = routeCalculator.leftStepDistance()
// Determine the maneuver type and corresponding icon
var streetName = currentStep.maneuver.street
var curManeuverType = currentStep.maneuver.type
if (navState.nextStep) {
if (distanceToNextStep > NEXT_STEP_THRESHOLD) {
streetName = currentStep.street
curManeuverType = Maneuver.TYPE_STRAIGHT
}
}
val exitNumber = currentStep.maneuver.exit
val maneuverIcon = navState.iconMapper.maneuverIcon(curManeuverType)
navState = navState.copy(maneuverType = curManeuverType)
val currentLanes = currentLanes()
// Construct and return the final StepData object
return StepData(
instruction = streetName,
street = currentStep.street,
leftStepDistance = distanceToNextStep,
currentManeuverType = navState.maneuverType,
icon = maneuverIcon,
arrivalTime = routeCalculator.arrivalTime(),
leftDistance = routeCalculator.travelLeftDistance(),
lane = currentLanes,
exitNumber = exitNumber,
message = currentStep.maneuver.message
)
}
fun isNavigating(): Boolean {
return navState.navigating
}

View File

@@ -0,0 +1,26 @@
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,18l0,-3l-2,0l0,3l-3,0l0,2l3,0l0,3l2,0l0,-3l3,0l0,-2z"/>
<path android:fillColor="@android:color/white" android:pathData="M18,4h2v9h-2z"/>
<path android:fillColor="@android:color/white" android:pathData="M4,4h2v16h-2z"/>
<path android:fillColor="@android:color/white" android:pathData="M11,4h2v4h-2z"/>
<path android:fillColor="@android:color/white" android:pathData="M11,10h2v4h-2z"/>
<path android:fillColor="@android:color/white" android:pathData="M11,16h2v4h-2z"/>
</vector>

View File

@@ -0,0 +1,21 @@
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,21c-1.39,0 -2.78,-0.47 -4,-1.32c-2.44,1.71 -5.56,1.71 -8,0C6.78,20.53 5.39,21 4,21H2v2h2c1.38,0 2.74,-0.35 4,-0.99c2.52,1.29 5.48,1.29 8,0c1.26,0.65 2.62,0.99 4,0.99h2v-2H20zM3.95,19H4c1.6,0 3.02,-0.88 4,-2c0.98,1.12 2.4,2 4,2s3.02,-0.88 4,-2c0.98,1.12 2.4,2 4,2h0.05l1.9,-6.68c0.11,-0.37 0.04,-1.06 -0.66,-1.28L20,10.62V6c0,-1.1 -0.9,-2 -2,-2h-3V1H9v3H6C4.9,4 4,4.9 4,6v4.62l-1.29,0.42c-0.63,0.19 -0.81,0.84 -0.66,1.28L3.95,19zM6,6h12v3.97L12,8L6,9.97V6z"/>
</vector>

View File

@@ -0,0 +1,22 @@
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M15,4c-4.42,0 -8,3.58 -8,8s3.58,8 8,8 8,-3.58 8,-8 -3.58,-8 -8,-8zM15,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6z"/>
<path android:fillColor="@android:color/white" android:pathData="M3,12c0,-2.61 1.67,-4.83 4,-5.65V4.26C3.55,5.15 1,8.27 1,12s2.55,6.85 6,7.74v-2.09c-2.33,-0.82 -4,-3.04 -4,-5.65z"/>
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

File diff suppressed because it is too large Load Diff