1use std::fmt;
4
5mod category;
6mod level;
7mod object;
8mod region;
9
10use std::{collections::HashMap, path::Path};
11
12pub use category::{Category, CategoryMapping, RegionCategory};
13pub use level::SemanticLevel;
14pub use object::SemanticObject;
15pub use region::SemanticRegion;
16
17use crate::{Aabb, LoadError, Mp3dLoader, Mp3dOptions, SemanticSceneLoader};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub enum ElementKind {
22 Images,
24 Panoramas,
26 Vertices,
28 Surfaces,
30 Segments,
32 Objects,
34 Categories,
36 Regions,
38 Portals,
40 Levels,
42}
43
44impl ElementKind {
45 pub(crate) const fn as_str(self) -> &'static str {
46 match self {
47 Self::Images => "images",
48 Self::Panoramas => "panoramas",
49 Self::Vertices => "vertices",
50 Self::Surfaces => "surfaces",
51 Self::Segments => "segments",
52 Self::Objects => "objects",
53 Self::Categories => "categories",
54 Self::Regions => "regions",
55 Self::Portals => "portals",
56 Self::Levels => "levels",
57 }
58 }
59}
60
61#[derive(Debug, Default, Clone)]
66pub struct SemanticScene {
67 pub(crate) name: String,
68 pub(crate) label: String,
69 pub(crate) counts: HashMap<&'static str, usize>,
70 pub(crate) aabb: Option<Aabb>,
71 pub(crate) categories: Vec<Category>,
72 pub(crate) levels: Vec<SemanticLevel>,
73 pub(crate) regions: Vec<SemanticRegion>,
74 pub(crate) objects: Vec<SemanticObject>,
75 pub(crate) semantic_index_map: HashMap<i32, usize>,
76}
77
78impl SemanticScene {
79 pub(crate) fn new() -> Self {
80 Self::default()
81 }
82
83 #[must_use]
85 pub fn name(&self) -> &str {
86 &self.name
87 }
88
89 #[must_use]
91 pub fn label(&self) -> &str {
92 &self.label
93 }
94
95 #[must_use]
100 pub const fn aabb(&self) -> Option<&Aabb> {
101 self.aabb.as_ref()
102 }
103
104 #[must_use]
106 pub fn count(&self, element: ElementKind) -> Option<usize> {
107 self.counts.get(element.as_str()).copied()
108 }
109
110 #[must_use]
112 pub fn categories(&self) -> &[Category] {
113 &self.categories
114 }
115
116 #[must_use]
118 pub fn levels(&self) -> &[SemanticLevel] {
119 &self.levels
120 }
121
122 #[must_use]
124 pub fn regions(&self) -> &[SemanticRegion] {
125 &self.regions
126 }
127
128 #[must_use]
130 pub fn objects(&self) -> &[SemanticObject] {
131 &self.objects
132 }
133
134 #[must_use]
136 pub const fn semantic_index_map(&self) -> &HashMap<i32, usize> {
137 &self.semantic_index_map
138 }
139
140 #[must_use]
145 pub fn semantic_index_to_object_index(&self, mask_index: i32) -> Option<usize> {
146 self.semantic_index_map.get(&mask_index).copied()
147 }
148
149 pub fn load_mp3d_house(path: impl AsRef<Path>) -> Result<Self, LoadError> {
155 Mp3dLoader::from_path(path, Mp3dOptions::default())
156 }
157
158 pub(crate) fn set_header(
159 &mut self,
160 name: String,
161 label: String,
162 counts: HashMap<&'static str, usize>,
163 aabb: Aabb,
164 ) {
165 self.name = name;
166 self.label = label;
167 self.counts = counts;
168 self.aabb = Some(aabb);
169 }
170
171 pub(crate) fn push_category(&mut self, category: Category) {
172 self.categories.push(category);
173 }
174
175 pub(crate) fn push_level(&mut self, level: SemanticLevel) {
176 self.levels.push(level);
177 }
178
179 pub(crate) fn push_region(&mut self, region: SemanticRegion) {
180 self.regions.push(region);
181 }
182
183 pub(crate) fn push_object(&mut self, object: SemanticObject) {
184 self.objects.push(object);
185 }
186
187 pub(crate) fn insert_segment(&mut self, segment_id: i32, object_index: usize) -> Option<usize> {
188 self.semantic_index_map.insert(segment_id, object_index)
189 }
190
191 pub(crate) fn level_position_by_index(&self, index: i32) -> Option<usize> {
192 self.levels.iter().position(|level| level.index() == index)
193 }
194
195 pub(crate) fn region_position_by_index(&self, index: i32) -> Option<usize> {
196 self.regions
197 .iter()
198 .position(|region| region.index() == index)
199 }
200
201 pub(crate) fn category_position_by_index(&self, index: i32) -> Option<usize> {
202 self.categories
203 .iter()
204 .position(|category| category.source_index() == index)
205 }
206
207 pub(crate) fn object_position_by_index(&self, index: i32) -> Option<usize> {
208 self.objects
209 .iter()
210 .position(|object| object.index() == index)
211 }
212
213 pub(crate) fn level_mut(&mut self, index: usize) -> Option<&mut SemanticLevel> {
214 self.levels.get_mut(index)
215 }
216
217 pub(crate) fn region_mut(&mut self, index: usize) -> Option<&mut SemanticRegion> {
218 self.regions.get_mut(index)
219 }
220}
221
222impl fmt::Display for SemanticScene {
223 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
224 if formatter.alternate() {
225 write!(
226 formatter,
227 "SemanticScene {:?}\n label: {:?}\n bounds: {}\n counts: {}",
228 self.name,
229 self.label,
230 self.display_aabb(),
231 self.display_counts()
232 )
233 } else {
234 write!(
235 formatter,
236 "SemanticScene {:?}: {}, bounds=[{}]",
237 self.name,
238 self.display_counts(),
239 self.display_aabb()
240 )
241 }
242 }
243}
244
245impl SemanticScene {
246 const fn display_aabb(&self) -> DisplayAabb<'_> {
247 DisplayAabb(self.aabb.as_ref())
248 }
249
250 const fn display_counts(&self) -> DisplayCounts<'_> {
251 DisplayCounts(self)
252 }
253}
254
255struct DisplayAabb<'a>(Option<&'a Aabb>);
256
257impl fmt::Display for DisplayAabb<'_> {
258 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
259 match self.0 {
260 Some(aabb) => aabb.fmt(formatter),
261 None => formatter.write_str("none"),
262 }
263 }
264}
265
266struct DisplayCounts<'a>(&'a SemanticScene);
267
268impl fmt::Display for DisplayCounts<'_> {
269 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
270 write!(
271 formatter,
272 "levels={}, regions={}, objects={}, categories={}, segments={}",
273 self.0
274 .count(ElementKind::Levels)
275 .unwrap_or(self.0.levels.len()),
276 self.0
277 .count(ElementKind::Regions)
278 .unwrap_or(self.0.regions.len()),
279 self.0
280 .count(ElementKind::Objects)
281 .unwrap_or(self.0.objects.len()),
282 self.0
283 .count(ElementKind::Categories)
284 .unwrap_or(self.0.categories.len()),
285 self.0
286 .count(ElementKind::Segments)
287 .unwrap_or(self.0.semantic_index_map.len()),
288 )
289 }
290}