Coverage for src/sensai/geoanalytics/map_tiles.py: 0%
41 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-13 22:17 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-13 22:17 +0000
1"""
2Utility functions and classes for geographic coordinates
3"""
5import math
6from typing import Tuple, List, Generator
8from ._globalmaptiles import GlobalMercator
9from .geo_coords import GeoRect
11EARTH_RADIUS = 6371000
12EARTH_CIRCUMFERENCE = 2 * math.pi * EARTH_RADIUS
13LATITUDE_PER_METRE = 360.0 / EARTH_CIRCUMFERENCE
16class MapTile:
17 def __init__(self, tx: int, ty: int, rect: GeoRect, zoom: int):
18 self.tx = tx
19 self.ty = ty
20 self.rect = rect
21 self.zoom = zoom
24class MapTiles:
25 def __init__(self, zoom=13):
26 self.zoom = zoom
27 self._mercator = GlobalMercator()
28 self._tiles = {}
30 def _get_tile(self, tx, ty):
31 key = (tx, ty)
32 tile = self._tiles.get(key)
33 if tile is None:
34 tile = MapTile(tx, ty, GeoRect(*self._mercator.TileLatLonBounds(tx, ty, self.zoom)), self.zoom)
35 self._tiles[key] = tile
36 return tile
38 def iter_tile_coordinates_in_rect(self, rect: GeoRect) -> Generator[Tuple[int, int], None, None]:
39 tx1, ty1 = self._mercator.LatLonToTile(rect.minLat, rect.minLon, self.zoom)
40 tx2, ty2 = self._mercator.LatLonToTile(rect.maxLat, rect.maxLon, self.zoom)
41 tx_min = min(tx1, tx2)
42 tx_max = max(tx1, tx2)
43 ty_min = min(ty1, ty2)
44 ty_max = max(ty1, ty2)
45 for tx in range(tx_min, tx_max+1):
46 for ty in range(ty_min, ty_max+1):
47 yield tx, ty
49 def get_tiles_in_rect(self, rect: GeoRect) -> List[MapTile]:
50 return [self._get_tile(tx, ty) for tx, ty in self.iter_tile_coordinates_in_rect(rect)]
52 def get_tile(self, lat: float, lon: float) -> MapTile:
53 return self._get_tile(*self.get_tile_coordinates(lat, lon))
55 def get_tile_coordinates(self, lat: float, lon: float) -> Tuple[int, int]:
56 return self._mercator.LatLonToTile(lat, lon, self.zoom)