use crate::types::{
basic::{Double, OSString},
entities::ScenarioObject,
enums::{PedestrianCategory, Role},
geometry::{BoundingBox, Center, Dimensions},
};
pub struct PedestrianBuilder<'parent> {
parent: &'parent mut crate::builder::scenario::ScenarioBuilder<
crate::builder::scenario::HasEntities,
>,
name: String,
pedestrian_data: PartialPedestrianData,
}
pub struct DetachedPedestrianBuilder {
name: String,
pedestrian_data: PartialPedestrianData,
}
#[derive(Debug, Default)]
struct PartialPedestrianData {
name: Option<String>,
pedestrian_category: Option<PedestrianCategory>,
mass: Option<Double>,
role: Option<Role>,
model3d: Option<String>,
bounding_box: Option<BoundingBox>,
properties: Option<crate::types::entities::vehicle::Properties>,
}
impl<'parent> PedestrianBuilder<'parent> {
pub fn new(
parent: &'parent mut crate::builder::scenario::ScenarioBuilder<
crate::builder::scenario::HasEntities,
>,
name: &str,
) -> Self {
Self {
parent,
name: name.to_string(),
pedestrian_data: PartialPedestrianData::default(),
}
}
pub fn pedestrian(mut self) -> Self {
self.pedestrian_data.pedestrian_category = Some(PedestrianCategory::Pedestrian);
self.pedestrian_data.name = Some("StandardPedestrian".to_string());
self.pedestrian_data.bounding_box = Some(BoundingBox {
center: Center {
x: Double::literal(0.0),
y: Double::literal(0.0),
z: Double::literal(0.9),
},
dimensions: Dimensions {
width: Double::literal(0.6),
length: Double::literal(0.6),
height: Double::literal(1.8),
},
});
self
}
pub fn wheelchair(mut self) -> Self {
self.pedestrian_data.pedestrian_category = Some(PedestrianCategory::Wheelchair);
self.pedestrian_data.name = Some("Wheelchair".to_string());
self.pedestrian_data.bounding_box = Some(BoundingBox {
center: Center {
x: Double::literal(0.0),
y: Double::literal(0.0),
z: Double::literal(0.7),
},
dimensions: Dimensions {
width: Double::literal(0.8),
length: Double::literal(1.0),
height: Double::literal(1.4),
},
});
self
}
pub fn animal(mut self) -> Self {
self.pedestrian_data.pedestrian_category = Some(PedestrianCategory::Animal);
self.pedestrian_data.name = Some("Animal".to_string());
self.pedestrian_data.bounding_box = Some(BoundingBox {
center: Center {
x: Double::literal(0.0),
y: Double::literal(0.0),
z: Double::literal(0.4),
},
dimensions: Dimensions {
width: Double::literal(0.5),
length: Double::literal(0.5),
height: Double::literal(0.8),
},
});
self
}
pub fn with_mass(mut self, mass: f64) -> Self {
self.pedestrian_data.mass = Some(Double::literal(mass));
self
}
pub fn with_dimensions(mut self, length: f64, width: f64, height: f64) -> Self {
let existing_bbox = self.pedestrian_data.bounding_box.unwrap_or_default();
self.pedestrian_data.bounding_box = Some(BoundingBox {
center: existing_bbox.center,
dimensions: Dimensions {
width: Double::literal(width),
length: Double::literal(length),
height: Double::literal(height),
},
});
self
}
pub fn with_role(mut self, role: Role) -> Self {
self.pedestrian_data.role = Some(role);
self
}
pub fn with_model3d(mut self, model: &str) -> Self {
self.pedestrian_data.model3d = Some(model.to_string());
self
}
pub fn finish(
self,
) -> &'parent mut crate::builder::scenario::ScenarioBuilder<crate::builder::scenario::HasEntities>
{
let pedestrian = crate::types::entities::Pedestrian {
name: OSString::literal(
self.pedestrian_data
.name
.unwrap_or_else(|| "DefaultPedestrian".to_string()),
),
pedestrian_category: self
.pedestrian_data
.pedestrian_category
.unwrap_or(PedestrianCategory::Pedestrian),
mass: self
.pedestrian_data
.mass
.unwrap_or_else(|| Double::literal(75.0)),
role: self.pedestrian_data.role,
model3d: self.pedestrian_data.model3d,
bounding_box: self.pedestrian_data.bounding_box.unwrap_or_default(),
properties: self.pedestrian_data.properties,
parameter_declarations: None,
};
let scenario_object = ScenarioObject::new_pedestrian(self.name.clone(), pedestrian);
if let Some(ref mut entities) = self.parent.data.entities {
entities.add_object(scenario_object);
}
self.parent
}
}
impl DetachedPedestrianBuilder {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
pedestrian_data: PartialPedestrianData::default(),
}
}
pub fn pedestrian(mut self) -> Self {
self.pedestrian_data.pedestrian_category = Some(PedestrianCategory::Pedestrian);
self.pedestrian_data.name = Some("StandardPedestrian".to_string());
self.pedestrian_data.bounding_box = Some(BoundingBox {
center: Center {
x: Double::literal(0.0),
y: Double::literal(0.0),
z: Double::literal(0.9),
},
dimensions: Dimensions {
width: Double::literal(0.6),
length: Double::literal(0.6),
height: Double::literal(1.8),
},
});
self
}
pub fn wheelchair(mut self) -> Self {
self.pedestrian_data.pedestrian_category = Some(PedestrianCategory::Wheelchair);
self.pedestrian_data.name = Some("Wheelchair".to_string());
self.pedestrian_data.bounding_box = Some(BoundingBox {
center: Center {
x: Double::literal(0.0),
y: Double::literal(0.0),
z: Double::literal(0.7),
},
dimensions: Dimensions {
width: Double::literal(0.8),
length: Double::literal(1.0),
height: Double::literal(1.4),
},
});
self
}
pub fn animal(mut self) -> Self {
self.pedestrian_data.pedestrian_category = Some(PedestrianCategory::Animal);
self.pedestrian_data.name = Some("Animal".to_string());
self.pedestrian_data.bounding_box = Some(BoundingBox {
center: Center {
x: Double::literal(0.0),
y: Double::literal(0.0),
z: Double::literal(0.4),
},
dimensions: Dimensions {
width: Double::literal(0.5),
length: Double::literal(0.5),
height: Double::literal(0.8),
},
});
self
}
pub fn with_mass(mut self, mass: f64) -> Self {
self.pedestrian_data.mass = Some(Double::literal(mass));
self
}
pub fn with_dimensions(mut self, length: f64, width: f64, height: f64) -> Self {
let existing_bbox = self.pedestrian_data.bounding_box.unwrap_or_default();
self.pedestrian_data.bounding_box = Some(BoundingBox {
center: existing_bbox.center,
dimensions: Dimensions {
width: Double::literal(width),
length: Double::literal(length),
height: Double::literal(height),
},
});
self
}
pub fn with_role(mut self, role: Role) -> Self {
self.pedestrian_data.role = Some(role);
self
}
pub fn with_model3d(mut self, model: &str) -> Self {
self.pedestrian_data.model3d = Some(model.to_string());
self
}
pub fn finish(self) -> Self {
self
}
pub fn build(self) -> ScenarioObject {
let pedestrian = crate::types::entities::Pedestrian {
name: OSString::literal(
self.pedestrian_data
.name
.unwrap_or_else(|| "DefaultPedestrian".to_string()),
),
pedestrian_category: self
.pedestrian_data
.pedestrian_category
.unwrap_or(PedestrianCategory::Pedestrian),
mass: self
.pedestrian_data
.mass
.unwrap_or_else(|| Double::literal(75.0)),
role: self.pedestrian_data.role,
model3d: self.pedestrian_data.model3d,
bounding_box: self.pedestrian_data.bounding_box.unwrap_or_default(),
properties: self.pedestrian_data.properties,
parameter_declarations: None,
};
ScenarioObject::new_pedestrian(self.name.clone(), pedestrian)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_detached_builder_defaults() {
let obj = DetachedPedestrianBuilder::new("ped1").build();
let p = obj.pedestrian.as_ref().unwrap();
assert_eq!(p.name.as_literal(), Some(&"DefaultPedestrian".to_string()));
assert_eq!(p.pedestrian_category, PedestrianCategory::Pedestrian);
assert_eq!(p.mass.as_literal(), Some(&75.0));
assert!(p.role.is_none());
assert!(p.model3d.is_none());
}
#[test]
fn test_pedestrian_preset_sets_dimensions() {
let obj = DetachedPedestrianBuilder::new("ped1").pedestrian().build();
let p = obj.pedestrian.as_ref().unwrap();
assert_eq!(p.name.as_literal(), Some(&"StandardPedestrian".to_string()));
assert_eq!(p.bounding_box.dimensions.height.as_literal(), Some(&1.8));
assert_eq!(p.bounding_box.dimensions.width.as_literal(), Some(&0.6));
}
#[test]
fn test_animal_preset_differs_from_pedestrian() {
let obj = DetachedPedestrianBuilder::new("dog").animal().build();
let p = obj.pedestrian.as_ref().unwrap();
assert_eq!(p.pedestrian_category, PedestrianCategory::Animal);
assert_eq!(p.bounding_box.dimensions.height.as_literal(), Some(&0.8));
}
#[test]
fn test_wheelchair_preset() {
let obj = DetachedPedestrianBuilder::new("w1").wheelchair().build();
let p = obj.pedestrian.as_ref().unwrap();
assert_eq!(p.pedestrian_category, PedestrianCategory::Wheelchair);
assert_eq!(p.bounding_box.dimensions.height.as_literal(), Some(&1.4));
}
#[test]
fn test_chained_customizations() {
let obj = DetachedPedestrianBuilder::new("ped1")
.pedestrian()
.with_mass(90.0)
.with_role(Role::Civil)
.with_model3d("models/person.fbx")
.with_dimensions(0.7, 0.7, 1.9)
.build();
let p = obj.pedestrian.as_ref().unwrap();
assert_eq!(p.mass.as_literal(), Some(&90.0));
assert_eq!(p.role, Some(Role::Civil));
assert_eq!(p.model3d, Some("models/person.fbx".to_string()));
assert_eq!(p.bounding_box.dimensions.height.as_literal(), Some(&1.9));
assert_eq!(p.bounding_box.center.z.as_literal(), Some(&0.9));
}
}