Source code for openworld_radio_twin.geodesy

from dataclasses import dataclass

from pyproj import Transformer
from pyproj.enums import TransformDirection


[docs] @dataclass(frozen=True) class LocalFrame: """WGS84 Earth-centered to local East-North-Up transformation.""" origin_longitude: float origin_latitude: float transformer: Transformer
[docs] @classmethod def at(cls, longitude: float, latitude: float) -> "LocalFrame": pipeline = ( "+proj=pipeline " "+step +proj=cart +ellps=WGS84 " f"+step +proj=topocentric +ellps=WGS84 +lon_0={longitude:.12f} " f"+lat_0={latitude:.12f} +h_0=0" ) return cls(longitude, latitude, Transformer.from_pipeline(pipeline))
[docs] def to_local( self, longitude: float, latitude: float, altitude_m: float = 0 ) -> tuple[float, float, float]: east, north, up = self.transformer.transform(longitude, latitude, altitude_m) return float(east), float(north), float(up)
[docs] def to_geographic( self, east_m: float, north_m: float, up_m: float = 0 ) -> tuple[float, float, float]: longitude, latitude, altitude = self.transformer.transform( east_m, north_m, up_m, direction=TransformDirection.INVERSE, ) return float(longitude), float(latitude), float(altitude)
[docs] def corners( self, west_m: float, south_m: float, east_m: float, north_m: float ) -> list[list[float]]: local_corners = [ (west_m, north_m), (east_m, north_m), (east_m, south_m), (west_m, south_m), ] return [list(self.to_geographic(east, north)[:2]) for east, north in local_corners]