49 lines
1.5 KiB
Python
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])
|