From 3a8bed8f610f8c5bcfb732bdbe86014046484a94 Mon Sep 17 00:00:00 2001 From: vincentsarago Date: Wed, 16 Oct 2024 23:50:48 +0200 Subject: [PATCH] revert and update xy_bounds and bounds methods --- morecantile/models.py | 77 +++++++++++++++++++++++++-------------- morecantile/utils.py | 1 - tests/test_models.py | 2 +- tests/test_morecantile.py | 15 +++++--- 4 files changed, 60 insertions(+), 35 deletions(-) diff --git a/morecantile/models.py b/morecantile/models.py index d9cd26f..84bcd08 100644 --- a/morecantile/models.py +++ b/morecantile/models.py @@ -487,14 +487,15 @@ class TileMatrixSet(BaseModel, arbitrary_types_allowed=True): # Private attributes _to_geographic: pyproj.Transformer = PrivateAttr() _from_geographic: pyproj.Transformer = PrivateAttr() - _tile_matrices_idx: Dict[str, int] = PrivateAttr() + + _tile_matrices_idx: Dict[int, int] = PrivateAttr() def __init__(self, **data): """Set private attributes.""" super().__init__(**data) self._tile_matrices_idx = { - mat.id: idx for idx, mat in enumerate(self.tileMatrices) + int(mat.id): idx for idx, mat in enumerate(self.tileMatrices) } try: @@ -770,7 +771,7 @@ def custom( def matrix(self, zoom: int) -> TileMatrix: """Return the TileMatrix for a specific zoom.""" - if (idx := self._tile_matrices_idx.get(str(zoom), None)) is not None: + if (idx := self._tile_matrices_idx.get(zoom, None)) is not None: return self.tileMatrices[idx] ####################################################################### @@ -1025,58 +1026,61 @@ def tile( x, y = self.xy(lng, lat, truncate=truncate) return self._tile(x, y, zoom, ignore_coalescence=ignore_coalescence) - def _ul(self, tile: Tile) -> Coords: + def _ul(self, *tile: Tile) -> Coords: """ Return the upper left coordinate of the tile in TMS coordinate reference system. Attributes ---------- - tile: Tile object we want the upper left coordinates of. + tile: (x, y, z) tile coordinates or a Tile object we want the upper left coordinates of. Returns ------- Coords: The upper left coordinates of the input tile. """ - matrix = self.matrix(tile.z) + t = _parse_tile_arg(*tile) + + matrix = self.matrix(t.z) origin_x, origin_y = self._matrix_origin(matrix) cf = ( - matrix.get_coalesce_factor(tile.y) + matrix.get_coalesce_factor(t.y) if matrix.variableMatrixWidths is not None else 1 ) return Coords( - origin_x - + math.floor(tile.x / cf) * matrix.cellSize * cf * matrix.tileWidth, - origin_y - tile.y * matrix.cellSize * matrix.tileHeight, + origin_x + math.floor(t.x / cf) * matrix.cellSize * cf * matrix.tileWidth, + origin_y - t.y * matrix.cellSize * matrix.tileHeight, ) - def _lr(self, tile: Tile) -> Coords: + def _lr(self, *tile: Tile) -> Coords: """ Return the lower right coordinate of the tile in TMS coordinate reference system. Attributes ---------- - tile: Tile object we want the lower right coordinates of. + tile: (x, y, z) tile coordinates or a Tile object we want the lower right coordinates of. Returns ------- Coords: The lower right coordinates of the input tile. """ - matrix = self.matrix(tile.z) + t = _parse_tile_arg(*tile) + + matrix = self.matrix(t.z) origin_x, origin_y = self._matrix_origin(matrix) cf = ( - matrix.get_coalesce_factor(tile.y) + matrix.get_coalesce_factor(t.y) if matrix.variableMatrixWidths is not None else 1 ) return Coords( origin_x - + (math.floor(tile.x / cf) + 1) * matrix.cellSize * cf * matrix.tileWidth, - origin_y - (tile.y + 1) * matrix.cellSize * matrix.tileHeight, + + (math.floor(t.x / cf) + 1) * matrix.cellSize * cf * matrix.tileWidth, + origin_y - (t.y + 1) * matrix.cellSize * matrix.tileHeight, ) def xy_bounds(self, *tile: Tile) -> BoundingBox: @@ -1094,40 +1098,59 @@ def xy_bounds(self, *tile: Tile) -> BoundingBox: """ t = _parse_tile_arg(*tile) - left, top = self._ul(t) - right, bottom = self._lr(t) + matrix = self.matrix(t.z) + origin_x, origin_y = self._matrix_origin(matrix) + + cf = ( + matrix.get_coalesce_factor(t.y) + if matrix.variableMatrixWidths is not None + else 1 + ) + + left = origin_x + math.floor(t.x / cf) * matrix.cellSize * cf * matrix.tileWidth + top = origin_y - t.y * matrix.cellSize * matrix.tileHeight + right = ( + origin_x + + (math.floor(t.x / cf) + 1) * matrix.cellSize * cf * matrix.tileWidth + ) + bottom = origin_y - (t.y + 1) * matrix.cellSize * matrix.tileHeight + return BoundingBox(left, bottom, right, top) - def ul(self, tile: Tile) -> Coords: + def ul(self, *tile: Tile) -> Coords: """ Return the upper left coordinates of the tile in geographic coordinate reference system. Attributes ---------- - tile (Tile): Tile object we want the upper left geographic coordinates of. + tile (tuple or Tile): (x, y, z) tile coordinates or a Tile object we want the upper left geographic coordinates of. Returns ------- Coords: The upper left geographic coordinates of the input tile. """ - x, y = self._ul(tile) + t = _parse_tile_arg(*tile) + + x, y = self._ul(t) return Coords(*self.lnglat(x, y)) - def lr(self, tile: Tile) -> Coords: + def lr(self, *tile: Tile) -> Coords: """ Return the lower right coordinates of the tile in geographic coordinate reference system. Attributes ---------- - tile (Tile): Tile object we want the lower right geographic coordinates of. + tile (tuple or Tile): (x, y, z) tile coordinates or a Tile object we want the lower right geographic coordinates of. Returns ------- Coords: The lower right geographic coordinates of the input tile. """ - x, y = self._lr(tile) + t = _parse_tile_arg(*tile) + + x, y = self._lr(t) return Coords(*self.lnglat(x, y)) def bounds(self, *tile: Tile) -> BoundingBox: @@ -1143,10 +1166,10 @@ def bounds(self, *tile: Tile) -> BoundingBox: BoundingBox: The bounding box of the input tile. """ - t = _parse_tile_arg(*tile) + _left, _bottom, _right, _top = self.xy_bounds(*tile) + left, top = self.lnglat(_left, _top) + right, bottom = self.lnglat(_right, _bottom) - left, top = self.ul(t) - right, bottom = self.lr(t) return BoundingBox(left, bottom, right, top) @property diff --git a/morecantile/utils.py b/morecantile/utils.py index da98fe3..5da80cb 100644 --- a/morecantile/utils.py +++ b/morecantile/utils.py @@ -32,7 +32,6 @@ def _parse_tile_arg(*args) -> Tile: """ if len(args) == 1: args = args[0] - if len(args) == 3: return Tile(*args) else: diff --git a/tests/test_models.py b/tests/test_models.py index 9e51da9..c1a84ca 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -384,7 +384,7 @@ def test_mars_local_tms(): assert syrtis_tms.geographic_crs assert syrtis_tms.model_dump(mode="json") - center = syrtis_tms.ul(Tile(1, 1, 1)) + center = syrtis_tms.ul(1, 1, 1) assert round(center.x, 6) == 76.5 assert round(center.y, 6) == 17 diff --git a/tests/test_morecantile.py b/tests/test_morecantile.py index d42f0e5..c49f8cc 100644 --- a/tests/test_morecantile.py +++ b/tests/test_morecantile.py @@ -133,7 +133,7 @@ def test_ul_tile(): test form https://github.com/mapbox/mercantile/blob/master/tests/test_funcs.py """ tms = morecantile.tms.get("WebMercatorQuad") - xy = tms.ul(morecantile.Tile(486, 332, 10)) + xy = tms.ul(486, 332, 10) expected = (-9.140625, 53.33087298301705) for a, b in zip(expected, xy): assert round(a - b, 6) == 0 @@ -146,7 +146,7 @@ def test_projul_tile(): test form https://github.com/mapbox/mercantile/blob/master/tests/test_funcs.py """ tms = morecantile.tms.get("WebMercatorQuad") - xy = tms._ul(morecantile.Tile(486, 332, 10)) + xy = tms._ul(486, 332, 10) expected = (-1017529.7205322663, 7044436.526761846) for a, b in zip(expected, xy): assert round(a - b, 6) == 0 @@ -191,12 +191,15 @@ def test_feature(): ################################################################################ # replicate mercantile tests -def test_ul(): +# https://github.com/mapbox/mercantile/blob/master/tests/test_funcs.py +@pytest.mark.parametrize( + "args", [(486, 332, 10), [(486, 332, 10)], [morecantile.Tile(486, 332, 10)]] +) +def test_ul(args): """test args.""" - tile = morecantile.Tile(486, 332, 10) tms = morecantile.tms.get("WebMercatorQuad") expected = (-9.140625, 53.33087298301705) - lnglat = tms.ul(tile) + lnglat = tms.ul(*args) for a, b in zip(expected, lnglat): assert round(a - b, 6) == 0 assert lnglat[0] == lnglat.x @@ -222,7 +225,7 @@ def test_bbox(args): def test_xy_tile(): """x, y for the 486-332-10 tile is correctly calculated.""" tms = morecantile.tms.get("WebMercatorQuad") - ul = tms.ul(morecantile.Tile(486, 332, 10)) + ul = tms.ul(486, 332, 10) xy = tms.xy(*ul) expected = (-1017529.7205322663, 7044436.526761846) for a, b in zip(expected, xy):