base_agent/uas/route/base_waypoint.py

192 lines
9.2 KiB
Python
Raw Normal View History

2026-06-18 03:28:14 +00:00
# -*- 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 # 潮汐修正量(米)