from dataclasses import dataclass, fields, is_dataclass
from enum import Enum
from typing import TypeVar, Any, get_origin, get_args
import types
from .geometry import Vector2, Vector3
T = TypeVar("T")
def _normalize_member_name(name: str) -> str:
"""将成员名称规则化,去掉下划线并转小写,
用于匹配 dataclass 中的字段和原始的 JSON 数据"""
return name.replace("_", "").lower()
def parse_data(cls: type[T], data: Any) -> T:
"""解析数据,将 JSON 数据转换为指定类型的对象。
支持基本类型、枚举、列表和 dataclass 类型的转换。
:param cls: 目标类型
:param data: 原始数据
:return: 转换后的对象
"""
if cls is type(None) and data is None:
return None
if cls in (int, float, bool, str) and isinstance(data, cls):
return cls(data)
if isinstance(cls, type) and issubclass(cls, Enum):
return cls(data)
if get_origin(cls) is list and isinstance(data, list):
return [parse_data(get_args(cls)[0], item) for item in data]
if is_dataclass(cls) and isinstance(data, dict):
normalized_data = {_normalize_member_name(k): v for k, v in data.items()}
cleaned_data = {}
for field in fields(cls):
try:
value = normalized_data[_normalize_member_name(field.name)]
except KeyError:
raise KeyError(f"Key '{field.name}' not found when parsing {cls}")
cleaned_data[field.name] = parse_data(field.type, value)
return cls(**cleaned_data)
if get_origin(cls) is types.UnionType:
# 尝试每一种类型,如果都不匹配,则抛出异常
for optional_type in get_args(cls):
try:
return parse_data(optional_type, data)
except Exception:
pass
raise TypeError(f"Cannot convert type {type(data)} to union type {cls}")
raise TypeError(f"Unsupported conversion from {type(data)} to {cls}")
[文档]
@dataclass
class SubSceneInfo:
"""子场景信息"""
sub_scene_name: str #: 子场景名称
start_point: Vector3 #: 起点
end_point: Vector3 #: 终点
@dataclass
class MapConfig:
"""地图配置"""
path: str #: 地图目录路径
route: str #: 路线文件名
map: str #: 地图文件名
sub_scene_info: list[SubSceneInfo] #: 子场景信息
[文档]
class LineType(Enum):
"""道路线类型"""
MIDDLE_LINE = 1 #: 中线
SIDE_LINE = 2 #: 侧线
SOLID_LINE = 3 #: 实线
STOP_LINE = 4 #: 停止线
ZEBRA_CROSSING = 5 #: 斑马线
DASH_LINE = 6 #: 虚线
[文档]
@dataclass
class BorderInfo:
"""车道边界信息"""
border_type: LineType #: 边界类型
path_point: list[Vector2] #: 组成边界线的点,相邻点间隔约 3~5 米
[文档]
@dataclass
class LaneInfo:
"""车道信息"""
id: str #: 车道 ID
left_border: BorderInfo #: 左侧边界
right_border: BorderInfo #: 右侧边界
left_lane: str #: 左侧车道 ID
right_lane: str #: 右侧车道 ID
width: float #: 车道宽度
path_point: list[Vector2] #: 车道中心线
[文档]
class DrivingType(Enum):
"""行驶类型"""
MOTOR_VEHICLE_ALLOWED = 1 #: 机动车可行驶
NON_MOTOR_VEHICLE_ALLOWED = 2 #: 非机动车可行驶
PEDESTRIAN_ALLOWED = 3 #: 行人可行
[文档]
class TrafficSign(Enum):
"""交通标志"""
NO_SIGN = 0 #: 无标志
SPEED_LIMIT_SIGN = 1 #: 限速标志
STOP_SIGN = 2 #: 停止标志
V2X_SIGN = 3 #: V2X 标志
[文档]
@dataclass
class RoadInfo:
"""道路信息,一条道路(Road)由一个或多个车道(Lane)组成"""
id: str #: 道路 ID
begin_pos: Vector3 #: 起点
end_pos: Vector3 #: 终点
driving_type: DrivingType #: 行驶类型
traffic_sign: TrafficSign #: 交通标志
stop_line: list[Vector2] #: 停止线位置
predecessor: list[str] #: 前驱道路 ID
successor: list[str] #: 后继道路 ID
lane_data: list[LaneInfo] #: 车道信息
[文档]
@dataclass
class SceneStaticData:
"""场景静态信息"""
route: list[Vector3] #: 路线
road_lines: list[RoadInfo] #: 道路信息
sub_scenes: list[SubSceneInfo] #: 子场景信息
[文档]
@dataclass
class PoseGnss:
"""车辆位姿信息"""
pos_x: float #: 位置 X
pos_y: float #: 位置 Y
pos_z: float #: 位置 Z
vel_x: float #: 速度 X
vel_y: float #: 速度 Y
vel_z: float #: 速度 Z
ori_x: float #: 欧拉角 X(单位:角度)
ori_y: float #: 欧拉角 Y(单位:角度)
ori_z: float #: 欧拉角 Z(单位:角度)
[文档]
class GearMode(Enum):
"""档位模式"""
NEUTRAL = 0 #: 空档
DRIVE = 1 #: 前进档
REVERSE = 2 #: 倒车档
PARKING = 3 #: 停车档
[文档]
@dataclass
class MainVehicleInfo:
"""主车信息"""
main_vehicle_id: int #: 主车 ID
speed: float #: 车速
gear: GearMode #: 档位
throttle: float #: 油门
brake: float #: 刹车
steering: float #: 方向盘
length: float #: 长度
width: float #: 宽度
height: float #: 高度
signal_light_left_blinker: bool #: 左转向灯
signal_light_right_blinker: bool #: 右转向灯
signal_light_double_flash: bool #: 双闪
signal_light_brake_light: bool #: 刹车灯
signal_light_front_light: bool #: 前灯
[文档]
@dataclass
class EulerAngle:
"""欧拉角"""
ori_x: float #: 欧拉角 X(单位:角度)
ori_y: float #: 欧拉角 Y(单位:角度)
ori_z: float #: 欧拉角 Z(单位:角度)
[文档]
@dataclass
class CamaraInfo:
"""摄像头信息"""
id: str #: 摄像头 ID
position: Vector3 #: 位置
angle: EulerAngle #: 角度
fov: float #: 视场角
intrinsic_matrix: list[float] #: 内参矩阵
image_w: int #: 图像宽度
image_h: int #: 图像高度
[文档]
@dataclass
class SensorInfo:
"""传感器信息"""
ego_rgb_cams: list[CamaraInfo] #: 主车摄像头
v2x_cams: list[CamaraInfo] #: V2X 摄像头
[文档]
class ObstacleType(Enum):
"""障碍物类型"""
UNKNOWN = 0 #: 未知障碍物
PEDESTRIAN = 4 #: 行人
CAR = 6 #: 小汽车
STATIC = 7 #: 静态障碍物
BICYCLE = 8 #: 自行车
ROAD_MARK = 12 #: 道路标记
TRAFFIC_SIGN = 13 #: 交通标志
TRAFFIC_LIGHT = 15 #: 交通信号灯
RIDER = 17 #: 骑手
TRUCK = 18 #: 卡车
BUS = 19 #: 公交车
SPECIAL_VEHICLE = 20 #: 特种车辆
MOTORCYCLE = 21 #: 摩托车
DYNAMIC = 22 #: 动态障碍物
SPEED_LIMIT_SIGN = 26 #: 限速标志(限速值以 "SpeedLimit|30"(单位:km/h) 的格式在 :attr:`ObstacleInfo.redundant_value` 中给出)
BICYCLE_STATIC = 27 #: 静止自行车
ROAD_OBSTACLE = 29 #: 道路障碍物
PARKING_SLOT = 30 #: 停车位
[文档]
@dataclass
class ObstacleInfo:
"""障碍物信息"""
id: int #: 障碍物 ID
type: ObstacleType #: 障碍物类型
pos_x: float #: 位置 X
pos_y: float #: 位置 Y
pos_z: float #: 位置 Z
vel_x: float #: 速度 X
vel_y: float #: 速度 Y
vel_z: float #: 速度 Z
ori_x: float #: 欧拉角 X(单位:角度)
ori_y: float #: 欧拉角 Y(单位:角度)
ori_z: float #: 欧拉角 Z(单位:角度)
length: float #: 长度
width: float #: 宽度
height: float #: 高度
redundant_value: str | None #: 冗余值(包含限速标志的限速值)
[文档]
class TrafficLightState(Enum):
"""交通灯状态"""
RED = 1 #: 红灯
GREEN = 2 #: 绿灯
YELLOW = 3 #: 黄灯
[文档]
@dataclass
class TrafficLightInfo:
"""一排交通灯的信息"""
id: str #: 交通灯 ID
road_id: str #: 道路 ID
position: Vector3 #: 位置
turn_left_state: TrafficLightState #: 左转状态
turn_left_remainder: float #: 左转剩余时间
turn_right_state: TrafficLightState #: 右转状态
turn_right_remainder: float #: 右转剩余时间
straight_state: TrafficLightState #: 直行状态
straight_remainder: float #: 直行剩余时间
[文档]
@dataclass
class TrafficLightGroupInfo:
"""交通灯组信息"""
id: str #: 交通灯组 ID
traffic_light_state: list[TrafficLightInfo] #: 交通灯信息
[文档]
@dataclass
class SceneStatus:
"""场景状态信息"""
sub_scene_name: str #: 子场景名称
used_time: float #: 已用时间
time_limit: float #: 时间限制
end_point: Vector3 #: 终点
[文档]
@dataclass
class SimCarMsg:
"""仿真动态信息"""
trajectory: list[Vector3] #: 推荐轨迹
pose_gnss: PoseGnss #: GNSS 数据
data_main_vehicle: MainVehicleInfo #: 主车信息
sensor: SensorInfo #: 传感器信息
obstacle_entry_list: list[ObstacleInfo] #: 障碍物信息
traffic_light_state_lists: list[TrafficLightGroupInfo] #: 交通灯组信息
scene_status: SceneStatus #: 场景状态信息
[文档]
@dataclass
class VehicleControl:
"""车辆控制信息"""
throttle: float = 0.0 #: 油门(0~1)
brake: float = 0.0 #: 刹车(0~1)
steering: float = 0.0 #: 方向盘(-1~1)
gear: GearMode = GearMode.DRIVE #: 档位
left_blinker: bool = False #: 左转向灯
right_blinker: bool = False #: 右转向灯
double_flash: bool = False #: 双闪
front_light: bool = False #: 前灯