Search code examples
mapboxmbtilestippecanoe

Incorrect coordinates in mbtiles generated with Tippecanoe


I generated an mbtiles file using Tippecanoe with just -zg and --drop-densest-as-needed as extra parameters. I uploaded the file to Mapbox Studio and everything works well, both in Studio and when loading the tiles through a mobile app.

I then tried my luck at self-hosting the tiles, using a very basic HTTP server in Go. Tiles were transferred from SQLite to a PostgreSQL database (the reason for this is Go + PSQL is the existing stack for the app).

For some reason the features are shifted depending on the zoom level. At level 1, data that's supposed to be in the US is in the Antarctic, at zoom level 2 it's off the coast of Chile, etc. The only one properly working is level 0 as there's only one tile.

I checked what tiles Mapbox was requesting when in San Francisco for zoom level 11: column 327, row 791. No tile exists for this row/col combination in the .mbtiles file although there's data there.

Is there additional things to be done to the mbtiles besides looking them up in the database using the z/x/y? Or maybe stuff to configure on the app side?

Server code:

row := db.QueryRow(`
    SELECT tile_data FROM tiles
    WHERE
        zoom_level = $1
        AND tile_column = $2
        AND tile_row = $3
    `,
    z, x, y,
)

On Android:

map.addSource(
        VectorSource(
                "tiles",
                TileSet("2.2.0", "http://my.local.server:4000/tiles/{z}/{x}/{y}.mvt?key=2448A697EACDDC41432AAD9A1833E")
        )
)

I tried setting the VectorSource's center and bounds found in the mbtiles metadata but it didn't change anything.


Solution

  • So I looked into existing server implementations and it turns out the offset is because the mbtiles are stored in a TMS format in which the Y coordinate is flipped. So we just need to convert the Y from the XYZ format to get the proper tile:

    From Mapbox's own Node implementation:

    // Flip Y coordinate because MBTiles files are TMS.
    y = (1 << z) - 1 - y;
    

    1 << z is the number of rows for a given zoom level, or two to the power of z.

    More info about XYZ vs TMS can also be found here.