TomTom Routing
This commit is contained in:
@@ -14,8 +14,8 @@ android {
|
|||||||
applicationId = "com.kouros.navigation"
|
applicationId = "com.kouros.navigation"
|
||||||
minSdk = 33
|
minSdk = 33
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 36
|
versionCode = 38
|
||||||
versionName = "0.2.0.36"
|
versionName = "0.2.0.38"
|
||||||
base.archivesName = "navi-$versionName"
|
base.archivesName = "navi-$versionName"
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ class MainActivity : ComponentActivity() {
|
|||||||
|
|
||||||
val routeModel = RouteModel()
|
val routeModel = RouteModel()
|
||||||
var tilt = 50.0
|
var tilt = 50.0
|
||||||
val useMock = true
|
val useMock = false
|
||||||
val type = 1 // simulate 2 test 3 gpx
|
val type = 3 // simulate 2 test 3 gpx 4 testSingle
|
||||||
|
|
||||||
var currentIndex = 0
|
var currentIndex = 0
|
||||||
val stepData: MutableLiveData<StepData> by lazy {
|
val stepData: MutableLiveData<StepData> by lazy {
|
||||||
@@ -109,14 +109,15 @@ class MainActivity : ComponentActivity() {
|
|||||||
3 -> gpx(
|
3 -> gpx(
|
||||||
context = applicationContext
|
context = applicationContext
|
||||||
)
|
)
|
||||||
|
|
||||||
|
4 -> testSingle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val cameraPosition = MutableLiveData(
|
val cameraPosition = MutableLiveData(
|
||||||
CameraPosition(
|
CameraPosition(
|
||||||
zoom = 15.0,
|
zoom = 15.0, target = Position(latitude = 48.1857475, longitude = 11.5793627)
|
||||||
target = Position(latitude = 48.1857475, longitude = 11.5793627)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -140,13 +141,11 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
|
locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
|
||||||
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
|
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
|
||||||
fusedLocationClient.lastLocation
|
fusedLocationClient.lastLocation.addOnSuccessListener { _: android.location.Location? ->
|
||||||
.addOnSuccessListener { _: android.location.Location? ->
|
|
||||||
if (useMock) {
|
if (useMock) {
|
||||||
mock = MockLocation(locationManager)
|
mock = MockLocation(locationManager)
|
||||||
mock.setMockLocation(
|
mock.setMockLocation(
|
||||||
homeVogelhart.latitude,
|
homeVogelhart.latitude, homeVogelhart.longitude
|
||||||
homeVogelhart.longitude
|
|
||||||
)
|
)
|
||||||
navigationViewModel.route.observe(this, observer)
|
navigationViewModel.route.observe(this, observer)
|
||||||
}
|
}
|
||||||
@@ -196,8 +195,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
val sheetPeekHeightState = remember { mutableStateOf(256.dp) }
|
val sheetPeekHeightState = remember { mutableStateOf(256.dp) }
|
||||||
|
|
||||||
val locationProvider = rememberDefaultLocationProvider(
|
val locationProvider = rememberDefaultLocationProvider(
|
||||||
updateInterval = 0.5.seconds,
|
updateInterval = 0.5.seconds, desiredAccuracy = DesiredAccuracy.Highest
|
||||||
desiredAccuracy = DesiredAccuracy.Highest
|
|
||||||
)
|
)
|
||||||
val userLocationState = rememberUserLocationState(locationProvider)
|
val userLocationState = rememberUserLocationState(locationProvider)
|
||||||
val locationState = locationProvider.location.collectAsState()
|
val locationState = locationProvider.location.collectAsState()
|
||||||
@@ -263,12 +261,10 @@ class MainActivity : ComponentActivity() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun Settings(navController: NavController, modifier: Modifier = Modifier) {
|
fun Settings(navController: NavController, modifier: Modifier = Modifier) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxSize()
|
||||||
.fillMaxSize()
|
|
||||||
) {
|
) {
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
modifier = Modifier
|
modifier = Modifier.padding(start = 10.dp, top = 40.dp),
|
||||||
.padding(start = 10.dp, top = 40.dp),
|
|
||||||
onClick = {
|
onClick = {
|
||||||
navController.navigate("settings")
|
navController.navigate("settings")
|
||||||
},
|
},
|
||||||
@@ -284,44 +280,35 @@ class MainActivity : ComponentActivity() {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SheetContent(
|
fun SheetContent(
|
||||||
locationState: Double,
|
locationState: Double, step: StepData?, nextStep: StepData?, closeSheet: () -> Unit
|
||||||
step: StepData?,
|
|
||||||
nextStep: StepData?,
|
|
||||||
closeSheet: () -> Unit
|
|
||||||
) {
|
) {
|
||||||
if (!routeModel.isNavigating()) {
|
if (!routeModel.isNavigating()) {
|
||||||
SearchSheet(applicationContext, navigationViewModel, lastLocation) { closeSheet() }
|
SearchSheet(applicationContext, navigationViewModel, lastLocation) { closeSheet() }
|
||||||
} else {
|
} else {
|
||||||
NavigationSheet(
|
NavigationSheet(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
routeModel, step!!, nextStep!!,
|
routeModel,
|
||||||
|
step!!,
|
||||||
|
nextStep!!,
|
||||||
{ stopNavigation { closeSheet() } },
|
{ stopNavigation { closeSheet() } },
|
||||||
{ simulateNavigation() }
|
{ simulateNavigation() })
|
||||||
)
|
|
||||||
}
|
}
|
||||||
// For recomposition!
|
// For recomposition!
|
||||||
Text("$locationState", fontSize = 12.sp)
|
Text("$locationState", fontSize = 12.sp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateLocation(location: Location?) {
|
fun updateLocation(location: Location?) {
|
||||||
if (location != null
|
if (location != null && lastLocation.latitude != location.position.latitude && lastLocation.longitude != location.position.longitude) {
|
||||||
&& lastLocation.latitude != location.position.latitude
|
|
||||||
&& lastLocation.longitude != location.position.longitude
|
|
||||||
) {
|
|
||||||
val currentLocation = location(location.position.longitude, location.position.latitude)
|
val currentLocation = location(location.position.longitude, location.position.latitude)
|
||||||
val bearing = bearing(lastLocation, currentLocation, cameraPosition.value!!.bearing)
|
val bearing = bearing(lastLocation, currentLocation, cameraPosition.value!!.bearing)
|
||||||
with(routeModel) {
|
with(routeModel) {
|
||||||
if (isNavigating()) {
|
if (isNavigating()) {
|
||||||
updateLocation(currentLocation, navigationViewModel)
|
updateLocation(currentLocation, navigationViewModel)
|
||||||
stepData.value = currentStep()
|
stepData.value = currentStep()
|
||||||
if (route.currentStepIndex + 1 <= curLeg.steps.size) {
|
|
||||||
nextStepData.value = nextStep()
|
nextStepData.value = nextStep()
|
||||||
}
|
if (navState.maneuverType in 39..42 && routeCalculator.leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE) {
|
||||||
if (maneuverType in 39..42
|
|
||||||
&& routeCalculator.leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE
|
|
||||||
) {
|
|
||||||
// stopNavigation()
|
// stopNavigation()
|
||||||
arrived = true
|
navState.copy(arrived = true)
|
||||||
routeData.value = ""
|
routeData.value = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,9 +316,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
val zoom = calculateZoom(location.speed)
|
val zoom = calculateZoom(location.speed)
|
||||||
cameraPosition.postValue(
|
cameraPosition.postValue(
|
||||||
cameraPosition.value!!.copy(
|
cameraPosition.value!!.copy(
|
||||||
zoom = zoom,
|
zoom = zoom, target = location.position, bearing = bearing
|
||||||
target = location.position,
|
|
||||||
bearing = bearing
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
lastLocation = currentLocation
|
lastLocation = currentLocation
|
||||||
@@ -361,13 +346,9 @@ class MainActivity : ComponentActivity() {
|
|||||||
private fun checkMockLocationEnabled() {
|
private fun checkMockLocationEnabled() {
|
||||||
try {
|
try {
|
||||||
// Check if mock location is enabled for this app
|
// Check if mock location is enabled for this app
|
||||||
val appOpsManager =
|
val appOpsManager = getSystemService(APP_OPS_SERVICE) as AppOpsManager
|
||||||
getSystemService(APP_OPS_SERVICE) as AppOpsManager
|
val mode = appOpsManager.checkOp(
|
||||||
val mode =
|
AppOpsManager.OPSTR_MOCK_LOCATION, Process.myUid(), packageName
|
||||||
appOpsManager.checkOp(
|
|
||||||
AppOpsManager.OPSTR_MOCK_LOCATION,
|
|
||||||
Process.myUid(),
|
|
||||||
packageName
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (mode != AppOpsManager.MODE_ALLOWED) {
|
if (mode != AppOpsManager.MODE_ALLOWED) {
|
||||||
@@ -389,7 +370,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
val deviation = 0.0
|
val deviation = 0.0
|
||||||
if (index in 0..routeModel.curRoute.waypoints.size) {
|
if (index in 0..routeModel.curRoute.waypoints.size) {
|
||||||
mock.setMockLocation(waypoint[1], waypoint[0])
|
mock.setMockLocation(waypoint[1], waypoint[0])
|
||||||
delay(500L) //
|
Thread.sleep(500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,24 +382,34 @@ class MainActivity : ComponentActivity() {
|
|||||||
//if (index in 3..3) {
|
//if (index in 3..3) {
|
||||||
for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
for ((windex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
||||||
routeModel.updateLocation(
|
routeModel.updateLocation(
|
||||||
location(waypoint[0], waypoint[1]),
|
location(waypoint[0], waypoint[1]), navigationViewModel
|
||||||
navigationViewModel
|
|
||||||
)
|
)
|
||||||
val step = routeModel.currentStep()
|
val step = routeModel.currentStep()
|
||||||
println("Step: ${step.instruction} ${step.leftStepDistance}")
|
val nextStep = routeModel.nextStep()
|
||||||
if (index + 1 <= routeModel.curLeg.steps.size) {
|
println("Step: ${step.instruction} ${step.leftStepDistance} ${nextStep.currentManeuverType}")
|
||||||
//nextStepData.value = routeModel.nextStep()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test2() {
|
fun testSingle() {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
testSingleUpdate(48.185976, 11.578463) // Silcherstr. 23-13
|
||||||
// Balanstr.
|
testSingleUpdate(48.186712, 11.578574) // Silcherstr. 27-33
|
||||||
mock.setMockLocation(48.119357, 11.599130)
|
testSingleUpdate(48.186899, 11.580480) // Schmalkadenerstr. 24-28
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testSingleUpdate(latitude: Double, longitude: Double) {
|
||||||
|
if (1 == 1) {
|
||||||
|
mock.setMockLocation(latitude, longitude)
|
||||||
|
} else {
|
||||||
|
routeModel.updateLocation(
|
||||||
|
location(longitude, latitude), navigationViewModel
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val step = routeModel.currentStep()
|
||||||
|
val nextStep = routeModel.nextStep()
|
||||||
|
println("Step: ${step.instruction} ${step.leftStepDistance} ${nextStep.currentManeuverType}")
|
||||||
|
Thread.sleep(1_000)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun gpx(context: Context) {
|
fun gpx(context: Context) {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ fun NavigationSheet(
|
|||||||
val distance = (step.leftDistance / 1000).round(1)
|
val distance = (step.leftDistance / 1000).round(1)
|
||||||
|
|
||||||
if (step.lane.isNotEmpty()) {
|
if (step.lane.isNotEmpty()) {
|
||||||
routeModel.iconMapper.addLanes( step)
|
routeModel.navState.iconMapper.addLanes( step)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ buildscript {
|
|||||||
val objectboxVersion by extra("5.0.1") // For KTS build scripts
|
val objectboxVersion by extra("5.0.1") // For KTS build scripts
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Android Gradle Plugin 8.0 or later supported
|
|
||||||
classpath(libs.gradle)
|
classpath(libs.gradle)
|
||||||
classpath("io.objectbox:objectbox-gradle-plugin:$objectboxVersion")
|
classpath("io.objectbox:objectbox-gradle-plugin:$objectboxVersion")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,11 +251,11 @@ class NavigationSession : Session(), NavigationScreen.Listener {
|
|||||||
fun updateLocation(location: Location) {
|
fun updateLocation(location: Location) {
|
||||||
if (routeModel.isNavigating()) {
|
if (routeModel.isNavigating()) {
|
||||||
navigationScreen.updateTrip(location)
|
navigationScreen.updateTrip(location)
|
||||||
if (!routeModel.arrived) {
|
if (!routeModel.navState.arrived) {
|
||||||
val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations())
|
val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations())
|
||||||
val distance = location.distanceTo(snapedLocation)
|
val distance = location.distanceTo(snapedLocation)
|
||||||
if (distance > MAXIMAL_ROUTE_DEVIATION) {
|
if (distance > MAXIMAL_ROUTE_DEVIATION) {
|
||||||
navigationScreen.calculateNewRoute(routeModel.destination)
|
navigationScreen.calculateNewRoute(routeModel.navState.destination)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (distance < MAXIMAL_SNAP_CORRECTION) {
|
if (distance < MAXIMAL_SNAP_CORRECTION) {
|
||||||
|
|||||||
@@ -470,7 +470,7 @@ fun DebugInfo(
|
|||||||
contentAlignment = Alignment.CenterStart
|
contentAlignment = Alignment.CenterStart
|
||||||
) {
|
) {
|
||||||
val textMeasurerLocation = rememberTextMeasurer()
|
val textMeasurerLocation = rememberTextMeasurer()
|
||||||
val location = routeModel.currentLocation.latitude.toString()
|
val location = routeModel.navState.currentLocation.latitude.toString()
|
||||||
val styleSpeed = TextStyle(
|
val styleSpeed = TextStyle(
|
||||||
fontSize = 26.sp,
|
fontSize = 26.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ class RouteCarModel() : RouteModel() {
|
|||||||
.setManeuver(
|
.setManeuver(
|
||||||
maneuver.build()
|
maneuver.build()
|
||||||
)
|
)
|
||||||
if (destination.street != null) {
|
if (navState.destination.street != null) {
|
||||||
step.setRoad(destination.street!!)
|
step.setRoad(navState.destination.street!!)
|
||||||
}
|
}
|
||||||
if (stepData.lane.isNotEmpty()) {
|
if (stepData.lane.isNotEmpty()) {
|
||||||
addLanes(carContext, step, stepData)
|
addLanes(carContext, step, stepData)
|
||||||
@@ -127,9 +127,9 @@ class RouteCarModel() : RouteModel() {
|
|||||||
.setRemainingTimeColor(CarColor.GREEN)
|
.setRemainingTimeColor(CarColor.GREEN)
|
||||||
.setRemainingDistanceColor(CarColor.BLUE)
|
.setRemainingDistanceColor(CarColor.BLUE)
|
||||||
|
|
||||||
if (travelMessage.isNotEmpty()) {
|
if (navState.travelMessage.isNotEmpty()) {
|
||||||
travelBuilder.setTripIcon(createCarIcon(carContext, R.drawable.warning_24px))
|
travelBuilder.setTripIcon(createCarIcon(carContext, R.drawable.warning_24px))
|
||||||
travelBuilder.setTripText(CarText.create(travelMessage))
|
travelBuilder.setTripText(CarText.create(navState.travelMessage))
|
||||||
}
|
}
|
||||||
return travelBuilder.build()
|
return travelBuilder.build()
|
||||||
}
|
}
|
||||||
@@ -147,10 +147,10 @@ class RouteCarModel() : RouteModel() {
|
|||||||
"${direction}_${it2.trim()}"
|
"${direction}_${it2.trim()}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val laneDirection = iconMapper.addLanes(direction, stepData)
|
val laneDirection = navState.iconMapper.addLanes(direction, stepData)
|
||||||
if (laneDirection != LaneDirection.SHAPE_UNKNOWN) {
|
if (laneDirection != LaneDirection.SHAPE_UNKNOWN) {
|
||||||
if (!laneImageAdded) {
|
if (!laneImageAdded) {
|
||||||
step.setLanesImage(createCarIcon(iconMapper.createLaneIcon(carContext, stepData)))
|
step.setLanesImage(createCarIcon(navState.iconMapper.createLaneIcon(carContext, stepData)))
|
||||||
laneImageAdded = true
|
laneImageAdded = true
|
||||||
}
|
}
|
||||||
val laneType =
|
val laneType =
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ class CategoryScreen(
|
|||||||
val loc = location(0.0, 0.0)
|
val loc = location(0.0, 0.0)
|
||||||
elements.forEach {
|
elements.forEach {
|
||||||
if (loc.latitude == 0.0) {
|
if (loc.latitude == 0.0) {
|
||||||
loc.longitude = it.lon!!
|
loc.longitude = it.lon
|
||||||
loc.latitude = it.lat!!
|
loc.latitude = it.lat
|
||||||
}
|
}
|
||||||
coordinates.add(listOf(it.lon!!, it.lat!!))
|
coordinates.add(listOf(it.lon, it.lat))
|
||||||
}
|
}
|
||||||
if (elements.isNotEmpty()) {
|
if (elements.isNotEmpty()) {
|
||||||
val route = createPointCollection(coordinates, category)
|
val route = createPointCollection(coordinates, category)
|
||||||
@@ -111,7 +111,7 @@ class CategoryScreen(
|
|||||||
}
|
}
|
||||||
val row = Row.Builder()
|
val row = Row.Builder()
|
||||||
.setOnClickListener {
|
.setOnClickListener {
|
||||||
val location = location(it.lon!!, it.lat!!)
|
val location = location(it.lon, it.lat)
|
||||||
surfaceRenderer.setCategoryLocation(location, category)
|
surfaceRenderer.setCategoryLocation(location, category)
|
||||||
}
|
}
|
||||||
.setTitle(name)
|
.setTitle(name)
|
||||||
|
|||||||
@@ -31,16 +31,12 @@ import com.kouros.navigation.data.Constants.DESTINATION_ARRIVAL_DISTANCE
|
|||||||
import com.kouros.navigation.data.Place
|
import com.kouros.navigation.data.Place
|
||||||
import com.kouros.navigation.data.nominatim.SearchResult
|
import com.kouros.navigation.data.nominatim.SearchResult
|
||||||
import com.kouros.navigation.data.overpass.Elements
|
import com.kouros.navigation.data.overpass.Elements
|
||||||
import com.kouros.navigation.data.tomtom.Features
|
|
||||||
import com.kouros.navigation.data.tomtom.Geometry
|
|
||||||
import com.kouros.navigation.model.ViewModel
|
import com.kouros.navigation.model.ViewModel
|
||||||
import com.kouros.navigation.utils.GeoUtils
|
import com.kouros.navigation.utils.GeoUtils
|
||||||
import com.kouros.navigation.utils.location
|
import com.kouros.navigation.utils.location
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.Period
|
|
||||||
import java.time.ZoneOffset
|
import java.time.ZoneOffset
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.time.Duration
|
|
||||||
|
|
||||||
class NavigationScreen(
|
class NavigationScreen(
|
||||||
carContext: CarContext,
|
carContext: CarContext,
|
||||||
@@ -154,11 +150,11 @@ class NavigationScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun navigationEndTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
private fun navigationEndTemplate(actionStripBuilder: ActionStrip.Builder): Template {
|
||||||
if (routeModel.arrived) {
|
if (routeModel.navState.arrived) {
|
||||||
val timer = object : CountDownTimer(8000, 1000) {
|
val timer = object : CountDownTimer(8000, 1000) {
|
||||||
override fun onTick(millisUntilFinished: Long) {}
|
override fun onTick(millisUntilFinished: Long) {}
|
||||||
override fun onFinish() {
|
override fun onFinish() {
|
||||||
routeModel.arrived = false
|
routeModel.navState = routeModel.navState.copy(arrived = false)
|
||||||
navigationType = NavigationType.VIEW
|
navigationType = NavigationType.VIEW
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
@@ -177,8 +173,8 @@ class NavigationScreen(
|
|||||||
|
|
||||||
fun navigationArrivedTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
fun navigationArrivedTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
|
||||||
var street = ""
|
var street = ""
|
||||||
if (routeModel.destination.street != null) {
|
if (routeModel.navState.destination.street != null) {
|
||||||
street = routeModel.destination.street!!
|
street = routeModel.navState.destination.street!!
|
||||||
}
|
}
|
||||||
return NavigationTemplate.Builder()
|
return NavigationTemplate.Builder()
|
||||||
.setNavigationInfo(
|
.setNavigationInfo(
|
||||||
@@ -316,7 +312,7 @@ class NavigationScreen(
|
|||||||
navigateTo,
|
navigateTo,
|
||||||
surfaceRenderer.carOrientation
|
surfaceRenderer.carOrientation
|
||||||
)
|
)
|
||||||
routeModel.destination = recentPlace
|
routeModel.navState = routeModel.navState.copy(destination = recentPlace)
|
||||||
}
|
}
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
@@ -444,7 +440,7 @@ class NavigationScreen(
|
|||||||
location,
|
location,
|
||||||
surfaceRenderer.carOrientation
|
surfaceRenderer.carOrientation
|
||||||
)
|
)
|
||||||
routeModel.destination = place
|
routeModel.navState = routeModel.navState.copy(destination = place)
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,14 +488,14 @@ class NavigationScreen(
|
|||||||
updateSpeedCamera(location)
|
updateSpeedCamera(location)
|
||||||
with(routeModel) {
|
with(routeModel) {
|
||||||
updateLocation(location, viewModel)
|
updateLocation(location, viewModel)
|
||||||
if ((maneuverType == Maneuver.TYPE_DESTINATION
|
if ((navState.maneuverType == Maneuver.TYPE_DESTINATION
|
||||||
|| maneuverType == Maneuver.TYPE_DESTINATION_LEFT
|
|| navState.maneuverType == Maneuver.TYPE_DESTINATION_LEFT
|
||||||
|| maneuverType == Maneuver.TYPE_DESTINATION_RIGHT
|
|| navState.maneuverType == Maneuver.TYPE_DESTINATION_RIGHT
|
||||||
|| maneuverType == Maneuver.TYPE_DESTINATION_STRAIGHT)
|
|| navState.maneuverType == Maneuver.TYPE_DESTINATION_STRAIGHT)
|
||||||
&& routeCalculator.leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE
|
&& routeCalculator.leftStepDistance() < DESTINATION_ARRIVAL_DISTANCE
|
||||||
) {
|
) {
|
||||||
stopNavigation()
|
stopNavigation()
|
||||||
arrived = true
|
navState = navState.copy(arrived = true)
|
||||||
surfaceRenderer.routeData.value = ""
|
surfaceRenderer.routeData.value = ""
|
||||||
navigationType = NavigationType.ARRIVAL
|
navigationType = NavigationType.ARRIVAL
|
||||||
invalidate()
|
invalidate()
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class PlaceListScreen(
|
|||||||
setSpan(
|
setSpan(
|
||||||
DistanceSpan.create(
|
DistanceSpan.create(
|
||||||
Distance.create(
|
Distance.create(
|
||||||
it.distance.toDouble(),
|
(it.distance/1000).toDouble(),
|
||||||
Distance.UNIT_KILOMETERS
|
Distance.UNIT_KILOMETERS
|
||||||
)
|
)
|
||||||
), 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE
|
), 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ class RoutePreviewScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onRouteSelected(index: Int) {
|
private fun onRouteSelected(index: Int) {
|
||||||
routeModel.currentRouteIndex = index
|
routeModel.navState = routeModel.navState.copy(currentRouteIndex = index)
|
||||||
surfaceRenderer.setPreviewRouteData(routeModel)
|
surfaceRenderer.setPreviewRouteData(routeModel)
|
||||||
//setResult(destination)
|
//setResult(destination)
|
||||||
//finish()
|
//finish()
|
||||||
|
|||||||
@@ -147,6 +147,10 @@ object Constants {
|
|||||||
|
|
||||||
const val DESTINATION_ARRIVAL_DISTANCE = 40.0
|
const val DESTINATION_ARRIVAL_DISTANCE = 40.0
|
||||||
|
|
||||||
|
const val NEAREST_LOCATION_DISTANCE = 10F
|
||||||
|
|
||||||
|
const val MAXIMUM_LOCATION_DISTANCE = 100000F
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -50,11 +50,10 @@ abstract class NavigationRepository {
|
|||||||
searchFilter: SearchFilter,
|
searchFilter: SearchFilter,
|
||||||
context: Context
|
context: Context
|
||||||
): Double {
|
): Double {
|
||||||
//val route = getRoute(context, currentLocation, location, carOrientation, searchFilter)
|
val route = getRoute(context, currentLocation, location, carOrientation, searchFilter)
|
||||||
//val routeModel = RouteModel()
|
val routeModel = RouteModel()
|
||||||
//routeModel.startNavigation(route, context)
|
routeModel.startNavigation(route, context)
|
||||||
// return routeModel.curRoute.summary.distance
|
return routeModel.curRoute.summary.distance
|
||||||
return 0.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun searchPlaces(search: String, location: Location): String {
|
fun searchPlaces(search: String, location: Location): String {
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ data class Route(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
data class Builder(
|
data class Builder(
|
||||||
|
|
||||||
var routeEngine: Int = 0,
|
var routeEngine: Int = 0,
|
||||||
var summary: Summary = Summary(),
|
var summary: Summary = Summary(),
|
||||||
var routes: List<com.kouros.navigation.data.route.Routes> = emptyList(),
|
var routes: List<com.kouros.navigation.data.route.Routes> = emptyList(),
|
||||||
@@ -76,8 +75,6 @@ data class Route(
|
|||||||
return Route(
|
return Route(
|
||||||
routeEngine = 0,
|
routeEngine = 0,
|
||||||
routes = emptyList(),
|
routes = emptyList(),
|
||||||
//waypoints = emptyList(),
|
|
||||||
//routeGeoJson = "",
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class OsrmRoute {
|
|||||||
}
|
}
|
||||||
val step = Step(
|
val step = Step(
|
||||||
index = stepIndex,
|
index = stepIndex,
|
||||||
name = step.name,
|
street = step.name,
|
||||||
distance = step.distance / 1000,
|
distance = step.distance / 1000,
|
||||||
duration = step.duration,
|
duration = step.duration,
|
||||||
maneuver = maneuver,
|
maneuver = maneuver,
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ data class Maneuver(
|
|||||||
val waypoints: List<List<Double>>,
|
val waypoints: List<List<Double>>,
|
||||||
val location: Location,
|
val location: Location,
|
||||||
val exit: Int = 0,
|
val exit: Int = 0,
|
||||||
|
val street: String = "",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,6 +10,6 @@ data class Step(
|
|||||||
val maneuver: Maneuver,
|
val maneuver: Maneuver,
|
||||||
val duration: Double = 0.0,
|
val duration: Double = 0.0,
|
||||||
val distance: Double = 0.0,
|
val distance: Double = 0.0,
|
||||||
val name : String = "",
|
val street : String = "",
|
||||||
val intersection: List<Intersection> = mutableListOf(),
|
val intersection: List<Intersection> = mutableListOf(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ data class Instruction(
|
|||||||
val roadNumbers: List<String>,
|
val roadNumbers: List<String>,
|
||||||
val routeOffsetInMeters: Int,
|
val routeOffsetInMeters: Int,
|
||||||
val signpostText: String,
|
val signpostText: String,
|
||||||
val street: String = "",
|
val street: String? = "",
|
||||||
val travelTimeInSeconds: Int,
|
val travelTimeInSeconds: Int,
|
||||||
val turnAngleInDecimalDegrees: Int,
|
val turnAngleInDecimalDegrees: Int,
|
||||||
val exitNumber: String? = "0",
|
val exitNumber: String? = "0",
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ package com.kouros.navigation.data.tomtom
|
|||||||
data class Route(
|
data class Route(
|
||||||
val guidance: Guidance,
|
val guidance: Guidance,
|
||||||
val legs: List<Leg>,
|
val legs: List<Leg>,
|
||||||
val sections: List<Section>,
|
val sections: List<Section>?,
|
||||||
val summary: SummaryX
|
val summary: SummaryX
|
||||||
)
|
)
|
||||||
@@ -18,6 +18,8 @@ val tomtomTrafficUrl = "https://api.tomtom.com/traffic/services/5/incidentDetail
|
|||||||
private val tomtomFields =
|
private val tomtomFields =
|
||||||
"{incidents{type,geometry{type,coordinates},properties{iconCategory,events{description}}}}"
|
"{incidents{type,geometry{type,coordinates},properties{iconCategory,events{description}}}}"
|
||||||
|
|
||||||
|
const val useAsset = false
|
||||||
|
|
||||||
class TomTomRepository : NavigationRepository() {
|
class TomTomRepository : NavigationRepository() {
|
||||||
override fun getRoute(
|
override fun getRoute(
|
||||||
context: Context,
|
context: Context,
|
||||||
@@ -26,9 +28,11 @@ class TomTomRepository : NavigationRepository() {
|
|||||||
carOrientation: Float,
|
carOrientation: Float,
|
||||||
searchFilter: SearchFilter
|
searchFilter: SearchFilter
|
||||||
): String {
|
): String {
|
||||||
|
if (useAsset) {
|
||||||
val routeJson = context.resources.openRawResource(R.raw.tomom_routing)
|
val routeJson = context.resources.openRawResource(R.raw.tomom_routing)
|
||||||
val routeJsonString = routeJson.bufferedReader().use { it.readText() }
|
val routeJsonString = routeJson.bufferedReader().use { it.readText() }
|
||||||
return routeJsonString
|
return routeJsonString
|
||||||
|
}
|
||||||
val url =
|
val url =
|
||||||
routeUrl + "${currentLocation.latitude},${currentLocation.longitude}:${location.latitude},${location.longitude}" +
|
routeUrl + "${currentLocation.latitude},${currentLocation.longitude}:${location.latitude},${location.longitude}" +
|
||||||
"/json?vehicleHeading=90§ionType=traffic&report=effectiveSettings&routeType=eco" +
|
"/json?vehicleHeading=90§ionType=traffic&report=effectiveSettings&routeType=eco" +
|
||||||
@@ -44,7 +48,6 @@ class TomTomRepository : NavigationRepository() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getTraffic(context: Context, location: Location, carOrientation: Float): String {
|
override fun getTraffic(context: Context, location: Location, carOrientation: Float): String {
|
||||||
val useAsset = true
|
|
||||||
val bbox = calculateSquareRadius(location.latitude, location.longitude, 15.0)
|
val bbox = calculateSquareRadius(location.latitude, location.longitude, 15.0)
|
||||||
return if (useAsset) {
|
return if (useAsset) {
|
||||||
val trafficJson = context.resources.openRawResource(R.raw.tomtom_traffic)
|
val trafficJson = context.resources.openRawResource(R.raw.tomtom_traffic)
|
||||||
|
|||||||
@@ -37,24 +37,28 @@ class TomTomRoute {
|
|||||||
val steps = mutableListOf<Step>()
|
val steps = mutableListOf<Step>()
|
||||||
var lastPointIndex = 0
|
var lastPointIndex = 0
|
||||||
for (index in 1..< route.guidance.instructions.size) {
|
for (index in 1..< route.guidance.instructions.size) {
|
||||||
|
val lastInstruction = route.guidance.instructions[index-1]
|
||||||
val instruction = route.guidance.instructions[index]
|
val instruction = route.guidance.instructions[index]
|
||||||
|
val street = lastInstruction.street ?: ""
|
||||||
|
val maneuverStreet = instruction.street ?: ""
|
||||||
val maneuver = RouteManeuver(
|
val maneuver = RouteManeuver(
|
||||||
bearingBefore = 0,
|
bearingBefore = 0,
|
||||||
bearingAfter = 0,
|
bearingAfter = 0,
|
||||||
type = convertType(instruction.maneuver),
|
type = convertType(instruction.maneuver),
|
||||||
waypoints = points.subList(
|
waypoints = points.subList(
|
||||||
lastPointIndex,
|
lastPointIndex,
|
||||||
instruction.pointIndex,
|
instruction.pointIndex+1,
|
||||||
),
|
),
|
||||||
exit = exitNumber(instruction),
|
exit = exitNumber(instruction),
|
||||||
location = location(
|
location = location(
|
||||||
instruction.point.longitude, instruction.point.latitude
|
instruction.point.longitude, instruction.point.latitude
|
||||||
),
|
),
|
||||||
|
street = maneuverStreet
|
||||||
)
|
)
|
||||||
|
|
||||||
lastPointIndex = instruction.pointIndex
|
lastPointIndex = instruction.pointIndex
|
||||||
val intersections = mutableListOf<Intersection>()
|
val intersections = mutableListOf<Intersection>()
|
||||||
route.sections.forEach { section ->
|
route.sections?.forEach { section ->
|
||||||
val lanes = mutableListOf<Lane>()
|
val lanes = mutableListOf<Lane>()
|
||||||
var startIndex = 0
|
var startIndex = 0
|
||||||
if (section.startPointIndex <= instruction.pointIndex - 3
|
if (section.startPointIndex <= instruction.pointIndex - 3
|
||||||
@@ -78,10 +82,9 @@ class TomTomRoute {
|
|||||||
allIntersections.addAll(intersections)
|
allIntersections.addAll(intersections)
|
||||||
stepDistance = route.guidance.instructions[index].routeOffsetInMeters - stepDistance
|
stepDistance = route.guidance.instructions[index].routeOffsetInMeters - stepDistance
|
||||||
stepDuration = route.guidance.instructions[index].travelTimeInSeconds - stepDuration
|
stepDuration = route.guidance.instructions[index].travelTimeInSeconds - stepDuration
|
||||||
val name = instruction.street
|
|
||||||
val step = Step(
|
val step = Step(
|
||||||
index = stepIndex,
|
index = stepIndex,
|
||||||
name = name,
|
street = street,
|
||||||
distance = stepDistance,
|
distance = stepDistance,
|
||||||
duration = stepDuration,
|
duration = stepDuration,
|
||||||
maneuver = maneuver,
|
maneuver = maneuver,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ValhallaRoute {
|
|||||||
if (it.streetNames != null && it.streetNames.isNotEmpty()) {
|
if (it.streetNames != null && it.streetNames.isNotEmpty()) {
|
||||||
name = it.streetNames[0]
|
name = it.streetNames[0]
|
||||||
}
|
}
|
||||||
val step = Step( index = stepIndex, name = name, distance = it.length, duration = it.time, maneuver = maneuver)
|
val step = Step( index = stepIndex, street = name, distance = it.length, duration = it.time, maneuver = maneuver)
|
||||||
steps.add(step)
|
steps.add(step)
|
||||||
stepIndex += 1
|
stepIndex += 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ import java.util.Collections
|
|||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.collections.forEach
|
import kotlin.collections.forEach
|
||||||
|
|
||||||
class IconMapper(var routeModel: RouteModel) {
|
class IconMapper() {
|
||||||
|
|
||||||
|
|
||||||
fun maneuverIcon(routeManeuverType: Int): Int {
|
fun maneuverIcon(routeManeuverType: Int): Int {
|
||||||
var currentTurnIcon = R.drawable.ic_turn_name_change
|
var currentTurnIcon = R.drawable.ic_turn_name_change
|
||||||
@@ -102,7 +101,7 @@ class IconMapper(var routeModel: RouteModel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"left", "slight_left" -> {
|
"left" -> {
|
||||||
when (stepData.currentManeuverType) {
|
when (stepData.currentManeuverType) {
|
||||||
Maneuver.TYPE_TURN_NORMAL_LEFT -> LaneDirection.SHAPE_NORMAL_LEFT
|
Maneuver.TYPE_TURN_NORMAL_LEFT -> LaneDirection.SHAPE_NORMAL_LEFT
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.kouros.navigation.model
|
|||||||
|
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import androidx.car.app.navigation.model.Step
|
import androidx.car.app.navigation.model.Step
|
||||||
|
import com.kouros.navigation.data.Constants.MAXIMUM_LOCATION_DISTANCE
|
||||||
|
import com.kouros.navigation.data.Constants.NEAREST_LOCATION_DISTANCE
|
||||||
import com.kouros.navigation.utils.location
|
import com.kouros.navigation.utils.location
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
@@ -12,37 +14,30 @@ class RouteCalculator(var routeModel: RouteModel) {
|
|||||||
|
|
||||||
var lastSpeedIndex: Int = 0
|
var lastSpeedIndex: Int = 0
|
||||||
|
|
||||||
|
|
||||||
fun findStep(location: Location) {
|
fun findStep(location: Location) {
|
||||||
var nearestDistance = 100000f
|
var nearestDistance = MAXIMUM_LOCATION_DISTANCE
|
||||||
for ((index, step) in routeModel.curLeg.steps.withIndex()) {
|
for ((index, step) in routeModel.curLeg.steps.withIndex()) {
|
||||||
if (index >= routeModel.route.currentStepIndex) {
|
if (index >= routeModel.navState.route.currentStepIndex) {
|
||||||
for ((wayIndex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
for ((wayIndex, waypoint) in step.maneuver.waypoints.withIndex()) {
|
||||||
if (wayIndex >= step.waypointIndex) {
|
if (wayIndex >= step.waypointIndex) {
|
||||||
val distance = location.distanceTo(location(waypoint[0], waypoint[1]))
|
val distance = location.distanceTo(location(waypoint[0], waypoint[1]))
|
||||||
if (distance < nearestDistance) {
|
if (distance < nearestDistance) {
|
||||||
nearestDistance = distance
|
nearestDistance = distance
|
||||||
routeModel.route.currentStepIndex = step.index
|
routeModel.navState.route.currentStepIndex = step.index
|
||||||
step.waypointIndex = wayIndex
|
step.waypointIndex = wayIndex
|
||||||
step.wayPointLocation = location(waypoint[0], waypoint[1])
|
step.wayPointLocation = location(waypoint[0], waypoint[1])
|
||||||
routeModel.routeBearing = routeModel.lastLocation.bearingTo(location)
|
routeModel.navState = routeModel.navState.copy(
|
||||||
} else {
|
routeBearing = routeModel.navState.lastLocation.bearingTo(location)
|
||||||
if (nearestDistance != 100000f) {
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nearestDistance < NEAREST_LOCATION_DISTANCE) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nearestDistance == 0F) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nearestDistance == 0F) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun travelLeftTime(): Double {
|
fun travelLeftTime(): Double {
|
||||||
var timeLeft = 0.0
|
var timeLeft = 0.0
|
||||||
@@ -102,10 +97,8 @@ class RouteCalculator(var routeModel: RouteModel) {
|
|||||||
if (distance > 500 || lastSpeedIndex < routeModel.route.currentStepIndex) {
|
if (distance > 500 || lastSpeedIndex < routeModel.route.currentStepIndex) {
|
||||||
lastSpeedIndex = routeModel.route.currentStepIndex
|
lastSpeedIndex = routeModel.route.currentStepIndex
|
||||||
lastSpeedLocation = location
|
lastSpeedLocation = location
|
||||||
viewModel.getMaxSpeed(location, routeModel.previousStreet())
|
viewModel.getMaxSpeed(location, routeModel.route.currentStep().street)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -13,75 +13,81 @@ import com.kouros.navigation.data.route.Leg
|
|||||||
import com.kouros.navigation.data.route.Routes
|
import com.kouros.navigation.data.route.Routes
|
||||||
import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue
|
import com.kouros.navigation.utils.NavigationUtils.getIntKeyValue
|
||||||
import com.kouros.navigation.utils.location
|
import com.kouros.navigation.utils.location
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
open class RouteModel() {
|
open class RouteModel {
|
||||||
|
|
||||||
var route = Route.Builder().buildEmpty()
|
// Immutable Data Class
|
||||||
|
data class NavigationState(
|
||||||
|
val route: Route = Route.Builder().buildEmpty(),
|
||||||
|
val iconMapper : IconMapper = IconMapper(),
|
||||||
|
val navigating: Boolean = false,
|
||||||
|
val arrived: Boolean = false,
|
||||||
|
val travelMessage: String = "",
|
||||||
|
val maneuverType: Int = 0,
|
||||||
|
val lastLocation: Location = location(0.0, 0.0),
|
||||||
|
val currentLocation: Location = location(0.0, 0.0),
|
||||||
|
val routeBearing: Float = 0F,
|
||||||
|
val currentRouteIndex: Int = 0,
|
||||||
|
val destination: Place = Place()
|
||||||
|
)
|
||||||
|
|
||||||
val routeCalculator = RouteCalculator(this)
|
var navState = NavigationState()
|
||||||
|
|
||||||
var iconMapper = IconMapper(this)
|
val route: Route
|
||||||
var navigating: Boolean = false
|
get() = navState.route
|
||||||
var destination: Place = Place()
|
|
||||||
var arrived: Boolean = false
|
|
||||||
var maneuverType: Int = 0
|
|
||||||
var travelMessage: String = ""
|
|
||||||
|
|
||||||
var currentLocation: Location = location(0.0, 0.0)
|
val routeCalculator : RouteCalculator = RouteCalculator(this)
|
||||||
|
|
||||||
var lastLocation: Location = location(0.0, 0.0)
|
|
||||||
var routeBearing: Float = 0F
|
|
||||||
|
|
||||||
var currentRouteIndex = 0
|
|
||||||
val curRoute: Routes
|
val curRoute: Routes
|
||||||
get() = route.routes[currentRouteIndex]
|
get() = navState.route.routes[navState.currentRouteIndex]
|
||||||
|
|
||||||
val curLeg: Leg
|
val curLeg: Leg
|
||||||
get() = route.routes[currentRouteIndex].legs.first()
|
get() = navState.route.routes[navState.currentRouteIndex].legs.first()
|
||||||
|
|
||||||
|
|
||||||
fun startNavigation(routeString: String, context: Context) {
|
fun startNavigation(routeString: String, context: Context) {
|
||||||
val routeEngine = getIntKeyValue(context = context, ROUTING_ENGINE)
|
val routeEngine = getIntKeyValue(context = context, ROUTING_ENGINE)
|
||||||
|
navState = navState.copy(
|
||||||
route = Route.Builder()
|
route = Route.Builder()
|
||||||
.routeEngine(routeEngine)
|
.routeEngine(routeEngine)
|
||||||
.route(routeString)
|
.route(routeString)
|
||||||
.build()
|
.build()
|
||||||
|
)
|
||||||
if (hasLegs()) {
|
if (hasLegs()) {
|
||||||
navigating = true
|
navState = navState.copy(navigating = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hasLegs(): Boolean {
|
private fun hasLegs(): Boolean {
|
||||||
return route.routes.isNotEmpty() && route.routes[0].legs.isNotEmpty()
|
return navState.route.routes.isNotEmpty() && navState.route.routes[0].legs.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopNavigation() {
|
fun stopNavigation() {
|
||||||
route = Route.Builder().buildEmpty()
|
navState = navState.copy(
|
||||||
navigating = false
|
route = Route.Builder().buildEmpty(),
|
||||||
arrived = false
|
navigating = false,
|
||||||
|
arrived = false,
|
||||||
maneuverType = Maneuver.TYPE_UNKNOWN
|
maneuverType = Maneuver.TYPE_UNKNOWN
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
|
||||||
fun updateLocation(curLocation: Location, viewModel: ViewModel) {
|
fun updateLocation(curLocation: Location, viewModel: ViewModel) {
|
||||||
currentLocation = curLocation
|
navState = navState.copy(currentLocation = curLocation)
|
||||||
routeCalculator.findStep(curLocation)
|
routeCalculator.findStep(curLocation)
|
||||||
routeCalculator.updateSpeedLimit(curLocation, viewModel)
|
routeCalculator.updateSpeedLimit(curLocation, viewModel)
|
||||||
lastLocation = currentLocation
|
navState = navState.copy(lastLocation = navState.currentLocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun currentLanes(location: Location): List<Lane> {
|
private fun currentLanes(): List<Lane> {
|
||||||
var lanes = emptyList<Lane>()
|
var lanes = emptyList<Lane>()
|
||||||
if (route.legs().isNotEmpty()) {
|
if (navState.route.legs().isNotEmpty()) {
|
||||||
route.legs().first().intersection.forEach { it ->
|
navState.route.legs().first().intersection.forEach {
|
||||||
if (it.lane.isNotEmpty()) {
|
if (it.lane.isNotEmpty()) {
|
||||||
val distance = lastLocation.distanceTo(location(it.location[0], it.location[1]))
|
val distance =
|
||||||
|
navState.lastLocation.distanceTo(location(it.location[0], it.location[1]))
|
||||||
val sectionBearing =
|
val sectionBearing =
|
||||||
lastLocation.bearingTo(location(it.location[0], it.location[1]))
|
navState.lastLocation.bearingTo(location(it.location[0], it.location[1]))
|
||||||
if (distance < 500 && (routeBearing.absoluteValue - sectionBearing.absoluteValue).absoluteValue < 10) {
|
if (distance < 500 && (navState.routeBearing.absoluteValue - sectionBearing.absoluteValue).absoluteValue < 10) {
|
||||||
lanes = it.lane
|
lanes = it.lane
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,25 +96,24 @@ open class RouteModel() {
|
|||||||
return lanes
|
return lanes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun currentStep(): StepData {
|
fun currentStep(): StepData {
|
||||||
val distanceToNextStep = routeCalculator.leftStepDistance()
|
val distanceToNextStep = routeCalculator.leftStepDistance()
|
||||||
// Determine the maneuver type and corresponding icon
|
// Determine the maneuver type and corresponding icon
|
||||||
val currentStep = route.nextStep(0)
|
val currentStep = navState.route.nextStep(0)
|
||||||
// Safely get the street name from the maneuver
|
// Safely get the street name from the maneuver
|
||||||
val streetName = currentStep.name
|
val streetName = currentStep.maneuver.street
|
||||||
val curManeuverType = currentStep.maneuver.type
|
val curManeuverType = currentStep.maneuver.type
|
||||||
val exitNumber = currentStep.maneuver.exit
|
val exitNumber = currentStep.maneuver.exit
|
||||||
val maneuverIcon = iconMapper.maneuverIcon(curManeuverType)
|
val maneuverIcon = navState.iconMapper.maneuverIcon(curManeuverType)
|
||||||
maneuverType = curManeuverType
|
navState = navState.copy(maneuverType = curManeuverType)
|
||||||
|
|
||||||
val lanes = currentLanes(currentLocation)
|
val lanes = currentLanes()
|
||||||
|
|
||||||
// Construct and return the final StepData object
|
// Construct and return the final StepData object
|
||||||
return StepData(
|
return StepData(
|
||||||
streetName,
|
streetName,
|
||||||
distanceToNextStep,
|
distanceToNextStep,
|
||||||
maneuverType,
|
navState.maneuverType,
|
||||||
maneuverIcon,
|
maneuverIcon,
|
||||||
routeCalculator.arrivalTime(),
|
routeCalculator.arrivalTime(),
|
||||||
routeCalculator.travelLeftDistance(),
|
routeCalculator.travelLeftDistance(),
|
||||||
@@ -118,22 +123,21 @@ open class RouteModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun nextStep(): StepData {
|
fun nextStep(): StepData {
|
||||||
val step = route.nextStep(1)
|
val step = navState.route.nextStep(1)
|
||||||
val maneuverType = step.maneuver.type
|
val maneuverType = step.maneuver.type
|
||||||
val distanceLeft = routeCalculator.leftStepDistance()
|
val distanceLeft = routeCalculator.leftStepDistance()
|
||||||
var text = ""
|
var text = ""
|
||||||
when (distanceLeft) {
|
when (distanceLeft) {
|
||||||
in 0.0..NEXT_STEP_THRESHOLD -> {
|
in 0.0..NEXT_STEP_THRESHOLD -> {
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
if (step.name.isNotEmpty()) {
|
if (step.street.isNotEmpty()) {
|
||||||
text = step.name
|
text = step.street
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val maneuverIcon = iconMapper.maneuverIcon(maneuverType)
|
val maneuverIcon = navState.iconMapper.maneuverIcon(maneuverType)
|
||||||
// Construct and return the final StepData object
|
// Construct and return the final StepData object
|
||||||
return StepData(
|
return StepData(
|
||||||
text,
|
text,
|
||||||
@@ -147,14 +151,7 @@ open class RouteModel() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun previousStreet(): String {
|
|
||||||
if (route.currentStepIndex > 0) {
|
|
||||||
return route.legs().first().steps[route.currentStepIndex - 1].name
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isNavigating(): Boolean {
|
fun isNavigating(): Boolean {
|
||||||
return navigating
|
return navState.navigating
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,6 @@ object GeoUtils {
|
|||||||
return newLocation
|
return newLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun decodePolyline(encoded: String, precision: Int = 6): List<List<Double>> {
|
fun decodePolyline(encoded: String, precision: Int = 6): List<List<Double>> {
|
||||||
val factor = 10.0.pow(precision)
|
val factor = 10.0.pow(precision)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user