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

Non-existent zoom on an overlay. #33

Closed ravenfeld closed 2 years ago

ravenfeld commented 2 years ago

Hi, I try to display a background with an overlay, if the 2 have the same zoom availability I have no problem but I would like that if one of the 2 maps does not have a zoom that it continues to be displayed but with the old zoom. The problem is that I do the overlay in getTileStream, maybe it's a mistake? Can we find the previous zoom and row and col value in the getTileStream method? I'm using a tile database and I don't have all the zoom so you can understand my request better.

Thank you in advance for your response

In french

Bonjour, j’essai d’afficher un fond avec une sur-couche. Si les 2 ont la même disponibilité de zoom je n’ai pas de souci mais j’aimerais que si l’une des 2 cartes n’a pas un zoom qu’elle continue a s’afficher mais avec l’ancien zoom. Le problème est peut etre lié au faite que je fais la sur couche dans getTileStream c’est peut être une erreur ? Peut on trouver le zoom précédent et la valeur row et col dans la méthode getTileStream ? J'utilise une base de donnée de tuile et je n'ai pas tout le zoom pour que tu comprennes mieux ma demande.

Merci d'avance de votre réponse

p-lr commented 2 years ago

Hi,

I'm not sure I follow, even though I get a sense of what you're trying to achieve. MapView automatically subsamples tiles when zooming out, so even if tiles aren't available at low scale, tiles from the last available level are rendered (and subsampled). However, MapView does not fill gaps between levels themselves. About overlaying, it looks like you did well by implementing that inside the TileStreamProvider, since MapView can only have one TileStreamProvider.

Perhaps you could fork the project, edit one of the demos and showcase the problem you're having? It would be much easier for me to provide advice.

P.S: I'm french, yes, but we can communicate in English (so that other people understand this conversation).

ravenfeld commented 2 years ago

I'm trying to render via a sqlite tile database. Except I didn't put all the zooms. I would like to have no white area when a zoom is not available. I have the problem as soon as I move the map. In the demo if you delete the zoom 3 directory and the requests are on this zoom you will have only a white card when moving.

p-lr commented 2 years ago

Taking your example, if we zoom in from level 0 to 4 (while level 3 is non existent), we should be able to see the level 2 before loading the level 4. Is that what you mean?

ravenfeld commented 2 years ago

If you only zoom in, no problem, zoom 2 stays in until you have zoom 4. The problem is if we go from 4 to 3 and move the map. I have this problem because the tiles of zoom 2 are not called nor zoom 4, so until I search a known zoom the map will not load anything. device-2022-01-04-074956

p-lr commented 2 years ago

Alright, it's clear now. FWIW, a proper way to handle missing levels (or "level gaps") is to subsample tiles from the next reachable level. The reason is: imagine you have levels 1 to 10 and levels 2 to 9 are missing. When zooming in from level 1, and when tiles from level 2 should be loaded, suddenly loading tiles from level 10 would result in loading way too many tiles (hundreds, or thousands). The result would be an out of memory error (OOM). MapView does subsampling, but only when zooming out, and using tiles from the lowest level. Enabling subsampling for level gaps is absolutely not a trivial task, and is actually a dramatic design shift. However, I believe it's acceptable to relax the current policy and allow for a gap of one level and no more. That would fix your use case, but I wouldn't allow for two consecutive levels to be missing as the risk of OOM is too great.

ravenfeld commented 2 years ago

Or maybe a mapView configuration where we give the available zoom levels? If the zoom 3 does not exist we recover the level 2. I did not understand well, you say that it is already done but why zoom 3 does not recover zoom 2 when you move the map? I may have forgotten a configuration.

p-lr commented 2 years ago

Or maybe a mapView configuration where we give the available zoom levels?

MapView wasn't designed for that. It's built with the assumption that there are no missing levels. Consequently, changing how tiles are requested based on missing levels doesn't fit with the current logic. Making exceptions for a custom configuration would complicate things and I'm afraid I'm not willing to do this. Is one missing level not enough ?

p-lr commented 2 years ago

Actually, as I'm thinking about it, I realized that what I suggested about tolerating one missing level would only be a workaround for zooming out. It wouldn't work when panning, as only tiles from the current level would be requested. Well... your issue requires a major design change. Maybe one day I'll have time to do this. But in the meantime, I guess your best bet is to fill the gaps.

ravenfeld commented 2 years ago

ok, I use OSMAnd and it handles this lack concern well, I'll look at how they did it. Because for the moment I can't modify the lib to have a good return.

ravenfeld commented 2 years ago

If you have any idea how to get the tile from the level out I'm interested, I've done some things that don't work now and I don't have much idea. Or if you know a lib that can meet my needs. Because to recover all the zoom while some are just zoom of the lower level it is a pity and so I did not recover all to not have a huge database.

p-lr commented 2 years ago

Imagine you have missing level n, but you have level n + 1. Each tile from level n is made of 4 tiles of level n + 1 which form a square. If tiles are 256 px wide, the square is 512 px wide. Then, the square is subsampled to make a tile of 256 px wide. It can be done iteratively. You can make level n from n+1, then level n-1 from level n.

Alternatively, if you start from a huge image, you can tile it and generate all intermediary levels using libvips. See this tutorial.

ravenfeld commented 2 years ago

I understood the principle but when I ask for zoom 3 col 5 row 4 I can't find the values for zoom 2 of col and row

ravenfeld commented 2 years ago

I don't see how getting the lower zoom will make a memory error since the image is smaller.

p-lr commented 2 years ago

A tile from level n, with row i and col j, noted Tile(n, i, j) corresponds to 4 tiles at level n + 1: Tile(n+1, 2i, 2j) Tile(n+1, 2i + 1, 2j) Tile(n+1, 2i, 2j + 1) Tile(n+1, 2i + 1, 2j + 1)

I don't see how getting the lower zoom will make a memory error since the image is smaller.

MapView does not look for lower levels, be cause it wasn't designed for missing levels.

ravenfeld commented 2 years ago

In the zoom direction I understood well but from zoom 3 to know the zoom 2 tile I can not. I understand that it doesn't work now, I'm trying to modify it so that it works.

p-lr commented 2 years ago

Well the formula is all there. You have to treat tiles from level n+1 four by four, starting from the upper left corner, and generate tiles for the lower level.

ravenfeld commented 2 years ago

We don't understand each other, I try to do this. Tile(n+1, 2i, 2j) => Tile(n, i, j) Tile(n+1, 2i + 1, 2j) => Tile(n, i, j) Tile(n+1, 2i, 2j + 1) => Tile(n, i, j) Tile(n+1, 2i + 1, 2j + 1) => Tile(n, i, j)

p-lr commented 2 years ago

You got it. Start from the upper left corner of level n+1:

Tile(n, 0, 0):

Tile(n, 0, 1):

And so on.

ravenfeld commented 2 years ago

Je passe en francais, nous nous sommes pas compris. je ne veux pas trouver les tuiles du zoom plus precis mais du zoom inférieur. Mon idée c'est que si j'ai pas le zoom precis j'affiche le zoom moins precis. Du coup quand le woker demande la tuile zoom 3 si je la trouve pas je demande la tuile zoom 2 pas la tuile zoom 4 qui comme tu l'as dit demandera beaucoup de ressource.

p-lr commented 2 years ago

Ce n'est malheureusement pas possible avec MapView, à moins de modifier la lib en profondeur. Le plus simple, quand on a la main sur les données, est de générer les niveaux manquants avec les formules au dessus.

ravenfeld commented 2 years ago

Thanks a lot, I'll see if I can do something. If not, I'll see if there are other libs.