openfree's picture
Deploy from GitHub repository
b20c769 verified
from dataclasses import dataclass
from math import cos, radians, sin
from typing import List, Optional, Tuple
@dataclass
class BBox:
min_lat: float
max_lat: float
min_lon: float
max_lon: float
name: Optional[str] = None
def __post_init__(self):
if self.max_lon < self.min_lon:
raise ValueError("max_lon should be larger than min_lon")
if self.max_lat < self.min_lat:
raise ValueError("max_lat should be larger than min_lat")
self.url = (
f"http://bboxfinder.com/#{self.min_lat},{self.min_lon},{self.max_lat},{self.max_lon}"
)
def contains(self, lat: float, lon: float) -> bool:
return (
(lat >= self.min_lat)
& (lat <= self.max_lat)
& (lon >= self.min_lon)
& (lon <= self.max_lon)
)
def contains_bbox(self, bbox: "BBox") -> bool:
return (
(bbox.min_lat >= self.min_lat)
& (bbox.max_lat <= self.max_lat)
& (bbox.min_lon >= self.min_lon)
& (bbox.max_lon <= self.max_lon)
)
@property
def three_dimensional_points(self) -> List[float]:
r"""
If we are passing the central latitude and longitude to
an ML model, we want it to know the extremes are close together.
Mapping them to 3d space allows us to do that
"""
lat, lon = self.get_centre(in_radians=True)
return [cos(lat) * cos(lon), cos(lat) * sin(lon), sin(lat)]
def get_centre(self, in_radians: bool = True) -> Tuple[float, float]:
# roughly calculate the centres
lat = self.min_lat + ((self.max_lat - self.min_lat) / 2)
lon = self.min_lon + ((self.max_lon - self.min_lon) / 2)
if in_radians:
return radians(lat), radians(lon)
else:
return lat, lon
def get_identifier(self, start_date, end_date) -> str:
# Identifier is rounded to the nearest ~10m
min_lon = round(self.min_lon, 4)
min_lat = round(self.min_lat, 4)
max_lon = round(self.max_lon, 4)
max_lat = round(self.max_lat, 4)
return (
f"min_lat={min_lat}_min_lon={min_lon}_max_lat={max_lat}_max_lon={max_lon}_"
f"dates={start_date}_{end_date}"
)
def __add__(self, other_box: "BBox") -> "BBox":
return BBox(
min_lat=min([self.min_lat, other_box.min_lat]),
min_lon=min([self.min_lon, other_box.min_lon]),
max_lon=max([self.max_lon, other_box.max_lon]),
max_lat=max([self.max_lat, other_box.max_lat]),
name="_".join([x for x in [self.name, other_box.name] if x is not None]),
)