jagua_rs/entities/
container.rs1use std::sync::Arc;
2
3use itertools::Itertools;
4
5use crate::collision_detection::hazards::Hazard;
6use crate::collision_detection::hazards::HazardEntity;
7use crate::collision_detection::{CDEConfig, CDEngine};
8use crate::geometry::OriginalShape;
9use crate::geometry::primitives::SPolygon;
10
11use anyhow::{Result, ensure};
12
13#[derive(Clone, Debug)]
15pub struct Container {
16 pub id: usize,
18 pub outer_orig: Arc<OriginalShape>,
20 pub outer_cd: Arc<SPolygon>,
22 pub quality_zones: [Option<InferiorQualityZone>; N_QUALITIES],
24 pub base_cde: Arc<CDEngine>,
26}
27
28impl Container {
29 pub fn new(
30 id: usize,
31 original_outer: OriginalShape,
32 quality_zones: Vec<InferiorQualityZone>,
33 cde_config: CDEConfig,
34 ) -> Result<Self> {
35 let outer = Arc::new(original_outer.convert_to_internal()?);
36 let outer_orig = Arc::new(original_outer);
37 ensure!(
38 quality_zones.len() == quality_zones.iter().map(|qz| qz.quality).unique().count(),
39 "Quality zones must have unique qualities"
40 );
41 ensure!(
42 quality_zones
43 .iter()
44 .map(|qz| qz.quality)
45 .all(|q| q < N_QUALITIES),
46 "All quality zones must be below N_QUALITIES: {N_QUALITIES}"
47 );
48 let quality_zones = {
49 let mut qz = <[_; N_QUALITIES]>::default();
50 for q in quality_zones {
51 let quality = q.quality;
52 qz[quality] = Some(q);
53 }
54 qz
55 };
56
57 let base_cde = {
58 let mut hazards = vec![Hazard::new(
59 HazardEntity::Exterior,
60 outer.as_ref().clone(),
61 false,
62 )];
63 let qz_hazards = quality_zones
64 .iter()
65 .flatten()
66 .flat_map(|qz| qz.to_hazards());
67 hazards.extend(qz_hazards);
68 let base_cde = CDEngine::new(outer.bbox.inflate_to_square(), hazards, cde_config);
69 Arc::new(base_cde)
70 };
71
72 Ok(Self {
73 id,
74 outer_cd: outer,
75 outer_orig,
76 quality_zones,
77 base_cde,
78 })
79 }
80
81 pub fn area(&self) -> f32 {
83 self.outer_orig.area() - self.quality_zones[0].as_ref().map_or(0.0, |qz| qz.area())
84 }
85}
86
87pub const N_QUALITIES: usize = 10;
89
90#[derive(Clone, Debug)]
92pub struct InferiorQualityZone {
93 pub quality: usize,
95 pub shapes_orig: Vec<Arc<OriginalShape>>,
97 pub shapes_cd: Vec<Arc<SPolygon>>,
99}
100
101impl InferiorQualityZone {
102 pub fn new(quality: usize, original_shapes: Vec<OriginalShape>) -> Result<Self> {
103 assert!(
104 quality < N_QUALITIES,
105 "Quality must be in range of N_QUALITIES"
106 );
107 let shapes: Result<Vec<Arc<SPolygon>>> = original_shapes
108 .iter()
109 .map(|orig| orig.convert_to_internal().map(Arc::new))
110 .collect();
111
112 let original_shapes = original_shapes.into_iter().map(Arc::new).collect_vec();
113
114 Ok(Self {
115 quality,
116 shapes_cd: shapes?,
117 shapes_orig: original_shapes,
118 })
119 }
120
121 pub fn to_hazards(&self) -> impl Iterator<Item = Hazard> {
123 self.shapes_cd.iter().enumerate().map(|(idx, shape)| {
124 let entity = match self.quality {
125 0 => HazardEntity::Hole { idx },
126 _ => HazardEntity::InferiorQualityZone {
127 quality: self.quality,
128 idx,
129 },
130 };
131 Hazard::new(entity, shape.as_ref().clone(), false)
132 })
133 }
134
135 pub fn area(&self) -> f32 {
136 self.shapes_orig.iter().map(|shape| shape.area()).sum()
137 }
138}