use crate::types::basic::{Double, OSString};
use serde::{Deserialize, Serialize};
pub mod relative;
pub mod road;
pub mod trajectory;
pub mod world;
pub use relative::RelativeObjectPosition;
pub use road::{
LaneCoordinate, LanePosition, Orientation, RelativeLanePosition, RelativeRoadPosition,
RoadCoordinate, RoadPosition,
};
pub use trajectory::{Trajectory, TrajectoryFollowingMode, TrajectoryPosition, TrajectoryRef};
pub use world::{GeographicPosition, WorldPosition};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Position {
#[serde(rename = "WorldPosition", skip_serializing_if = "Option::is_none")]
pub world_position: Option<WorldPosition>,
#[serde(
rename = "RelativeWorldPosition",
skip_serializing_if = "Option::is_none"
)]
pub relative_world_position: Option<RelativeWorldPosition>,
#[serde(rename = "RoadPosition", skip_serializing_if = "Option::is_none")]
pub road_position: Option<RoadPosition>,
#[serde(
rename = "RelativeRoadPosition",
skip_serializing_if = "Option::is_none"
)]
pub relative_road_position: Option<RelativeRoadPosition>,
#[serde(rename = "LanePosition", skip_serializing_if = "Option::is_none")]
pub lane_position: Option<LanePosition>,
#[serde(
rename = "RelativeLanePosition",
skip_serializing_if = "Option::is_none"
)]
pub relative_lane_position: Option<RelativeLanePosition>,
#[serde(rename = "TrajectoryPosition", skip_serializing_if = "Option::is_none")]
pub trajectory_position: Option<TrajectoryPosition>,
#[serde(rename = "GeographicPosition", skip_serializing_if = "Option::is_none")]
pub geographic_position: Option<GeographicPosition>,
#[serde(
rename = "RelativeObjectPosition",
skip_serializing_if = "Option::is_none"
)]
pub relative_object_position: Option<RelativeObjectPosition>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct RelativeWorldPosition {
#[serde(rename = "@entityRef")]
pub entity_ref: OSString,
#[serde(rename = "@dx")]
pub dx: Double,
#[serde(rename = "@dy")]
pub dy: Double,
#[serde(rename = "@dz")]
pub dz: Double,
}
impl Default for Position {
fn default() -> Self {
Position {
world_position: Some(WorldPosition::default()),
relative_world_position: None,
road_position: None,
relative_road_position: None,
lane_position: None,
relative_lane_position: None,
trajectory_position: None,
geographic_position: None,
relative_object_position: None,
}
}
}
impl Default for RelativeWorldPosition {
fn default() -> Self {
Self {
entity_ref: OSString::literal("DefaultEntity".to_string()),
dx: Double::literal(0.0),
dy: Double::literal(0.0),
dz: Double::literal(0.0),
}
}
}
impl Position {
pub fn empty() -> Self {
Self {
world_position: None,
relative_world_position: None,
road_position: None,
relative_road_position: None,
lane_position: None,
relative_lane_position: None,
trajectory_position: None,
geographic_position: None,
relative_object_position: None,
}
}
pub fn relative_road(relative_road_position: RelativeRoadPosition) -> Self {
Self {
world_position: None,
relative_world_position: None,
road_position: None,
relative_road_position: Some(relative_road_position),
lane_position: None,
relative_lane_position: None,
trajectory_position: None,
geographic_position: None,
relative_object_position: None,
}
}
pub fn relative_lane(relative_lane_position: RelativeLanePosition) -> Self {
Self {
world_position: None,
relative_world_position: None,
road_position: None,
relative_road_position: None,
lane_position: None,
relative_lane_position: Some(relative_lane_position),
trajectory_position: None,
geographic_position: None,
relative_object_position: None,
}
}
pub fn trajectory(trajectory_position: TrajectoryPosition) -> Self {
Self {
world_position: None,
relative_world_position: None,
road_position: None,
relative_road_position: None,
lane_position: None,
relative_lane_position: None,
trajectory_position: Some(trajectory_position),
geographic_position: None,
relative_object_position: None,
}
}
pub fn geographic(geographic_position: GeographicPosition) -> Self {
Self {
world_position: None,
relative_world_position: None,
road_position: None,
relative_road_position: None,
lane_position: None,
relative_lane_position: None,
trajectory_position: None,
geographic_position: Some(geographic_position),
relative_object_position: None,
}
}
pub fn relative_object(relative_object_position: RelativeObjectPosition) -> Self {
Self {
world_position: None,
relative_world_position: None,
road_position: None,
relative_road_position: None,
lane_position: None,
relative_lane_position: None,
trajectory_position: None,
geographic_position: None,
relative_object_position: Some(relative_object_position),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_position_default_has_world_position() {
let pos = Position::default();
assert!(pos.world_position.is_some());
assert!(pos.lane_position.is_none());
assert!(pos.road_position.is_none());
}
#[test]
fn test_position_empty_has_all_none() {
let pos = Position::empty();
assert!(pos.world_position.is_none());
assert!(pos.relative_world_position.is_none());
assert!(pos.road_position.is_none());
assert!(pos.lane_position.is_none());
assert!(pos.trajectory_position.is_none());
assert!(pos.geographic_position.is_none());
assert!(pos.relative_object_position.is_none());
}
#[test]
fn test_position_trajectory_constructor() {
let tp = TrajectoryPosition::new(10.0);
let pos = Position::trajectory(tp.clone());
assert!(pos.trajectory_position.is_some());
assert!(pos.world_position.is_none());
}
#[test]
fn test_position_geographic_constructor() {
let gp = GeographicPosition::new(48.0, 11.0);
let pos = Position::geographic(gp);
assert!(pos.geographic_position.is_some());
assert!(pos.world_position.is_none());
}
#[test]
fn test_relative_world_position_default() {
let rwp = RelativeWorldPosition::default();
assert_eq!(rwp.entity_ref.as_literal().unwrap(), "DefaultEntity");
assert_eq!(rwp.dx.as_literal().unwrap(), &0.0);
}
#[test]
fn test_position_xml_roundtrip() {
let pos = Position::default();
let xml = quick_xml::se::to_string(&pos).unwrap();
assert!(xml.contains("WorldPosition"));
let deserialized: Position = quick_xml::de::from_str(&xml).unwrap();
assert_eq!(pos, deserialized);
}
}