Diverse Änderungen

This commit is contained in:
Dimitris
2025-11-28 11:42:41 +01:00
parent c79fd157e4
commit 5ca9e4b174
43 changed files with 217 additions and 581 deletions

View File

@@ -350,8 +350,8 @@ class MainActivity : ComponentActivity() {
var bearing: Double var bearing: Double
if (routeModel.isNavigating()) { if (routeModel.isNavigating()) {
snapedLocation = snapLocation(location, routeModel.route.maneuverLocations()) snapedLocation = snapLocation(location, routeModel.route.maneuverLocations())
routeModel.updateLocation(location)
bearing = routeModel.currentStep().bearing bearing = routeModel.currentStep().bearing
routeModel.updateLocation(snapedLocation)
instruction.postValue(routeModel.currentStep()) instruction.postValue(routeModel.currentStep())
} else { } else {
bearing = cameraPosition.value!!.bearing bearing = cameraPosition.value!!.bearing

View File

@@ -1 +0,0 @@
/build

View File

@@ -1,47 +0,0 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "com.kouros.navigation.automotive"
compileSdk {
version = release(36)
}
defaultConfig {
applicationId = "com.kouros.navigation.automotive"
minSdk = 35
targetSdk = 36
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}

View File

@@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -1,24 +0,0 @@
package com.kouros.navigation.automotive
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.kouros.navigation.automotive", appContext.packageName)
}
}

View File

@@ -1,66 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES" />
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
<uses-feature
android:name="android.software.car.templates_host"
android:required="true" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.portrait"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.landscape"
android:required="false" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Navigation">
<meta-data
android:name="com.android.automotive"
android:resource="@xml/automotive_app_desc"
tools:ignore="MetadataTagInsideApplicationTag" />
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"
tools:ignore="MetadataTagInsideApplicationTag" />
<activity
android:name="androidx.car.app.activity.CarAppActivity"
android:configChanges="uiMode"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
android:exported="true"
android:launchMode="singleTask"
android:label="Navigation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="androidx.car.app.action.NAVIGATE" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="geo" />
</intent-filter>
<meta-data android:name="distractionOptimized" android:value="true"/>
</activity>
<application />
</manifest>

View File

@@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -1,30 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -1,16 +0,0 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Navigation" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -1,3 +0,0 @@
<resources>
<string name="app_name">automotive</string>
</resources>

View File

@@ -1,16 +0,0 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Navigation" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -1,17 +0,0 @@
package com.kouros.navigation.automotive
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

View File

@@ -15,6 +15,8 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.vectorResource import androidx.compose.ui.res.vectorResource
@@ -45,7 +47,13 @@ import org.maplibre.spatialk.geojson.Position
@Composable @Composable
fun cameraState(width: Int, height: Int, position: CameraPosition?, tilt: Double, preview: Boolean): CameraState { fun cameraState(
width: Int,
height: Int,
position: CameraPosition?,
tilt: Double,
preview: Boolean
): CameraState {
val padding = getPaddingValues(width, height, preview) val padding = getPaddingValues(width, height, preview)
return rememberCameraState( return rememberCameraState(
firstPosition = firstPosition =
@@ -118,12 +126,13 @@ fun DrawImage(location: Location) {
Box( Box(
modifier = Modifier modifier = Modifier
.size(48.dp, 48.dp)
.padding(start = 450.dp - 30.dp, top = 350.dp - 30.dp) .padding(start = 450.dp - 30.dp, top = 350.dp - 30.dp)
.drawBehind { .drawBehind {
with(painter) { with(painter) {
draw( draw(
size = Size(60F, 60F), size = Size(60F, 60F),
colorFilter = tint colorFilter = tint,
) )
} }
}) })
@@ -145,7 +154,6 @@ fun DrawImage(location: Location) {
drawText(measuredText) drawText(measuredText)
} }
} }
.fillMaxSize()
) )
} }

View File

