kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
commit
c567420294
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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"
|
||||
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
Ładowanie…
Reference in New Issue