diff --git a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapState.kt b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapState.kt index c9c992c..ddd45be 100644 --- a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapState.kt +++ b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapState.kt @@ -11,21 +11,23 @@ internal class MapState internal constructor( config: ViewConfig, canvasSize: DpSize, viewPoint: ViewPoint, - public val tileSize: Int, + val tileSize: Int, ) : CoordinateViewState(config, canvasSize, viewPoint) { override val space: CoordinateSpace get() = GmcCoordinateSpace public val scaleFactor: Double get() = WebMercatorProjection.scaleFactor(viewPoint.zoom) + val intZoom: Int get() = floor(zoom).toInt() + public val centerCoordinates: WebMercatorCoordinates - get() = WebMercatorProjection.toMercator(viewPoint.focus, zoom) + get() = WebMercatorProjection.toMercator(viewPoint.focus, intZoom) internal val tileScale: Double - get() = 2.0.pow(viewPoint.zoom - zoom) + get() = 2.0.pow(viewPoint.zoom - floor(viewPoint.zoom)) private fun DpOffset.toMercator(): WebMercatorCoordinates = WebMercatorCoordinates( - floor(zoom).toInt(), + intZoom, (x - canvasSize.width / 2).value / tileScale + centerCoordinates.x, (y - canvasSize.height / 2).value / tileScale + centerCoordinates.y, ) @@ -42,7 +44,7 @@ internal class MapState internal constructor( ) override fun Gmc.toDpOffset(): DpOffset = - WebMercatorProjection.toMercator(this, zoom).toOffset() + WebMercatorProjection.toMercator(this, intZoom).toOffset() override fun Rectangle.toDpRect(): DpRect { val topLeft = topLeft.toDpOffset() diff --git a/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/MapViewJvm.kt b/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/MapViewJvm.kt index e351689..2447a59 100644 --- a/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/MapViewJvm.kt +++ b/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/MapViewJvm.kt @@ -20,7 +20,10 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope import mu.KotlinLogging import org.jetbrains.skia.Paint -import kotlin.math.* +import kotlin.math.ceil +import kotlin.math.max +import kotlin.math.min +import kotlin.math.pow private fun Color.toPaint(): Paint = Paint().apply { @@ -57,7 +60,7 @@ public actual fun MapView( // Load tiles asynchronously LaunchedEffect(viewPoint, canvasSize) { with(mapTileProvider) { - val indexRange = 0 until 2.0.pow(zoom).toInt() + val indexRange = 0 until 2.0.pow(intZoom).toInt() val left = centerCoordinates.x - canvasSize.width.value / 2 / tileScale val right = centerCoordinates.x + canvasSize.width.value / 2 / tileScale @@ -71,7 +74,7 @@ public actual fun MapView( for (j in verticalIndices) { for (i in horizontalIndices) { - val id = TileId(floor(zoom).toInt(), i, j) + val id = TileId(intZoom, i, j) //ensure that failed tiles do not fail the application supervisorScope { //start all diff --git a/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/WebMercatorProjection.kt b/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/WebMercatorProjection.kt index a1de7b4..d29e4c4 100644 --- a/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/WebMercatorProjection.kt +++ b/maps-kt-core/src/commonMain/kotlin/center/sciprog/maps/coordinates/WebMercatorProjection.kt @@ -26,12 +26,12 @@ public object WebMercatorProjection { /** * https://en.wikipedia.org/wiki/Web_Mercator_projection#Formulas */ - public fun toMercator(gmc: GeodeticMapCoordinates, zoom: Double): WebMercatorCoordinates { + public fun toMercator(gmc: GeodeticMapCoordinates, zoom: Int): WebMercatorCoordinates { require(abs(gmc.latitude) <= MercatorProjection.MAXIMUM_LATITUDE) { "Latitude exceeds the maximum latitude for mercator coordinates" } - val scaleFactor = scaleFactor(zoom) + val scaleFactor = scaleFactor(zoom.toDouble()) return WebMercatorCoordinates( - zoom = floor(zoom).toInt(), + zoom = zoom, x = scaleFactor * (gmc.longitude.radians.value + PI), y = scaleFactor * (PI - ln(tan(PI / 4 + gmc.latitude.radians.value / 2))) )