Lanes
This commit is contained in:
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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,10 +88,12 @@ class MainActivity : ComponentActivity() {
|
||||
val observer = Observer<String> { newRoute ->
|
||||
if (newRoute.isNotEmpty()) {
|
||||
routeModel.startNavigation(newRoute, applicationContext)
|
||||
routeData.value = routeModel.route.routeGeoJson
|
||||
simulate()
|
||||
//test()
|
||||
///gpx(applicationContext)
|
||||
routeData.value = routeModel.curRoute.routeGeoJson
|
||||
if (useMock) {
|
||||
simulate()
|
||||
//test()
|
||||
///gpx(applicationContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
val cameraPosition = MutableLiveData(
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,30 +95,40 @@ class RoutePreviewScreen(
|
||||
)
|
||||
.build()
|
||||
|
||||
val message = if (routeModel.isNavigating() && routeModel.route.waypoints!!.isNotEmpty()) {
|
||||
createRouteText()
|
||||
} else {
|
||||
CarText.Builder("Wait")
|
||||
.build()
|
||||
}
|
||||
val messageTemplate = MessageTemplate.Builder(
|
||||
message
|
||||
)
|
||||
.setHeader(header)
|
||||
.addAction(navigateAction)
|
||||
.setLoading(message.toString() == "Wait")
|
||||
.build()
|
||||
|
||||
val timer = object : CountDownTimer(5000, 1000) {
|
||||
override fun onTick(millisUntilFinished: Long) {}
|
||||
override fun onFinish() {
|
||||
//onNavigate()
|
||||
val message =
|
||||
if (routeModel.isNavigating() && routeModel.curRoute.waypoints!!.isNotEmpty()) {
|
||||
createRouteText(0)
|
||||
} else {
|
||||
CarText.Builder("Wait")
|
||||
.build()
|
||||
}
|
||||
if (routeModel.route.routes.size == 1) {
|
||||
val timer = object : CountDownTimer(5000, 1000) {
|
||||
override fun onTick(millisUntilFinished: Long) {}
|
||||
override fun onFinish() {
|
||||
onNavigate()
|
||||
}
|
||||
}
|
||||
timer.start()
|
||||
}
|
||||
timer.start()
|
||||
|
||||
val content = if (routeModel.route.routes.size > 1) {
|
||||
ListTemplate.Builder()
|
||||
.setHeader(header)
|
||||
.setSingleList(itemListBuilder.build())
|
||||
.build()
|
||||
} else {
|
||||
MessageTemplate.Builder(
|
||||
message
|
||||
)
|
||||
.setHeader(header)
|
||||
.addAction(navigateAction)
|
||||
.setLoading(message.toString() == "Wait")
|
||||
.build()
|
||||
|
||||
}
|
||||
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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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>>,
|
||||
)
|
||||
@@ -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,
|
||||
)
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user