geop_ops_model/placed/
explode.rs1use geop_core_math::{geop_error::GeopResult, primitives::Pose};
10use geop_core_program::{
11 element::{ElementReference, HasElements, Kind, whole},
12 placed::INSTANCE_SEPARATOR,
13 reader::Reader,
14 target::{Target, TargetReference},
15};
16
17#[derive(Clone, Debug, PartialEq)]
22pub struct Explosion {
23 pub parts: Vec<String>,
24 pub motion: Pose,
25}
26
27impl Explosion {
28 pub fn moves(&self, path: &str) -> bool {
31 (self.parts.iter()).any(|part| {
32 path.strip_prefix(part.as_str())
33 .is_some_and(|rest| rest.is_empty() || rest.starts_with(INSTANCE_SEPARATOR))
34 })
35 }
36}
37
38impl Target for Explosion {}
40
41impl Kind for Explosion {
43 const NAME: &'static str = "explosion";
44}
45
46const PREFIX: &str = "explosion:";
48
49impl HasElements<Explosion> for Explosion {
50 type Element<'a> = &'a Explosion;
51
52 fn element(&self, name: &str) -> GeopResult<&Explosion> {
53 whole(self, name)
54 }
55
56 fn names_target(name: &str) -> bool {
57 name.starts_with(PREFIX)
58 }
59}
60
61pub fn explosion(step: &str) -> TargetReference<Explosion> {
63 TargetReference::new(format!("{PREFIX}{step}"))
64}
65
66pub fn explosions<'a>(reader: &Reader<'a>) -> Vec<&'a Explosion> {
71 (reader.targets_of::<Explosion>().into_iter())
72 .filter_map(|target| {
73 reader
74 .retrieve_element(&ElementReference::whole(target))
75 .ok()
76 })
77 .collect()
78}
79
80pub fn exploded(explosions: &[&Explosion], path: &str, world: &Pose) -> Pose {
83 (explosions.iter())
84 .filter(|explosion| explosion.moves(path))
85 .fold(*world, |at, explosion| explosion.motion.compose(&at))
86}