Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route path - drawing issue #121

Open
DenisDemyanko opened this issue Oct 24, 2024 · 5 comments
Open

Route path - drawing issue #121

DenisDemyanko opened this issue Oct 24, 2024 · 5 comments

Comments

@DenisDemyanko
Copy link

DenisDemyanko commented Oct 24, 2024

Hello, how to fix this problem with displaying the route path?
I added a route, when the map is zoomed out, the route is displayed fine, but when the map is zoomed in, I have problems displaying the path.

I tried adding a simplify parameter in the add Path method, but nothing changed.

      state.addPath(
            id = "route",
            color = color,
            zIndex = Float.MAX_VALUE - 3,
        ) {
            addPoints(coordinates)
        }

Thanks.

Screenshot 2024-10-24 at 18 35 36 Screenshot 2024-10-24 at 18 35 46
@DenisDemyanko DenisDemyanko changed the title Route lines issue Route path - drawing issue Oct 24, 2024
@p-lr
Copy link
Owner

p-lr commented Oct 24, 2024

It looks like the route is made of a series of paths, because the route isn't continuous. Perhaps some addPath calls are missing.
Can you reproduce the issue in a fork of the demo app?

@DenisDemyanko
Copy link
Author

DenisDemyanko commented Oct 24, 2024

It looks like the route is made of a series of paths, because the route isn't continuous. Perhaps some addPath calls are missing.
Can you reproduce the issue in a fork of the demo app?

I use OSM for tiles.
I added paths in your demo project in OsmVM.

I have an array of coordinates, like a route (file attached) - coordinates.txt
P.s - this is a real bike route

I convert the coordinates to points and get an array of points.
Then I pass these points to the route construction method.

class OsmVM : ScreenModel {

    val MAP_X_0 = -2.0037508342789248E7

    private val tileStreamProvider = makeOsmTileStreamProvider()

    private val maxLevel = 19
    private val minLevel = 10

    private val mapSize = mapSizeAtLevel(maxLevel, tileSize = 256)
    private val coordinates: MutableList<Pair<Double, Double>> = mutableListOf()

    private val route = arrayListOf<Pair<Double, Double>>()

    val state = MapState(levelCount = maxLevel + 1, mapSize, mapSize, workerCount = 16) {
        minimumScaleMode(Forced((1 / 2.0.pow(maxLevel - minLevel)).toFloat()))
    }.apply {
        addLayer(tileStreamProvider)
        scale = 0f  // to zoom out initially
    }

    init {
        screenModelScope.launch {
            setRoute()
        }
    }

    private suspend fun setRoute() {
        readCoordinatesArrayFromFile()
        route.forEach { coordinate ->
            val latitude = coordinate.first
            val longitude = coordinate.second
            val (X, Y) = doProjection(latitude, longitude)
            val x = normalize(X, min = MAP_X_0, max = -MAP_X_0)
            val y = normalize(Y, min = -MAP_X_0, max = MAP_X_0)
            coordinates.add(Pair(x, y))
        }

        state.addPath(
            id = "route",
            color = Color.Red
        ) {
            addPoints(coordinates)
        }
        state.scrollTo(coordinates[0].first, coordinates[0].second)
    }


    @OptIn(ExperimentalResourceApi::class)
    private suspend fun readCoordinatesArrayFromFile() {
        val lines = Res.readBytes("files/tracks/coordinates.txt").decodeToString().lineSequence()
        for (line in lines) {
            val values = line.split(',').map(String::toDouble)
            route.add(Pair(values[0], values[1]))
        }
    }

    private fun doProjection(latitude: Double, longitude: Double): Pair<Double, Double> {
        if (abs(latitude) > 90 || abs(longitude) > 180) {
            return Pair(0.0, 0.0)
        }
        val num = longitude * 0.017453292519943295 // 2*pi / 360
        val x = 6378137.0 * num
        val a = latitude * 0.017453292519943295
        val y = 3189068.5 * ln((1.0 + sin(a)) / (1.0 - sin(a)))

        return Pair(x, y)
    }

    private fun normalize(t: Double, min: Double, max: Double): Double {
        return (t - min) / (max - min)
    }

}

Result:

Screenshot 2024-10-24 at 22 08 27 Screenshot 2024-10-24 at 22 08 56

@DenisDemyanko
Copy link
Author

Also, video attached.

Screen.Recording.2024-10-24.at.22.19.42.mp4

@p-lr
Copy link
Owner

p-lr commented Oct 24, 2024

Oh you're using MapComposeMP. You posted the issue on the Android native version, which is probably not affected by this issue. Nevertheless I'll have a look.

@p-lr
Copy link
Owner

p-lr commented Oct 25, 2024

It looks like there is a precision issue. When the map size is too big, converting coordinates from Double to Float (as required by the underlying drawing api) causes a precision loss.
This can be mitigated by reducing the map size.

With using:

private val maxLevel = 16
[...] 
// notice the max scale change
val state = MapState(levelCount = maxLevel + 1, mapSize, mapSize, workerCount = 16) {
        minimumScaleMode(Forced((1 / 2.0.pow(maxLevel - minLevel)).toFloat()))
        maxScale(4f)
    }.apply {
        addLayer(tileStreamProvider)
        scale = 0f  // to zoom out initially
    }
[...]

The are no more holes in the route when zooming in. FWIW, I tested on an android device.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants