team-3/src/c3nav/mapdata/nocutils.py
2024-12-24 22:59:38 +01:00

49 lines
1.5 KiB
Python

import math
from functools import cached_property
import numpy as np
from pydantic.main import BaseModel
from pydantic.type_adapter import TypeAdapter
from shapely import Point
def deg2pos(lat_deg, lon_deg):
lat_rad = math.radians(lat_deg)
xpos = (lon_deg + 180.0) / 360.0
ypos = math.asinh(math.tan(lat_rad)) / math.pi / 2.0
return ypos, xpos
class NocTransformLayerSchema(BaseModel):
level_id: int
scale: float | int
offset: tuple[float, float] | int
def convert(self, lat, lng) -> Point:
return Point(*reversed(tuple(np.array(deg2pos(lat, lng)) * self.scale + np.array(self.offset))))
class NocTwoPointLayerSchema(BaseModel):
level_id: int
latlng1_noc: tuple[float, float]
latlng1_nav: tuple[float, float]
latlng2_noc: tuple[float, float]
latlng2_nav: tuple[float, float]
@cached_property
def to_transform(self) -> NocTransformLayerSchema:
diff_noc = np.array(deg2pos(*self.latlng1_noc)) - np.array(deg2pos(*self.latlng2_noc))
diff_nav = np.array(self.latlng1_nav) - np.array(self.latlng2_nav)
scale = np.linalg.norm(diff_nav) / np.linalg.norm(diff_noc)
offset = np.array(self.latlng1_nav) - (np.array(deg2pos(*self.latlng1_noc)) * scale)
return NocTransformLayerSchema(
level_id=self.level_id,
scale=scale,
offset=tuple(offset),
)
def convert(self, lat, lng) -> Point:
return self.to_transform.convert(lat, lng)
NocLayersSchema = TypeAdapter(dict[str, NocTransformLayerSchema | NocTwoPointLayerSchema])