CheckRoute, Simulation, Closed Streets
This commit is contained in:
@@ -17,8 +17,8 @@ android {
|
|||||||
applicationId = "com.kouros.navigation"
|
applicationId = "com.kouros.navigation"
|
||||||
minSdk = 33
|
minSdk = 33
|
||||||
targetSdk = 37
|
targetSdk = 37
|
||||||
versionCode = 110
|
versionCode = 111
|
||||||
versionName = "0.3.0.110"
|
versionName = "0.3.0.111"
|
||||||
base.archivesName = "navi-$versionName"
|
base.archivesName = "navi-$versionName"
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,8 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
|
|||||||
|
|
||||||
var speedCameras = listOf<Elements>()
|
var speedCameras = listOf<Elements>()
|
||||||
|
|
||||||
var lastRouteDate: LocalDateTime = LocalDateTime.now()
|
|
||||||
|
private var lastRouteCheckLocation = location(0.0, 0.0)
|
||||||
|
|
||||||
var navigationManagerStarted = false
|
var navigationManagerStarted = false
|
||||||
|
|
||||||
@@ -461,10 +462,11 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
|
|||||||
* Snaps location to route and checks for deviation requiring reroute.
|
* Snaps location to route and checks for deviation requiring reroute.
|
||||||
*/
|
*/
|
||||||
private fun handleNavigationLocation(location: Location) {
|
private fun handleNavigationLocation(location: Location) {
|
||||||
|
val start = System.currentTimeMillis()
|
||||||
routeModel.updateLocation(location, navigationViewModel)
|
routeModel.updateLocation(location, navigationViewModel)
|
||||||
val snappedLocation = snapLocation(location, routeModel.route.maneuverLocations())
|
val snappedLocation = snapLocation(location, routeModel.route.maneuverLocations())
|
||||||
val streetName = routeModel.currentStep().street
|
val streetName = routeModel.currentStep().street
|
||||||
if (checkLocationDeviation(location, snappedLocation, streetName)) {
|
if (checkLocationDeviation(location, snappedLocation, streetName)) {
|
||||||
if (routeModel.navState.arrived) return
|
if (routeModel.navState.arrived) return
|
||||||
if (guidanceAudio == 1) {
|
if (guidanceAudio == 1) {
|
||||||
handleGuidanceAudio()
|
handleGuidanceAudio()
|
||||||
@@ -472,16 +474,22 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
|
|||||||
val currentDate = LocalDateTime.now(ZoneOffset.UTC)
|
val currentDate = LocalDateTime.now(ZoneOffset.UTC)
|
||||||
checkTraffic(currentDate, snappedLocation)
|
checkTraffic(currentDate, snappedLocation)
|
||||||
updateSpeedCamera(snappedLocation)
|
updateSpeedCamera(snappedLocation)
|
||||||
checkRoute(currentDate, snappedLocation)
|
checkRoute(snappedLocation)
|
||||||
updateNavigationScreen()
|
updateNavigationScreen()
|
||||||
checkArrival()
|
checkArrival()
|
||||||
}
|
}
|
||||||
|
val end = System.currentTimeMillis()
|
||||||
|
// Log.d(TAG, "UpdateLoction ${end-start} ms")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the location deviation is acceptable.
|
* Checks if the location deviation is acceptable.
|
||||||
*/
|
*/
|
||||||
private fun checkLocationDeviation(location: Location, snappedLocation: Location, streetName: String): Boolean {
|
private fun checkLocationDeviation(
|
||||||
|
location: Location,
|
||||||
|
snappedLocation: Location,
|
||||||
|
streetName: String
|
||||||
|
): Boolean {
|
||||||
val distance = location.distanceTo(snappedLocation)
|
val distance = location.distanceTo(snappedLocation)
|
||||||
when {
|
when {
|
||||||
distance > MAXIMAL_ROUTE_DEVIATION -> {
|
distance > MAXIMAL_ROUTE_DEVIATION -> {
|
||||||
@@ -493,6 +501,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
|
|||||||
distance < MAXIMAL_SNAP_CORRECTION -> {
|
distance < MAXIMAL_SNAP_CORRECTION -> {
|
||||||
surfaceRenderer.updateLocation(snappedLocation, streetName)
|
surfaceRenderer.updateLocation(snappedLocation, streetName)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
surfaceRenderer.updateLocation(location, streetName)
|
surfaceRenderer.updateLocation(location, streetName)
|
||||||
}
|
}
|
||||||
@@ -657,8 +666,10 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
|
|||||||
val newRouteModel = RouteModel()
|
val newRouteModel = RouteModel()
|
||||||
newRouteModel.navState = routeModel.navState.copy(routingEngine = routingEngine)
|
newRouteModel.navState = routeModel.navState.copy(routingEngine = routingEngine)
|
||||||
newRouteModel.startNavigation(route)
|
newRouteModel.startNavigation(route)
|
||||||
routeModel.curRoute.summary.trafficDelay = newRouteModel.curRoute.summary.trafficDelay
|
if ((routeModel.curRoute.summary.trafficDelay - newRouteModel.curRoute.summary.trafficDelay).absoluteValue > 300) {
|
||||||
updateNavigationScreen()
|
routeModel.startNavigation(route)
|
||||||
|
updateNavigationScreen()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -767,7 +778,7 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
|
|||||||
* Periodically requests speed camera information near the current location.
|
* Periodically requests speed camera information near the current location.
|
||||||
*/
|
*/
|
||||||
private fun updateSpeedCamera(location: Location) {
|
private fun updateSpeedCamera(location: Location) {
|
||||||
if (lastCameraSearch % 100 == 0) {
|
if (lastCameraSearch % 200 == 0) {
|
||||||
navigationViewModel.getSpeedCameras(location, 5.0)
|
navigationViewModel.getSpeedCameras(location, 5.0)
|
||||||
}
|
}
|
||||||
if (speedCameras.isNotEmpty() && lastCameraSearch % 15 == 0) {
|
if (speedCameras.isNotEmpty() && lastCameraSearch % 15 == 0) {
|
||||||
@@ -811,24 +822,36 @@ class NavigationSession : CarSession(), NavigationListener, NavigationObserverCa
|
|||||||
/**
|
/**
|
||||||
* Checks if a new route is needed based on the time since the last update.
|
* Checks if a new route is needed based on the time since the last update.
|
||||||
*/
|
*/
|
||||||
private fun checkRoute(currentDate: LocalDateTime, location: Location) {
|
private fun checkRoute(location: Location) {
|
||||||
val duration = Duration.between(currentDate, lastRouteDate)
|
val distance = location.distanceTo(lastRouteCheckLocation)
|
||||||
val routeUpdate = routeModel.curRoute.summary.duration / 4
|
if (distance > checkDistance(routeModel)) {
|
||||||
if (duration.abs().seconds > routeUpdate) {
|
Log.d(TAG, "CheckRoute $distance ${checkDistance(routeModel)}")
|
||||||
lastRouteDate = currentDate
|
if (lastRouteCheckLocation.latitude != 0.0) {
|
||||||
val destination = location(
|
val destination = location(
|
||||||
routeModel.navState.destination.longitude,
|
routeModel.navState.destination.longitude,
|
||||||
routeModel.navState.destination.latitude
|
routeModel.navState.destination.latitude
|
||||||
)
|
)
|
||||||
navigationViewModel.loadRoute(
|
navigationViewModel.loadRoute(
|
||||||
carContext,
|
carContext,
|
||||||
location,
|
location,
|
||||||
listOf(destination),
|
listOf(destination),
|
||||||
surfaceRenderer.carOrientation
|
surfaceRenderer.carOrientation
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
lastRouteCheckLocation = location
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkDistance(routeModel: RouteModel): Double {
|
||||||
|
val factor = when (routeModel.curRoute.summary.distance) {
|
||||||
|
in 0.0..20000.0 -> 4
|
||||||
|
in 20000.0..100000.0 -> 5
|
||||||
|
in 10000.0..200000.0 -> 6
|
||||||
|
else -> 7
|
||||||
|
}
|
||||||
|
return (routeModel.curRoute.summary.distance / factor)
|
||||||
|
}
|
||||||
|
|
||||||
override fun invalidateNavigationScreen() {
|
override fun invalidateNavigationScreen() {
|
||||||
navigationScreen.invalidate()
|
navigationScreen.invalidate()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,7 @@ import androidx.compose.ui.unit.Dp
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.kouros.data.R
|
import com.kouros.data.R
|
||||||
import com.kouros.navigation.data.ClosedColor
|
|
||||||
import com.kouros.navigation.data.Constants
|
import com.kouros.navigation.data.Constants
|
||||||
import com.kouros.navigation.data.Constants.homeVogelhart
|
|
||||||
import com.kouros.navigation.data.HeavyColor
|
import com.kouros.navigation.data.HeavyColor
|
||||||
import com.kouros.navigation.data.LaneColor
|
import com.kouros.navigation.data.LaneColor
|
||||||
import com.kouros.navigation.data.NavigationColorDark
|
import com.kouros.navigation.data.NavigationColorDark
|
||||||
@@ -43,7 +41,6 @@ import com.kouros.navigation.data.SlowColor
|
|||||||
import com.kouros.navigation.data.SpeedColor
|
import com.kouros.navigation.data.SpeedColor
|
||||||
import com.kouros.navigation.data.StationaryColor
|
import com.kouros.navigation.data.StationaryColor
|
||||||
import com.kouros.navigation.data.ViewStyle
|
import com.kouros.navigation.data.ViewStyle
|
||||||
import com.kouros.navigation.utils.GeoUtils.createEndCollection
|
|
||||||
import com.kouros.navigation.utils.GeoUtils.createPointCollection
|
import com.kouros.navigation.utils.GeoUtils.createPointCollection
|
||||||
import com.kouros.navigation.utils.isMetricSystem
|
import com.kouros.navigation.utils.isMetricSystem
|
||||||
import com.kouros.navigation.utils.location
|
import com.kouros.navigation.utils.location
|
||||||
@@ -143,7 +140,7 @@ fun MapLibre(
|
|||||||
@Composable
|
@Composable
|
||||||
fun StartEndLayer(routeData: String?) {
|
fun StartEndLayer(routeData: String?) {
|
||||||
if (!routeData.isNullOrEmpty()) {
|
if (!routeData.isNullOrEmpty()) {
|
||||||
val end = createEndCollection(routeData)
|
val end = createPointCollection(routeData)
|
||||||
val routes = rememberGeoJsonSource(GeoJsonData.JsonString(end))
|
val routes = rememberGeoJsonSource(GeoJsonData.JsonString(end))
|
||||||
val img = image(painterResource(R.drawable.sports_score_48px), drawAsSdf = true)
|
val img = image(painterResource(R.drawable.sports_score_48px), drawAsSdf = true)
|
||||||
SymbolLayer(
|
SymbolLayer(
|
||||||
@@ -186,23 +183,48 @@ fun RouteLayer(routeData: String?) {
|
|||||||
@Composable
|
@Composable
|
||||||
fun TrafficLayer(trafficData: Map<String, String>) {
|
fun TrafficLayer(trafficData: Map<String, String>) {
|
||||||
trafficData.forEach {
|
trafficData.forEach {
|
||||||
val traffic = rememberGeoJsonSource(GeoJsonData.JsonString(it.value))
|
if (it.key == "closed") {
|
||||||
LineLayer(
|
ClosedLayer(it)
|
||||||
id = "traffic-${it.key}-casing",
|
} else {
|
||||||
source = traffic,
|
val traffic = rememberGeoJsonSource(GeoJsonData.JsonString(it.value))
|
||||||
color = const(Color.White),
|
LineLayer(
|
||||||
width = routeLineWidth(base = 2.dp, isCasing = true),
|
id = "traffic-${it.key}-casing",
|
||||||
)
|
source = traffic,
|
||||||
LineLayer(
|
color = const(Color.White),
|
||||||
id = "traffic-${it.key}",
|
width = routeLineWidth(base = 2.dp, isCasing = true),
|
||||||
source = traffic,
|
)
|
||||||
color = trafficColor(it.key),
|
LineLayer(
|
||||||
width = routeLineWidth(base = 1.dp, isCasing = false),
|
id = "traffic-${it.key}",
|
||||||
)
|
source = traffic,
|
||||||
|
color = trafficColor(it.key),
|
||||||
|
width = routeLineWidth(base = 1.dp, isCasing = false),
|
||||||
|
)
|
||||||
|
}
|
||||||
// TrafficIcons(it)
|
// TrafficIcons(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ClosedLayer(entry: Map.Entry<String, String>) {
|
||||||
|
val routes = rememberGeoJsonSource(GeoJsonData.JsonString(entry.value))
|
||||||
|
val img = image(painterResource(R.drawable.do_not_disturb_on_24px), drawAsSdf = true)
|
||||||
|
SymbolLayer(
|
||||||
|
id = "closed-layer",
|
||||||
|
source = routes,
|
||||||
|
iconColor = const(Color.Red),
|
||||||
|
iconImage = img,
|
||||||
|
iconSize =
|
||||||
|
interpolate(
|
||||||
|
type = exponential(2.0f),
|
||||||
|
input = zoom(),
|
||||||
|
5 to const(2.0f),
|
||||||
|
10 to const(2.0f),
|
||||||
|
15 to const(3.0f),
|
||||||
|
20 to const(4.0f),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TrafficIcons(entry: Map.Entry<String, String>) {
|
private fun TrafficIcons(entry: Map.Entry<String, String>) {
|
||||||
val featureCollection = FeatureCollection.fromJson(entry.value)
|
val featureCollection = FeatureCollection.fromJson(entry.value)
|
||||||
@@ -307,7 +329,6 @@ fun trafficColor(key: String): Expression<ColorValue> {
|
|||||||
"stationary" -> return const(StationaryColor)
|
"stationary" -> return const(StationaryColor)
|
||||||
"heavy" -> return const(HeavyColor)
|
"heavy" -> return const(HeavyColor)
|
||||||
"roadworks" -> return const(RoadworksColor)
|
"roadworks" -> return const(RoadworksColor)
|
||||||
"closed" -> return const(ClosedColor)
|
|
||||||
"lane" -> return const(LaneColor)
|
"lane" -> return const(LaneColor)
|
||||||
}
|
}
|
||||||
return const(Color.Blue)
|
return const(Color.Blue)
|
||||||
|
|||||||
@@ -56,14 +56,14 @@ class Simulation {
|
|||||||
longitude = point[0]
|
longitude = point[0]
|
||||||
bearing = curBearing
|
bearing = curBearing
|
||||||
speedAccuracyMetersPerSecond = 1.0f // ~1 m/s
|
speedAccuracyMetersPerSecond = 1.0f // ~1 m/s
|
||||||
speed = 9.0f
|
speed = 10.0f
|
||||||
time = System.currentTimeMillis()
|
time = System.currentTimeMillis()
|
||||||
elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
|
elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
|
||||||
}
|
}
|
||||||
// Update your app's state as if a real GPS update occurred
|
// Update your app's state as if a real GPS update occurred
|
||||||
updateLocation(fakeLocation)
|
updateLocation(fakeLocation)
|
||||||
// Wait before moving to the next point (e.g., every 1 second)
|
// Wait before moving to the next point (e.g., every 1 second)
|
||||||
delay(500)
|
delay(1500)
|
||||||
lastLocation = fakeLocation
|
lastLocation = fakeLocation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package com.kouros.navigation.data
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
val NavigationColorLight = Color(0xFF17A119)
|
val NavigationColorLight = Color(0xFF17A119)
|
||||||
val NavigationColorDark = Color(0xFF1055DE)
|
val NavigationColorDark = Color(0xFF2B007A)
|
||||||
|
|
||||||
val RouteColor = Color(0xFF5201B4)
|
val RouteColor = Color(0xFF5201B4)
|
||||||
|
|
||||||
@@ -18,7 +18,6 @@ val SlowColor = Color(0xFFC43E3E)
|
|||||||
val StationaryColor = Color(0xFF910A0A)
|
val StationaryColor = Color(0xFF910A0A)
|
||||||
val HeavyColor = Color(0xFF6B0404)
|
val HeavyColor = Color(0xFF6B0404)
|
||||||
val RoadworksColor = Color(0xFFDAA707)
|
val RoadworksColor = Color(0xFFDAA707)
|
||||||
val ClosedColor = Color(0xFF280C10)
|
|
||||||
val LaneColor = Color(0xFFEFBAC1)
|
val LaneColor = Color(0xFFEFBAC1)
|
||||||
|
|
||||||
val PharmacyColor = Color(0xFF054603)
|
val PharmacyColor = Color(0xFF054603)
|
||||||
@@ -166,6 +166,8 @@ object Constants {
|
|||||||
const val TILT = 60.0
|
const val TILT = 60.0
|
||||||
|
|
||||||
const val TANKER_KOENIG_DELAY = 300000
|
const val TANKER_KOENIG_DELAY = 300000
|
||||||
|
|
||||||
|
const val LAST_CHECK_ROUTE_DISTANCE = 5000
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const val tomtomTrafficUrl = "https://api.tomtom.com/traffic/services/5/incident
|
|||||||
private const val tomtomFields =
|
private const val tomtomFields =
|
||||||
"{incidents{type,geometry{type,coordinates},properties{iconCategory,events{description}}}}"
|
"{incidents{type,geometry{type,coordinates},properties{iconCategory,events{description}}}}"
|
||||||
|
|
||||||
val useLocal = BuildConfig.DEBUG
|
val useLocal = BuildConfig.DEBUG
|
||||||
|
|
||||||
val useLocalTraffic = BuildConfig.DEBUG
|
val useLocalTraffic = BuildConfig.DEBUG
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.kouros.navigation.model
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||||
import androidx.compose.runtime.toMutableStateList
|
import androidx.compose.runtime.toMutableStateList
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
@@ -14,7 +13,6 @@ import com.kouros.navigation.data.Constants
|
|||||||
import com.kouros.navigation.data.Constants.FAVORITES
|
import com.kouros.navigation.data.Constants.FAVORITES
|
||||||
import com.kouros.navigation.data.Constants.SPEED_BEARING_DEVIATION
|
import com.kouros.navigation.data.Constants.SPEED_BEARING_DEVIATION
|
||||||
import com.kouros.navigation.data.Constants.SPEED_UPDATE_DISTANCE
|
import com.kouros.navigation.data.Constants.SPEED_UPDATE_DISTANCE
|
||||||
import com.kouros.navigation.data.Constants.TAG
|
|
||||||
import com.kouros.navigation.data.Constants.TANKER_KOENIG_DELAY
|
import com.kouros.navigation.data.Constants.TANKER_KOENIG_DELAY
|
||||||
import com.kouros.navigation.data.NavigationRepository
|
import com.kouros.navigation.data.NavigationRepository
|
||||||
import com.kouros.navigation.data.Place
|
import com.kouros.navigation.data.Place
|
||||||
@@ -30,7 +28,8 @@ import com.kouros.navigation.data.overpass.Elements
|
|||||||
import com.kouros.navigation.data.overpass.Overpass
|
import com.kouros.navigation.data.overpass.Overpass
|
||||||
import com.kouros.navigation.repository.SettingsRepository
|
import com.kouros.navigation.repository.SettingsRepository
|
||||||
import com.kouros.navigation.utils.GeoUtils.snapLocation
|
import com.kouros.navigation.utils.GeoUtils.snapLocation
|
||||||
import com.kouros.navigation.utils.GeoUtils.transferCoordinates
|
import com.kouros.navigation.utils.GeoUtils.buildLineStrings
|
||||||
|
import com.kouros.navigation.utils.GeoUtils.buildPointCollection
|
||||||
import com.kouros.navigation.utils.bearingPositive
|
import com.kouros.navigation.utils.bearingPositive
|
||||||
import com.kouros.navigation.utils.countryCodeSpeedLimit
|
import com.kouros.navigation.utils.countryCodeSpeedLimit
|
||||||
import com.kouros.navigation.utils.getSettingsRepository
|
import com.kouros.navigation.utils.getSettingsRepository
|
||||||
@@ -290,25 +289,25 @@ class NavigationViewModel(private val repository: NavigationRepository) : ViewMo
|
|||||||
val incidents = mutableMapOf<String, String>()
|
val incidents = mutableMapOf<String, String>()
|
||||||
val queuing = featureCollection.features()!!
|
val queuing = featureCollection.features()!!
|
||||||
.filter { it.properties()!!.get("events").toString().contains("Queuing traffic") }
|
.filter { it.properties()!!.get("events").toString().contains("Queuing traffic") }
|
||||||
incidents["queuing"] = transferCoordinates(queuing)
|
incidents["queuing"] = buildLineStrings(queuing)
|
||||||
val stationary = featureCollection.features()!!
|
val stationary = featureCollection.features()!!
|
||||||
.filter { it.properties()!!.get("events").toString().contains("Stationary traffic") }
|
.filter { it.properties()!!.get("events").toString().contains("Stationary traffic") }
|
||||||
incidents["stationary"] = transferCoordinates(stationary)
|
incidents["stationary"] = buildLineStrings(stationary)
|
||||||
val slow = featureCollection.features()!!
|
val slow = featureCollection.features()!!
|
||||||
.filter { it.properties()!!.get("events").toString().contains("Slow traffic") }
|
.filter { it.properties()!!.get("events").toString().contains("Slow traffic") }
|
||||||
incidents["slow"] = transferCoordinates(slow)
|
incidents["slow"] = buildLineStrings(slow)
|
||||||
val heavy = featureCollection.features()!!
|
val heavy = featureCollection.features()!!
|
||||||
.filter { it.properties()!!.get("events").toString().contains("Heavy traffic") }
|
.filter { it.properties()!!.get("events").toString().contains("Heavy traffic") }
|
||||||
incidents["heavy"] = transferCoordinates(heavy)
|
incidents["heavy"] = buildLineStrings(heavy)
|
||||||
val roadworks = featureCollection.features()!!
|
val roadworks = featureCollection.features()!!
|
||||||
.filter { it.properties()!!.get("events").toString().contains("Roadworks") }
|
.filter { it.properties()!!.get("events").toString().contains("Roadworks") }
|
||||||
incidents["roadworks"] = transferCoordinates(roadworks)
|
incidents["roadworks"] = buildLineStrings(roadworks)
|
||||||
val laneClosed = featureCollection.features()!!
|
val laneClosed = featureCollection.features()!!
|
||||||
.filter { it.properties()!!.get("events").toString().contains("Lane closed") }
|
.filter { it.properties()!!.get("events").toString().contains("Lane closed") }
|
||||||
incidents["lane"] = transferCoordinates(laneClosed)
|
incidents["lane"] = buildLineStrings(laneClosed)
|
||||||
val closed = featureCollection.features()!!
|
val closed = featureCollection.features()!!
|
||||||
.filter { it.properties()!!.get("events").toString().contains("Closed") }
|
.filter { it.properties()!!.get("events").toString().contains("Closed") }
|
||||||
incidents["closed"] = transferCoordinates(closed)
|
incidents["closed"] = buildPointCollection(closed)
|
||||||
|
|
||||||
return incidents
|
return incidents
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.maplibre.spatialk.geojson.Feature
|
|||||||
import org.maplibre.spatialk.geojson.dsl.addFeature
|
import org.maplibre.spatialk.geojson.dsl.addFeature
|
||||||
import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection
|
import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection
|
||||||
import org.maplibre.spatialk.geojson.dsl.buildLineString
|
import org.maplibre.spatialk.geojson.dsl.buildLineString
|
||||||
|
import org.maplibre.spatialk.geojson.dsl.buildMultiPoint
|
||||||
import org.maplibre.spatialk.geojson.toJson
|
import org.maplibre.spatialk.geojson.toJson
|
||||||
import org.maplibre.turf.TurfMeasurement
|
import org.maplibre.turf.TurfMeasurement
|
||||||
import org.maplibre.turf.TurfMisc
|
import org.maplibre.turf.TurfMisc
|
||||||
@@ -136,7 +137,7 @@ object GeoUtils {
|
|||||||
return points
|
return points
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createEndCollection(geoJson: String): String {
|
fun createPointCollection(geoJson: String): String {
|
||||||
val featureCollection = FeatureCollection.fromJson(geoJson)
|
val featureCollection = FeatureCollection.fromJson(geoJson)
|
||||||
val geometry = featureCollection.features()!!.first().geometry()
|
val geometry = featureCollection.features()!!.first().geometry()
|
||||||
val coordinates = (geometry as LineString)
|
val coordinates = (geometry as LineString)
|
||||||
@@ -187,41 +188,66 @@ object GeoUtils {
|
|||||||
return isInside
|
return isInside
|
||||||
}
|
}
|
||||||
|
|
||||||
fun transferCoordinates(features: List<org.maplibre.geojson.Feature>): String {
|
fun buildLineStrings(features: List<org.maplibre.geojson.Feature>): String {
|
||||||
return buildFeatureCollection {
|
return buildFeatureCollection {
|
||||||
features.forEach {
|
features.forEach {
|
||||||
val movedCoordinates = arrayListOf<org.maplibre.spatialk.geojson.Point>()
|
val movedCoordinates = arrayListOf<org.maplibre.spatialk.geojson.Point>()
|
||||||
val coordinates = it.geometry() as LineString
|
val coordinates = it.geometry() as LineString
|
||||||
val geo = coordinates.coordinates()
|
val geo = coordinates.coordinates()
|
||||||
var bearing = 0.0F
|
var bearing = 0.0F
|
||||||
for (index in 0..<geo.size) {
|
for (index in 0..<geo.size) {
|
||||||
val current = location(geo[index].longitude(), geo[index].latitude())
|
val current = location(geo[index].longitude(), geo[index].latitude())
|
||||||
bearing = if (index < geo.size - 1) {
|
bearing = if (index < geo.size - 1) {
|
||||||
val next =
|
val next =
|
||||||
location(geo[index + 1].longitude(), geo[index + 1].latitude())
|
location(geo[index + 1].longitude(), geo[index + 1].latitude())
|
||||||
current.bearingPositive(next)
|
current.bearingPositive(next)
|
||||||
} else {
|
} else {
|
||||||
bearing
|
bearing
|
||||||
}
|
}
|
||||||
val point = movePoint(
|
val point = movePoint(
|
||||||
current.latitude,
|
current.latitude,
|
||||||
current.longitude,
|
current.longitude,
|
||||||
bearingDegrees = bearing + 90.0
|
bearingDegrees = bearing + 90.0
|
||||||
|
)
|
||||||
|
movedCoordinates.add(point)
|
||||||
|
}
|
||||||
|
val lineString = buildLineString {
|
||||||
|
movedCoordinates.forEach { ft ->
|
||||||
|
add(
|
||||||
|
ft
|
||||||
)
|
)
|
||||||
movedCoordinates.add(point)
|
|
||||||
}
|
|
||||||
val lineString = buildLineString {
|
|
||||||
movedCoordinates.forEach { ft ->
|
|
||||||
add(
|
|
||||||
ft
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addFeature {
|
|
||||||
geometry = lineString
|
|
||||||
properties = buildJsonObject { null }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
addFeature {
|
||||||
|
geometry = lineString
|
||||||
|
properties = buildJsonObject { null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.toJson()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildPointCollection(features: List<org.maplibre.geojson.Feature>): String {
|
||||||
|
return buildFeatureCollection {
|
||||||
|
features.forEach {
|
||||||
|
val movedCoordinates = arrayListOf<org.maplibre.spatialk.geojson.Point>()
|
||||||
|
val coordinates = it.geometry() as LineString
|
||||||
|
val geo = coordinates.coordinates()
|
||||||
|
var point = org.maplibre.spatialk.geojson.Point(geo.first().longitude(), geo.first().latitude())
|
||||||
|
movedCoordinates.add(point)
|
||||||
|
point = org.maplibre.spatialk.geojson.Point(geo.last().longitude(), geo.last().latitude())
|
||||||
|
movedCoordinates.add(point)
|
||||||
|
val multiPoint = buildMultiPoint {
|
||||||
|
movedCoordinates.forEach { ft ->
|
||||||
|
add(
|
||||||
|
ft
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addFeature {
|
||||||
|
geometry = multiPoint
|
||||||
|
properties = buildJsonObject { null }
|
||||||
|
}
|
||||||
|
}
|
||||||
}.toJson()
|
}.toJson()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,18 +49,20 @@ object NavigationUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun calculateZoom(speed: Double?): Double {
|
fun calculateZoom(speed: Double?): Double {
|
||||||
|
val zoom = 16.5
|
||||||
if (speed == null) {
|
if (speed == null) {
|
||||||
return 17.0
|
return zoom
|
||||||
}
|
}
|
||||||
val speedKmh = (speed * 3.6).toInt()
|
val speedKmh = (speed * 3.6).toInt()
|
||||||
val zoom = when (speedKmh) {
|
return when (speedKmh) {
|
||||||
in 0..10 -> 17.0
|
in 0..10 -> zoom + 1.0
|
||||||
in 11..30 -> 17.5
|
in 11..30 -> zoom + 0.5
|
||||||
in 31..65 -> 17.0
|
in 31..65 -> zoom
|
||||||
in 66..70 -> 16.5
|
in 66..70 -> zoom - 0.5
|
||||||
else -> 16.0
|
in 71..90 -> zoom - 1.0
|
||||||
|
in 91..100 -> zoom - 2.0
|
||||||
|
else -> zoom - 3.0
|
||||||
}
|
}
|
||||||
return zoom
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun previewZoom(centerLocation: Location, previewDistance: Double): Double {
|
fun previewZoom(centerLocation: Location, previewDistance: Double): Double {
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M280,520L680,520L680,440L280,440L280,520ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z"/>
|
||||||
|
</vector>
|
||||||
Reference in New Issue
Block a user