p-lr / MapView

A Fast, memory efficient Android library to display tiled maps, with support for markers, paths, and rotation.
Apache License 2.0
184 stars 38 forks source link

Help needed for displaying single image from Remote #1

Closed shriharsha-bhagwat closed 4 years ago

shriharsha-bhagwat commented 4 years ago

Thanks for the wonderful library. I have used old java tileview library and now happy to use improved Kotlin version of it. I need one help with respect to displaying of a single image from remote. I just have a single image of size 1200 900. I would like to display it with zooming enabled. How would i configure it without using deep-zoom map.
My image : http://androidbash.com/data/floor1.jpg I tried following config and i am unable to load the map. var tileSize = 1200 val config = MapViewConfiguration( 1, 1200, 900, tileSize, tileStreamProvider ).setMaxScale(4f).setPadding(tileSize
2).setWorkerCount(16)

p-lr commented 4 years ago

First, you need to make a deep-zoom map from your 1200*900 image. To do that, you can follow this tutorial.

Then, the configuration should be:

val tileSize = 256
val config = MapViewConfiguration(
            4, 1200, 900, tileSize, tileStreamProvider
        ).setMaxScale(2f).setPadding(tileSize * 2).setWorkerCount(16)

I've done it myself, I get 4 levels: image

If you need more help don't hesitate.

p-lr commented 4 years ago

Then, you will have to define a TileStreamProvider. This is the component which knows how to fetch tiles. It's implementation depends on the location of the tiles (are they in the app assets, on internal memory, or on remote server).

Assuming you will want those tiles to be served by your http server which hosts your website, then this implementation could look like this:

val tileStreamProvider = object : TileStreamProvider {
            override fun getTileStream(row: Int, col: Int, zoomLvl: Int): InputStream? {
                return try {
                    val url = URL("http://androidbash.com/data/floor/$zoomLvl/$row/$col.jpg")
                    val connection = createConnection(url)
                    connection.connect()
                    BufferedInputStream(connection.inputStream)
                } catch (e: Exception) {
                    null
                }
            }

            fun createConnection(url: URL): HttpURLConnection {
                val connection = url.openConnection() as HttpURLConnection
                connection.doInput = true
                return connection
            }
        }
shriharsha-bhagwat commented 4 years ago

Thanks for such a quick response. I really appreciate it.

Yes after creating deep zoom map it works perfectly. But Can i display the map/image without creating deep-zoom map i.e just with single image as in the above link?

I was doing it in Tileview old java version with following code :

    String encodedImage = imageData.getFile().getBody();
    String decodedString = Base64.decode(encodedImage, Base64.DEFAULT);

    tileView.setSize(1200, 900);
    tileView.addDetailLevel(1.000f, decodedString, 1200, 900);
    tileView.setMarkerAnchorPoints(-0.5f, -0.5f);
    tileView.setBitmapProvider(new BitmapProviderInternalStorage());
    tileView.setScaleLimits(0, 2f);

Is there something similar i can do in this?

p-lr commented 4 years ago

You have to "tile" your image somehow, as MapView (and also TileView in its latest version) only supports squared tiles, and your image is rectangular. As an alternative, you can only take the last level (folder number 3), rename it to 0 and delete the others. Then, in your configuration:

val tileSize = 256
val config = MapViewConfiguration(
            1, 1200, 900, tileSize, tileStreamProvider
        ).setMaxScale(2f).setPadding(tileSize * 2)

Of course, your TileStreamProvider should be adapted. This way, you will see your image only at its full resolution while still leveraging the benefits of MapView.

shriharsha-bhagwat commented 4 years ago

Yes you are right. I understood now. Also one last thing. If you know any sample for indoor map and navigation using tileview please provide a link.

Thanks for helping out. Great work :)

p-lr commented 4 years ago

An example of app using MapView is TrekMe (my own app).

But if your question was really about TileView, again TrekMe, but the trekadvisor branch. Indeed, I used TileView but recently switched the app to use MapView. To save you from looking for the needle in haystack, here's a direct link of a real life TileView usage in trekadvisor branch: https://github.com/peterLaurence/TrekMe/blob/431bf08c2b47e00e1b16288899386d288fd80249/app/src/main/java/com/peterlaurence/trekadvisor/menu/mapview/MapViewFragment.java#L461

shriharsha-bhagwat commented 4 years ago

Okay i observing something in demo project as well as in mine. In RemoteHttpFragment, it will load initially well (First Image).

Then if i go to background and come back (i.e onResume) it is not loading properly. (Second Image)

What do you think is the cause? For now I have resolved it by modifying the initialization of mapView as done in MapPathsFragment.

Screenshot_20191122-095134

Screenshot_20191122-095142

p-lr commented 4 years ago

Good catch! It's in fact a misuse of MapView, which I mistakenly did inside some of the demos. The MapMarkersFragment and MapPathFragment weren't affected though.

I updated the demos to show proper usage, and it's fixed now. The issue were that the configuration was done inside onStart(). But onStart is called everytime the app regains focus after being in background (it's called right before onResume). So the existing MapView was reconfigured. And this is bad - by design, a MapView shoul'dnt be configured twice, or it should be destroyed by calling MapView.destroy(), then re-created and configured. The recommended way is to configure the MapView inside onCreate - see the updated demos for that. If you absolutely need to configure after onCreate, I suggest you take a look at DeferredFragment.

So I updated the demo and added a safeguard in the library. If we configure the MapView multiple times, we get an IllegalStateException with a message indicating the problem. This safeguard will be shipped in the next version.

shriharsha-bhagwat commented 4 years ago

Thanks for such quick replies and such quick updates.

You can close the issue as it is fixed :)