TileUtils#

class rapidtools.data_sources.TileUtils[source]#

Bases: object

Utility methods for Web Mercator/Mapbox Vector Tile operations.

This class provides static helpers for:

  • Converting between WGS84 (lat/lon) and XYZ tile coordinates

  • Converting Mapbox Vector Tile (MVT) local coordinates to WGS84

  • Determining zoom levels and tile coverage for bounding boxes

  • Converting millisecond timestamps to UTC dates

All geographic coordinates are assumed to be:

  • Latitude in degrees, in the range [-85.05112878, 85.05112878]

  • Longitude in degrees, in the range [-180, 180]

Example

>>> from rapidtools.core import BoundingBox
>>> from rapidtools.data_sources import TileUtils
>>>
>>> bbox = BoundingBox(-118.251, 34.050, -118.250, 34.051)
>>> tiles = TileUtils.bbox_to_mapbox_tiles(bbox, zoom=16)
>>> all(z == 16 for _, _, z in tiles)
True

Methods

bbox_to_mapbox_tiles

Compute XYZ tiles that cover a bounding box.

get_enclosing_zoom

Find the highest zoom where the bounding box fits inside one tile.

latlon_to_tile

Convert latitude/longitude to fractional XYZ tile coordinates.

ms_to_date_utc

Convert a millisecond UNIX timestamp to a UTC date string.

mvt_to_wgs84

Convert MVT local tile coordinates to WGS84 (longitude, latitude).

static latlon_to_tile(lat: float, lon: float, z: int) → tuple[float, float][source]#

Convert latitude/longitude to fractional XYZ tile coordinates.

Uses the Web Mercator tiling scheme where: at zoom level z there are 2^z tiles in both X and Y.

Parameters:
  • lat – Latitude in degrees.

  • lon – Longitude in degrees.

  • z – Zoom level (e.g., 0-22).

Returns:

A tuple (xtile, ytile) of fractional tile coordinates at zoom z. The integer parts floor(xtile) and floor(ytile) are the tile indices; the fractional parts represent the position within that tile.

Example

>>> TileUtils.latlon_to_tile(0.0, 0.0, 1)
(1.0, 1.0)
static mvt_to_wgs84(shape_x: int, shape_y: int, tile_x: int, tile_y: int, tile_z: int, extent: int = 4096) → tuple[float, float][source]#

Convert MVT local tile coordinates to WGS84 (longitude, latitude).

The local coordinates shape_x and shape_y are integers in the coordinate space of a single Mapbox Vector Tile (commonly 0..extent). The enclosing tile is specified by global XYZ tile indices.

Parameters:
  • shape_x – X coordinate in the MVT local coordinate space (0 to extent).

  • shape_y – Y coordinate in the MVT local coordinate space (0 to extent).

  • tile_x – Global tile X index at zoom tile_z.

  • tile_y – Global tile Y index at zoom tile_z.

  • tile_z – Zoom level of the tile.

  • extent – Resolution of the local tile coordinate grid. Defaults to 4096 (typical for Mapbox Vector Tiles).

Returns:

A tuple (lon, lat) where –

  • lon is longitude in degrees (WGS84).

  • lat is latitude in degrees (WGS84).

Example

>>> lon, lat = TileUtils.mvt_to_wgs84(0, 0, 0, 0, 0)
>>> lon, round(lat, 6)
(-180.0, 85.051129)
static ms_to_date_utc(timestamp_ms: int) → str[source]#

Convert a millisecond UNIX timestamp to a UTC date string.

The input timestamp is interpreted as milliseconds since the Unix epoch (1970-01-01T00:00:00Z). The function converts it to a UTC date and returns an ISO 8601 formatted string (YYYY-MM-DD).

Parameters:

timestamp_ms – Timestamp in milliseconds since Unix epoch (UTC).

Returns:

A Unicode string representing the UTC date in ISO format (YYYY-MM-DD).

Example

>>> TileUtils.ms_to_date_utc(0)
'1970-01-01'
>>> TileUtils.ms_to_date_utc(1_700_000_000_000)
'2023-11-14'
static get_enclosing_zoom(bbox: BoundingBox) → int[source]#

Find the highest zoom where the bounding box fits inside one tile.

This method searches zoom levels from 22 down to 14 and returns the maximum zoom level at which the entire bounding box is contained within a single XYZ tile. If the bounding box spans multiple tiles at all zooms in that range, 14 is returned.

The bounding box is expected to provide Shapely-like bounds in the order (min_lon, min_lat, max_lon, max_lat).

Parameters:

bbox – Bounding box object with a shapely geometry exposing a .bounds attribute.

Returns:

The highest integer zoom level in the range [14, 22] at which the bounding box fits into a single tile. Returns 14 if no higher zoom level satisfies this condition.

Example

>>> from rapidtools.core import BoundingBox
>>> # A very large box never fits in one tile above zoom 14:
>>> TileUtils.get_enclosing_zoom(BoundingBox(-120, 30, -110, 40))
14
static bbox_to_mapbox_tiles(bbox: BoundingBox, zoom: int | None = None) → list[tuple[int, int, int]][source]#

Compute XYZ tiles that cover a bounding box.

The bounding box is given in WGS84 coordinates via the bbox.bounds attribute. Tiles are computed using the standard Web Mercator XYZ scheme.

If zoom is not provided, the highest zoom at which the entire bounding box fits into a single tile (as returned by get_enclosing_zoom()) is used. In that case the result is often a single tile.

Parameters:
  • bbox – Bounding box object with a shapely geometry exposing a .bounds attribute in the order (min_lon, min_lat, max_lon, max_lat).

  • zoom – Zoom level at which to compute coverage. If None, the zoom level is determined by get_enclosing_zoom().

Returns:

A list of tile coordinates (x, y, z) covering the bounding box, including all integer tiles from min_x..max_x and min_y..max_y inclusive.

Example

>>> from rapidtools.core import BoundingBox
>>> TileUtils.bbox_to_mapbox_tiles(BoundingBox(-1, -1, 1, 1), zoom=1)
[(0, 0, 1), (0, 1, 1), (1, 0, 1), (1, 1, 1)]