p-lr / MapCompose

A fast, memory efficient Jetpack Compose library to display tiled maps, with support for markers, paths, and rotation.
Apache License 2.0
220 stars 19 forks source link

Zoom not work #103

Closed lamanovpv closed 9 months ago

lamanovpv commented 9 months ago

Level sampling does not work when zooming if you specify a depth greater than 4

p-lr commented 9 months ago

Could you make a fork of the demo that illustrate the problem?

lamanovpv commented 9 months ago

https://github.com/p-lr/MapCompose/assets/79468198/9bb6219a-ab33-4b50-af47-cbb71bf31300

In MapState levelCount=4

https://github.com/p-lr/MapCompose/assets/79468198/183b4c47-c213-423e-9f3d-bb93a0f32992

In MapState levelCount=8

I get tiles from "https://tile3.maps.2gis.com/tiles?v=1.3&x=$col&y=$row&z=$zoomLvl" In mapsforge map with tiles from this link work correctly. Also with big level count we can't see other tiles.

p-lr commented 9 months ago

You probably didn't set the appropriate map size. You're rendering a map using WMTS format. Each level has a specific size. The size you have to specify is the size of the highest level, which is tileSize * 2.pow(lvlCnt - 1). This works:

/**
 * Shows how MapCompose behaves with remote HTTP tiles.
 */
class HttpTilesVM : ViewModel() {
    private val tileStreamProvider = makeTileStreamProvider()

    private val lvlCnt = 8
    private val mapSize = mapSizeAtLevel(lvlCnt - 1, tileSize = 256)
    val state: MapState by mutableStateOf(
        MapState(lvlCnt, mapSize, mapSize, workerCount = 16).apply {
            addLayer(tileStreamProvider)
            scale = 0f
            shouldLoopScale = true
        }
    )
}

/**
 * A [TileStreamProvider] which performs HTTP requests.
 */
private fun makeTileStreamProvider() =
    TileStreamProvider { row, col, zoomLvl ->
        try {
            val url = URL("https://tile3.maps.2gis.com/tiles?v=1.3&x=$col&y=$row&z=$zoomLvl")
            val connection = url.openConnection() as HttpURLConnection
            connection.doInput = true
            connection.connect()
            BufferedInputStream(connection.inputStream)
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

/**
 * wmts level are 0 based.
 * At level 0, the map corresponds to just one tile.
 */
private fun mapSizeAtLevel(wmtsLevel: Int, tileSize: Int): Int {
    return tileSize * 2.0.pow(wmtsLevel).toInt()
}
rt-bishop commented 9 months ago

Hey @lamanovpv! It's not the zoom related issue but rather the tile scaling one. The docs state that fullWidth, fullHeight set the size of the map in pixels at scale 1f. To me that means if I want to increase the maximum levels in "tiles pyramid" I also need to tweak those parameters to align with the level. That should fix the behaviour you get.

The docs suggest these values as initial setup: val state: MapState by mutableStateOf(MapState(4, 4096, 4096).apply {...}

My code has these values and it works fine with OSM tiles: val state: MapState by mutableStateOf(MapState(6, 8192, 8192).apply {...}

It seems that for every two levels you double the fullWidth, fullHeight. Just experiment and you'll find the matching values.

lamanovpv commented 9 months ago

Thanks for your quick replies! I'll test this.