Merge remote-tracking branch 'space/main'
# Conflicts: # maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapFeature.kt # maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/MapTextFeature.kt
This commit is contained in:
commit
d490b3f37c
@ -133,3 +133,13 @@ public class MapFeatureGroup(
|
|||||||
) : MapFeature {
|
) : MapFeature {
|
||||||
override fun getBoundingBox(zoom: Int): GmcRectangle? = children.values.mapNotNull { it.getBoundingBox(zoom) }.wrapAll()
|
override fun getBoundingBox(zoom: Int): GmcRectangle? = 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)
|
val feature = MapFeatureGroup(map, zoomRange)
|
||||||
return addFeature(id, feature)
|
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.GmcRectangle
|
|
||||||
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): GmcRectangle = GmcRectangle(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
|
@ -197,20 +197,21 @@ public actual fun MapView(
|
|||||||
for (j in verticalIndices) {
|
for (j in verticalIndices) {
|
||||||
for (i in horizontalIndices) {
|
for (i in horizontalIndices) {
|
||||||
val id = TileId(zoom, i, j)
|
val id = TileId(zoom, i, j)
|
||||||
//start all
|
try {
|
||||||
val deferred = loadTileAsync(id)
|
//start all
|
||||||
//wait asynchronously for it to finish
|
val deferred = loadTileAsync(id)
|
||||||
launch {
|
//wait asynchronously for it to finish
|
||||||
try {
|
launch {
|
||||||
mapTiles += deferred.await()
|
mapTiles += deferred.await()
|
||||||
} catch (ex: Exception) {
|
}
|
||||||
if (ex !is CancellationException) {
|
} catch (ex: Exception) {
|
||||||
//displaying the error is maps responsibility
|
if (ex !is CancellationException) {
|
||||||
logger.error(ex) { "Failed to load tile with id=$id" }
|
//displaying the error is maps responsibility
|
||||||
}
|
logger.error(ex) { "Failed to load tile with id=$id" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import kotlin.io.path.*
|
|||||||
public class OpenStreetMapTileProvider(
|
public class OpenStreetMapTileProvider(
|
||||||
private val client: HttpClient,
|
private val client: HttpClient,
|
||||||
private val cacheDirectory: Path,
|
private val cacheDirectory: Path,
|
||||||
parallelism: Int = 1,
|
parallelism: Int = 4,
|
||||||
cacheCapacity: Int = 200,
|
cacheCapacity: Int = 200,
|
||||||
) : MapTileProvider {
|
) : MapTileProvider {
|
||||||
private val semaphore = Semaphore(parallelism)
|
private val semaphore = Semaphore(parallelism)
|
||||||
@ -37,7 +37,7 @@ public class OpenStreetMapTileProvider(
|
|||||||
/**
|
/**
|
||||||
* Download and cache the tile image
|
* 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 ->
|
id.cacheFilePath()?.let { path ->
|
||||||
if (path.exists()) {
|
if (path.exists()) {
|
||||||
@ -54,9 +54,7 @@ public class OpenStreetMapTileProvider(
|
|||||||
semaphore.withPermit {
|
semaphore.withPermit {
|
||||||
val url = id.osmUrl()
|
val url = id.osmUrl()
|
||||||
val byteArray = client.get(url).readBytes()
|
val byteArray = client.get(url).readBytes()
|
||||||
|
|
||||||
logger.debug { "Finished downloading map tile with id $id from $url" }
|
logger.debug { "Finished downloading map tile with id $id from $url" }
|
||||||
|
|
||||||
id.cacheFilePath()?.let { path ->
|
id.cacheFilePath()?.let { path ->
|
||||||
logger.debug { "Caching map tile $id to $path" }
|
logger.debug { "Caching map tile $id to $path" }
|
||||||
|
|
||||||
@ -79,11 +77,11 @@ public class OpenStreetMapTileProvider(
|
|||||||
|
|
||||||
//collect the result asynchronously
|
//collect the result asynchronously
|
||||||
return async {
|
return async {
|
||||||
val image = try {
|
val image: ImageBitmap = try {
|
||||||
imageDeferred.await()
|
imageDeferred.await()
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
cache.remove(tileId)
|
cache.remove(tileId)
|
||||||
if(ex !is CancellationException) {
|
if (ex !is CancellationException) {
|
||||||
logger.error(ex) { "Failed to load tile image with id=$tileId" }
|
logger.error(ex) { "Failed to load tile image with id=$tileId" }
|
||||||
}
|
}
|
||||||
throw ex
|
throw ex
|
||||||
|
Loading…
Reference in New Issue
Block a user