feat(map): adopt DC Default scene

This commit is contained in:
DCCONSTRUCTIONS
2026-07-29 17:55:44 +03:00
parent 5a06194962
commit b91d3b913e
9 changed files with 1299 additions and 331 deletions
+15
View File
@@ -13,6 +13,7 @@ from fastapi import APIRouter, HTTPException, Path, Query, Request
from fastapi.responses import JSONResponse, Response, StreamingResponse
MAP_GATEWAY_URL_ENV: Final = "MISSIONCORE_MAP_GATEWAY_INTERNAL_URL"
MAP_SANDBOX_HIDE_CREDITS_ENV: Final = "MISSIONCORE_MAP_SANDBOX_HIDE_CREDITS"
MAP_SCHEMA_VERSION: Final = "missioncore.map-gateway/v1"
MAP_RUNTIME_SCHEMA_VERSION: Final = "missioncore.map-runtime/v1"
MAP_PAGE_VERSION: Final = "0.1.0"
@@ -149,6 +150,11 @@ class MapGatewayProxy:
"terrain": 1,
"buildings": 96188,
},
"sandbox": {
"hide_credit_overlay": _environment_flag(
MAP_SANDBOX_HIDE_CREDITS_ENV
)
},
},
headers={"Cache-Control": "no-store"},
)
@@ -309,6 +315,15 @@ def _validate_internal_url(raw_url: str) -> str:
return raw_url.rstrip("/")
def _environment_flag(name: str) -> bool:
return os.environ.get(name, "").strip().lower() in {
"1",
"true",
"yes",
"on",
}
def _validate_cache_target(target_url: str) -> None:
if len(target_url) > MAX_CACHE_TARGET_LENGTH:
raise HTTPException(status_code=422, detail="Map resource URL is too long.")
+128 -15
View File
@@ -10,7 +10,7 @@ from typing import Literal
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, ConfigDict, Field, model_validator
MAP_VIEW_SCHEMA_VERSION: Literal["missioncore.map-view/v1"] = "missioncore.map-view/v1"
MAP_VIEW_SCHEMA_VERSION: Literal["missioncore.map-view/v2"] = "missioncore.map-view/v2"
MapInspectorSection = Literal[
"base-terrain",
"atmosphere-light",
@@ -37,15 +37,49 @@ class MapCamera(StrictMapModel):
class MapVisualSettings(StrictMapModel):
atmosphere_enabled: bool = True
lighting_enabled: bool = True
atmosphere_enabled: bool = False
atmosphere_hue: float = Field(default=0.0, ge=-100.0, le=100.0)
atmosphere_saturation: float = Field(default=0.0, ge=-100.0, le=100.0)
atmosphere_brightness: float = Field(default=0.0, ge=-100.0, le=100.0)
fog_enabled: bool = True
fog_density: float = Field(default=2.0, ge=0.0, le=100.0)
sun_enabled: bool = True
sun_hour: float = Field(default=12.0, ge=0.0, le=24.0)
sun_intensity: float = Field(default=200.0, ge=0.0, le=200.0)
shadows_enabled: bool = True
monochrome_enabled: bool = False
terrain_exaggeration: float = Field(default=1.0, ge=0.1, le=20.0)
monochrome_color: str = Field(default="#15151b", pattern=r"^#[0-9A-Fa-f]{6}$")
imagery_brightness: float = Field(default=118.0, ge=0.0, le=200.0)
imagery_contrast: float = Field(default=102.0, ge=0.0, le=200.0)
imagery_saturation: float = Field(default=0.0, ge=0.0, le=200.0)
imagery_gamma: float = Field(default=57.0, ge=0.0, le=300.0)
imagery_hue: float = Field(default=13.0, ge=-180.0, le=180.0)
imagery_alpha: float = Field(default=27.0, ge=0.0, le=100.0)
globe_color: str = Field(default="#15151b", pattern=r"^#[0-9A-Fa-f]{6}$")
background_color: str = Field(default="#08090d", pattern=r"^#[0-9A-Fa-f]{6}$")
terrain_exaggeration: float = Field(default=1.0, ge=0.25, le=3.0)
buildings_color: str = Field(default="#a27aff", pattern=r"^#[0-9A-Fa-f]{6}$")
buildings_opacity: float = Field(default=1.0, ge=0.0, le=1.0)
buildings_maximum_screen_space_error: float = Field(
default=16.0,
ge=1.0,
le=64.0,
default=4.0,
ge=4.0,
le=32.0,
)
grid_lod_enabled: bool = True
grid_height_meters: float = Field(default=500.0, ge=0.0, le=1000.0)
grid_lod_1_max_height_km: float = Field(default=10.0, ge=1.0, le=50.0)
grid_lod_1_step_km: float = Field(default=1.0, ge=1.0, le=10.0)
grid_lod_2_max_height_km: float = Field(default=50.0, ge=10.0, le=200.0)
grid_lod_2_step_km: float = Field(default=5.0, ge=1.0, le=25.0)
grid_lod_3_step_km: float = Field(default=25.0, ge=5.0, le=100.0)
grid_radius_km: float = Field(default=40.0, ge=5.0, le=150.0)
grid_line_width: float = Field(default=4.0, ge=1.0, le=8.0)
grid_color: str = Field(default="#f5f5f5", pattern=r"^#[0-9A-Fa-f]{6}$")
grid_opacity: float = Field(default=12.0, ge=0.0, le=100.0)
grid_dots_enabled: bool = True
grid_dots_size: float = Field(default=7.0, ge=2.0, le=28.0)
grid_dots_color: str = Field(default="#ffffff", pattern=r"^#[0-9A-Fa-f]{6}$")
grid_dots_opacity: float = Field(default=58.0, ge=0.0, le=100.0)
camera_animation_enabled: bool = True
@@ -53,7 +87,7 @@ class MapLayerVisibility(StrictMapModel):
imagery: bool = True
terrain: bool = True
buildings: bool = True
grid: bool = False
grid: bool = True
targets: bool = True
@@ -63,9 +97,18 @@ class MapCacheIntent(StrictMapModel):
class MapViewContent(StrictMapModel):
camera: MapCamera | None = None
camera: MapCamera | None = Field(
default_factory=lambda: MapCamera(
longitude=37.618423,
latitude=55.751244,
height=40_000.0,
heading=0.0,
pitch=-51.56620156177409,
roll=0.0,
)
)
visual_settings: MapVisualSettings = Field(default_factory=MapVisualSettings)
map_height: int = Field(default=720, ge=420, le=2160)
map_height: int = Field(default=694, ge=420, le=2160)
inspector_open_sections: list[MapInspectorSection] = Field(
default_factory=list,
max_length=1,
@@ -91,7 +134,43 @@ class MapViewPut(StrictMapModel):
class MapViewDocument(MapViewPut):
schema_version: Literal["missioncore.map-view/v1"] = MAP_VIEW_SCHEMA_VERSION
schema_version: Literal["missioncore.map-view/v2"] = MAP_VIEW_SCHEMA_VERSION
class LegacyMapVisualSettings(StrictMapModel):
atmosphere_enabled: bool = True
lighting_enabled: bool = True
monochrome_enabled: bool = False
terrain_exaggeration: float = Field(default=1.0, ge=0.1, le=20.0)
buildings_maximum_screen_space_error: float = Field(
default=16.0,
ge=1.0,
le=64.0,
)
camera_animation_enabled: bool = True
class LegacyMapViewContent(StrictMapModel):
camera: MapCamera | None = None
visual_settings: LegacyMapVisualSettings = Field(default_factory=LegacyMapVisualSettings)
map_height: int = Field(default=720, ge=420, le=2160)
inspector_open_sections: list[MapInspectorSection] = Field(
default_factory=list,
max_length=1,
)
cache_intent: MapCacheIntent = Field(default_factory=MapCacheIntent)
selected_subject_id: str | None = Field(
default=None,
max_length=160,
pattern=r"^[A-Za-z0-9][A-Za-z0-9._:/-]{0,159}$",
)
layer_visibility: MapLayerVisibility = Field(default_factory=MapLayerVisibility)
class LegacyMapViewDocument(StrictMapModel):
schema_version: Literal["missioncore.map-view/v1"]
revision: int = Field(ge=0)
view: LegacyMapViewContent
def default_map_view() -> MapViewDocument:
@@ -101,6 +180,36 @@ def default_map_view() -> MapViewDocument:
)
def upgrade_legacy_map_view(document: LegacyMapViewDocument) -> MapViewDocument:
legacy_settings = document.view.visual_settings
settings = MapVisualSettings(
atmosphere_enabled=legacy_settings.atmosphere_enabled,
sun_enabled=legacy_settings.lighting_enabled,
monochrome_enabled=legacy_settings.monochrome_enabled,
terrain_exaggeration=min(
3.0,
max(0.25, legacy_settings.terrain_exaggeration),
),
buildings_maximum_screen_space_error=min(
32.0,
max(4.0, legacy_settings.buildings_maximum_screen_space_error),
),
camera_animation_enabled=legacy_settings.camera_animation_enabled,
)
return MapViewDocument(
revision=document.revision,
view=MapViewContent(
camera=document.view.camera,
visual_settings=settings,
map_height=document.view.map_height,
inspector_open_sections=document.view.inspector_open_sections,
cache_intent=document.view.cache_intent,
selected_subject_id=document.view.selected_subject_id,
layer_visibility=document.view.layer_visibility,
),
)
class MapViewStore:
def __init__(self, root: Path) -> None:
self.root = root.expanduser().resolve()
@@ -138,10 +247,14 @@ class MapViewStore:
if not self.document_path.is_file():
return default_map_view()
try:
return MapViewDocument.model_validate_json(
self.document_path.read_text(encoding="utf-8")
)
except (OSError, ValueError) as exc:
payload = json.loads(self.document_path.read_text(encoding="utf-8"))
if (
isinstance(payload, dict)
and payload.get("schema_version") == "missioncore.map-view/v1"
):
return upgrade_legacy_map_view(LegacyMapViewDocument.model_validate(payload))
return MapViewDocument.model_validate(payload)
except (OSError, ValueError, TypeError) as exc:
raise RuntimeError("map view is corrupt") from exc