@@ -23,9 +23,11 @@ import com.kouros.navigation.car.screen.NavigationScreen
import com.kouros.navigation.car.screen.RequestPermissionScreen import com.kouros.navigation.car.screen.RequestPermissionScreen
import com.kouros.navigation.car.screen.SearchScreen import com.kouros.navigation.car.screen.SearchScreen
import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION
import com.kouros.navigation.data.Constants.MAXIMAL_SNAP_CORRECTION
import com.kouros.navigation.data.Constants.TAG import com.kouros.navigation.data.Constants.TAG
import com.kouros.navigation.data.ObjectBox import com.kouros.navigation.data.ObjectBox
import com.kouros.navigation.utils.NavigationUtils.snapLocation import com.kouros.navigation.utils.NavigationUtils.snapLocation
import com.kouros.navigation.utils.location
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -44,7 +46,7 @@ class NavigationSession : Session(), NavigationScreen.Listener {
var locationIndex = 0 var locationIndex = 0
val simulate = true val simulate = false
var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? -> var mLocationListener: LocationListenerCompat = LocationListenerCompat { location: Location? ->
updateLocation(location) updateLocation(location)
@@ -160,7 +162,7 @@ class NavigationSession : Session(), NavigationScreen.Listener {
updateLocation(location) updateLocation(location)
locationManager.requestLocationUpdates( locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, LocationManager.GPS_PROVIDER,
/* minTimeMs= */ 100, /* minTimeMs= */ 500,
/* minDistanceM= */ 0f, /* minDistanceM= */ 0f,
mLocationListener mLocationListener
) )
@@ -179,18 +181,13 @@ class NavigationSession : Session(), NavigationScreen.Listener {
fun simulate(location: Location?) { fun simulate(location: Location?) {
if (routeModel.isNavigating() && locationIndex < routeModel.route.waypoints.size) { if (routeModel.isNavigating() && locationIndex < routeModel.route.waypoints.size) {
coroutineScope.launch { coroutineScope.launch {
delay( if (locationIndex >= routeModel.route.waypoints.size) {
100 return@launch
) }
val loc = routeModel.route.waypoints[locationIndex] val loc = routeModel.route.waypoints[locationIndex]
val curLocation = Location(LocationManager.GPS_PROVIDER) val curLocation = Location(LocationManager.GPS_PROVIDER)
if ( locationIndex == 1500) { curLocation.longitude = loc[0]// + 0.00001 * locationIndex
curLocation.longitude = loc[0] + 0.003 curLocation.latitude = loc[1] //+ 0.00001 * locationIndex
curLocation.latitude = loc[1] + 0.003
} else {
curLocation.longitude = loc[0]
curLocation.latitude = loc[1]
}
curLocation.speed = 15F curLocation.speed = 15F
update(curLocation) update(curLocation)
locationIndex += 1 locationIndex += 1
@@ -207,12 +204,22 @@ class NavigationSession : Session(), NavigationScreen.Listener {
fun update(location: Location) { fun update(location: Location) {
if (routeModel.isNavigating()) { if (routeModel.isNavigating()) {
val snapedLocation = snapLocation(location, routeModel.route.maneuverLocations())
val distance = location.distanceTo(snapedLocation)
println(distance)
if (distance > MAXIMAL_ROUTE_DEVIATION) {
// navigationScreen.calculateNewRoute()
//return
}
routeModel.updateLocation(location) routeModel.updateLocation(location)
navigationScreen.updateTrip() navigationScreen.updateTrip()
} if (distance < MAXIMAL_SNAP_CORRECTION) {
val result = surfaceRenderer.updateLocation(location) surfaceRenderer.updateLocation(snapedLocation)
if (!result) { } else {
navigationScreen.stopNavigation() surfaceRenderer.updateLocation(location)
}
} else {
surfaceRenderer.updateLocation(location)
} }
} }

View File

@@ -26,6 +26,7 @@ import androidx.savedstate.setViewTreeSavedStateRegistryOwner
import com.kouros.navigation.car.navigation.RouteCarModel import com.kouros.navigation.car.navigation.RouteCarModel
import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION import com.kouros.navigation.data.Constants.MAXIMAL_ROUTE_DEVIATION
import com.kouros.navigation.data.Constants.NEXT_STEP_THRESHOLD
import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING import com.kouros.navigation.data.Constants.SHOW_THREED_BUILDING
import com.kouros.navigation.model.RouteModel import com.kouros.navigation.model.RouteModel
import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue import com.kouros.navigation.utils.NavigationUtils.getBooleanKeyValue
@@ -189,7 +190,7 @@ class SurfaceRenderer(
@Composable @Composable
fun ShowPosition(cameraState: CameraState, position: CameraPosition?) { fun ShowPosition(cameraState: CameraState, position: CameraPosition?) {
var cameraDuration = duration(position) val cameraDuration = duration(position)
var bearing = position!!.bearing var bearing = position!!.bearing
var zoom = position.zoom var zoom = position.zoom
var target = position.target var target = position.target
@@ -197,9 +198,8 @@ class SurfaceRenderer(
if (!preview) { if (!preview) {
DrawImage(lastLocation) DrawImage(lastLocation)
} else { } else {
cameraDuration = 3.seconds
bearing = 0.0 bearing = 0.0
zoom = 11.0 zoom = previewZoom()
target = Position(centerLocation.longitude, centerLocation.latitude) target = Position(centerLocation.longitude, centerLocation.latitude)
localTilt = 0.0 localTilt = 0.0
} }
@@ -224,10 +224,13 @@ class SurfaceRenderer(
} }
private fun duration(position: CameraPosition?): Duration { private fun duration(position: CameraPosition?): Duration {
if (preview) {
return 3.seconds
}
val cameraDuration = if ((lastBearing - position!!.bearing).absoluteValue > 20.0) { val cameraDuration = if ((lastBearing - position!!.bearing).absoluteValue > 20.0) {
0.4.seconds 2.seconds
} else { } else {
1.seconds 2.seconds
} }
return cameraDuration return cameraDuration
} }
@@ -250,31 +253,24 @@ class SurfaceRenderer(
} }
} }
fun updateLocation(location: Location) : Boolean { fun updateLocation(location: Location) {
synchronized(this) { synchronized(this) {
if (!preview) { if (!preview) {
var snapedLocation = location var bearing = cameraPosition.value!!.bearing
var bearing: Double
bearing = cameraPosition.value!!.bearing
if (routeModel.isNavigating()) { if (routeModel.isNavigating()) {
snapedLocation = snapLocation(location, routeModel.route.maneuverLocations())
bearing = routeModel.currentStep().bearing bearing = routeModel.currentStep().bearing
if (snapedLocation.longitude == 0.0) {
//reRoute()
return false
}
} }
val zoom = if (!panView) { val zoom = if (!panView) {
calculateZoom(snapedLocation.speed.toDouble()) calculateZoom(location.speed.toDouble())
} else { } else {
cameraPosition.value!!.zoom cameraPosition.value!!.zoom
} }
updateCameraPosition(bearing, zoom, Position(snapedLocation.longitude, snapedLocation.latitude)) updateCameraPosition(bearing, zoom, Position(location.longitude, location.latitude))
lastBearing = cameraPosition.value!!.bearing lastBearing = cameraPosition.value!!.bearing
lastLocation = snapedLocation lastLocation = location
} else { } else {
val bearing = 0.0 val bearing = 0.0
val zoom = 14.0 val zoom = previewZoom()
updateCameraPosition( updateCameraPosition(
bearing, bearing,
zoom, zoom,
@@ -282,7 +278,6 @@ class SurfaceRenderer(
) )
} }
} }
return true
} }
private fun updateCameraPosition(bearing: Double, zoom: Double, target: Position) { private fun updateCameraPosition(bearing: Double, zoom: Double, target: Position) {
@@ -310,6 +305,23 @@ class SurfaceRenderer(
preview = true preview = true
} }
private fun previewZoom(): Double {
if (routeModel.isNavigating()) {
when (routeModel.route.distance) {
in 0.0..10.0 -> {
return 14.0
}
in 10.0..20.0 -> {
return 12.0
}
in 20.0..30.0 -> {
return 11.0
}
}
}
return 10.0
}
companion companion
object { object {
private const val TAG = "MapRenderer" private const val TAG = "MapRenderer"

View File

@@ -1,13 +1,7 @@
package com.kouros.navigation.car.navigation package com.kouros.navigation.car.navigation
import android.R
import android.app.Activity
import android.location.Location import android.location.Location
import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.view.Menu
import android.view.View
import android.widget.TextView
import org.xml.sax.SAXException import org.xml.sax.SAXException
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream

View File

@@ -86,11 +86,7 @@ class RouteCarModel() : RouteModel() {
when (distanceLeft) { when (distanceLeft) {
in 0.0..NEXT_STEP_THRESHOLD -> { in 0.0..NEXT_STEP_THRESHOLD -> {
return null return null
// if (maneuver.streetNames != null && maneuver.streetNames!!.isNotEmpty()) {
// text = maneuver.streetNames!![0]
// }
} }
else -> { else -> {
if (maneuver.streetNames != null && maneuver.streetNames!!.isNotEmpty()) { if (maneuver.streetNames != null && maneuver.streetNames!!.isNotEmpty()) {
text = maneuver.streetNames!![0] text = maneuver.streetNames!![0]
@@ -118,6 +114,7 @@ class RouteCarModel() : RouteModel() {
type = Maneuver.TYPE_STRAIGHT type = Maneuver.TYPE_STRAIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change) currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change)
} }
ManeuverType.Destination.value, ManeuverType.Destination.value,
ManeuverType.DestinationRight.value, ManeuverType.DestinationRight.value,
ManeuverType.DestinationLeft.value, ManeuverType.DestinationLeft.value,
@@ -125,35 +122,51 @@ class RouteCarModel() : RouteModel() {
type = Maneuver.TYPE_DESTINATION type = Maneuver.TYPE_DESTINATION
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_destination) currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_destination)
} }
ManeuverType.Right.value -> { ManeuverType.Right.value -> {
type = Maneuver.TYPE_TURN_NORMAL_RIGHT type = Maneuver.TYPE_TURN_NORMAL_RIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_right) currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_right)
} }
ManeuverType.Left.value -> { ManeuverType.Left.value -> {
type = Maneuver.TYPE_TURN_NORMAL_LEFT type = Maneuver.TYPE_TURN_NORMAL_LEFT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_left) currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_left)
} }
ManeuverType.RampRight.value -> { ManeuverType.RampRight.value -> {
type = Maneuver.TYPE_OFF_RAMP_SLIGHT_RIGHT type = Maneuver.TYPE_OFF_RAMP_SLIGHT_RIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_slight_right) currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_slight_right)
} }
ManeuverType.RampLeft.value -> { ManeuverType.RampLeft.value -> {
type = Maneuver.TYPE_TURN_NORMAL_LEFT type = Maneuver.TYPE_TURN_NORMAL_LEFT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_left) currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_normal_left)
} }
ManeuverType.ExitRight.value -> { ManeuverType.ExitRight.value -> {
type = Maneuver.TYPE_TURN_SLIGHT_RIGHT type = Maneuver.TYPE_TURN_SLIGHT_RIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_slight_right) currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_slight_right)
} }
ManeuverType.StayRight.value -> { ManeuverType.StayRight.value -> {
type = Maneuver.TYPE_KEEP_RIGHT type = Maneuver.TYPE_KEEP_RIGHT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change) currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change)
} }
ManeuverType.StayLeft.value -> { ManeuverType.StayLeft.value -> {
type = Maneuver.TYPE_KEEP_LEFT type = Maneuver.TYPE_KEEP_LEFT
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change) currentTurnIcon = createCarIcon(carContext, R.drawable.ic_turn_name_change)
} }
ManeuverType.RoundaboutEnter.value -> {
type = Maneuver.TYPE_ROUNDABOUT_ENTER_CCW
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_roundabout_ccw)
}
ManeuverType.RoundaboutExit.value -> {
type = Maneuver.TYPE_ROUNDABOUT_EXIT_CCW
currentTurnIcon = createCarIcon(carContext, R.drawable.ic_roundabout_ccw)
}
} }
maneuverType = type maneuverType = type
return Pair(type, currentTurnIcon) return Pair(type, currentTurnIcon)

