use std::fmt;
mod category;
mod level;
mod object;
mod region;
use std::{collections::HashMap, path::Path};
pub use category::{Category, CategoryMapping, RegionCategory};
pub use level::SemanticLevel;
pub use object::SemanticObject;
pub use region::SemanticRegion;
use crate::{Aabb, LoadError, Mp3dLoader, Mp3dOptions, SemanticSceneLoader};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ElementKind {
Images,
Panoramas,
Vertices,
Surfaces,
Segments,
Objects,
Categories,
Regions,
Portals,
Levels,
}
impl ElementKind {
pub(crate) const fn as_str(self) -> &'static str {
match self {
Self::Images => "images",
Self::Panoramas => "panoramas",
Self::Vertices => "vertices",
Self::Surfaces => "surfaces",
Self::Segments => "segments",
Self::Objects => "objects",
Self::Categories => "categories",
Self::Regions => "regions",
Self::Portals => "portals",
Self::Levels => "levels",
}
}
}
#[derive(Debug, Default, Clone)]
pub struct SemanticScene {
pub(crate) name: String,
pub(crate) label: String,
pub(crate) counts: HashMap<&'static str, usize>,
pub(crate) aabb: Option<Aabb>,
pub(crate) categories: Vec<Category>,
pub(crate) levels: Vec<SemanticLevel>,
pub(crate) regions: Vec<SemanticRegion>,
pub(crate) objects: Vec<SemanticObject>,
pub(crate) semantic_index_map: HashMap<i32, usize>,
}
impl SemanticScene {
pub(crate) fn new() -> Self {
Self::default()
}
#[must_use]
pub fn name(&self) -> &str {
&self.name
}
#[must_use]
pub fn label(&self) -> &str {
&self.label
}
#[must_use]
pub const fn aabb(&self) -> Option<&Aabb> {
self.aabb.as_ref()
}
#[must_use]
pub fn count(&self, element: ElementKind) -> Option<usize> {
self.counts.get(element.as_str()).copied()
}
#[must_use]
pub fn categories(&self) -> &[Category] {
&self.categories
}
#[must_use]
pub fn levels(&self) -> &[SemanticLevel] {
&self.levels
}
#[must_use]
pub fn regions(&self) -> &[SemanticRegion] {
&self.regions
}
#[must_use]
pub fn objects(&self) -> &[SemanticObject] {
&self.objects
}
#[must_use]
pub const fn semantic_index_map(&self) -> &HashMap<i32, usize> {
&self.semantic_index_map
}
#[must_use]
pub fn semantic_index_to_object_index(&self, mask_index: i32) -> Option<usize> {
self.semantic_index_map.get(&mask_index).copied()
}
pub fn load_mp3d_house(path: impl AsRef<Path>) -> Result<Self, LoadError> {
Mp3dLoader::from_path(path, Mp3dOptions::default())
}
pub(crate) fn set_header(
&mut self,
name: String,
label: String,
counts: HashMap<&'static str, usize>,
aabb: Aabb,
) {
self.name = name;
self.label = label;
self.counts = counts;
self.aabb = Some(aabb);
}
pub(crate) fn push_category(&mut self, category: Category) {
self.categories.push(category);
}
pub(crate) fn push_level(&mut self, level: SemanticLevel) {
self.levels.push(level);
}
pub(crate) fn push_region(&mut self, region: SemanticRegion) {
self.regions.push(region);
}
pub(crate) fn push_object(&mut self, object: SemanticObject) {
self.objects.push(object);
}
pub(crate) fn insert_segment(&mut self, segment_id: i32, object_index: usize) -> Option<usize> {
self.semantic_index_map.insert(segment_id, object_index)
}
pub(crate) fn level_position_by_index(&self, index: i32) -> Option<usize> {
self.levels.iter().position(|level| level.index() == index)
}
pub(crate) fn region_position_by_index(&self, index: i32) -> Option<usize> {
self.regions
.iter()
.position(|region| region.index() == index)
}
pub(crate) fn category_position_by_index(&self, index: i32) -> Option<usize> {
self.categories
.iter()
.position(|category| category.source_index() == index)
}
pub(crate) fn object_position_by_index(&self, index: i32) -> Option<usize> {
self.objects
.iter()
.position(|object| object.index() == index)
}
pub(crate) fn level_mut(&mut self, index: usize) -> Option<&mut SemanticLevel> {
self.levels.get_mut(index)
}
pub(crate) fn region_mut(&mut self, index: usize) -> Option<&mut SemanticRegion> {
self.regions.get_mut(index)
}
}
impl fmt::Display for SemanticScene {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
if formatter.alternate() {
write!(
formatter,
"SemanticScene {:?}\n label: {:?}\n bounds: {}\n counts: {}",
self.name,
self.label,
self.display_aabb(),
self.display_counts()
)
} else {
write!(
formatter,
"SemanticScene {:?}: {}, bounds=[{}]",
self.name,
self.display_counts(),
self.display_aabb()
)
}
}
}
impl SemanticScene {
const fn display_aabb(&self) -> DisplayAabb<'_> {
DisplayAabb(self.aabb.as_ref())
}
const fn display_counts(&self) -> DisplayCounts<'_> {
DisplayCounts(self)
}
}
struct DisplayAabb<'a>(Option<&'a Aabb>);
impl fmt::Display for DisplayAabb<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Some(aabb) => aabb.fmt(formatter),
None => formatter.write_str("none"),
}
}
}
struct DisplayCounts<'a>(&'a SemanticScene);
impl fmt::Display for DisplayCounts<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"levels={}, regions={}, objects={}, categories={}, segments={}",
self.0
.count(ElementKind::Levels)
.unwrap_or(self.0.levels.len()),
self.0
.count(ElementKind::Regions)
.unwrap_or(self.0.regions.len()),
self.0
.count(ElementKind::Objects)
.unwrap_or(self.0.objects.len()),
self.0
.count(ElementKind::Categories)
.unwrap_or(self.0.categories.len()),
self.0
.count(ElementKind::Segments)
.unwrap_or(self.0.semantic_index_map.len()),
)
}
}