Merge pull request #473 from meshtastic/osm-features

add osm map features
pull/475/head
Andre K 2022-08-30 17:32:43 -03:00 zatwierdzone przez GitHub
commit 97cf35a4e6
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
11 zmienionych plików z 120 dodań i 43 usunięć

Wyświetl plik

@ -141,6 +141,7 @@ dependencies {
//OSMAND
implementation 'org.osmdroid:osmdroid-android:6.1.14'
implementation 'mil.nga:mgrs:2.0.0'
// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"

Wyświetl plik

@ -120,7 +120,9 @@ data class NodeInfo(
var deviceMetrics: DeviceMetrics? = null
) : Parcelable {
val batteryPctLevel get() = deviceMetrics?.batteryLevel
val batteryLevel get() = deviceMetrics?.batteryLevel
val voltage get() = deviceMetrics?.voltage
val batteryStr get() = String.format("%d%% %.2fV", batteryLevel, voltage ?: 0)
/**
* true if the device was heard from recently
@ -150,6 +152,13 @@ data class NodeInfo(
return if (p != null && op != null) p.distance(op).toInt() else null
}
/// @return bearing to the other position in degrees
fun bearing(o: NodeInfo?): Int? {
val p = validPosition
val op = o?.validPosition
return if (p != null && op != null) p.bearing(op).toInt() else null
}
/// @return a nice human readable string for the distance, or null for unknown
fun distanceStr(o: NodeInfo?) = distance(o)?.let { dist ->
when {

Wyświetl plik

@ -19,9 +19,9 @@ import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.repository.datastore.LocalConfigRepository
import com.geeksville.mesh.service.MeshService
import com.geeksville.mesh.util.GPSFormat
import com.geeksville.mesh.util.positionToMeter
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -215,6 +215,16 @@ class UIViewModel @Inject constructor(
}
}
fun gpsString(pos: Position): String {
return when (_localConfig.value?.display?.gpsFormat) {
ConfigProtos.Config.DisplayConfig.GpsCoordinateFormat.GpsFormatDec -> GPSFormat.dec(pos)
ConfigProtos.Config.DisplayConfig.GpsCoordinateFormat.GpsFormatDMS -> GPSFormat.toDMS(pos)
ConfigProtos.Config.DisplayConfig.GpsCoordinateFormat.GpsFormatUTM -> GPSFormat.toUTM(pos)
ConfigProtos.Config.DisplayConfig.GpsCoordinateFormat.GpsFormatMGRS -> GPSFormat.toMGRS(pos)
else -> GPSFormat.dec(pos)
}
}
@Suppress("MemberVisibilityCanBePrivate")
val isRouter: Boolean =
localConfig.value?.device?.role == ConfigProtos.Config.DeviceConfig.Role.Router

Wyświetl plik

@ -70,7 +70,7 @@ class MapFragment : ScreenFragment("Map"), Logging {
map.let {
if (view != null) {
mapController = map.controller
binding.fabStyleToggle.setOnClickListener {
binding.mapStyleButton.setOnClickListener {
chooseMapStyle()
}
model.nodeDB.nodes.value?.let { nodes ->
@ -121,17 +121,22 @@ class MapFragment : ScreenFragment("Map"), Logging {
val mrkr = nodesWithPosition.map { node ->
val p = node.position!!
debug("Showing on map: $node")
val f = GeoPoint(p.latitude, p.longitude)
lateinit var marker: MarkerWithLabel
node.user?.let {
val label = it.longName + " " + formatAgo(p.time)
marker = MarkerWithLabel(map, label)
marker.title = label
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
marker.position = f
marker.title = buildString {
append("$label ${node.batteryStr}\n${model.gpsString(p)}")
model.nodeDB.ourNodeInfo?.let { our ->
val dist = our.distanceStr(node)
if (dist != null) append(" (${our.bearing(node)}° $dist)")
}
}
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
marker.position = GeoPoint(p.latitude, p.longitude)
marker.icon = ContextCompat.getDrawable(
requireActivity(),
R.drawable.ic_twotone_person_pin_24
R.drawable.ic_twotone_location_on_24
)
}
marker
@ -238,12 +243,12 @@ class MapFragment : ScreenFragment("Map"), Logging {
val p = mPositionPixels
val textPaint = Paint()
textPaint.textSize = 50f
textPaint.textSize = 40f
textPaint.color = Color.RED
textPaint.isAntiAlias = true
textPaint.textAlign = Paint.Align.CENTER
c.drawText(mLabel, (p.x - 0).toFloat(), (p.y - 60).toFloat(), textPaint)
c.drawText(mLabel, (p.x - 0f), (p.y - 80f), textPaint)
}
}
}

Wyświetl plik

@ -114,15 +114,9 @@ class UsersFragment : ScreenFragment("Users"), Logging {
val pos = n.validPosition
if (pos != null) {
val coords =
String.format("%.5f %.5f", pos.latitude, pos.longitude).replace(",", ".")
val html =
"<a href='geo:${pos.latitude},${pos.longitude}?z=17&label=${
URLEncoder.encode(
name,
"utf-8"
)
}'>${coords}</a>"
val html = "<a href='geo:${pos.latitude},${pos.longitude}?z=17&label=${
URLEncoder.encode(name, "utf-8")
}'>${model.gpsString(pos)}</a>"
holder.coordsView.text = HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY)
holder.coordsView.movementMethod = LinkMovementMethod.getInstance()
holder.coordsView.visibility = View.VISIBLE
@ -138,7 +132,7 @@ class UsersFragment : ScreenFragment("Users"), Logging {
} else {
holder.distanceView.visibility = View.INVISIBLE
}
renderBattery(n.batteryPctLevel, n.deviceMetrics?.voltage, holder)
renderBattery(n.batteryLevel, n.voltage, holder)
holder.lastTime.text = formatAgo(n.lastHeard)

Wyświetl plik

@ -1,6 +1,10 @@
package com.geeksville.mesh.util
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.Position
import mil.nga.grid.features.Point
import mil.nga.mgrs.MGRS
import mil.nga.mgrs.utm.UTM
import kotlin.math.abs
import kotlin.math.acos
import kotlin.math.atan2
@ -15,6 +19,42 @@ import kotlin.math.sin
* text of this license is included in the Gaggle source, see assets/manual/gpl-2.0.txt.
******************************************************************************/
object GPSFormat {
fun dec(p: Position): String {
return String.format("%.5f %.5f", p.latitude, p.longitude).replace(",", ".")
}
fun toDMS(p: Position): String {
val lat = degreesToDMS(p.latitude, true)
val lon = degreesToDMS(p.longitude, false)
fun string(a: Array<String>) = String.format("%s°%s'%.5s\"%s", a[0], a[1], a[2], a[3])
return string(lat) + " " + string(lon)
}
fun toUTM(p: Position): String {
val UTM = UTM.from(Point.point(p.longitude, p.latitude))
return String.format(
"%s%s %.6s %.7s",
UTM.zone,
UTM.toMGRS().band,
UTM.easting,
UTM.northing
)
}
fun toMGRS(p: Position): String {
val MGRS = MGRS.from(Point.point(p.longitude, p.latitude))
return String.format(
"%s%s %s%s %05d %05d",
MGRS.zone,
MGRS.band,
MGRS.column,
MGRS.row,
MGRS.easting,
MGRS.northing
)
}
}
/**
* Format as degrees, minutes, secs

Wyświetl plik

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M11.99,18.54l-7.37,-5.73L3,14.07l9,7 9,-7 -1.63,-1.27 -7.38,5.74zM12,16l7.36,-5.73L21,9l-9,-7 -9,7 1.63,1.27L12,16z"/>
</vector>

Wyświetl plik

@ -0,0 +1,8 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillAlpha="0.3"
android:fillColor="@android:color/white"
android:pathData="M6.26,9L12,13.47 17.74,9 12,4.53z" android:strokeAlpha="0.3"/>
<path android:fillColor="@android:color/white" android:pathData="M19.37,12.8l-7.38,5.74 -7.37,-5.73L3,14.07l9,7 9,-7zM12,2L3,9l1.63,1.27L12,16l7.36,-5.73L21,9l-9,-7zM12,13.47L6.26,9 12,4.53 17.74,9 12,13.47z"/>
</vector>

Wyświetl plik

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#3388ff"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillAlpha="0.3"
android:fillColor="@android:color/white"
android:pathData="M12,4C9.24,4 7,6.24 7,9c0,2.85 2.92,7.21 5,9.88 2.11,-2.69 5,-7 5,-9.88 0,-2.76 -2.24,-5 -5,-5zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z"
android:strokeAlpha="0.3" />
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z" />
<path
android:fillColor="@android:color/white"
android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0" />
</vector>

Wyświetl plik

@ -1,15 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M9.83,18l0.59,0.59L12,20.17l1.59,-1.59 0.58,-0.58H19V4H5v14h4.83zM12,5c1.65,0 3,1.35 3,3s-1.35,3 -3,3 -3,-1.35 -3,-3 1.35,-3 3,-3zM6,15.58C6,13.08 9.97,12 12,12s6,1.08 6,3.58V17H6v-1.42z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
android:pathData="M9,20l3,3 3,-3h4c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2L5,2c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h4zM5,4h14v14h-4.83l-0.59,0.59L12,20.17l-1.59,-1.59 -0.58,-0.58L5,18L5,4zM12,11c1.65,0 3,-1.35 3,-3s-1.35,-3 -3,-3 -3,1.35 -3,3 1.35,3 3,3zM12,7c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM18,15.58c0,-2.5 -3.97,-3.58 -6,-3.58s-6,1.08 -6,3.58L6,17h12v-1.42zM8.48,15c0.74,-0.51 2.23,-1 3.52,-1s2.78,0.49 3.52,1L8.48,15z"/>
</vector>

Wyświetl plik

@ -10,6 +10,20 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/mapStyleButton"
android:layout_width="48sp"
android:layout_height="56sp"
android:layout_margin="8dp"
android:backgroundTint="@color/colorAdvancedBackground"
android:contentDescription="@string/style_selection"
app:icon="@drawable/ic_twotone_layers_24"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconTint="@color/colorIconTint"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_style_toggle"
android:layout_width="wrap_content"
@ -18,9 +32,8 @@
android:backgroundTint="@color/design_default_color_secondary"
android:contentDescription="@string/style_selection"
android:orientation="vertical"
android:src="@drawable/baseline_layers_white_24dp"
app:layout_constraintBottom_toBottomOf="parent"
android:visibility="visible"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
tools:background="@color/design_default_color_secondary" />
</androidx.constraintlayout.widget.ConstraintLayout>