Merge pull request #505 from ScriptTactics/osmdroid-phase3

Map View Updates
pull/507/head 1.3.48
Andre K 2022-10-27 17:20:25 -03:00 zatwierdzone przez GitHub
commit c567420294
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
6 zmienionych plików z 266 dodań i 53 usunięć

Wyświetl plik

@ -8,13 +8,47 @@ import org.osmdroid.util.MapTileIndex
class CustomTileSource {
companion object {
// Map Server information: https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer
// Arcgis Information: https://www.arcgis.com/home/item.html?id=10df2279f9684e4a9f6a7f08febac2a9
companion object {
val OPENWEATHER_RADAR = OnlineTileSourceAuth(
"Open Weather Map", 1, 22, 256, ".png", arrayOf(
"https://tile.openweathermap.org/map/"
), "Openweathermap",
TileSourcePolicy(
4,
TileSourcePolicy.FLAG_NO_BULK
or TileSourcePolicy.FLAG_NO_PREVENTIVE
or TileSourcePolicy.FLAG_USER_AGENT_MEANINGFUL
or TileSourcePolicy.FLAG_USER_AGENT_NORMALIZED
),
"precipitation",
""
)
//
// val RAIN_VIEWER = object : OnlineTileSourceBase(
// "RainViewer", 1, 15, 256, ".png", arrayOf(
// "https://tilecache.rainviewer.com/v2/coverage/"
// ), "RainViewer",
// TileSourcePolicy(
// 4,
// TileSourcePolicy.FLAG_NO_BULK
// or TileSourcePolicy.FLAG_NO_PREVENTIVE
// or TileSourcePolicy.FLAG_USER_AGENT_MEANINGFUL
// or TileSourcePolicy.FLAG_USER_AGENT_NORMALIZED
// )
// ) {
// override fun getTileURLString(pMapTileIndex: Long): String {
// return baseUrl + (MapTileIndex.getZoom(pMapTileIndex)
// .toString() + "/" + MapTileIndex.getY(pMapTileIndex)
// + "/" + MapTileIndex.getX(pMapTileIndex)
// + mImageFilenameEnding)
// }
// }
private val ESRI_IMAGERY = object : OnlineTileSourceBase(
"ESRI World Overview", 0, 18, 256, ".jpg", arrayOf(
"https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/"
"ESRI World Overview", 1, 20, 256, ".jpg", arrayOf(
"https://clarity.maptiles.arcgis.com/arcgis/rest/services/World_Imagery/MapServer/tile/"
), "Esri, Maxar, Earthstar Geographics, and the GIS User Community",
TileSourcePolicy(
4,
@ -32,20 +66,18 @@ class CustomTileSource {
}
}
//Transparent Background
//https://earthlive.maptiles.arcgis.com/arcgis/rest/services/GOES/GOES31D/MapServer/tile/
private val NOAA_RADAR = object : OnlineTileSourceBase(
"NOAA GOES Radar",
0,
18,
private val ESRI_WORLD_TOPO = object : OnlineTileSourceBase(
"ESRI World TOPO",
1,
20,
256,
"",
".jpg",
arrayOf(
"https://earthlive.maptiles.arcgis.com/arcgis/rest/services/GOES/GOES31C/MapServer/tile/"
"https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/"
),
"Dataset Citation: GOES-R Calibration Working Group and GOES-R Series Program, (2017): NOAA GOES-R Series Advanced Baseline Imager (ABI) Level 1b Radiances Band 13. NOAA National Centers for Environmental Information. doi:10.7289/V5BV7DSR",
"Esri, HERE, Garmin, FAO, NOAA, USGS, © OpenStreetMap contributors, and the GIS User Community ",
TileSourcePolicy(
2,
4,
TileSourcePolicy.FLAG_NO_BULK
or TileSourcePolicy.FLAG_NO_PREVENTIVE
or TileSourcePolicy.FLAG_USER_AGENT_MEANINGFUL
@ -116,18 +148,7 @@ class CustomTileSource {
"Recent Weather Radar",
arrayOf("https://new.nowcoast.noaa.gov/arcgis/services/nowcoast/radar_meteo_imagery_nexrad_time/MapServer/WmsServer?"),
"1",
"1.3.0",
"",
"EPSG%3A3857",
"",
"image/png"
)
val NOAA_SATELLITE_RADAR_WMS = NOAAWmsTileSource(
"Weather Satellite Imagery",
arrayOf("https://new.nowcoast.noaa.gov/arcgis/services/nowcoast/sat_meteo_imagery_time/MapServer/WmsServer?"),
"1,5,9,13,17,21,25",
"1.3.0",
"1.1.0",
"",
"EPSG%3A3857",
"",
@ -153,6 +174,7 @@ class CustomTileSource {
MAPNIK,
USGS_TOPO,
OPEN_TOPO,
ESRI_WORLD_TOPO,
USGS_SAT,
ESRI_IMAGERY,
)

Wyświetl plik

@ -4,6 +4,7 @@ import android.content.res.Resources
import android.util.Log
import org.osmdroid.api.IMapView
import org.osmdroid.tileprovider.tilesource.OnlineTileSourceBase
import org.osmdroid.tileprovider.tilesource.TileSourcePolicy
import org.osmdroid.util.MapTileIndex
import kotlin.math.atan
import kotlin.math.pow
@ -15,10 +16,18 @@ open class NOAAWmsTileSource(
layername: String,
version: String,
time: String?,
crs: String,
srs: String,
style: String?,
format: String
) : OnlineTileSourceBase(aName, 0, 22, 256, "png", aBaseUrl) {
format: String,
) : OnlineTileSourceBase(
aName, 0, 5, 256, "png", aBaseUrl, "", TileSourcePolicy(
2,
TileSourcePolicy.FLAG_NO_BULK
or TileSourcePolicy.FLAG_NO_PREVENTIVE
or TileSourcePolicy.FLAG_USER_AGENT_MEANINGFUL
or TileSourcePolicy.FLAG_USER_AGENT_NORMALIZED
)
) {
// array indexes for array to hold bounding boxes.
private val MINX = 0
@ -37,8 +46,7 @@ open class NOAAWmsTileSource(
private val MAP_SIZE = 20037508.34789244 * 2
private var layer = ""
private var version = "1.1.0"
private var crs = "EPSG:3A3857" //used by geo server
private var size = ""
private var srs = "EPSG%3A3857" //used by geo server
private var format = ""
private var time = ""
private var style: String? = null
@ -49,7 +57,7 @@ open class NOAAWmsTileSource(
Log.i(IMapView.LOGTAG, "WMS support is BETA. Please report any issues")
layer = layername
this.version = version
this.crs = crs
this.srs = srs
this.style = style
this.format = format
if (time != null) this.time = time
@ -128,7 +136,8 @@ open class NOAAWmsTileSource(
sb.append("&transparent=true")
sb.append("&height=").append(Resources.getSystem().displayMetrics.heightPixels)
sb.append("&width=").append(Resources.getSystem().displayMetrics.widthPixels)
sb.append("&crs=").append(crs)
sb.append("&srs=").append(srs)
sb.append("&size=").append(getSize())
sb.append("&bbox=")
val bbox = getBoundingBox(
MapTileIndex.getX(pMapTileIndex),
@ -139,8 +148,14 @@ open class NOAAWmsTileSource(
sb.append(bbox[MINY]).append(",")
sb.append(bbox[MAXX]).append(",")
sb.append(bbox[MAXY])
Log.i(IMapView.LOGTAG, sb.toString())
return sb.toString()
}
private fun getSize(): String {
val height = Resources.getSystem().displayMetrics.heightPixels
val width = Resources.getSystem().displayMetrics.widthPixels
return "$width,$height"
}
}

Wyświetl plik

@ -0,0 +1,47 @@
package com.geeksville.mesh.model.map
import org.osmdroid.tileprovider.tilesource.OnlineTileSourceBase
import org.osmdroid.tileprovider.tilesource.TileSourcePolicy
import org.osmdroid.util.MapTileIndex
open class OnlineTileSourceAuth(
aName: String,
aZoomLevel: Int,
aZoomMaxLevel: Int,
aTileSizePixels: Int,
aImageFileNameEnding: String,
aBaseUrl: Array<String>,
pCopyright: String,
tileSourcePolicy: TileSourcePolicy,
layerName: String?,
apiKey: String
) :
OnlineTileSourceBase(
aName,
aZoomLevel,
aZoomMaxLevel,
aTileSizePixels,
aImageFileNameEnding,
aBaseUrl,
pCopyright,
tileSourcePolicy
) {
private var layerName = ""
private var apiKey = ""
init {
if (layerName != null) {
this.layerName = layerName
}
this.apiKey = apiKey
}
override fun getTileURLString(pMapTileIndex: Long): String {
return "$baseUrl$layerName/" + (MapTileIndex.getZoom(pMapTileIndex)
.toString() + "/" + MapTileIndex.getX(pMapTileIndex)
.toString() + "/" + MapTileIndex.getY(pMapTileIndex)
.toString()) + mImageFilenameEnding + "?appId=$apiKey"
}
}

Wyświetl plik

@ -22,6 +22,7 @@ import com.geeksville.mesh.databinding.MapViewBinding
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.model.map.CustomOverlayManager
import com.geeksville.mesh.model.map.CustomTileSource
import com.geeksville.mesh.util.SqlTileWriterExt
import com.geeksville.mesh.util.formatAgo
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
@ -30,9 +31,9 @@ import org.osmdroid.config.Configuration
import org.osmdroid.events.MapListener
import org.osmdroid.events.ScrollEvent
import org.osmdroid.events.ZoomEvent
import org.osmdroid.tileprovider.MapTileProviderBasic
import org.osmdroid.tileprovider.cachemanager.CacheManager
import org.osmdroid.tileprovider.cachemanager.CacheManager.CacheManagerCallback
import org.osmdroid.tileprovider.modules.SqlTileWriter
import org.osmdroid.tileprovider.modules.SqliteArchiveTileWriter
import org.osmdroid.tileprovider.tilesource.ITileSource
import org.osmdroid.tileprovider.tilesource.OnlineTileSourceBase
@ -57,6 +58,7 @@ class MapFragment : ScreenFragment("Map"), Logging, View.OnClickListener {
private lateinit var executeJob: Button
private var downloadPrompt: AlertDialog? = null
private var alertDialog: AlertDialog? = null
private var cache: SqlTileWriterExt? = null
// constants
private val defaultMinZoom = 1.5
@ -85,7 +87,6 @@ class MapFragment : ScreenFragment("Map"), Logging, View.OnClickListener {
private lateinit var cacheManager: CacheManager
private lateinit var downloadRegionBoundingBox: BoundingBox
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
@ -165,7 +166,7 @@ class MapFragment : ScreenFragment("Map"), Logging, View.OnClickListener {
downloadJobAlert()
dialog.dismiss()
}
2 -> clearCache()
2 -> purgeTileSource()
else -> dialog.dismiss()
}
}
@ -177,16 +178,48 @@ class MapFragment : ScreenFragment("Map"), Logging, View.OnClickListener {
}
/**
* Clears active tile source cache
*/
private fun clearCache() {
val b: Boolean = SqlTileWriter().purgeCache()
SqlTileWriter().onDetach()
val title = if (b) "SQL Cache purged" else "SQL Cache purge failed, see logcat for details"
val length = if (b) Toast.LENGTH_SHORT else Toast.LENGTH_LONG
Toast.makeText(activity, title, length).show()
alertDialog!!.dismiss()
private fun purgeTileSource() {
cache = SqlTileWriterExt()
val builder = AlertDialog.Builder(context)
builder.setTitle("Tile Source")
val sources = cache!!.sources
val sourceList = mutableListOf<String>()
for (i in sources.indices) {
sourceList.add(sources[i].source as String)
}
val selected: BooleanArray? = null
val selectedList = mutableListOf<Int>()
builder.setMultiChoiceItems(
sourceList.toTypedArray(),
selected
) { _, i, b ->
if (b) {
selectedList.add(i)
} else {
selectedList.remove(i)
}
}
builder.setPositiveButton("Clear") { _, _ ->
for (x in selectedList) {
val item = sources[x]
val b = cache!!.purgeCache(item.source)
if (b) Toast.makeText(
context,
"SQL Cache purged for ${item.source}",
Toast.LENGTH_SHORT
)
.show() else Toast.makeText(
context,
"SQL Cache purge failed, see logcat for details",
Toast.LENGTH_LONG
).show()
}
}
builder.setNegativeButton(
"Cancel"
) { dialog, _ -> dialog.cancel() }
builder.show()
}
@ -357,22 +390,20 @@ class MapFragment : ScreenFragment("Map"), Logging, View.OnClickListener {
private fun chooseMapStyle() {
/// Prepare dialog and its items
val builder = MaterialAlertDialogBuilder(context!!)
builder.setTitle(getString(R.string.preferences_map_style))
val mapStyles by lazy { resources.getStringArray(R.array.map_styles) }
val builder = MaterialAlertDialogBuilder(context!!)
/// Load preferences and its value
val editor: SharedPreferences.Editor = mPrefs.edit()
val mapStyleInt = mPrefs.getInt(mapStyleId, 1)
debug("mapStyleId from prefs: $mapStyleInt")
builder.setSingleChoiceItems(mapStyles, mapStyleInt) { dialog, which ->
debug("Set mapStyleId pref to $which")
val editor: SharedPreferences.Editor = mPrefs.edit()
editor.putInt(mapStyleId, which)
editor.apply()
dialog.dismiss()
map.setTileSource(loadOnlineTileSourceBase())
renderDownloadButton()
drawOverlays()
}
val dialog = builder.create()
dialog.show()
@ -478,6 +509,22 @@ class MapFragment : ScreenFragment("Map"), Logging, View.OnClickListener {
map.invalidate()
}
// private fun addWeatherLayer() {
// if (map.tileProvider.tileSource.name()
// .equals(CustomTileSource.getTileSource("ESRI World TOPO").name())
// ) {
// val layer = TilesOverlay(
// MapTileProviderBasic(
// activity,
// CustomTileSource.OPENWEATHER_RADAR
// ), context
// )
// layer.loadingBackgroundColor = Color.TRANSPARENT
// layer.loadingLineColor = Color.TRANSPARENT
// map.overlayManager.add(layer)
// }
// }
/**
* Adds copyright to map depending on what source is showing
*/

Wyświetl plik

@ -0,0 +1,81 @@
package com.geeksville.mesh.util
import android.database.Cursor
import org.osmdroid.tileprovider.modules.DatabaseFileArchive
import org.osmdroid.tileprovider.modules.SqlTileWriter
/**
* Extended the sqlite tile writer to have some additional query functions. A this point
* it's unclear if there is a need to put these with the osmdroid-android library, thus they were
* put here as more of an example.
*
*
* created on 12/21/2016.
*
* @author Alex O'Ree
* @since 5.6.2
*/
class SqlTileWriterExt() : SqlTileWriter() {
fun select(rows: Int, offset: Int): Cursor? {
return this.db?.rawQuery(
"select " + DatabaseFileArchive.COLUMN_KEY + "," + COLUMN_EXPIRES + "," + DatabaseFileArchive.COLUMN_PROVIDER + " from " + DatabaseFileArchive.TABLE + " limit ? offset ?",
arrayOf(rows.toString() + "", offset.toString() + "")
)
}
/**
* gets all the tiles sources that we have tiles for in the cache database and their counts
*
* @return
*/
val sources: List<SourceCount>
get() {
val db = db
val ret: MutableList<SourceCount> = ArrayList()
if (db == null) {
return ret
}
var cur: Cursor? = null
try {
cur = db.rawQuery(
"select "
+ DatabaseFileArchive.COLUMN_PROVIDER
+ ",count(*) "
+ ",min(length(" + DatabaseFileArchive.COLUMN_TILE + ")) "
+ ",max(length(" + DatabaseFileArchive.COLUMN_TILE + ")) "
+ ",sum(length(" + DatabaseFileArchive.COLUMN_TILE + ")) "
+ "from " + DatabaseFileArchive.TABLE + " "
+ "group by " + DatabaseFileArchive.COLUMN_PROVIDER, null
)
while (cur.moveToNext()) {
val c = SourceCount()
c.source = cur.getString(0)
c.rowCount = cur.getLong(1)
c.sizeMin = cur.getLong(2)
c.sizeMax = cur.getLong(3)
c.sizeTotal = cur.getLong(4)
c.sizeAvg = c.sizeTotal / c.rowCount
ret.add(c)
}
} catch (e: Exception) {
catchException(e)
} finally {
cur?.close()
}
return ret
}
val rowCountExpired: Long
get() = getRowCount(
"$COLUMN_EXPIRES<?", arrayOf(System.currentTimeMillis().toString())
)
class SourceCount() {
var rowCount: Long = 0
var source: String? = null
var sizeTotal: Long = 0
var sizeMin: Long = 0
var sizeMax: Long = 0
var sizeAvg: Long = 0
}
}

Wyświetl plik

@ -90,6 +90,7 @@
<item>OpenStreetMap</item>
<item>USGS TOPO</item>
<item>Open TOPO</item>
<item>ESRI World TOPO</item>
<item>USGS Satellite</item>
<item>ESRI World Overview</item>
</string-array>