Connect timeout exception handling #16
@ -133,3 +133,13 @@ public class MapFeatureGroup(
|
||||
) : MapFeature {
|
||||
override fun getBoundingBox(zoom: Int): GmcBox? = children.values.mapNotNull { it.getBoundingBox(zoom) }.wrapAll()
|
||||
}
|
||||
|
||||
public class MapTextFeature(
|
||||
public val position: GeodeticMapCoordinates,
|
||||
public val text: String,
|
||||
override val zoomRange: IntRange = defaultZoomRange,
|
||||
public val color: Color,
|
||||
public val fontConfig: MapTextFeatureFont.() -> Unit,
|
||||
) : MapFeature {
|
||||
override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(position, position)
|
||||
}
|
||||
|
@ -144,3 +144,21 @@ public fun MapFeatureBuilder.group(
|
||||
val feature = MapFeatureGroup(map, zoomRange)
|
||||
return addFeature(id, feature)
|
||||
}
|
||||
|
||||
public fun MapFeatureBuilder.text(
|
||||
position: GeodeticMapCoordinates,
|
||||
text: String,
|
||||
zoomRange: IntRange = defaultZoomRange,
|
||||
color: Color = Color.Red,
|
||||
font: MapTextFeatureFont.() -> Unit = { size = 16f },
|
||||
id: FeatureId? = null,
|
||||
): FeatureId = addFeature(id, MapTextFeature(position, text, zoomRange, color, font))
|
||||
|
||||
public fun MapFeatureBuilder.text(
|
||||
position: Pair<Double, Double>,
|
||||
text: String,
|
||||
zoomRange: IntRange = defaultZoomRange,
|
||||
color: Color = Color.Red,
|
||||
font: MapTextFeatureFont.() -> Unit = { size = 16f },
|
||||
id: FeatureId? = null,
|
||||
): FeatureId = addFeature(id, MapTextFeature(position.toCoordinates(), text, zoomRange, color, font))
|
||||
|
@ -0,0 +1,5 @@
|
||||
package center.sciprog.maps.compose
|
||||
|
||||
public expect class MapTextFeatureFont {
|
||||
public var size: Float
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package center.sciprog.maps.compose
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import center.sciprog.maps.coordinates.GeodeticMapCoordinates
|
||||
import center.sciprog.maps.coordinates.GmcBox
|
||||
import org.jetbrains.skia.Font
|
||||
|
||||
|
||||
public class MapTextFeature(
|
||||
public val position: GeodeticMapCoordinates,
|
||||
public val text: String,
|
||||
override val zoomRange: IntRange = defaultZoomRange,
|
||||
public val color: Color,
|
||||
public val fontConfig: Font.() -> Unit,
|
||||
) : MapFeature {
|
||||
override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(position, position)
|
||||
}
|
||||
|
||||
public fun MapFeatureBuilder.text(
|
||||
position: GeodeticMapCoordinates,
|
||||
text: String,
|
||||
zoomRange: IntRange = defaultZoomRange,
|
||||
color: Color = Color.Red,
|
||||
font: Font.() -> Unit = { size = 16f },
|
||||
id: FeatureId? = null,
|
||||
): FeatureId = addFeature(id, MapTextFeature(position, text, zoomRange, color, font))
|
||||
|
||||
public fun MapFeatureBuilder.text(
|
||||
position: Pair<Double, Double>,
|
||||
text: String,
|
||||
zoomRange: IntRange = defaultZoomRange,
|
||||
color: Color = Color.Red,
|
||||
font: Font.() -> Unit = { size = 16f },
|
||||
id: FeatureId? = null,
|
||||
): FeatureId = addFeature(id, MapTextFeature(position.toCoordinates(), text, zoomRange, color, font))
|
@ -0,0 +1,5 @@
|
||||
package center.sciprog.maps.compose
|
||||
|
||||
import org.jetbrains.skia.Font
|
||||
|
||||
public actual typealias MapTextFeatureFont = Font
|
@ -195,20 +195,21 @@ public actual fun MapView(
|
||||
for (j in verticalIndices) {
|
||||
for (i in horizontalIndices) {
|
||||
val id = TileId(zoom, i, j)
|
||||
//start all
|
||||
val deferred = loadTileAsync(id)
|
||||
//wait asynchronously for it to finish
|
||||
launch {
|
||||
try {
|
||||
try {
|
||||
//start all
|
||||
val deferred = loadTileAsync(id)
|
||||
//wait asynchronously for it to finish
|
||||
launch {
|
||||
mapTiles += deferred.await()
|
||||
} catch (ex: Exception) {
|
||||
if (ex !is CancellationException) {
|
||||
//displaying the error is maps responsibility
|
||||
logger.error(ex) { "Failed to load tile with id=$id" }
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
if (ex !is CancellationException) {
|
||||
//displaying the error is maps responsibility
|
||||
logger.error(ex) { "Failed to load tile with id=$id" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -232,6 +233,7 @@ public actual fun MapView(
|
||||
feature.size,
|
||||
center = feature.center.toOffset()
|
||||
)
|
||||
|
||||
is MapRectangleFeature -> drawRect(
|
||||
feature.color,
|
||||
topLeft = feature.center.toOffset() - Offset(
|
||||
@ -240,6 +242,7 @@ public actual fun MapView(
|
||||
),
|
||||
size = feature.size.toSize()
|
||||
)
|
||||
|
||||
is MapLineFeature -> drawLine(feature.color, feature.a.toOffset(), feature.b.toOffset())
|
||||
is MapArcFeature -> {
|
||||
val topLeft = feature.oval.topLeft.toOffset()
|
||||
@ -252,6 +255,7 @@ public actual fun MapView(
|
||||
drawPath(path, color = feature.color, style = Stroke())
|
||||
|
||||
}
|
||||
|
||||
is MapBitmapImageFeature -> drawImage(feature.image, feature.position.toOffset())
|
||||
is MapVectorImageFeature -> {
|
||||
val offset = feature.position.toOffset()
|
||||
@ -262,6 +266,7 @@ public actual fun MapView(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is MapTextFeature -> drawIntoCanvas { canvas ->
|
||||
val offset = feature.position.toOffset()
|
||||
canvas.nativeCanvas.drawString(
|
||||
@ -272,17 +277,20 @@ public actual fun MapView(
|
||||
feature.color.toPaint()
|
||||
)
|
||||
}
|
||||
|
||||
is MapDrawFeature -> {
|
||||
val offset = feature.position.toOffset()
|
||||
translate(offset.x, offset.y) {
|
||||
feature.drawFeature(this)
|
||||
}
|
||||
}
|
||||
|
||||
is MapFeatureGroup -> {
|
||||
feature.children.values.forEach {
|
||||
drawFeature(zoom, it)
|
||||
}
|
||||
}
|
||||
|
||||
is MapPointsFeature -> {
|
||||
val points = feature.points.map { it.toOffset() }
|
||||
drawPoints(
|
||||
@ -292,6 +300,7 @@ public actual fun MapView(
|
||||
pointMode = feature.pointMode
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
logger.error { "Unrecognized feature type: ${feature::class}" }
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import kotlin.io.path.*
|
||||
public class OpenStreetMapTileProvider(
|
||||
private val client: HttpClient,
|
||||
private val cacheDirectory: Path,
|
||||
parallelism: Int = 1,
|
||||
parallelism: Int = 4,
|
||||
cacheCapacity: Int = 200,
|
||||
) : MapTileProvider {
|
||||
private val semaphore = Semaphore(parallelism)
|
||||
@ -37,7 +37,7 @@ public class OpenStreetMapTileProvider(
|
||||
/**
|
||||
* Download and cache the tile image
|
||||
*/
|
||||
private fun CoroutineScope.downloadImageAsync(id: TileId) = async(Dispatchers.IO) {
|
||||
private fun CoroutineScope.downloadImageAsync(id: TileId): Deferred<ImageBitmap> = async(Dispatchers.IO) {
|
||||
|
||||
id.cacheFilePath()?.let { path ->
|
||||
if (path.exists()) {
|
||||
@ -54,9 +54,7 @@ public class OpenStreetMapTileProvider(
|
||||
semaphore.withPermit {
|
||||
val url = id.osmUrl()
|
||||
val byteArray = client.get(url).readBytes()
|
||||
|
||||
logger.debug { "Finished downloading map tile with id $id from $url" }
|
||||
|
||||
id.cacheFilePath()?.let { path ->
|
||||
logger.debug { "Caching map tile $id to $path" }
|
||||
|
||||
@ -79,11 +77,11 @@ public class OpenStreetMapTileProvider(
|
||||
|
||||
//collect the result asynchronously
|
||||
return async {
|
||||
val image = try {
|
||||
val image: ImageBitmap = try {
|
||||
imageDeferred.await()
|
||||
} catch (ex: Exception) {
|
||||
cache.remove(tileId)
|
||||
if(ex !is CancellationException) {
|
||||
if (ex !is CancellationException) {
|
||||
logger.error(ex) { "Failed to load tile image with id=$tileId" }
|
||||
}
|
||||
throw ex
|
||||
|
Loading…
Reference in New Issue
Block a user