192 lines
9.2 KiB
Python
192 lines
9.2 KiB
Python
|
|
# -*- 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 # 潮汐修正量(米)
|