diff --git a/src/c3nav/mapdata/nocutils.py b/src/c3nav/mapdata/nocutils.py new file mode 100644 index 00000000..d1cd8d76 --- /dev/null +++ b/src/c3nav/mapdata/nocutils.py @@ -0,0 +1,51 @@ +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 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)) + print(diff_noc) + diff_nav = np.array(self.latlng1_nav) - np.array(self.latlng2_nav) + print(diff_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]) diff --git a/src/c3nav/settings.py b/src/c3nav/settings.py index c21b9587..c34cd746 100644 --- a/src/c3nav/settings.py +++ b/src/c3nav/settings.py @@ -14,9 +14,12 @@ from django.core.exceptions import ImproperlyConfigured from django.utils.crypto import get_random_string from django.utils.dateparse import parse_duration from django.utils.translation import gettext_lazy as _ +from pydantic.type_adapter import TypeAdapter from pyproj import Proj, Transformer from c3nav import __version__ as c3nav_version +from c3nav.api.schema import BaseSchema +from c3nav.mapdata.nocutils import NocLayersSchema from c3nav.utils.config import C3navConfigParser from c3nav.utils.environ import Env @@ -215,6 +218,9 @@ if not HUB_API_SECRET: if HUB_API_SECRET_FILE.exists(): HUB_API_SECRET = HUB_API_SECRET_FILE.read_text().strip() +NOC_API_BASE = config.get('c3nav', 'noc_api_base', fallback='').removesuffix('/') +NOC_LAYERS = NocLayersSchema.validate_json(config.get('c3nav', 'noc_layers', fallback='{}')) + _db_backend = config.get('database', 'backend', fallback='sqlite3') DATABASES: dict[str, dict[str, str | int | Path]] = { 'default': env.db_url('C3NAV_DATABASE') if 'C3NAV_DATABASE' in env else {