ngageoint / geopackage-android

GeoPackage Android Library
http://ngageoint.github.io/geopackage-android
MIT License
94 stars 32 forks source link

X/Y Offset in TileRetriever.getTile() #61

Closed b3nn0 closed 4 years ago

b3nn0 commented 4 years ago

Hi, I‘m using this library (v3.4.0) to display a fairly large GeoPackage file on Android (Samsung Galaxy A50 with OSMDroid, but not with osmdroid-geopackage, as that was not flexible enough for me). The GeoPackage File is in EPSG:3857 and was generated with GDAL. The Tilematrix overviews were built with gdaladdo.

When viewing the file with a gdal-based application (e.g. Qgis), everything is fine. However, on Android with this library, the file is slightly shifted in X direction. E.g. when using TileRetriever.getTile(551010, 365532, 20) with a tile size of 627x627. This translates to this bounding box (taken from the Android Debugger inside getTile()):

minLongitude=1021275.134918239
minLatitude=6067380.212706579
maxLongitude=1021313.3534323834
maxLatitude=6067418.431220721

The resulting Tile from android is this: android_result

Trying the same with gdal: gdal_translate -projwin 1021275.134918239 6067418.431220721 1021313.3534323834 6067380.212706579 -outsize 672 672 -of PNG in.gpkg out.png gdal_result

The code is not much more than the a standard OSMDroid tile provider. Basically:

        int zoom = MapTileIndex.getZoom(pMapTileIndex);
        int x = MapTileIndex.getX(pMapTileIndex);
        int y = MapTileIndex.getY(pMapTileIndex);
        GeoPackageTile geoPackageTile = tileRetriever.getTile(x, y, zoom);

Is there anything I‘m doing wrong? I‘m fairly certain, that the issue is in geopackage-android, not in GDAL. Reason: When I‘m going outside with a centimeter-precise RTK GPS, I‘m seeing the same offset when the underlying map is drawn with geopackage-android.

Tile matrix of the input image:

sqlite> select * from gpkg_tile_matrix; 
table_name|zoom_level|matrix_width|matrix_height|tile_width|tile_height|pixel_x_size|pixel_y_size 
tiles|0|1|1|256|256|152.455059500864|152.455059500864 
tiles|1|2|2|256|256|76.2275297504321|76.2275297504321 
tiles|2|3|3|256|256|38.1137648752161|38.1137648752161 
tiles|3|5|5|256|256|19.056882437608|19.056882437608 
tiles|4|10|10|256|256|9.52844121880402|9.52844121880402 
tiles|5|20|20|256|256|4.76422060940201|4.76422060940201 
tiles|6|40|40|256|256|2.382110304701|2.382110304701 
tiles|7|79|79|256|256|1.1910551523505|1.1910551523505 
tiles|8|157|157|256|256|0.595527576175251|0.595527576175251 
tiles|9|313|314|256|256|0.297763788087625|0.297763788087625 
tiles|10|626|628|256|256|0.148881894043813|0.148881894043813

EDIT: Note that the offset seems to be absolute in terms of world coordinates. I.e. when zooming out, everything is still shifted in the same way (the same "amount of meters"). Only when zooming out even further into the next overview in the tile matrix, there is a sudden jump (and it then again stays the same offset for the complete zoom-range for that overview).

EDIT2: Just noticed the same with other geo package files, too. However, it's not always in x-direction. For some files, there is an y-shift. All files were created with gdal.

bosborn commented 4 years ago

The bounds taken from the debugger for that tile appear correct.

From a tile server perspective the GDAL one lines up, however the GeoPackage appears to have an issue.

http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x=551010&y=365532&z=20 image

Without seeing your GeoPackage or visibility into the Tile Matrix Set table "tiles" row, the Tile Matrix still looks off. The pixel sizes between zoom levels are a factor of 2 which is common. The matrix width and height however are not. So at zoom 1 you have a width of 2 matrix width * 256 tile width * 76.2275297504321 pixel x size = 39028.4952322 Which is a different width from zoom 2 3 matrix width * 256 tile width * 38.1137648752161 pixel x size = 29271.3714242

Each tile matrix shares the same width (and height) as defined in the Tile Matrix Set row. So this violates the following requirement.

Requirement 45

The width of a tile matrix (the difference between min_x and max_x in gpkg_tile_matrix_set) SHALL equal the product of matrix_width, tile_width, and pixel_x_size for that zoom level. Similarly, height of a tile matrix (the difference between min_y and max_y in gpkg_tile_matrix_set) SHALL equal the product of matrix_height, tile_height, and pixel_y_size for that zoom level.

All tile matrix zoom levels share the same tile matrix set bounds. So with a factor of 2 pixel change between zoom levels, the tile matrix width and height should double (even though tiles are not required to exist in all locations). Assuming zoom 0 is correct, the matrix width and height at zoom 10 should be 1024 x 1024.

See this example

So I'm not sure if the bug is in the GDAL creation. I pointed out a related bug to @rouault which he fixed on Feb 22, 2017. https://trac.osgeo.org/gdal/ticket/6826

b3nn0 commented 4 years ago

Oh wow, thank your for your insight, I think you are right. I shared the load to create all my GPKGs between two different servers. One running gdal 2.4.2, the other one running 2.1.2. I'm not sure which one created which GPKG, but looking at it, I find several files having the issue you describe, and several other that are fine. So I assume that the issue is in the files created with gdal 2.1.2. Which would make sense, since the bug you referenced was only fixed in 2.1.4.

I will recreate the affected files with gdal 2.4.2 and report back if that itself fixes the issue.

b3nn0 commented 4 years ago

Alright, instead of recreating all the GeoPackage files, which would take a couple of days, I just created a quick python scripts that corrects the entries in the tile matrix. That seems to have solved the issue for me. Thanks again.