# -*- coding: utf-8 -*- """ 路径点抽象基类 ───────────────────────────────────────────────────────────────── BaseWaypoint —— 所有路径点的公共基类(dataclass + 可扩展) 子类扩展示例: AirWaypoint 继承 BaseWaypoint,增加 fly_over / turn_radius GroundWaypoint 继承 BaseWaypoint,增加 road_type / heading_constraint WaterWaypoint 继承 BaseWaypoint,增加 depth / tide_correction ───────────────────────────────────────────────────────────────── """ from __future__ import annotations from dataclasses import dataclass, field from enum import Enum from typing import Any, Dict, Optional # ───────────────────────────────────────────────────────────────── # 装备域枚举 # ───────────────────────────────────────────────────────────────── class EquipmentDomain(Enum): AIR = "air" # 空中(飞行器) GROUND = "ground" # 陆地(车辆/步兵) WATER = "water" # 水面(舰艇) SUBSEA = "subsea" # 水下(潜艇/UUV) SPACE = "space" # 太空(预留) # ───────────────────────────────────────────────────────────────── # 路径点约束类型 # ───────────────────────────────────────────────────────────────── class AltConstraint(Enum): NONE = "none" AT = "at" AT_OR_ABOVE = "at_or_above" AT_OR_BELOW = "at_or_below" BETWEEN = "between" class SpeedConstraint(Enum): NONE = "none" AT = "at" AT_OR_ABOVE = "at_or_above" AT_OR_BELOW = "at_or_below" MAX = "max" # ───────────────────────────────────────────────────────────────── # 路径点基类 # ───────────────────────────────────────────────────────────────── @dataclass class BaseWaypoint: """ 路径点公共基类 所有域(空/地/水)的路径点均继承此类。 子类通过新增 dataclass 字段扩展特有属性, 无需修改基类。 坐标约定: latitude —— 纬度(度,WGS-84,北正南负) longitude —— 经度(度,WGS-84,东正西负) altitude —— 高度/深度(米,MSL;水下为负值) """ # ── 标识 ────────────────────────────────────────────────────── identifier: str = "" # 路径点标识符 name: str = "" # 全称/描述 domain: EquipmentDomain = EquipmentDomain.AIR # ── 坐标 ────────────────────────────────────────────────────── latitude: float = 0.0 # 纬度(度) longitude: float = 0.0 # 经度(度) altitude: float = 0.0 # 高度/深度(米,MSL) # ── 运动参数 ────────────────────────────────────────────────── speed: float = 0.0 # 过点速度(m/s) heading: Optional[float] = None # 指定过点航向(度,None=自动计算) # ── 速度约束 ────────────────────────────────────────────────── speed_constraint: SpeedConstraint = SpeedConstraint.NONE speed_limit: Optional[float] = None # 约束速度值(m/s) # ── 高度约束 ────────────────────────────────────────────────── alt_constraint: AltConstraint = AltConstraint.NONE alt_value: Optional[float] = None # 约束高度(米) alt_value2: Optional[float] = None # BETWEEN 时的上限 # ── 停留参数 ────────────────────────────────────────────────── dwell_time: float = 0.0 # 在此点停留时间(秒,0=不停留) # ── 扩展元数据 ──────────────────────────────────────────────── metadata: Dict[str, Any] = field(default_factory=dict) # ── 属性 ────────────────────────────────────────────────────── @property def position(self) -> tuple: """返回 (lat, lon, alt) 三元组""" return (self.latitude, self.longitude, self.altitude) @property def has_speed_constraint(self) -> bool: return self.speed_constraint != SpeedConstraint.NONE @property def has_alt_constraint(self) -> bool: return self.alt_constraint != AltConstraint.NONE def effective_speed(self, default: float = 0.0) -> float: """返回有效过点速度(优先使用 speed,否则用 default)""" return self.speed if self.speed > 1e-6 else default def validate(self) -> list: """ 校验路径点合法性 :return: 错误信息列表(空列表表示合法) """ errors = [] if not (-90 <= self.latitude <= 90): errors.append(f"纬度越界: {self.latitude}") if not (-180 <= self.longitude <= 180): errors.append(f"经度越界: {self.longitude}") if self.speed < 0: errors.append(f"速度不能为负: {self.speed}") if self.dwell_time < 0: errors.append(f"停留时间不能为负: {self.dwell_time}") return errors def copy_with(self, **kwargs) -> "BaseWaypoint": """返回修改了指定字段的副本""" import copy wp = copy.copy(self) for k, v in kwargs.items(): setattr(wp, k, v) return wp def __str__(self) -> str: return (f"WP[{self.identifier}]" f"({self.latitude:.4f}°,{self.longitude:.4f}°," f"{self.altitude:.0f}m) " f"spd={self.speed:.1f}m/s") # ───────────────────────────────────────────────────────────────── # 各域路径点子类 # ───────────────────────────────────────────────────────────────── @dataclass class AirWaypoint(BaseWaypoint): """空中路径点(兼容 ARINC 424)""" domain: EquipmentDomain = EquipmentDomain.AIR # 转弯参数 fly_over: bool = False # True=飞越点,False=Fly-by turn_radius: float = 0.0 # 过点转弯半径(米,0=自动) # ARINC 424 字段 path_terminator: str = "TF" # TF/CF/DF/IF/RF/AF course_angle: Optional[float] = None # 指定进场航道(度) waypoint_type: str = "FIX" # FIX/AIRPORT/VOR/NDB @dataclass class GroundWaypoint(BaseWaypoint): """陆地路径点""" domain: EquipmentDomain = EquipmentDomain.GROUND # 道路/地形约束 road_type: str = "any" # road/offroad/any max_slope_deg: float = 30.0 # 最大允许坡度(度) heading_constraint: Optional[float] = None # 强制过点航向(度) stop_required: bool = False # 是否必须停车 @dataclass class WaterWaypoint(BaseWaypoint): """水中路径点(水面/水下通用)""" domain: EquipmentDomain = EquipmentDomain.WATER # 水下参数(潜艇/UUV) depth: float = 0.0 # 水下深度(米,正值向下) is_subsurface: bool = False # True=水下,False=水面 # 水文约束 min_water_depth: float = 0.0 # 最小水深要求(米) tide_correction: float = 0.0 # 潮汐修正量(米)