Serialize Json
This commit is contained in:
@@ -57,9 +57,8 @@ data class StepData (
|
||||
var bearing: Double
|
||||
)
|
||||
|
||||
|
||||
//val places = mutableListOf<Place>()
|
||||
/* Place(
|
||||
val dataPlaces = listOf(
|
||||
Place(
|
||||
id = 0,
|
||||
name = "Vogelhartstr. 17",
|
||||
category = "Favorites",
|
||||
@@ -80,7 +79,7 @@ data class StepData (
|
||||
city = "München",
|
||||
street = "Hohenwaldeckstr. 27",
|
||||
)
|
||||
) */
|
||||
)
|
||||
|
||||
// GeoJSON data classes
|
||||
@Serializable
|
||||
@@ -106,7 +105,6 @@ data class Locations (
|
||||
var lat : Double,
|
||||
var lon : Double,
|
||||
var street : String = ""
|
||||
|
||||
)
|
||||
|
||||
@Serializable
|
||||
@@ -120,6 +118,8 @@ data class ValhallaLocation (
|
||||
|
||||
object Constants {
|
||||
|
||||
const val STYLE: String = "https://kouros-online.de/liberty2"
|
||||
//baseStyle = BaseStyle.Uri("https://tiles.openfreemap.org/styles/liberty"),
|
||||
const val TAG: String = "Navigation"
|
||||
|
||||
const val CONTACTS: String = "Contacts"
|
||||
|
||||
@@ -52,7 +52,7 @@ class NavigationRepository {
|
||||
val route = getRoute(currentLocation, location)
|
||||
val routeModel = RouteModel()
|
||||
routeModel.startNavigation(route)
|
||||
return routeModel.routeDistance
|
||||
return routeModel.route.distance
|
||||
}
|
||||
|
||||
fun getPlaces(): List<Place> {
|
||||
@@ -87,7 +87,6 @@ class NavigationRepository {
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
println(url)
|
||||
val httpURLConnection = URL(url).openConnection() as HttpURLConnection
|
||||
httpURLConnection.setRequestProperty(
|
||||
|
||||
115
common/data/src/main/java/com/kouros/navigation/data/Route.kt
Normal file
115
common/data/src/main/java/com/kouros/navigation/data/Route.kt
Normal file
@@ -0,0 +1,115 @@
|
||||
package com.kouros.navigation.data
|
||||
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.kouros.navigation.data.valhalla.Maneuvers
|
||||
import com.kouros.navigation.data.valhalla.Summary
|
||||
import com.kouros.navigation.data.valhalla.Trip
|
||||
import com.kouros.navigation.data.valhalla.ValhallaJson
|
||||
import com.kouros.navigation.utils.NavigationUtils.createGeoJson
|
||||
import com.kouros.navigation.utils.NavigationUtils.decodePolyline
|
||||
import org.maplibre.geojson.Point
|
||||
|
||||
|
||||
data class Route (
|
||||
/**
|
||||
* A Leg is a route between only two waypoints.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
val maneuvers: List<Maneuvers>,
|
||||
|
||||
/**
|
||||
* The distance traveled from origin to destination.
|
||||
*
|
||||
* @return a double number with unit meters
|
||||
* @since 1.0.0
|
||||
*/
|
||||
val distance: Double,
|
||||
|
||||
/**
|
||||
* List of [List<Double>] objects. Each `waypoint` is an input coordinate
|
||||
* snapped to the road and path network. The `waypoint` appear in the list in the order of
|
||||
* the input coordinates.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
var waypoints: List<List<Double>>,
|
||||
|
||||
val pointLocations : List<Point>,
|
||||
|
||||
val summary: Summary,
|
||||
|
||||
val trip: Trip,
|
||||
|
||||
val time: Double,
|
||||
|
||||
var routingManeuvers : List<Maneuvers>,
|
||||
|
||||
var routeGeoJson : String,
|
||||
|
||||
var currentIndex: Int
|
||||
|
||||
) {
|
||||
|
||||
class Builder {
|
||||
private lateinit var maneuvers: List<Maneuvers>
|
||||
private var distance: Double = 0.0
|
||||
|
||||
private var time: Double = 0.0
|
||||
private lateinit var waypoints: List<List<Double>>
|
||||
private lateinit var pointLocations: List<Point>
|
||||
|
||||
private lateinit var summary : Summary
|
||||
|
||||
private lateinit var trip : Trip
|
||||
|
||||
private lateinit var routingManeuvers: List<Maneuvers>
|
||||
|
||||
private var routeGeoJson = ""
|
||||
|
||||
fun route (route: String ) = apply {
|
||||
if (route.isNotEmpty() && route != "[]") {
|
||||
val gson = GsonBuilder().serializeNulls().create()
|
||||
val valhalla = gson.fromJson(route, ValhallaJson::class.java)
|
||||
trip = valhalla.trip
|
||||
}
|
||||
}
|
||||
|
||||
fun build(): Route {
|
||||
maneuvers = trip.legs[0].maneuvers
|
||||
summary = trip.summary
|
||||
distance = summary.length
|
||||
time = summary.time
|
||||
waypoints = decodePolyline(trip.legs[0].shape)
|
||||
val points = mutableListOf<Point>()
|
||||
for (loc in waypoints) {
|
||||
val point = Point.fromLngLat(loc[0], loc[1])
|
||||
points.add(point)
|
||||
}
|
||||
pointLocations = points
|
||||
val routings = mutableListOf<Maneuvers>()
|
||||
for (maneuver in maneuvers) {
|
||||
routings.add(maneuver)
|
||||
}
|
||||
this.routingManeuvers = routings
|
||||
this.routeGeoJson = createGeoJson(waypoints)
|
||||
return Route(
|
||||
maneuvers, distance, waypoints, pointLocations, summary, trip, time, routingManeuvers, routeGeoJson, 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
waypoints = mutableListOf()
|
||||
routingManeuvers = mutableListOf()
|
||||
routeGeoJson = ""
|
||||
}
|
||||
|
||||
fun currentManeuver() : Maneuvers {
|
||||
return maneuvers[currentIndex]
|
||||
}
|
||||
|
||||
fun nextManeuver() : Maneuvers {
|
||||
return maneuvers[currentIndex+1]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@JsonIgnoreUnknownKeys
|
||||
data class Legs (
|
||||
|
||||
@SerializedName("maneuvers" ) var maneuvers : ArrayList<Maneuvers> = arrayListOf(),
|
||||
@SerializedName("summary" ) var summary : Summary = Summary(),
|
||||
@SerializedName("shape" ) var shape : String = ""
|
||||
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@JsonIgnoreUnknownKeys
|
||||
data class Locations (
|
||||
|
||||
@SerializedName("type" ) var type : String = "",
|
||||
@SerializedName("lat" ) var lat : Double = 0.0,
|
||||
@SerializedName("lon" ) var lon : Double = 0.0,
|
||||
@SerializedName("side_of_street" ) var sideOfStreet : String = "",
|
||||
@SerializedName("original_index" ) var originalIndex : Int = 0
|
||||
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@JsonIgnoreUnknownKeys
|
||||
data class Maneuvers(
|
||||
|
||||
@SerializedName("begin_shape_index") var beginShapeIndex: Int,
|
||||
@SerializedName("end_shape_index") var endShapeIndex: Int,
|
||||
@SerializedName("type") var type: Int = 0,
|
||||
@SerializedName("instruction") var instruction: String = "",
|
||||
@SerializedName("verbal_succinct_transition_instruction") var verbalSuccinctTransitionInstruction: String = "",
|
||||
@SerializedName("verbal_pre_transition_instruction") var verbalPreTransitionInstruction: String = "",
|
||||
@SerializedName("verbal_post_transition_instruction") var verbalPostTransitionInstruction: String = "",
|
||||
@SerializedName("street_names") val streetNames: List<String>? = arrayListOf(),
|
||||
@SerializedName("bearing_after") var bearingAfter: Int = 0,
|
||||
@SerializedName("time") var time: Double = 0.0,
|
||||
@SerializedName("length") var length: Double = 0.0,
|
||||
@SerializedName("cost") var cost: Double = 0.0,
|
||||
@SerializedName("verbal_multi_cue") var verbalMultiCue: Boolean = false,
|
||||
@SerializedName("travel_mode") var travelMode: String = "",
|
||||
@SerializedName("travel_type") var travelType: String = "",
|
||||
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@JsonIgnoreUnknownKeys
|
||||
data class Summary (
|
||||
|
||||
@SerializedName("has_time_restrictions" ) var hasTimeRestrictions : Boolean = false,
|
||||
@SerializedName("has_toll" ) var hasToll : Boolean = false,
|
||||
@SerializedName("has_highway" ) var hasHighway : Boolean = false,
|
||||
@SerializedName("has_ferry" ) var hasFerry : Boolean = false,
|
||||
@SerializedName("min_lat" ) var minLat : Double = 0.0,
|
||||
@SerializedName("min_lon" ) var minLon : Double = 0.0,
|
||||
@SerializedName("max_lat" ) var maxLat : Double = 0.0,
|
||||
@SerializedName("max_lon" ) var maxLon : Double = 0.0,
|
||||
@SerializedName("time" ) var time : Double = 0.0,
|
||||
@SerializedName("length" ) var length : Double = 0.0,
|
||||
@SerializedName("cost" ) var cost : Double = 0.0
|
||||
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@JsonIgnoreUnknownKeys
|
||||
data class Trip (
|
||||
|
||||
@SerializedName("locations" ) var locations : ArrayList<Locations> = arrayListOf(),
|
||||
@SerializedName("legs" ) var legs : ArrayList<Legs> = arrayListOf(),
|
||||
@SerializedName("summary" ) var summary : Summary = Summary(),
|
||||
@SerializedName("status_message" ) var statusMessage : String = "",
|
||||
@SerializedName("status" ) var status : Int = 0,
|
||||
@SerializedName("units" ) var units : String = "",
|
||||
@SerializedName("language" ) var language : String = "",
|
||||
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.kouros.navigation.data.valhalla
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonIgnoreUnknownKeys
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@JsonIgnoreUnknownKeys
|
||||
data class ValhallaJson (
|
||||
|
||||
@SerializedName("trip" ) var trip : Trip = Trip(),
|
||||
@SerializedName("id" ) var id : String = ""
|
||||
|
||||
)
|
||||
@@ -2,32 +2,29 @@ package com.kouros.navigation.model
|
||||
|
||||
import android.location.Location
|
||||
import android.location.LocationManager
|
||||
import com.kouros.navigation.data.Constants.homeLocation
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.Route
|
||||
import com.kouros.navigation.data.StepData
|
||||
import com.kouros.navigation.utils.NavigationUtils
|
||||
import com.kouros.navigation.utils.NavigationUtils.Utils.createGeoJson
|
||||
import com.kouros.navigation.utils.NavigationUtils.Utils.decodePolyline
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import com.kouros.navigation.utils.location
|
||||
import org.maplibre.geojson.Point
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
open class RouteModel () {
|
||||
var polylineLocations: List<List<Double>> = emptyList()
|
||||
lateinit var maneuvers: JSONArray
|
||||
lateinit var locations: JSONArray
|
||||
private lateinit var summary: JSONObject
|
||||
var routeDistance = 0.0
|
||||
|
||||
var routeTime = 0.0
|
||||
|
||||
open class RouteModel() {
|
||||
lateinit var centerLocation: Location
|
||||
|
||||
lateinit var destination: Place
|
||||
|
||||
var navigating = false
|
||||
|
||||
var arrived = false
|
||||
var maneuverIndex = 0
|
||||
|
||||
var maneuverType = 0
|
||||
|
||||
/*
|
||||
Index in a maneuver
|
||||
*/
|
||||
var currentIndex = 0
|
||||
|
||||
var distanceToStepEnd = 0F
|
||||
@@ -38,53 +35,27 @@ open class RouteModel () {
|
||||
|
||||
var endIndex = 0
|
||||
|
||||
var routingManeuvers = mutableListOf<JSONObject>()
|
||||
|
||||
var route = ""
|
||||
|
||||
data class Builder(
|
||||
var route: String? = null,
|
||||
var fromLocation: Location? = null,
|
||||
var toLocation: Location? = null) {
|
||||
|
||||
fun route(route: String) = apply { this.route = route }
|
||||
fun fromLocation(fromLocation: Location) = apply { this.fromLocation = fromLocation }
|
||||
fun toLocation(toLocation: Location) = apply { this.toLocation = toLocation }
|
||||
//fun build() = RouteModel(route!!, fromLocation!!, toLocation!!)
|
||||
}
|
||||
private fun decodeValhallaRoute(valhallaRoute: String) {
|
||||
if (valhallaRoute.isEmpty() || valhallaRoute == "[]") {
|
||||
return;
|
||||
}
|
||||
val jObject = JSONObject(valhallaRoute)
|
||||
val trip = jObject.getJSONObject("trip")
|
||||
locations = trip.getJSONArray("locations")
|
||||
val legs = trip.getJSONArray("legs")
|
||||
summary = trip.getJSONObject("summary")
|
||||
routeTime = summary.getDouble("time")
|
||||
routeDistance = summary.getDouble("length")
|
||||
centerLocation = createCenterLocation()
|
||||
maneuvers = legs.getJSONObject(0).getJSONArray("maneuvers")
|
||||
val shape = legs.getJSONObject(0).getString("shape")
|
||||
polylineLocations = decodePolyline(shape)
|
||||
}
|
||||
|
||||
private fun createCenterLocation() : Location {
|
||||
val latitude = summary.getDouble("max_lat") - (summary.getDouble("max_lat") - summary.getDouble("min_lat"))
|
||||
val longitude = summary.getDouble("max_lon") - (summary.getDouble("max_lon") - summary.getDouble("min_lon"))
|
||||
return NavigationUtils().location(latitude, longitude)
|
||||
}
|
||||
lateinit var route: Route
|
||||
|
||||
fun startNavigation(valhallaRoute: String) {
|
||||
decodeValhallaRoute(valhallaRoute)
|
||||
for (i in 0..<maneuvers.length()) {
|
||||
val maneuver = (maneuvers[i] as JSONObject)
|
||||
routingManeuvers.add(maneuver)
|
||||
}
|
||||
route = createGeoJson(polylineLocations)
|
||||
route = Route.Builder()
|
||||
.route(valhallaRoute)
|
||||
.build()
|
||||
centerLocation = createCenterLocation()
|
||||
navigating = true
|
||||
}
|
||||
|
||||
|
||||
private fun createCenterLocation(): Location {
|
||||
if (route.summary.maxLat == 0.0) {
|
||||
return location(homeLocation.latitude, homeLocation.longitude)
|
||||
}
|
||||
val latitude =
|
||||
route.summary.maxLat - (route.summary.maxLat - route.summary.minLat)
|
||||
val longitude =
|
||||
route.summary.maxLon - (route.summary.maxLon - route.summary.minLon)
|
||||
return location(latitude, longitude)
|
||||
}
|
||||
val currentDistance: Double
|
||||
/** Returns the current [Step] with information such as the cue text and images. */
|
||||
get() {
|
||||
@@ -93,45 +64,42 @@ open class RouteModel () {
|
||||
|
||||
fun updateLocation(location: Location) {
|
||||
var nearestDistance = 100000.0f
|
||||
maneuverIndex = -1
|
||||
route.currentIndex = -1
|
||||
// find maneuver
|
||||
for (i in 0..<maneuvers.length()) {
|
||||
val maneuver = (maneuvers[i] as JSONObject)
|
||||
val beginShapeIndex = maneuver.getString("begin_shape_index").toInt()
|
||||
val endShapeIndex = maneuver.getString("end_shape_index").toInt()
|
||||
for ((i, maneuver) in route.maneuvers.withIndex()) {
|
||||
val beginShapeIndex = maneuver.beginShapeIndex
|
||||
val endShapeIndex = maneuver.endShapeIndex
|
||||
val distance = calculateDistance(beginShapeIndex, endShapeIndex, location)
|
||||
if (distance < nearestDistance) {
|
||||
nearestDistance = distance
|
||||
maneuverIndex = i
|
||||
route.currentIndex = i
|
||||
calculateCurrentIndex(beginShapeIndex, endShapeIndex, location)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun currentStep(): StepData {
|
||||
val maneuver = (maneuvers[maneuverIndex] as JSONObject)
|
||||
val maneuver = route.currentManeuver()
|
||||
var text = ""
|
||||
if (maneuver.optJSONArray("street_names") != null) {
|
||||
text = maneuver.getJSONArray("street_names").get(0) as String
|
||||
println("Maneuver $maneuver")
|
||||
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
|
||||
text = maneuver.streetNames[0]
|
||||
}
|
||||
if (bearing == 0F) {
|
||||
if (maneuver.has("bearing_after")) {
|
||||
bearing = maneuver.getInt("bearing_after").toFloat()
|
||||
}
|
||||
bearing = maneuver.bearingAfter.toFloat()
|
||||
}
|
||||
val distanceStepLeft = leftStepDistance() * 1000
|
||||
when (distanceStepLeft) {
|
||||
in 0.0..100.0 -> {
|
||||
if (maneuverIndex < maneuvers.length()) {
|
||||
val maneuver = (maneuvers[maneuverIndex + 1] as JSONObject)
|
||||
if (maneuver.optJSONArray("street_names") != null) {
|
||||
text = maneuver.getJSONArray("street_names").get(0) as String
|
||||
if (route.currentIndex < route.maneuvers.size) {
|
||||
val maneuver = route.nextManeuver()
|
||||
if (maneuver.streetNames != null && maneuver.streetNames.isNotEmpty()) {
|
||||
text = maneuver.streetNames[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return StepData(text, distanceStepLeft, bearing.toDouble())
|
||||
|
||||
}
|
||||
|
||||
/** Calculates the index in a maneuver. */
|
||||
@@ -143,8 +111,8 @@ open class RouteModel () {
|
||||
var nearestLocation = 100000.0f
|
||||
for (i in beginShapeIndex..endShapeIndex) {
|
||||
val polylineLocation = Location(LocationManager.GPS_PROVIDER)
|
||||
polylineLocation.longitude = polylineLocations[i][0]
|
||||
polylineLocation.latitude = polylineLocations[i][1]
|
||||
polylineLocation.longitude = route.waypoints[i][0]
|
||||
polylineLocation.latitude = route.waypoints[i][1]
|
||||
val distance: Float = location.distanceTo(polylineLocation)
|
||||
if (distance < nearestLocation) {
|
||||
nearestLocation = distance
|
||||
@@ -154,16 +122,16 @@ open class RouteModel () {
|
||||
distanceToStepEnd = 0F
|
||||
val loc1 = Location(LocationManager.GPS_PROVIDER)
|
||||
val loc2 = Location(LocationManager.GPS_PROVIDER)
|
||||
loc1.longitude = polylineLocations[i][0]
|
||||
loc1.latitude = polylineLocations[i][1]
|
||||
loc2.longitude = polylineLocations[i+1][0]
|
||||
loc2.latitude = polylineLocations[i+1][1]
|
||||
loc1.longitude = route.waypoints[i][0]
|
||||
loc1.latitude = route.waypoints[i][1]
|
||||
loc2.longitude = route.waypoints[i + 1][0]
|
||||
loc2.latitude = route.waypoints[i + 1][1]
|
||||
bearing = loc1.bearingTo(loc2).absoluteValue
|
||||
for (j in i + 1..endShapeIndex) {
|
||||
loc1.longitude = polylineLocations[j - 1][0]
|
||||
loc1.latitude = polylineLocations[j - 1][1]
|
||||
loc2.longitude = polylineLocations[j][0]
|
||||
loc2.latitude = polylineLocations[j][1]
|
||||
loc1.longitude = route.waypoints[j - 1][0]
|
||||
loc1.latitude = route.waypoints[j - 1][1]
|
||||
loc2.longitude = route.waypoints[j][0]
|
||||
loc2.latitude = route.waypoints[j][1]
|
||||
distanceToStepEnd += loc1.distanceTo(loc2)
|
||||
}
|
||||
}
|
||||
@@ -178,8 +146,8 @@ open class RouteModel () {
|
||||
var nearestLocation = 100000.0f
|
||||
for (i in beginShapeIndex..endShapeIndex) {
|
||||
val polylineLocation = Location(LocationManager.GPS_PROVIDER)
|
||||
polylineLocation.longitude = polylineLocations[i][0]
|
||||
polylineLocation.latitude = polylineLocations[i][1]
|
||||
polylineLocation.longitude = route.waypoints[i][0]
|
||||
polylineLocation.latitude = route.waypoints[i][1]
|
||||
val distance: Float = location.distanceTo(polylineLocation)
|
||||
if (distance < nearestLocation) {
|
||||
nearestLocation = distance
|
||||
@@ -188,15 +156,21 @@ open class RouteModel () {
|
||||
return nearestLocation
|
||||
}
|
||||
|
||||
fun maneuverLocations(): List<Point> {
|
||||
val beginShapeIndex = route.currentManeuver().beginShapeIndex
|
||||
val endShapeIndex = route.currentManeuver().endShapeIndex
|
||||
return route.pointLocations.subList(beginShapeIndex, endShapeIndex)
|
||||
}
|
||||
|
||||
fun travelLeftTime(): Double {
|
||||
var timeLeft = 0.0
|
||||
for (i in maneuverIndex + 1..<routingManeuvers.size) {
|
||||
val maneuver = routingManeuvers[i]
|
||||
timeLeft += maneuver.getDouble("time")
|
||||
for (i in route.currentIndex + 1..<route.routingManeuvers.size) {
|
||||
val maneuver = route.routingManeuvers[i]
|
||||
timeLeft += maneuver.time
|
||||
}
|
||||
if (endIndex > 0) {
|
||||
val maneuver = routingManeuvers[maneuverIndex]
|
||||
val curTime = maneuver.getDouble("time")
|
||||
val maneuver = route.currentManeuver()
|
||||
val curTime = maneuver.time
|
||||
val percent = 100 * (endIndex - currentIndex) / (endIndex - beginIndex)
|
||||
val time = curTime * percent / 100
|
||||
timeLeft += time
|
||||
@@ -206,8 +180,8 @@ open class RouteModel () {
|
||||
|
||||
/** Returns the current [Step] left distance in km. */
|
||||
fun leftStepDistance(): Double {
|
||||
val maneuver = routingManeuvers[maneuverIndex]
|
||||
var leftDistance = maneuver.getDouble("length")
|
||||
val maneuver = route.routingManeuvers[route.currentIndex]
|
||||
var leftDistance = maneuver.length
|
||||
if (endIndex > 0) {
|
||||
leftDistance = (distanceToStepEnd / 1000).toDouble()
|
||||
}
|
||||
@@ -216,13 +190,13 @@ open class RouteModel () {
|
||||
|
||||
fun travelLeftDistance(): Double {
|
||||
var leftDistance = 0.0
|
||||
for (i in maneuverIndex + 1..<routingManeuvers.size) {
|
||||
val maneuver = routingManeuvers[i]
|
||||
leftDistance += maneuver.getDouble("length")
|
||||
for (i in route.currentIndex + 1..<route.routingManeuvers.size) {
|
||||
val maneuver = route.routingManeuvers[i]
|
||||
leftDistance += maneuver.length
|
||||
}
|
||||
if (endIndex > 0) {
|
||||
val maneuver = routingManeuvers[maneuverIndex]
|
||||
val curDistance = maneuver.getDouble("length")
|
||||
val maneuver = route.routingManeuvers[route.currentIndex]
|
||||
val curDistance = maneuver.length
|
||||
val percent = 100 * (endIndex - currentIndex) / (endIndex - beginIndex)
|
||||
val time = curDistance * percent / 100
|
||||
leftDistance += time
|
||||
@@ -239,11 +213,9 @@ open class RouteModel () {
|
||||
}
|
||||
|
||||
fun stopNavigation() {
|
||||
route.clear()
|
||||
navigating = false
|
||||
polylineLocations = mutableListOf()
|
||||
routingManeuvers = mutableListOf()
|
||||
route = ""
|
||||
maneuverIndex = 0
|
||||
//maneuverIndex = 0
|
||||
currentIndex = 0
|
||||
distanceToStepEnd = 0F
|
||||
beginIndex = 0
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.kouros.navigation.data.ObjectBox.boxStore
|
||||
import com.kouros.navigation.data.Place
|
||||
import com.kouros.navigation.data.Place_
|
||||
import com.kouros.navigation.utils.NavigationUtils
|
||||
import com.kouros.navigation.utils.location
|
||||
import io.objectbox.kotlin.boxFor
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -43,7 +44,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
val placeBox = boxStore.boxFor(Place::class)
|
||||
pl.addAll(placeBox.all)
|
||||
for (place in pl) {
|
||||
val plLocation = NavigationUtils().location(place.latitude, place.longitude)
|
||||
val plLocation = location(place.latitude, place.longitude)
|
||||
val distance = repository.getRouteDistance(location, plLocation)
|
||||
place.distance = distance.toFloat()
|
||||
}
|
||||
@@ -87,7 +88,7 @@ class ViewModel(private val repository: NavigationRepository) : ViewModel() {
|
||||
address.address, 5) {
|
||||
for (adr in it) {
|
||||
if (addressLines.size > 1) {
|
||||
val plLocation = NavigationUtils().location(adr.latitude, adr.longitude)
|
||||
val plLocation = location(adr.latitude, adr.longitude)
|
||||
val distance = repository.getRouteDistance(currentLocation, plLocation)
|
||||
contactList.add(
|
||||
Place(
|
||||
|
||||
@@ -6,6 +6,13 @@ import com.kouros.navigation.data.GeoJsonFeature
|
||||
import com.kouros.navigation.data.GeoJsonFeatureCollection
|
||||
import com.kouros.navigation.data.GeoJsonLineString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.maplibre.geojson.Point
|
||||
import org.maplibre.turf.TurfClassification
|
||||
import org.maplibre.turf.TurfConversion
|
||||
import org.maplibre.turf.TurfJoins
|
||||
import org.maplibre.turf.TurfMeta
|
||||
import org.maplibre.turf.TurfMisc
|
||||
import org.maplibre.turf.TurfTransformation
|
||||
import java.lang.Math.toDegrees
|
||||
import java.lang.Math.toRadians
|
||||
import kotlin.math.asin
|
||||
@@ -14,118 +21,130 @@ import kotlin.math.cos
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
|
||||
class NavigationUtils() {
|
||||
object Utils {
|
||||
fun decodePolyline(encoded: String, vararg precisionOptional: Int): List<List<Double>> {
|
||||
val precision = if (precisionOptional.isNotEmpty()) precisionOptional[0] else 6
|
||||
val factor = 10.0.pow(precision)
|
||||
|
||||
var lat = 0
|
||||
var lng = 0
|
||||
val coordinates = mutableListOf<List<Double>>()
|
||||
var index = 0
|
||||
|
||||
while (index < encoded.length) {
|
||||
var byte = 0x20
|
||||
var shift = 0
|
||||
var result = 0
|
||||
while (byte >= 0x20) {
|
||||
byte = encoded[index].code - 63
|
||||
result = result or ((byte and 0x1f) shl shift)
|
||||
shift += 5
|
||||
index++
|
||||
}
|
||||
lat += if ((result and 1) > 0) (result shr 1).inv() else (result shr 1)
|
||||
object NavigationUtils {
|
||||
|
||||
byte = 0x20
|
||||
shift = 0
|
||||
result = 0
|
||||
while (byte >= 0x20) {
|
||||
byte = encoded[index].code - 63
|
||||
result = result or ((byte and 0x1f) shl shift)
|
||||
shift += 5
|
||||
index++
|
||||
}
|
||||
lng += if ((result and 1) > 0) (result shr 1).inv() else (result shr 1)
|
||||
coordinates.add(listOf(lng.toDouble() / factor, lat.toDouble() / factor))
|
||||
}
|
||||
|
||||
return coordinates
|
||||
fun snapLocation(location: Location, stepCoordinates: List<Point>): Location {
|
||||
val oldPoint = Point.fromLngLat(location.longitude, location.latitude)
|
||||
if (stepCoordinates.size > 1) {
|
||||
val pointFeature = TurfMisc.nearestPointOnLine(oldPoint, stepCoordinates)
|
||||
val point = pointFeature.geometry() as Point
|
||||
location.latitude = point.latitude()
|
||||
location.longitude = point.longitude()
|
||||
}
|
||||
|
||||
fun createGeoJson(lineCoordinates: List<List<Double>>): String {
|
||||
val lineString = GeoJsonLineString(type = "LineString", coordinates = lineCoordinates)
|
||||
val feature = GeoJsonFeature(type = "Feature", geometry = lineString)
|
||||
val featureCollection =
|
||||
GeoJsonFeatureCollection(type = "FeatureCollection", features = listOf(feature))
|
||||
val jsonString = Json.Default.encodeToString(featureCollection)
|
||||
return jsonString
|
||||
}
|
||||
|
||||
fun getBoundingBox(
|
||||
lat: Double,
|
||||
lon: Double,
|
||||
radius: Double
|
||||
): Map<String, Map<String, Double>> {
|
||||
val earthRadius = 6371.0
|
||||
val maxLat = lat + Math.toDegrees(radius / earthRadius)
|
||||
val minLat = lat - Math.toDegrees(radius / earthRadius)
|
||||
val maxLon = lon + Math.toDegrees(radius / earthRadius / cos(Math.toRadians(lat)))
|
||||
val minLon = lon - Math.toDegrees(radius / earthRadius / cos(Math.toRadians(lat)))
|
||||
|
||||
return mapOf(
|
||||
"nw" to mapOf("lat" to maxLat, "lon" to minLon),
|
||||
"ne" to mapOf("lat" to maxLat, "lon" to maxLon),
|
||||
"sw" to mapOf("lat" to minLat, "lon" to minLon),
|
||||
"se" to mapOf("lat" to minLat, "lon" to maxLon)
|
||||
)
|
||||
}
|
||||
|
||||
fun computeOffset(from: Location, distance: Double, heading: Double): Location {
|
||||
val earthRadius = 6371009.0
|
||||
var distance = distance
|
||||
var heading = heading
|
||||
distance /= earthRadius
|
||||
heading = toRadians(heading)
|
||||
val fromLat: Double = toRadians(from.latitude)
|
||||
val fromLng: Double = toRadians(from.longitude)
|
||||
val cosDistance: Double = cos(distance)
|
||||
val sinDistance = sin(distance)
|
||||
val sinFromLat = sin(fromLat)
|
||||
val cosFromLat: Double = cos(fromLat)
|
||||
val sinLat: Double = cosDistance * sinFromLat + sinDistance * cosFromLat * cos(heading)
|
||||
val dLng: Double = atan2(
|
||||
sinDistance * cosFromLat * sin(heading),
|
||||
cosDistance - sinFromLat * sinLat
|
||||
)
|
||||
val snap = Location(LocationManager.GPS_PROVIDER)
|
||||
snap.latitude = toDegrees(asin(sinLat))
|
||||
snap.longitude = toDegrees(fromLng + dLng)
|
||||
return snap
|
||||
//return LatLng(toDegrees(asin(sinLat)), toDegrees(fromLng + dLng))
|
||||
}
|
||||
}
|
||||
|
||||
fun calculateZoom(speed: Double?): Double {
|
||||
if (speed == null) {
|
||||
return 18.0
|
||||
}
|
||||
val zoom = when (speed.toInt()) {
|
||||
in 0..10 -> 17.0
|
||||
in 11..20 -> 17.0
|
||||
in 21..30 -> 17.0
|
||||
in 31..40 -> 16.0
|
||||
in 41..50 -> 15.0
|
||||
in 51..60 -> 14.0
|
||||
else -> 11
|
||||
}
|
||||
return zoom.toDouble()
|
||||
}
|
||||
|
||||
fun location(latitude: Double, longitude: Double): Location {
|
||||
val location = Location(LocationManager.GPS_PROVIDER)
|
||||
location.longitude = longitude
|
||||
location.latitude = latitude
|
||||
return location
|
||||
}
|
||||
|
||||
fun decodePolyline(encoded: String, vararg precisionOptional: Int): List<List<Double>> {
|
||||
val precision = if (precisionOptional.isNotEmpty()) precisionOptional[0] else 6
|
||||
val factor = 10.0.pow(precision)
|
||||
|
||||
var lat = 0
|
||||
var lng = 0
|
||||
val coordinates = mutableListOf<List<Double>>()
|
||||
var index = 0
|
||||
|
||||
while (index < encoded.length) {
|
||||
var byte = 0x20
|
||||
var shift = 0
|
||||
var result = 0
|
||||
while (byte >= 0x20) {
|
||||
byte = encoded[index].code - 63
|
||||
result = result or ((byte and 0x1f) shl shift)
|
||||
shift += 5
|
||||
index++
|
||||
}
|
||||
lat += if ((result and 1) > 0) (result shr 1).inv() else (result shr 1)
|
||||
|
||||
byte = 0x20
|
||||
shift = 0
|
||||
result = 0
|
||||
while (byte >= 0x20) {
|
||||
byte = encoded[index].code - 63
|
||||
result = result or ((byte and 0x1f) shl shift)
|
||||
shift += 5
|
||||
index++
|
||||
}
|
||||
lng += if ((result and 1) > 0) (result shr 1).inv() else (result shr 1)
|
||||
coordinates.add(listOf(lng.toDouble() / factor, lat.toDouble() / factor))
|
||||
}
|
||||
|
||||
return coordinates
|
||||
}
|
||||
|
||||
fun createGeoJson(lineCoordinates: List<List<Double>>): String {
|
||||
val lineString = GeoJsonLineString(type = "LineString", coordinates = lineCoordinates)
|
||||
val feature = GeoJsonFeature(type = "Feature", geometry = lineString)
|
||||
val featureCollection =
|
||||
GeoJsonFeatureCollection(type = "FeatureCollection", features = listOf(feature))
|
||||
val jsonString = Json.encodeToString(featureCollection)
|
||||
return jsonString
|
||||
}
|
||||
|
||||
fun getBoundingBox(
|
||||
lat: Double,
|
||||
lon: Double,
|
||||
radius: Double
|
||||
): Map<String, Map<String, Double>> {
|
||||
val earthRadius = 6371.0
|
||||
val maxLat = lat + Math.toDegrees(radius / earthRadius)
|
||||
val minLat = lat - Math.toDegrees(radius / earthRadius)
|
||||
val maxLon = lon + Math.toDegrees(radius / earthRadius / cos(Math.toRadians(lat)))
|
||||
val minLon = lon - Math.toDegrees(radius / earthRadius / cos(Math.toRadians(lat)))
|
||||
|
||||
return mapOf(
|
||||
"nw" to mapOf("lat" to maxLat, "lon" to minLon),
|
||||
"ne" to mapOf("lat" to maxLat, "lon" to maxLon),
|
||||
"sw" to mapOf("lat" to minLat, "lon" to minLon),
|
||||
"se" to mapOf("lat" to minLat, "lon" to maxLon)
|
||||
)
|
||||
}
|
||||
|
||||
fun computeOffset(from: Location, distance: Double, heading: Double): Location {
|
||||
val earthRadius = 6371009.0
|
||||
var distance = distance
|
||||
var heading = heading
|
||||
distance /= earthRadius
|
||||
heading = toRadians(heading)
|
||||
val fromLat: Double = toRadians(from.latitude)
|
||||
val fromLng: Double = toRadians(from.longitude)
|
||||
val cosDistance: Double = cos(distance)
|
||||
val sinDistance = sin(distance)
|
||||
val sinFromLat = sin(fromLat)
|
||||
val cosFromLat: Double = cos(fromLat)
|
||||
val sinLat: Double = cosDistance * sinFromLat + sinDistance * cosFromLat * cos(heading)
|
||||
val dLng: Double = atan2(
|
||||
sinDistance * cosFromLat * sin(heading),
|
||||
cosDistance - sinFromLat * sinLat
|
||||
)
|
||||
val snap = Location(LocationManager.GPS_PROVIDER)
|
||||
snap.latitude = toDegrees(asin(sinLat))
|
||||
snap.longitude = toDegrees(fromLng + dLng)
|
||||
return snap
|
||||
//return LatLng(toDegrees(asin(sinLat)), toDegrees(fromLng + dLng))
|
||||
}
|
||||
}
|
||||
|
||||
fun calculateZoom(speed: Double?): Double {
|
||||
if (speed == null) {
|
||||
return 18.0
|
||||
}
|
||||
val zoom = when (speed.toInt()) {
|
||||
in 0..10 -> 17.0
|
||||
in 11..20 -> 17.0
|
||||
in 21..30 -> 17.0
|
||||
in 31..40 -> 16.0
|
||||
in 41..50 -> 15.0
|
||||
in 51..60 -> 14.0
|
||||
else -> 11
|
||||
}
|
||||
return zoom.toDouble()
|
||||
}
|
||||
|
||||
fun location(latitude: Double, longitude: Double): Location {
|
||||
val location = Location(LocationManager.GPS_PROVIDER)
|
||||
location.longitude = longitude
|
||||
location.latitude = latitude
|
||||
return location
|
||||
}
|
||||
Reference in New Issue
Block a user