View File

@@ -5,6 +5,8 @@ import android.content.Intent
import android.location.Location import android.location.Location
import android.location.LocationManager import android.location.LocationManager
import android.os.CountDownTimer import android.os.CountDownTimer
import android.os.Handler
import android.os.Looper
import androidx.car.app.CarContext import androidx.car.app.CarContext
import androidx.car.app.Screen import androidx.car.app.Screen
import androidx.car.app.model.Action import androidx.car.app.model.Action
@@ -46,6 +48,8 @@ class NavigationScreen(
} }
var currentNavigationLocation = Location(LocationManager.GPS_PROVIDER) var currentNavigationLocation = Location(LocationManager.GPS_PROVIDER)
var calculateNewRoute = false
val vieModel = ViewModel(NavigationRepository()) val vieModel = ViewModel(NavigationRepository())
val observer = Observer<String> { route -> val observer = Observer<String> { route ->
if (route.isNotEmpty()) { if (route.isNotEmpty()) {
@@ -80,7 +84,11 @@ class NavigationScreen(
.build() .build()
) )
return if (routeModel.isNavigating()) { return if (routeModel.isNavigating()) {
getNavigationTemplate(actionStripBuilder) if (calculateNewRoute) {
getNavigationLoadingTemplate(actionStripBuilder)
} else {
getNavigationTemplate(actionStripBuilder)
}
} else { } else {
getNavigationEndTemplate(actionStripBuilder) getNavigationEndTemplate(actionStripBuilder)
} }
@@ -155,6 +163,14 @@ class NavigationScreen(
} }
} }
fun getNavigationLoadingTemplate(actionStripBuilder: ActionStrip.Builder): NavigationTemplate {
return NavigationTemplate.Builder()
.setNavigationInfo(RoutingInfo.Builder().setLoading(true).build())
.setActionStrip(actionStripBuilder.build())
.setBackgroundColor(CarColor.SECONDARY)
.build()
}
fun getRoutingInfo(): RoutingInfo { fun getRoutingInfo(): RoutingInfo {
var currentDistance = routeModel.currentDistance var currentDistance = routeModel.currentDistance
val displayUnit = if (currentDistance > 1000.0) { val displayUnit = if (currentDistance > 1000.0) {
@@ -281,6 +297,21 @@ class NavigationScreen(
invalidate() invalidate()
} }
fun calculateNewRoute() {
calculateNewRoute = true
invalidate()
val mainThreadhandler = Handler(carContext.mainLooper)
mainThreadhandler.post {
object : CountDownTimer(5000, 1000) {
override fun onTick(millisUntilFinished: Long) { }
override fun onFinish() {
calculateNewRoute = false
stopNavigation()
}
}.start()
}
}
fun reRoute() { fun reRoute() {
NavigationMessage(carContext).createAlert() NavigationMessage(carContext).createAlert()
vieModel.loadRoute(surfaceRenderer.lastLocation, currentNavigationLocation) vieModel.loadRoute(surfaceRenderer.lastLocation, currentNavigationLocation)

View File

@@ -17,7 +17,7 @@ import com.kouros.navigation.data.Category
import com.kouros.navigation.data.Constants import com.kouros.navigation.data.Constants
import com.kouros.navigation.data.NavigationRepository import com.kouros.navigation.data.NavigationRepository
import com.kouros.navigation.data.Place import com.kouros.navigation.data.Place
import com.kouros.navigation.data.nominatim.Search import com.kouros.navigation.data.nominatim.SearchResult
import com.kouros.navigation.model.ViewModel import com.kouros.navigation.model.ViewModel
@@ -34,9 +34,9 @@ class SearchScreen(
Category(id = Constants.CONTACTS, name = carContext.getString(R.string.contacts)) Category(id = Constants.CONTACTS, name = carContext.getString(R.string.contacts))
) )
lateinit var searchResult: Search lateinit var searchResult: List<SearchResult>
val observer = Observer<Search> { newSearch -> val observer = Observer<List<SearchResult>> { newSearch ->
println(newSearch) println(newSearch)
searchResult = newSearch searchResult = newSearch
invalidate() invalidate()
@@ -93,13 +93,9 @@ class SearchScreen(
return SearchTemplate.Builder( return SearchTemplate.Builder(
object : SearchCallback { object : SearchCallback {
override fun onSearchTextChanged(searchText: String) {
//doSearch(searchText, searchItemListBuilder)
}
override fun onSearchSubmitted(searchTerm: String) { override fun onSearchSubmitted(searchTerm: String) {
isSearchComplete = true isSearchComplete = true
viewModel.searchPlaces(searchTerm) viewModel.searchPlaces(searchTerm, location)
} }
}) })
.setHeaderAction(Action.BACK) .setHeaderAction(Action.BACK)
@@ -111,15 +107,9 @@ class SearchScreen(
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
fun doSearch(searchItemListBuilder: ItemList.Builder) { fun doSearch(searchItemListBuilder: ItemList.Builder) {
searchResult.forEach { searchResult.forEach {
println(it.displayName)
//val name: String = address.getAddressLine(0)
//addressLocation.latitude = address.latitude
//adressLocation.longitude = address.longitude
//val distance = location.distanceTo(addressLocation)
//val dist = String.format("%.1f", (distance / 1000))
searchItemListBuilder.addItem( searchItemListBuilder.addItem(
Row.Builder() Row.Builder()
.setTitle(it.displayName) .setTitle("${(it.distance/1000).toInt()} km ${it.displayName} ")
.setOnClickListener { .setOnClickListener {
val place = Place( val place = Place(
name = it.displayName, name = it.displayName,
@@ -127,7 +117,8 @@ class SearchScreen(
longitude = it.lon.toDouble(), longitude = it.lon.toDouble(),
street = it.address.road, street = it.address.road,
city = it.address.city, city = it.address.city,
postalCode = it.address.postcode postalCode = it.address.postcode,
distance = it.distance
) )
setResult(place) setResult(place)
finish() finish()
@@ -136,8 +127,6 @@ class SearchScreen(
.build() .build()
) )
} }
// val itemList = searchItemListBuilder.build()
invalidate() invalidate()
} }
} }

View File

@@ -5,7 +5,7 @@
"entities": [ "entities": [
{ {
"id": "3:3556253001994555353", "id": "3:3556253001994555353",
"lastPropertyId": "10:2074102010889685023", "lastPropertyId": "11:1275950563592034592",
"name": "Place", "name": "Place",
"properties": [ "properties": [
{ {
@@ -53,6 +53,11 @@
"id": "10:2074102010889685023", "id": "10:2074102010889685023",
"name": "distance", "name": "distance",
"type": 7 "type": 7
},
{
"id": "11:1275950563592034592",
"name": "lastDate",
"type": 6
} }
], ],
"relations": [] "relations": []

View File

@@ -5,7 +5,7 @@
"entities": [ "entities": [
{ {
"id": "3:3556253001994555353", "id": "3:3556253001994555353",
"lastPropertyId": "10:2074102010889685023", "lastPropertyId": "11:1275950563592034592",
"name": "Place", "name": "Place",
"properties": [ "properties": [
{ {
@@ -53,32 +53,11 @@
"id": "10:2074102010889685023", "id": "10:2074102010889685023",
"name": "distance", "name": "distance",
"type": 7 "type": 7
}
],
"relations": []
},
{
"id": "4:4849917137448238840",
"lastPropertyId": "3:6908702166041138446",
"name": "ObjectBoxTile",
"properties": [
{
"id": "1:6365540590424804057",
"name": "id",
"type": 6,
"flags": 1
}, },
{ {
"id": "2:8979494032513344145", "id": "11:1275950563592034592",
"name": "key", "name": "lastDate",
"indexId": "3:8164654097637798551", "type": 10
"type": 9,
"flags": 2048
},
{
"id": "3:6908702166041138446",
"name": "bitmap",
"type": 23
} }
], ],
"relations": [] "relations": []
@@ -92,11 +71,13 @@
"modelVersionParserMinimum": 5, "modelVersionParserMinimum": 5,
"retiredEntityUids": [ "retiredEntityUids": [
5232739161494262087, 5232739161494262087,
1670248357005659634 1670248357005659634,
4849917137448238840
], ],
"retiredIndexUids": [ "retiredIndexUids": [
1988419626350568402, 1988419626350568402,
5426976851182536573 5426976851182536573,
8164654097637798551
], ],
"retiredPropertyUids": [ "retiredPropertyUids": [
2083347946807922223, 2083347946807922223,
@@ -106,7 +87,10 @@
3637730979227083476, 3637730979227083476,
8954406503424388478, 8954406503424388478,
7467083398837280132, 7467083398837280132,
6885676442906238720 6885676442906238720,
6365540590424804057,
8979494032513344145,
6908702166041138446
], ],
"retiredRelationUids": [], "retiredRelationUids": [],
"version": 1 "version": 1

View File

@@ -2,6 +2,6 @@ package com.kouros.navigation.data
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
val NavigationColor = Color(0xFF1965D9) val NavigationColor = Color(0xFF094DB6)
val RouteColor = Color(0xFF2E75E1) val RouteColor = Color(0xFF5582D0)

View File

@@ -22,6 +22,8 @@ import android.net.Uri
import io.objectbox.annotation.Entity import io.objectbox.annotation.Entity
import io.objectbox.annotation.Id import io.objectbox.annotation.Id
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import java.time.LocalDate
import java.util.Date
data class Category( data class Category(
val id: String, val id: String,
@@ -41,7 +43,8 @@ data class Place(
var street: String? = null, var street: String? = null,
var distance: Float = 0F, var distance: Float = 0F,
@Transient @Transient
var avatar: Uri? = null var avatar: Uri? = null,
var lastDate: Long = 0
) )
data class ContactData( data class ContactData(
@@ -148,7 +151,9 @@ object Constants {
const val NEXT_STEP_THRESHOLD = 100.0 const val NEXT_STEP_THRESHOLD = 100.0
const val MAXIMAL_ROUTE_DEVIATION = 70.0 const val MAXIMAL_SNAP_CORRECTION = 50.0
const val MAXIMAL_ROUTE_DEVIATION = 100.0
} }

View File

@@ -92,7 +92,11 @@ data class Route (
fun maneuverLocations(): List<Point> { fun maneuverLocations(): List<Point> {
val beginShapeIndex = currentManeuver().beginShapeIndex val beginShapeIndex = currentManeuver().beginShapeIndex
val endShapeIndex = currentManeuver().endShapeIndex val endShapeIndex = if (currentManeuver().endShapeIndex >= waypoints.size) {
waypoints.size
} else {
currentManeuver().endShapeIndex + 1
}
return pointLocations.subList(beginShapeIndex, endShapeIndex) return pointLocations.subList(beginShapeIndex, endShapeIndex)
} }

View File

@@ -25,6 +25,6 @@ data class SearchResult(
@SerializedName("address") var address: Address, @SerializedName("address") var address: Address,
@SerializedName("name") var name: String = "", @SerializedName("name") var name: String = "",
@SerializedName("display_name") var displayName: String = "", @SerializedName("display_name") var displayName: String = "",
@SerializedName("boundingbox") var boundingbox: ArrayList<String> = arrayListOf() @SerializedName("boundingbox") var boundingbox: ArrayList<String> = arrayListOf(),
var distance : Float = 0.0F
) )

View File

@@ -22,11 +22,12 @@ data class Maneuvers(
@SerializedName("length") var length: Double = 0.0, @SerializedName("length") var length: Double = 0.0,
@SerializedName("cost") var cost: Double = 0.0, @SerializedName("cost") var cost: Double = 0.0,
@SerializedName("verbal_multi_cue") var verbalMultiCue: Boolean = false, @SerializedName("verbal_multi_cue") var verbalMultiCue: Boolean = false,
@SerializedName("begin_shape_index") var beginShapeIndex: Int, @SerializedName("begin_shape_index") var beginShapeIndex: Int = 0,
@SerializedName("end_shape_index") var endShapeIndex: Int, @SerializedName("end_shape_index") var endShapeIndex: Int = 0,
@SerializedName("highway") var highway: Boolean = false, @SerializedName("highway") var highway: Boolean = false,
@SerializedName("sign") var sign: Sign = Sign(), @SerializedName("sign") var sign: Sign = Sign(),
@SerializedName("travel_mode") var travelMode: String = "", @SerializedName("travel_mode") var travelMode: String = "",
@SerializedName("travel_type") var travelType: String = "", @SerializedName("travel_type") var travelType: String = "",
@SerializedName("roundabout_exit_count") var roundaboutExitCount: Int = 0
) )

View File

@@ -27,7 +27,7 @@ open class RouteModel() {
/* /*
current shapeIndex current shapeIndex
*/ */
private var currentShapeIndex = 0 private var currentShapeIndex = 0
var distanceToStepEnd = 0F var distanceToStepEnd = 0F
@@ -63,7 +63,7 @@ open class RouteModel() {
fun updateLocation(location: Location) { fun updateLocation(location: Location) {
var nearestDistance = 100000.0f var nearestDistance = 100000.0f
route.currentManeuverIndex = -1 route.currentManeuverIndex = -1
// find maneuver // find maneuver
for ((i, maneuver) in route.maneuvers.withIndex()) { for ((i, maneuver) in route.maneuvers.withIndex()) {
val beginShapeIndex = maneuver.beginShapeIndex val beginShapeIndex = maneuver.beginShapeIndex
@@ -83,8 +83,15 @@ open class RouteModel() {
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) { if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
text = maneuver.streetNames[0] text = maneuver.streetNames[0]
} }
val curLocation = location(route.pointLocations[currentShapeIndex].latitude(), route.pointLocations[currentShapeIndex].longitude()) // TODO: +1 check
val nextLocation = location(route.pointLocations[currentShapeIndex+1].latitude(), route.pointLocations[currentShapeIndex+1].longitude()) 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) bearing = curLocation.bearingTo(nextLocation)
val distanceStepLeft = leftStepDistance() * 1000 val distanceStepLeft = leftStepDistance() * 1000
when (distanceStepLeft) { when (distanceStepLeft) {
@@ -120,17 +127,14 @@ open class RouteModel() {
distanceToStepEnd = 0F distanceToStepEnd = 0F
val loc1 = Location(LocationManager.GPS_PROVIDER) val loc1 = Location(LocationManager.GPS_PROVIDER)
val loc2 = Location(LocationManager.GPS_PROVIDER) val loc2 = Location(LocationManager.GPS_PROVIDER)
loc1.longitude = route.waypoints[i][0] if (i + 1 < route.waypoints.size) {
loc1.latitude = route.waypoints[i][1] for (j in i + 1..endShapeIndex) {
loc2.longitude = route.waypoints[i + 1][0] loc1.longitude = route.waypoints[j - 1][0]
loc2.latitude = route.waypoints[i + 1][1] loc1.latitude = route.waypoints[j - 1][1]
bearing = loc1.bearingTo(loc2).absoluteValue loc2.longitude = route.waypoints[j][0]
for (j in i + 1..endShapeIndex) { loc2.latitude = route.waypoints[j][1]
loc1.longitude = route.waypoints[j - 1][0] distanceToStepEnd += loc1.distanceTo(loc2)
loc1.latitude = route.waypoints[j - 1][1] }
loc2.longitude = route.waypoints[j][0]
loc2.latitude = route.waypoints[j][1]
distanceToStepEnd += loc1.distanceTo(loc2)
} }
} }
} }

View File

@@ -13,10 +13,14 @@ import com.kouros.navigation.data.ObjectBox.boxStore
import com.kouros.navigation.data.Place import com.kouros.navigation.data.Place
import com.kouros.navigation.data.Place_ import com.kouros.navigation.data.Place_
import com.kouros.navigation.data.nominatim.Search import com.kouros.navigation.data.nominatim.Search
import com.kouros.navigation.data.nominatim.SearchResult
import com.kouros.navigation.utils.location import com.kouros.navigation.utils.location
import io.objectbox.kotlin.boxFor import io.objectbox.kotlin.boxFor
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneOffset
class ViewModel(private val repository: NavigationRepository) : ViewModel() { class ViewModel(private val repository: NavigationRepository) : ViewModel() {
@@ -32,8 +36,8 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
MutableLiveData<List<Place>>() MutableLiveData<List<Place>>()
} }
val searchPlaces: MutableLiveData<Search> by lazy { val searchPlaces: MutableLiveData<List<SearchResult>> by lazy {
MutableLiveData<Search>() MutableLiveData<List<SearchResult>>()
} }
val contactAddress: MutableLiveData<List<Place>> by lazy { val contactAddress: MutableLiveData<List<Place>> by lazy {
@@ -44,15 +48,20 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
fun loadPlaces(location: Location) { fun loadPlaces(location: Location) {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
val pl = mutableListOf<Place>()
val placeBox = boxStore.boxFor(Place::class) val placeBox = boxStore.boxFor(Place::class)
pl.addAll(placeBox.all) val query = placeBox
for (place in pl) { .query(Place_.name.notEqual(""))
.orderDesc(Place_.lastDate)
.build()
val results = query.find()
query.close()
for (place in results) {
val plLocation = location(place.latitude, place.longitude) val plLocation = location(place.latitude, place.longitude)
val distance = repository.getRouteDistance(location, plLocation) val distance = repository.getRouteDistance(location, plLocation)
place.distance = distance.toFloat() place.distance = distance.toFloat()
println(place.lastDate)
} }
places.postValue(pl) places.postValue(results)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
@@ -121,12 +130,21 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
} }
} }
fun searchPlaces(search: String) { fun searchPlaces(search: String, location: Location) {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val placesJson = repository.searchPlaces(search) val placesJson = repository.searchPlaces(search)
val gson = GsonBuilder().serializeNulls().create() val gson = GsonBuilder().serializeNulls().create()
val places = gson.fromJson(placesJson, Search::class.java) val places = gson.fromJson(placesJson, Search::class.java)
searchPlaces.postValue(places) val distPlaces = mutableListOf<SearchResult>()
places.forEach {
val plLocation =
location(latitude = it.lat.toDouble(), longitude = it.lon.toDouble())
val distance = plLocation.distanceTo(location)
it.distance = distance
distPlaces.add(it)
}
val sortedList = distPlaces.sortedWith(compareBy({ it.distance }))
searchPlaces.postValue(sortedList)
} }
} }
@@ -140,9 +158,12 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
.build() .build()
val results = query.find() val results = query.find()
query.close() query.close()
if (results.isEmpty()) { if (results.isNotEmpty()) {
placeBox.put(place) placeBox.remove(results.first())
} }
val current = LocalDateTime.now(ZoneOffset.UTC)
place.lastDate = current.atZone(ZoneOffset.UTC).toEpochSecond()
placeBox.put(place)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
@@ -160,7 +181,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
val results = query.find() val results = query.find()
query.close() query.close()
if (results.isNotEmpty()) { if (results.isNotEmpty()) {
placeBox.remove(place) placeBox.remove(results.first())
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()

View File

@@ -56,21 +56,16 @@ object NavigationUtils {
apply() apply()
} }
} }
fun snapLocation(location: Location, stepCoordinates: List<Point>): Location { fun snapLocation(location: Location, stepCoordinates: List<Point>) : Location {
val newLocation = location(latitude = location.latitude, longitude = location.longitude)
val oldPoint = Point.fromLngLat(location.longitude, location.latitude) val oldPoint = Point.fromLngLat(location.longitude, location.latitude)
val oldLocation = location(location.latitude, location.longitude)
if (stepCoordinates.size > 1) { if (stepCoordinates.size > 1) {
val pointFeature = TurfMisc.nearestPointOnLine(oldPoint, stepCoordinates) val pointFeature = TurfMisc.nearestPointOnLine(oldPoint, stepCoordinates)
val point = pointFeature.geometry() as Point val point = pointFeature.geometry() as Point
location.latitude = point.latitude() newLocation.latitude = point.latitude()
location.longitude = point.longitude() newLocation.longitude = point.longitude()
val distance = oldLocation.distanceTo(location)
if (distance > MAXIMAL_ROUTE_DEVIATION) {
println("Distance to big")
return location(0.0, 0.0)
}
} }
return location return newLocation
} }
fun decodePolyline(encoded: String, vararg precisionOptional: Int): List<List<Double>> { fun decodePolyline(encoded: String, vararg precisionOptional: Int): List<List<Double>> {

View File

@@ -30,7 +30,3 @@ include(
) )
include(":common:automotive")
include(":app:automotive")
include(":automotive")