loadTileAsync refactor
loadTileAsync consumes all tileIds
This commit is contained in:
parent
fc0f223766
commit
5d3db81c4f
@ -2,7 +2,6 @@ package centre.sciprog.maps.compose
|
|||||||
|
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Deferred
|
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
|
||||||
data class TileId(
|
data class TileId(
|
||||||
@ -17,7 +16,7 @@ data class MapTile(
|
|||||||
)
|
)
|
||||||
|
|
||||||
interface MapTileProvider {
|
interface MapTileProvider {
|
||||||
suspend fun loadTileAsync(id: TileId, scope: CoroutineScope): Deferred<MapTile>
|
suspend fun loadTileAsync(tileIds: List<TileId>, scope: CoroutineScope, onTileLoad: (mapTile: MapTile) -> Unit)
|
||||||
|
|
||||||
val tileSize: Int get() = DEFAULT_TILE_SIZE
|
val tileSize: Int get() = DEFAULT_TILE_SIZE
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ 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
|
||||||
@ -46,21 +45,23 @@ actual fun MapView(
|
|||||||
) {
|
) {
|
||||||
var canvasSize by remember { mutableStateOf(DpSize(512.dp, 512.dp)) }
|
var canvasSize by remember { mutableStateOf(DpSize(512.dp, 512.dp)) }
|
||||||
|
|
||||||
var viewPointOverride by remember { mutableStateOf<MapViewPoint?>(
|
var viewPointOverride by remember {
|
||||||
if(config.inferViewBoxFromFeatures){
|
mutableStateOf<MapViewPoint?>(
|
||||||
features.values.computeBoundingBox(1)?.let { box ->
|
if (config.inferViewBoxFromFeatures) {
|
||||||
val zoom = log2(
|
features.values.computeBoundingBox(1)?.let { box ->
|
||||||
min(
|
val zoom = log2(
|
||||||
canvasSize.width.value / box.width,
|
min(
|
||||||
canvasSize.height.value / box.height
|
canvasSize.width.value / box.width,
|
||||||
) * PI / mapTileProvider.tileSize
|
canvasSize.height.value / box.height
|
||||||
)
|
) * PI / mapTileProvider.tileSize
|
||||||
MapViewPoint(box.center, zoom)
|
)
|
||||||
|
MapViewPoint(box.center, zoom)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
} else {
|
)
|
||||||
null
|
}
|
||||||
}
|
|
||||||
) }
|
|
||||||
|
|
||||||
val viewPoint by derivedStateOf { viewPointOverride ?: computeViewPoint(canvasSize) }
|
val viewPoint by derivedStateOf { viewPointOverride ?: computeViewPoint(canvasSize) }
|
||||||
|
|
||||||
@ -163,21 +164,17 @@ actual fun MapView(
|
|||||||
|
|
||||||
mapTiles.clear()
|
mapTiles.clear()
|
||||||
|
|
||||||
verticalIndices
|
val tileIds = verticalIndices
|
||||||
.flatMap { j ->
|
.flatMap { j ->
|
||||||
horizontalIndices
|
horizontalIndices
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.map { TileId(zoom, it, j) }
|
.map { TileId(zoom, it, j) }
|
||||||
}
|
}
|
||||||
.forEach {
|
|
||||||
try {
|
mapTileProvider.loadTileAsync(
|
||||||
launch {
|
tileIds = tileIds,
|
||||||
mapTiles += mapTileProvider.loadTileAsync(it, this).await()
|
scope = this
|
||||||
}
|
) { mapTiles += it }
|
||||||
} catch (ex: Exception) {
|
|
||||||
logger.error(ex) { "Failed to load tile $it" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,10 +6,7 @@ import centre.sciprog.maps.LruCache
|
|||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.request.*
|
import io.ktor.client.request.*
|
||||||
import io.ktor.client.statement.*
|
import io.ktor.client.statement.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.Deferred
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.sync.Semaphore
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import org.jetbrains.skia.Image
|
import org.jetbrains.skia.Image
|
||||||
@ -63,17 +60,31 @@ class OpenStreetMapTileProvider(
|
|||||||
Image.makeFromEncoded(byteArray).toComposeImageBitmap()
|
Image.makeFromEncoded(byteArray).toComposeImageBitmap()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun loadTileAsync(id: TileId, scope: CoroutineScope) = scope.async {
|
override suspend fun loadTileAsync(
|
||||||
semaphore.acquire()
|
tileIds: List<TileId>,
|
||||||
try {
|
scope: CoroutineScope,
|
||||||
val image = cache.getOrPut(id) { downloadImageAsync(id) }
|
onTileLoad: (mapTile: MapTile) -> Unit,
|
||||||
MapTile(id, image.await())
|
) {
|
||||||
} catch (e: Exception) {
|
tileIds
|
||||||
cache.remove(id)
|
.forEach { id ->
|
||||||
throw e
|
try {
|
||||||
} finally {
|
scope.launch {
|
||||||
semaphore.release()
|
semaphore.acquire()
|
||||||
}
|
try {
|
||||||
|
val image = cache.getOrPut(id) { downloadImageAsync(id) }
|
||||||
|
val result = MapTile(id, image.await())
|
||||||
|
onTileLoad(result)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
cache.remove(id)
|
||||||
|
throw e
|
||||||
|
} finally {
|
||||||
|
semaphore.release()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
logger.error(ex) { "Failed to load tile $id" }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
Loading…
Reference in New Issue
Block a user