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

1""" 

2Utility functions and classes for geographic coordinates 

3""" 

4 

5import math 

6from typing import Tuple, List, Generator 

7 

8from ._globalmaptiles import GlobalMercator 

9from .geo_coords import GeoRect 

10 

11EARTH_RADIUS = 6371000 

12EARTH_CIRCUMFERENCE = 2 * math.pi * EARTH_RADIUS 

13LATITUDE_PER_METRE = 360.0 / EARTH_CIRCUMFERENCE 

14 

15 

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 

22 

23 

24class MapTiles: 

25 def __init__(self, zoom=13): 

26 self.zoom = zoom 

27 self._mercator = GlobalMercator() 

28 self._tiles = {} 

29 

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 

37 

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 

48 

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)] 

51 

52 def get_tile(self, lat: float, lon: float) -> MapTile: 

53 return self._get_tile(*self.get_tile_coordinates(lat, lon)) 

54 

55 def get_tile_coordinates(self, lat: float, lon: float) -> Tuple[int, int]: 

56 return self._mercator.LatLonToTile(lat, lon, self.zoom)