Async load
This commit is contained in:
parent
bebd33f859
commit
f92ccb4838
@ -1,6 +1,7 @@
|
|||||||
package centre.sciprog.maps.compose
|
package centre.sciprog.maps.compose
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
|
||||||
data class TileId(
|
data class TileId(
|
||||||
@ -15,7 +16,7 @@ data class MapTile(
|
|||||||
)
|
)
|
||||||
|
|
||||||
interface MapTileProvider {
|
interface MapTileProvider {
|
||||||
suspend fun loadTile(id: TileId): MapTile
|
fun loadTileAsync(id: TileId): Deferred<MapTile>
|
||||||
|
|
||||||
val tileSize: Int get() = DEFAULT_TILE_SIZE
|
val tileSize: Int get() = DEFAULT_TILE_SIZE
|
||||||
|
|
||||||
@ -27,3 +28,5 @@ interface MapTileProvider {
|
|||||||
const val DEFAULT_TILE_SIZE = 256
|
const val DEFAULT_TILE_SIZE = 256
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun MapTileProvider.loadTile(id: TileId): MapTile = loadTileAsync(id).await()
|
@ -17,6 +17,7 @@ import androidx.compose.ui.graphics.toArgb
|
|||||||
import androidx.compose.ui.input.pointer.*
|
import androidx.compose.ui.input.pointer.*
|
||||||
import androidx.compose.ui.unit.*
|
import androidx.compose.ui.unit.*
|
||||||
import centre.sciprog.maps.*
|
import centre.sciprog.maps.*
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import org.jetbrains.skia.Font
|
import org.jetbrains.skia.Font
|
||||||
import org.jetbrains.skia.Paint
|
import org.jetbrains.skia.Paint
|
||||||
@ -149,8 +150,10 @@ actual fun MapView(
|
|||||||
if (i in indexRange && j in indexRange) {
|
if (i in indexRange && j in indexRange) {
|
||||||
val tileId = TileId(zoom, i, j)
|
val tileId = TileId(zoom, i, j)
|
||||||
try {
|
try {
|
||||||
val tile = mapTileProvider.loadTile(tileId)
|
launch {
|
||||||
mapTiles.add(tile)
|
val tile = mapTileProvider.loadTileAsync(tileId)
|
||||||
|
mapTiles.add(tile.await())
|
||||||
|
}
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
logger.error(ex) { "Failed to load tile $tileId" }
|
logger.error(ex) { "Failed to load tile $tileId" }
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,10 @@ import androidx.compose.ui.graphics.toComposeImageBitmap
|
|||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
import io.ktor.client.statement.readBytes
|
import io.ktor.client.statement.readBytes
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.async
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import org.jetbrains.skia.Image
|
import org.jetbrains.skia.Image
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
@ -16,7 +19,11 @@ import kotlin.math.pow
|
|||||||
/**
|
/**
|
||||||
* A [MapTileProvider] based on Open Street Map API. With in-memory and file cache
|
* A [MapTileProvider] based on Open Street Map API. With in-memory and file cache
|
||||||
*/
|
*/
|
||||||
public class OpenStreetMapTileProvider(private val scope: CoroutineScope, private val client: HttpClient, private val cacheDirectory: Path): MapTileProvider {
|
public class OpenStreetMapTileProvider(
|
||||||
|
private val scope: CoroutineScope,
|
||||||
|
private val client: HttpClient,
|
||||||
|
private val cacheDirectory: Path,
|
||||||
|
) : MapTileProvider {
|
||||||
private val cache = HashMap<TileId, Deferred<ImageBitmap>>()
|
private val cache = HashMap<TileId, Deferred<ImageBitmap>>()
|
||||||
|
|
||||||
private fun TileId.osmUrl() = URL("https://tile.openstreetmap.org/${zoom}/${i}/${j}.png")
|
private fun TileId.osmUrl() = URL("https://tile.openstreetmap.org/${zoom}/${i}/${j}.png")
|
||||||
@ -53,20 +60,22 @@ public class OpenStreetMapTileProvider(private val scope: CoroutineScope, privat
|
|||||||
Image.makeFromEncoded(byteArray).toComposeImageBitmap()
|
Image.makeFromEncoded(byteArray).toComposeImageBitmap()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun loadTile(id: TileId): MapTile {
|
override fun loadTileAsync(id: TileId): Deferred<MapTile> {
|
||||||
val indexRange = indexRange(id.zoom)
|
val indexRange = indexRange(id.zoom)
|
||||||
if(id.i !in indexRange || id.j !in indexRange){
|
if (id.i !in indexRange || id.j !in indexRange) {
|
||||||
error("Indices (${id.i}, ${id.j}) are not in index range $indexRange for zoom ${id.zoom}")
|
error("Indices (${id.i}, ${id.j}) are not in index range $indexRange for zoom ${id.zoom}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val image = cache.getOrPut(id) {
|
val image = cache.getOrPut(id) {
|
||||||
downloadImageAsync(id)
|
downloadImageAsync(id)
|
||||||
}.await()
|
}
|
||||||
|
|
||||||
return MapTile(id, image)
|
return scope.async {
|
||||||
|
MapTile(id, image.await())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object{
|
companion object {
|
||||||
private val logger = KotlinLogging.logger("OpenStreetMapCache")
|
private val logger = KotlinLogging.logger("OpenStreetMapCache")
|
||||||
private fun indexRange(zoom: Int): IntRange = 0 until 2.0.pow(zoom).toInt()
|
private fun indexRange(zoom: Int): IntRange = 0 until 2.0.pow(zoom).toInt()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user