Skip to content

xy_bbox does not consider cornerOfOrigin #193

@claxn

Description

@claxn

When requesting the xy_bbox property from a TileMatrixSet instance with cornerOfOrigin="bottomLeft", top and bottom of the bounding box are flipped. There is probably a bug in xy_bbox, since it does not consider the cornerOfOrigin. The following lines need to consider the right tile indices, depending on cornerOfOrigin:

https://github.com/developmentseed/morecantile/blob/main/morecantile/models.py#L1262-L1266

Here is a MWE with a walkthrough of the issues:

from morecantile.models import TileMatrixSet, Tile
import pyproj

extent = [-100_000, -100_000, 200_000, 200_000]
tms = TileMatrixSet.custom(
            extent,
            pyproj.CRS.from_epsg(3857),
            minzoom=0,
            maxzoom=1,
            corner_of_origin="bottomLeft",
        )

The expected bounding box is BoundingBox(left=-100000.0, bottom=-100000.0, right=200000.0, top=200000.0), but the result is flipped in y:

tms.xy_bbox
BoundingBox(left=-100000.0, bottom=200000.0, right=200000.0, top=-100000.0)

This is due to two reasons. First, tms._lr and tms._ul return the wrong coordinates for y:

tms._ul(Tile(0, 0, 0)).y, tms._lr(Tile(0, 0, 0)).y 
(-100000.0, 200000.0)

xy_bounds of a tile is correct:

tms.xy_bounds(Tile(0, 0, 0))
BoundingBox(left=-100000.0, bottom=-100000.0, right=200000.0, top=200000.0)

The first issue is because there is a wrong index in the coordinate computation:

https://github.com/developmentseed/morecantile/blob/main/morecantile/models.py#L1123

https://github.com/developmentseed/morecantile/blob/main/morecantile/models.py#L1158

This should be the same as in xy_bounds, which means:

origin_y + (t.y + 1) * matrix.cellSize * matrix.tileHeight in tms._ul and origin_y + t.y * matrix.cellSize * matrix.tileHeight in tms._lr.

The second issue is, that tms.xy_bbox uses the wrong tile to compute the bounding box of the tms:

https://github.com/developmentseed/morecantile/blob/main/morecantile/models.py#L1262-L1266

This needs to be adjusted to:

if matrix.cornerOfOrigin == "topLeft":
    left, top = self._ul(Tile(0, 0, zoom))
    right, bottom = self._lr(Tile(matrix.matrixWidth - 1, matrix.matrixHeight - 1, zoom))
else:
    left, top = self._ul(Tile(0, matrix.matrixHeight - 1, zoom))
    right, bottom = self._lr(Tile(matrix.matrixWidth - 1, 0, zoom))

I hope I am not misunderstanding sth. here - please let me know if you require further inputs from my side. Maybe it would be also a good idea to cross-compare bounds in new tests, e.g.: tms._lr(Tile(0, 0, 0)).y == tms.xy_bounds(Tile(0, 0, 0)).bottom

Thank you in advance!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions