This commit is contained in:
Dimitris
2025-12-04 08:10:03 +01:00
parent cddb193260
commit 9f53db8e76
29 changed files with 590 additions and 623 deletions

View File

@@ -16,14 +16,19 @@
package com.kouros.navigation.data
import android.R
import android.location.Location
import android.location.LocationManager
import android.net.Uri
import com.google.gson.GsonBuilder
import com.kouros.navigation.data.valhalla.Maneuvers
import com.kouros.navigation.data.valhalla.ValhallaJson
import com.kouros.navigation.utils.NavigationUtils.createGeoJson
import com.kouros.navigation.utils.NavigationUtils.decodePolyline
import io.objectbox.annotation.Entity
import io.objectbox.annotation.Id
import kotlinx.serialization.Serializable
import java.time.LocalDate
import java.util.Date
import org.maplibre.geojson.Point
data class Category(
val id: String,
@@ -60,29 +65,6 @@ data class StepData (
var bearing: Double
)
val dataPlaces = listOf(
Place(
id = 0,
name = "Vogelhartstr. 17",
category = "Favorites",
latitude = 48.1857475,
longitude = 11.5793627,
postalCode = "80807",
city = "München",
street = "Vogelhartstr. 17"
),
Place(
id = 0,
name = "Hohenwaldeckstr. 27",
category = "Recent",
latitude = 48.1165005,
longitude = 11.594349,
postalCode = "81541",
city = "München",
street = "Hohenwaldeckstr. 27",
)
)
// GeoJSON data classes
@Serializable
@@ -107,9 +89,41 @@ data class GeoJsonFeatureCollection(
data class Locations (
var lat : Double,
var lon : Double,
var street : String = ""
var street : String = "",
val search_filter: SearchFilter,
)
@Serializable
data class SearchFilter(
var max_road_class: String = "",
var exclude_toll : Boolean = false
) {
class Builder {
private var avoidMotorway = false
private var avoidTollway = false
fun avoidMotorway (value: Boolean ) = apply {
avoidMotorway = value
}
fun avoidTollway (value: Boolean ) = apply {
avoidTollway = value
}
fun build(): SearchFilter {
val filter = SearchFilter()
if (avoidMotorway) {
filter.max_road_class = "trunk"
}
if (avoidTollway) {
filter.exclude_toll = true
}
return filter
}
}
}
@Serializable
data class ValhallaLocation (
var locations: List<Locations>,
@@ -149,6 +163,10 @@ object Constants {
const val SHOW_THREED_BUILDING = "Show3D"
const val AVOID_MOTORWAY = "AvoidMotorway"
const val AVOID_TOLLWAY = "AvoidTollway"
const val NEXT_STEP_THRESHOLD = 100.0
const val MAXIMAL_SNAP_CORRECTION = 50.0

View File

@@ -34,10 +34,15 @@ class NavigationRepository {
private val nominatimUrl = "https://nominatim.openstreetmap.org/"
fun getRoute(currentLocation : Location, location: Location): String {
// Road classes from highest to lowest are:
// motorway, trunk, primary, secondary, tertiary, unclassified, residential, service_other.
// exclude_toll
fun getRoute(currentLocation: Location, location: Location, SearchFilter: SearchFilter): String {
SearchFilter
val vLocation = listOf(
Locations(lat = currentLocation.latitude, lon = currentLocation.longitude),
Locations(lat = location.latitude, lon = location.longitude)
Locations(lat = currentLocation.latitude, lon = currentLocation.longitude, search_filter = SearchFilter),
Locations(lat = location.latitude, lon = location.longitude, search_filter = SearchFilter)
)
val valhallaLocation = ValhallaLocation(
locations = vLocation,
@@ -50,8 +55,8 @@ class NavigationRepository {
return fetchUrl(routeUrl + routeLocation, true)
}
fun getRouteDistance(currentLocation : Location, location: Location): Double {
val route = getRoute(currentLocation, location)
fun getRouteDistance(currentLocation: Location, location: Location, searchFilter: SearchFilter): Double {
val route = getRoute(currentLocation, location, searchFilter)
val routeModel = RouteModel()
routeModel.startNavigation(route)
return routeModel.route.distance
@@ -108,7 +113,6 @@ class NavigationRepository {
httpURLConnection.setRequestProperty("User-Agent", "email=nominatim@kouros-online.de");
httpURLConnection.requestMethod = "GET"
val responseCode = httpURLConnection.responseCode
println(responseCode)
if (responseCode == HttpURLConnection.HTTP_OK) {
val response = httpURLConnection.inputStream.bufferedReader()
.use { it.readText() } // defaults to UTF-8

View File

@@ -10,6 +10,7 @@ import com.kouros.navigation.utils.location
import org.maplibre.geojson.FeatureCollection
import org.maplibre.geojson.Point
import org.maplibre.turf.TurfMeasurement
import org.maplibre.turf.TurfMisc
import kotlin.math.absoluteValue
import kotlin.math.roundToInt
@@ -72,7 +73,7 @@ open class RouteModel() {
if (distance < nearestDistance) {
nearestDistance = distance
route.currentManeuverIndex = i
calculateCurrentIndex(beginShapeIndex, endShapeIndex, location)
calculateCurrentShapeIndex(beginShapeIndex, endShapeIndex, location)
}
}
}
@@ -83,16 +84,17 @@ open class RouteModel() {
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
text = maneuver.streetNames[0]
}
// TODO: +1 check
val curLocation = location(
route.pointLocations[currentShapeIndex].latitude(),
route.pointLocations[currentShapeIndex].longitude()
)
val nextLocation = location(
route.pointLocations[currentShapeIndex + 1].latitude(),
route.pointLocations[currentShapeIndex + 1].longitude()
)
bearing = curLocation.bearingTo(nextLocation)
if (currentShapeIndex < route.pointLocations.size) {
val nextLocation = location(
route.pointLocations[currentShapeIndex + 1].latitude(),
route.pointLocations[currentShapeIndex + 1].longitude()
)
bearing = curLocation.bearingTo(nextLocation).absoluteValue
}
val distanceStepLeft = leftStepDistance() * 1000
when (distanceStepLeft) {
in 0.0..NEXT_STEP_THRESHOLD -> {
@@ -108,7 +110,7 @@ open class RouteModel() {
}
/** Calculates the index in a maneuver. */
private fun calculateCurrentIndex(
private fun calculateCurrentShapeIndex(
beginShapeIndex: Int,
endShapeIndex: Int,
location: Location

View File

@@ -3,8 +3,6 @@ package com.kouros.navigation.model
import android.content.Context
import android.location.Geocoder
import android.location.Location
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@@ -14,13 +12,14 @@ import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.ObjectBox.boxStore
import com.kouros.navigation.data.Place
import com.kouros.navigation.data.Place_
import com.kouros.navigation.data.SearchFilter
import com.kouros.navigation.data.nominatim.Search
import com.kouros.navigation.data.nominatim.SearchResult
import com.kouros.navigation.utils.NavigationUtils
import com.kouros.navigation.utils.location
import io.objectbox.kotlin.boxFor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneOffset
@@ -66,7 +65,6 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
//place.distance = distance.toFloat()
if (place.distance == 0F) {
recentPlace.postValue(place)
println("RecentPlace $recentPlace")
return@launch
}
}
@@ -75,7 +73,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
}
}
}
fun loadPlaces(location: Location) {
fun loadPlaces(context: Context, location: Location) {
viewModelScope.launch(Dispatchers.IO) {
try {
val placeBox = boxStore.boxFor(Place::class)
@@ -87,7 +85,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
query.close()
for (place in results) {
val plLocation = location(place.latitude, place.longitude)
val distance = repository.getRouteDistance(location, plLocation)
val distance = repository.getRouteDistance(location, plLocation, getSearchFilter(context))
place.distance = distance.toFloat()
}
places.postValue(results)
@@ -97,20 +95,20 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
}
}
fun loadRoute(currentLocation: Location, location: Location) {
fun loadRoute(context: Context, currentLocation: Location, location: Location) {
viewModelScope.launch(Dispatchers.IO) {
try {
route.postValue(repository.getRoute(currentLocation, location))
route.postValue(repository.getRoute(currentLocation, location, getSearchFilter(context)))
} catch (e: Exception) {
e.printStackTrace()
}
}
}
fun loadPreviewRoute(currentLocation: Location, location: Location) {
fun loadPreviewRoute(context: Context, currentLocation: Location, location: Location) {
viewModelScope.launch(Dispatchers.IO) {
try {
previewRoute.postValue(repository.getRoute(currentLocation, location))
previewRoute.postValue(repository.getRoute(currentLocation, location, getSearchFilter(context)))
} catch (e: Exception) {
e.printStackTrace()
}
@@ -133,7 +131,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
if (addressLines.size > 1) {
val plLocation = location(adr.latitude, adr.longitude)
val distance =
repository.getRouteDistance(currentLocation, plLocation)
repository.getRouteDistance(currentLocation, plLocation, getSearchFilter(context))
contactList.add(
Place(
id = address.contactId,
@@ -179,7 +177,6 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
fun reverseAddress(location: Location ): String {
val address = repository.reverseAddress(location)
println(address)
val gson = GsonBuilder().serializeNulls().create()
val place = gson.fromJson(address, SearchResult::class.java)
println(place.address.road)
@@ -226,5 +223,21 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
}
}
}
fun getSearchFilter(context: Context): SearchFilter {
val avoidMotorway = NavigationUtils.getBooleanKeyValue(
context = context,
Constants.AVOID_MOTORWAY
)
val avoidTollway = NavigationUtils.getBooleanKeyValue(
context = context,
Constants.AVOID_TOLLWAY
)
return SearchFilter.Builder()
.avoidMotorway(avoidMotorway)
.avoidTollway(avoidTollway)
.build()
}
}