use super::actions::InitActionBuilder;
use crate::builder::actions::ActionBuilder as ActionBuilderTrait;
use crate::builder::actions::{
AssignRouteActionBuilder, FollowRouteActionBuilder, FollowTrajectoryActionBuilder,
LongitudinalDistanceActionBuilder, SpeedProfileActionBuilder, SynchronizeActionBuilder,
VisibilityActionBuilder,
};
use crate::builder::BuilderResult;
use crate::types::{
actions::appearance::VisibilityAction,
actions::movement::{
LateralAction, LongitudinalAction as LongitudinalActionType, RoutingAction, SpeedAction,
SpeedActionTarget, SynchronizeAction, TeleportAction, TransitionDynamics,
},
actions::wrappers::PrivateAction as PrivateActionWrapper,
basic::{Double, Value},
enums::{DynamicsDimension, DynamicsShape},
environment::Environment,
positions::Position,
routing::{Route, RouteRef},
scenario::init::{EnvironmentAction, GlobalAction, LongitudinalAction, Private, PrivateAction},
};
#[derive(Debug)]
pub struct PrivateActionBuilder {
parent: InitActionBuilder,
entity_ref: String,
actions: Vec<PrivateActionWrapper>,
}
impl PrivateActionBuilder {
pub fn new(parent: InitActionBuilder, entity_ref: &str) -> Self {
Self {
parent,
entity_ref: entity_ref.to_string(),
actions: Vec::new(),
}
}
pub fn add_teleport_action(mut self, position: Position) -> Self {
let action = PrivateActionWrapper::TeleportAction(TeleportAction { position });
self.actions.push(action);
self
}
pub fn add_speed_action(mut self, speed: f64) -> Self {
let speed_action = SpeedAction {
speed_action_dynamics: TransitionDynamics {
dynamics_dimension: DynamicsDimension::Time,
dynamics_shape: DynamicsShape::Step,
value: Double::literal(1.0),
},
speed_action_target: SpeedActionTarget {
absolute: Some(crate::types::actions::movement::AbsoluteTargetSpeed {
value: Double::literal(speed),
}),
relative: None,
},
};
let action = PrivateActionWrapper::LongitudinalAction(LongitudinalActionType {
longitudinal_action_choice:
crate::types::actions::movement::LongitudinalActionChoice::SpeedAction(speed_action),
});
self.actions.push(action);
self
}
pub fn add_action(mut self, action: PrivateActionWrapper) -> Self {
self.actions.push(action);
self
}
pub fn add_longitudinal_distance_action(mut self, target_entity: &str, distance: f64) -> Self {
let builder_action = LongitudinalDistanceActionBuilder::new()
.from_entity(target_entity)
.at_distance(distance)
.build_action()
.unwrap();
self.actions.push(builder_action);
self
}
pub fn add_speed_profile_action_direct(mut self, entries: Vec<(f64, f64)>) -> Self {
let mut builder = SpeedProfileActionBuilder::new();
for (time, speed) in entries {
builder = builder.add_entry_direct(time, speed);
}
if let Ok(builder_action) = builder.build_action() {
self.actions.push(builder_action);
}
self
}
pub fn add_assign_route_action(mut self, route: Route) -> Self {
let builder_action = AssignRouteActionBuilder::new()
.with_direct_route(route)
.build_action()
.unwrap();
self.actions.push(builder_action);
self
}
pub fn add_assign_route_catalog(
mut self,
catalog_name: impl Into<String>,
entry_name: impl Into<String>,
) -> Self {
let builder_action = AssignRouteActionBuilder::new()
.with_catalog_route(catalog_name, entry_name)
.build_action()
.unwrap();
self.actions.push(builder_action);
self
}
pub fn add_follow_route_action(mut self, route_ref: RouteRef) -> Self {
let builder_action = FollowRouteActionBuilder::new()
.with_route_ref(route_ref)
.build_action()
.unwrap();
self.actions.push(builder_action);
self
}
pub fn add_synchronize_action(
mut self,
master_entity: &str,
master_position: Position,
entity_position: Position,
) -> Self {
let builder_action = SynchronizeActionBuilder::new()
.with_master(master_entity)
.master_position(master_position)
.entity_position(entity_position)
.build_action()
.unwrap();
self.actions.push(builder_action);
self
}
pub fn add_visibility_action(mut self, graphics: bool, sensors: bool, traffic: bool) -> Self {
let builder_action = VisibilityActionBuilder::new()
.graphics(graphics)
.sensors(sensors)
.traffic(traffic)
.build_action()
.unwrap();
self.actions.push(builder_action);
self
}
pub fn make_visible(self) -> Self {
self.add_visibility_action(true, true, true)
}
pub fn make_invisible(self) -> Self {
self.add_visibility_action(false, false, false)
}
fn convert_to_init_action(action: PrivateActionWrapper) -> PrivateAction {
match action {
PrivateActionWrapper::LongitudinalAction(long_action) => {
PrivateAction {
longitudinal_action: Some(LongitudinalAction {
speed_action: match &long_action.longitudinal_action_choice {
crate::types::actions::movement::LongitudinalActionChoice::SpeedAction(a) => Some(a.clone()),
_ => None,
},
longitudinal_distance_action: match &long_action.longitudinal_action_choice {
crate::types::actions::movement::LongitudinalActionChoice::LongitudinalDistanceAction(a) => Some(a.clone()),
_ => None,
},
speed_profile_action: match &long_action.longitudinal_action_choice {
crate::types::actions::movement::LongitudinalActionChoice::SpeedProfileAction(a) => Some(a.clone()),
_ => None,
},
}),
..Default::default()
}
}
PrivateActionWrapper::LateralAction(lateral_action) => {
PrivateAction {
lateral_action: Some(lateral_action),
..Default::default()
}
}
PrivateActionWrapper::RoutingAction(routing_action) => {
PrivateAction {
routing_action: Some(routing_action),
..Default::default()
}
}
PrivateActionWrapper::VisibilityAction(visibility_action) => {
PrivateAction {
visibility_action: Some(visibility_action),
..Default::default()
}
}
PrivateActionWrapper::SynchronizeAction(sync_action) => {
PrivateAction {
synchronize_action: Some(sync_action),
..Default::default()
}
}
PrivateActionWrapper::TeleportAction(teleport_action) => {
PrivateAction {
teleport_action: Some(teleport_action),
..Default::default()
}
}
PrivateActionWrapper::ControllerAction(controller_action) => {
PrivateAction {
controller_action: Some(controller_action),
..Default::default()
}
}
_ => PrivateAction::default(),
}
}
pub fn finish(self) -> InitActionBuilder {
let private_actions: Vec<PrivateAction> = self
.actions
.into_iter()
.map(Self::convert_to_init_action)
.collect();
let private = Private {
entity_ref: Value::literal(self.entity_ref),
private_actions,
};
self.parent.add_private(private)
}
pub fn build(self) -> BuilderResult<Private> {
let private_actions: Vec<PrivateAction> = self
.actions
.into_iter()
.map(Self::convert_to_init_action)
.collect();
Ok(Private {
entity_ref: Value::literal(self.entity_ref),
private_actions,
})
}
}
#[derive(Debug)]
pub struct GlobalActionBuilder {
parent: InitActionBuilder,
environment_action: Option<EnvironmentAction>,
}
impl GlobalActionBuilder {
pub fn new(parent: InitActionBuilder) -> Self {
Self {
parent,
environment_action: None,
}
}
pub fn add_environment_action(mut self, environment: Environment) -> Self {
self.environment_action = Some(EnvironmentAction { environment });
self
}
pub fn add_default_environment_action(mut self) -> Self {
self.environment_action = Some(EnvironmentAction {
environment: Environment::default(),
});
self
}
pub fn finish(self) -> InitActionBuilder {
let global_action = GlobalAction {
environment_action: self.environment_action,
};
self.parent.add_global(global_action)
}
pub fn build(self) -> BuilderResult<GlobalAction> {
Ok(GlobalAction {
environment_action: self.environment_action,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::builder::positions::WorldPositionBuilder;
#[test]
fn test_private_action_builder() {
let position = WorldPositionBuilder::new()
.at_coordinates(10.0, 20.0, 0.0)
.build()
.unwrap();
let private = PrivateActionBuilder::new(InitActionBuilder::new(), "ego")
.add_teleport_action(position)
.add_speed_action(30.0)
.build()
.unwrap();
assert_eq!(private.entity_ref.as_literal().unwrap(), "ego");
assert_eq!(private.private_actions.len(), 2);
assert!(private.private_actions[0].teleport_action.is_some());
assert!(private.private_actions[1].longitudinal_action.is_some());
let longitudinal = private.private_actions[1]
.longitudinal_action
.as_ref()
.unwrap();
assert!(longitudinal.speed_action.is_some());
let speed_action = longitudinal.speed_action.as_ref().unwrap();
assert_eq!(
speed_action
.speed_action_target
.absolute
.as_ref()
.unwrap()
.value
.as_literal()
.unwrap(),
&30.0
);
}
#[test]
fn test_private_action_builder_fluent() {
let position = WorldPositionBuilder::new()
.at_coordinates(0.0, 0.0, 0.0)
.build()
.unwrap();
let init = InitActionBuilder::new()
.create_private_action("ego")
.add_teleport_action(position)
.add_speed_action(25.0)
.finish()
.build()
.unwrap();
assert_eq!(init.actions.private_actions.len(), 1);
assert_eq!(
init.actions.private_actions[0]
.entity_ref
.as_literal()
.unwrap(),
"ego"
);
assert_eq!(init.actions.private_actions[0].private_actions.len(), 2);
}
#[test]
fn test_global_action_builder() {
let global = GlobalActionBuilder::new(InitActionBuilder::new())
.add_default_environment_action()
.build()
.unwrap();
assert!(global.environment_action.is_some());
}
#[test]
fn test_global_action_builder_fluent() {
let init = InitActionBuilder::new()
.create_global_action()
.add_default_environment_action()
.finish()
.build()
.unwrap();
assert_eq!(init.actions.global_actions.len(), 1);
assert!(init.actions.global_actions[0].environment_action.is_some());
}
#[test]
fn test_combined_builders() {
let position = WorldPositionBuilder::new()
.at_coordinates(5.0, 10.0, 0.0)
.build()
.unwrap();
let init = InitActionBuilder::new()
.create_global_action()
.add_default_environment_action()
.finish()
.create_private_action("ego")
.add_teleport_action(position)
.add_speed_action(40.0)
.finish()
.create_private_action("target")
.add_speed_action(35.0)
.finish()
.build()
.unwrap();
assert_eq!(init.actions.global_actions.len(), 1);
assert_eq!(init.actions.private_actions.len(), 2);
let ego_private = &init.actions.private_actions[0];
assert_eq!(ego_private.entity_ref.as_literal().unwrap(), "ego");
assert_eq!(ego_private.private_actions.len(), 2);
let target_private = &init.actions.private_actions[1];
assert_eq!(target_private.entity_ref.as_literal().unwrap(), "target");
assert_eq!(target_private.private_actions.len(), 1);
}
}