Lanes
@@ -20,6 +20,7 @@ import android.location.Location
|
||||
import android.location.LocationManager
|
||||
import android.net.Uri
|
||||
import com.kouros.navigation.data.route.Lane
|
||||
import com.kouros.navigation.utils.location
|
||||
import io.objectbox.annotation.Entity
|
||||
import io.objectbox.annotation.Id
|
||||
import kotlinx.serialization.Serializable
|
||||
@@ -58,7 +59,7 @@ data class StepData (
|
||||
|
||||
var leftStepDistance: Double,
|
||||
|
||||
var maneuverType: Int,
|
||||
var currentManeuverType: Int,
|
||||
|
||||
var icon: Int,
|
||||
|
||||
@@ -66,7 +67,7 @@ data class StepData (
|
||||
|
||||
var leftDistance: Double,
|
||||
|
||||
var lane: List<Lane> = listOf(Lane(valid = false, indications = emptyList())),
|
||||
var lane: List<Lane> = listOf(Lane(location(0.0, 0.0), valid = false, indications = emptyList())),
|
||||
)
|
||||
|
||||
|
||||
@@ -176,7 +177,7 @@ object Constants {
|
||||
|
||||
const val ROUTING_ENGINE = "RoutingEngine"
|
||||
|
||||
const val NEXT_STEP_THRESHOLD = 100.0
|
||||
const val NEXT_STEP_THRESHOLD = 120.0
|
||||
|
||||
const val MAXIMAL_SNAP_CORRECTION = 50.0
|
||||
|
||||
|
||||
@@ -30,7 +30,9 @@ import kotlinx.serialization.json.Json
|
||||
|
||||
abstract class NavigationRepository {
|
||||
|
||||
private val nominatimUrl = "https://nominatim.openstreetmap.org/"
|
||||
//private val nominatimUrl = "https://nominatim.openstreetmap.org/"
|
||||
|
||||
private val nominatimUrl = "https://kouros-online.de/nominatim/"
|
||||
|
||||
|
||||
abstract fun getRoute(currentLocation: Location, location: Location, searchFilter: SearchFilter): String
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.kouros.navigation.data.route.Step
|
||||
import com.kouros.navigation.data.route.Summary
|
||||
import com.kouros.navigation.utils.GeoUtils.createLineStringCollection
|
||||
import com.kouros.navigation.utils.GeoUtils.decodePolyline
|
||||
import com.kouros.navigation.utils.location
|
||||
|
||||
class OsrmRoute {
|
||||
|
||||
@@ -34,8 +35,14 @@ class OsrmRoute {
|
||||
if (it2.location[0] != 0.0) {
|
||||
val lanes = mutableListOf<Lane>()
|
||||
it2.lanes.forEach { it3 ->
|
||||
val lane = Lane(it3.valid, it3.indications)
|
||||
lanes.add(lane)
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.kouros.navigation.data.route
|
||||
|
||||
import android.location.Location
|
||||
|
||||
data class Lane (
|
||||
val location: Location,
|
||||
val valid: Boolean,
|
||||
var indications: List<String>,
|
||||
)
|
||||
@@ -28,6 +28,7 @@ import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.Collections
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@@ -44,7 +45,7 @@ open class RouteModel() {
|
||||
val maxSpeed: Int = 0,
|
||||
val location: Location = location(0.0, 0.0),
|
||||
val lastLocation: Location = location(0.0, 0.0),
|
||||
val bearing : Float = 0F
|
||||
val bearing: Float = 0F
|
||||
)
|
||||
|
||||
var routeState = RouteState()
|
||||
@@ -104,7 +105,8 @@ open class RouteModel() {
|
||||
step.waypointIndex = wayIndex
|
||||
step.wayPointLocation = location(waypoint[0], waypoint[1])
|
||||
val bearing = routeState.lastLocation.bearingTo(location)
|
||||
this.routeState = routeState.copy(lastLocation = location, bearing = bearing)
|
||||
this.routeState =
|
||||
routeState.copy(lastLocation = location, bearing = bearing)
|
||||
}
|
||||
}
|
||||
if (nearestDistance == 0F) {
|
||||
@@ -174,15 +176,15 @@ open class RouteModel() {
|
||||
if (shouldAdvance) {
|
||||
maneuverType = relevantStep.maneuver.type
|
||||
}
|
||||
val maneuverIconPair = maneuverIcon(maneuverType)
|
||||
routeState = routeState.copy(maneuverType = maneuverIconPair.first)
|
||||
val maneuverIcon = maneuverIcon(maneuverType)
|
||||
routeState = routeState.copy(maneuverType = maneuverType)
|
||||
// Construct and return the final StepData object
|
||||
val intersection = currentIntersection(routeState.location)
|
||||
return StepData(
|
||||
streetName,
|
||||
distanceToNextStep,
|
||||
maneuverIconPair.first,
|
||||
maneuverIconPair.second,
|
||||
maneuverType,
|
||||
maneuverIcon,
|
||||
arrivalTime(),
|
||||
travelLeftDistance(),
|
||||
intersection.lane
|
||||
@@ -206,13 +208,13 @@ open class RouteModel() {
|
||||
}
|
||||
}
|
||||
|
||||
val routing: (Pair<Int, Int>) = maneuverIcon(maneuverType)
|
||||
val maneuverIcon = maneuverIcon(maneuverType)
|
||||
// Construct and return the final StepData object
|
||||
return StepData(
|
||||
text,
|
||||
distanceLeft,
|
||||
routing.first,
|
||||
routing.second,
|
||||
maneuverType,
|
||||
maneuverIcon,
|
||||
arrivalTime(),
|
||||
travelLeftDistance()
|
||||
)
|
||||
@@ -247,13 +249,15 @@ open class RouteModel() {
|
||||
/** Returns the current [Step] left distance in m. */
|
||||
fun leftStepDistance(): Double {
|
||||
val step = route.currentStep()
|
||||
var leftDistance = step.distance
|
||||
val percent =
|
||||
100 * (step.maneuver.waypoints.size - step.waypointIndex) / (step.maneuver.waypoints.size)
|
||||
leftDistance = leftDistance * percent / 100
|
||||
// The remaining distance to the step, rounded to the nearest 10 units.
|
||||
return (leftDistance * 1000 / 10.0).roundToInt() * 10.0
|
||||
|
||||
var leftDistance = 0.0
|
||||
for (i in step.waypointIndex..<step.maneuver.waypoints.size - 1) {
|
||||
val loc1 = location(step.maneuver.waypoints[i][0], step.maneuver.waypoints[i][1])
|
||||
val loc2 =
|
||||
location(step.maneuver.waypoints[i + 1][0], step.maneuver.waypoints[i + 1][1])
|
||||
val distance = loc1.distanceTo(loc2)
|
||||
leftDistance += distance
|
||||
}
|
||||
return (leftDistance / 10.0).roundToInt() * 10.0
|
||||
}
|
||||
|
||||
/** Returns the left distance in km. */
|
||||
@@ -263,17 +267,11 @@ open class RouteModel() {
|
||||
val step = route.legs!![0].steps[i]
|
||||
leftDistance += step.distance
|
||||
}
|
||||
|
||||
val step = route.currentStep()
|
||||
val curDistance = step.distance
|
||||
val percent =
|
||||
100 * (step.maneuver.waypoints.size - step.waypointIndex) / (step.maneuver.waypoints.size)
|
||||
val distance = curDistance * percent / 100
|
||||
leftDistance += distance
|
||||
leftDistance += leftStepDistance() / 1000
|
||||
return leftDistance
|
||||
}
|
||||
|
||||
fun maneuverIcon(routeManeuverType: Int): (Pair<Int, Int>) {
|
||||
fun maneuverIcon(routeManeuverType: Int): Int {
|
||||
var currentTurnIcon = R.drawable.ic_turn_name_change
|
||||
when (routeManeuverType) {
|
||||
Maneuver.TYPE_STRAIGHT -> {
|
||||
@@ -304,9 +302,11 @@ open class RouteModel() {
|
||||
Maneuver.TYPE_KEEP_RIGHT -> {
|
||||
currentTurnIcon = R.drawable.ic_turn_name_change
|
||||
}
|
||||
|
||||
Maneuver.TYPE_KEEP_LEFT -> {
|
||||
currentTurnIcon = R.drawable.ic_turn_name_change
|
||||
}
|
||||
|
||||
Maneuver.TYPE_ROUNDABOUT_ENTER_CCW -> {
|
||||
currentTurnIcon = R.drawable.ic_roundabout_ccw
|
||||
}
|
||||
@@ -316,7 +316,7 @@ open class RouteModel() {
|
||||
currentTurnIcon = R.drawable.ic_roundabout_ccw
|
||||
}
|
||||
}
|
||||
return Pair(routeManeuverType, currentTurnIcon)
|
||||
return currentTurnIcon
|
||||
}
|
||||
|
||||
fun isNavigating(): Boolean {
|
||||
@@ -333,31 +333,30 @@ open class RouteModel() {
|
||||
fun createLaneIcon(context: Context, stepData: StepData): IconCompat {
|
||||
val bitmaps = mutableListOf<Bitmap>()
|
||||
stepData.lane.forEach {
|
||||
if (it.indications.isNotEmpty()) {
|
||||
it.indications.forEach { it2 ->
|
||||
val resource = laneToResource(it2, it, stepData)
|
||||
if (it2 != "none") {
|
||||
println("Direction $resource")
|
||||
if (resource.isNotEmpty()) {
|
||||
val id = resourceId( resource);
|
||||
val bitMap = BitmapFactory.decodeResource(context.resources, id)
|
||||
bitmaps.add(bitMap)
|
||||
}
|
||||
}
|
||||
if (it.indications.isNotEmpty() && it.valid) {
|
||||
Collections.sort<String>(it.indications)
|
||||
val resource = laneToResource(it.indications, stepData)
|
||||
if (resource.isNotEmpty()) {
|
||||
val id = resourceId(resource);
|
||||
val bitMap = BitmapFactory.decodeResource(context.resources, id)
|
||||
bitmaps.add(bitMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
return IconCompat.createWithBitmap(overlay(bitmaps = bitmaps))
|
||||
return if (bitmaps.isEmpty()) {
|
||||
IconCompat.createWithResource(context, R.drawable.ic_close_white_24dp)
|
||||
} else {
|
||||
IconCompat.createWithBitmap(overlay(bitmaps = bitmaps))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun overlay(bitmaps: List<Bitmap>): Bitmap {
|
||||
val matrix = Matrix()
|
||||
if (bitmaps.size == 1) {
|
||||
return bitmaps.first()
|
||||
}
|
||||
val bmOverlay = createBitmap(
|
||||
bitmaps.first().getWidth() * bitmaps.size,
|
||||
bitmaps.first().getWidth() * (bitmaps.size) ,
|
||||
bitmaps.first().getHeight(),
|
||||
bitmaps.first().getConfig()!!
|
||||
)
|
||||
@@ -366,7 +365,7 @@ open class RouteModel() {
|
||||
var i = 0
|
||||
bitmaps.forEach {
|
||||
if (i > 0) {
|
||||
matrix.setTranslate(i * 40F, 0F)
|
||||
matrix.setTranslate(i * 45F, 0F)
|
||||
canvas.drawBitmap(it, matrix, null)
|
||||
}
|
||||
i++
|
||||
@@ -374,33 +373,66 @@ open class RouteModel() {
|
||||
return bmOverlay
|
||||
}
|
||||
|
||||
private fun laneToResource(direction: String, lane: Lane, stepData: StepData): String {
|
||||
println("Maneuver ${stepData.maneuverType}")
|
||||
return when (val direction = direction.replace(" ", "_")) {
|
||||
"left" -> if (stepData.maneuverType == Maneuver.TYPE_TURN_NORMAL_LEFT) "${direction}_valid" else "${direction}_not_valid"
|
||||
"right" -> if (stepData.maneuverType == Maneuver.TYPE_TURN_NORMAL_RIGHT) "${direction}_valid" else "${direction}_not_valid"
|
||||
"straight" -> if (stepData.maneuverType == Maneuver.TYPE_STRAIGHT) "${direction}_valid" else "${direction}_not_valid"
|
||||
"slight_right" -> if (stepData.maneuverType == Maneuver.TYPE_TURN_SLIGHT_RIGHT) "${direction}_valid" else "${direction}_not_valid"
|
||||
"slight_left" -> if (stepData.maneuverType == Maneuver.TYPE_TURN_SLIGHT_LEFT) "${direction}_valid" else "${direction}_not_valid"
|
||||
else -> {""}
|
||||
private fun laneToResource(directions: List<String>, stepData: StepData): String {
|
||||
var direction = ""
|
||||
directions.forEach {
|
||||
direction = if (direction.isEmpty()) {
|
||||
it.trim()
|
||||
} else {
|
||||
"${direction}_${it.trim()}"
|
||||
}
|
||||
}
|
||||
return when (direction) {
|
||||
"left_straight" -> {
|
||||
when (stepData.currentManeuverType) {
|
||||
Maneuver.TYPE_TURN_NORMAL_LEFT -> "left_o_straight_x"
|
||||
Maneuver.TYPE_STRAIGHT -> "left_x_straight_o"
|
||||
else
|
||||
-> "left_x_straight_x"
|
||||
}
|
||||
}
|
||||
|
||||
"right_straight" -> {
|
||||
when (stepData.currentManeuverType) {
|
||||
Maneuver.TYPE_TURN_NORMAL_RIGHT -> "right_x_straight_x"
|
||||
Maneuver.TYPE_STRAIGHT -> "right_x_straight_o"
|
||||
Maneuver.TYPE_TURN_SLIGHT_RIGHT -> "right_o_straight_o"
|
||||
else
|
||||
-> "right_x_straight_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"
|
||||
"right_slight" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_RIGHT) "${direction}_o" else "${direction}_x"
|
||||
"left_slight" -> if (stepData.currentManeuverType == Maneuver.TYPE_TURN_SLIGHT_LEFT) "${direction}_o" else "${direction}_x"
|
||||
else -> {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resourceId(
|
||||
variableName: String,
|
||||
): Int {
|
||||
return when(variableName) {
|
||||
"left_not_valid" -> R.drawable.left_not_valid
|
||||
"left_valid" -> R.drawable.left_valid
|
||||
"left_valid_right_not_valid" -> R.drawable.left_valid_right_not_valid
|
||||
"right_not_valid" -> R.drawable.right_not_valid
|
||||
"right_valid" -> R.drawable.right_valid
|
||||
"slight_right_not_valid" -> R.drawable.slight_right_not_valid
|
||||
"slight_right_valid" -> R.drawable.slight_right_valid
|
||||
"straight_not_valid" -> R.drawable.straight_not_valid
|
||||
"straight_not_valid_right_valid" -> R.drawable.straight_not_valid_right_valid
|
||||
"straight_valid" -> R.drawable.straight_valid
|
||||
else -> {R.drawable.ic_close_white_24dp}
|
||||
return when (variableName) {
|
||||
"left_x" -> R.drawable.left_x
|
||||
"left_o" -> R.drawable.left_o
|
||||
"left_o_right_x" -> R.drawable.left_o_right_x
|
||||
"right_x" -> R.drawable.right_x
|
||||
"right_o" -> R.drawable.right_o
|
||||
"slight_right_x" -> R.drawable.slight_right_x
|
||||
"slight_right_o" -> R.drawable.slight_right_o
|
||||
"straight_x" -> R.drawable.straight_x
|
||||
"right_o_straight_x" -> R.drawable.right_o_straight_x
|
||||
"right_x_straight_x" -> R.drawable.right_x_straight_x
|
||||
"right_x_straight_o" -> R.drawable.right_x_straight_x
|
||||
"straight_o" -> R.drawable.straight_o
|
||||
"left_o_straight_x" -> R.drawable.left_o_straight_x
|
||||
"left_x_straight_o" -> R.drawable.left_x_straight_o
|
||||
else -> {
|
||||
R.drawable.ic_close_white_24dp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 914 B After Width: | Height: | Size: 914 B |
|
Before Width: | Height: | Size: 883 B After Width: | Height: | Size: 883 B |
BIN
common/data/src/main/res/drawable/left_o_straight_x.png
Normal file
|
After Width: | Height: | Size: 881 B |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
BIN
common/data/src/main/res/drawable/left_x_straight_o.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 888 B After Width: | Height: | Size: 888 B |
|
Before Width: | Height: | Size: 895 B After Width: | Height: | Size: 895 B |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
BIN
common/data/src/main/res/drawable/right_x_straight_x.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 888 B After Width: | Height: | Size: 888 B |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 723 B After Width: | Height: | Size: 723 B |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |