from typing import Literal from pydantic import BaseModel, Field from app.models.common import AntennaPoint, GeoJSON, Point, SurfaceKind class ElevationResponse(Point): elevation_m: float surface: SurfaceKind class TerrainProfileRequest(BaseModel): start: Point end: Point samples: int = Field(default=512, ge=2, le=10000) include_buildings: bool = True include_canopy: bool = True k_factor: float = Field(default=1.333, gt=0) class ProfileSample(BaseModel): i: int lat: float lon: float distance_m: float ground_m: float building_m: float canopy_m: float surface_m: float curvature_corr_m: float class TerrainProfileResponse(BaseModel): distance_m: float samples: list[ProfileSample] path_geojson: GeoJSON class LosRequest(BaseModel): tx: AntennaPoint rx: AntennaPoint frequency_mhz: float = Field(gt=0) fresnel_clearance: float = Field(default=0.6, ge=0) include_buildings: bool = True include_canopy: bool = True k_factor: float = Field(default=1.333, gt=0) samples: int = Field(default=512, ge=2, le=10000) class Obstruction(BaseModel): distance_m: float clearance_m: float fresnel_radius_m: float required_clearance_m: float type: Literal["terrain", "building", "canopy"] class LosResponse(BaseModel): los_clear: bool geometric_los: bool first_fresnel_clearance_pct: float worst_obstruction: Obstruction | None obstructions: list[Obstruction] geometric_obstructions: list[Obstruction] fresnel_violations_count: int geometric_obstructions_count: int building_obstructions_count: int diffraction_loss_db: float profile_ref: str