use std::{collections::HashMap, fmt, io::BufRead, path::Path};
mod level;
mod object;
mod region;
pub use level::SemanticLevel;
pub use object::SemanticObject;
pub use region::SemanticRegion;
use crate::{Aabb, Dataset};
#[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, Clone)]
pub struct SemanticScene<ObjectCategory, RegionCategory> {
pub(crate) name: String,
pub(crate) label: String,
pub(crate) counts: HashMap<&'static str, usize>,
pub(crate) aabb: Option<Aabb>,
pub(crate) levels: Vec<SemanticLevel<ObjectCategory, RegionCategory>>,
}
impl<ObjectCategory, RegionCategory> Default for SemanticScene<ObjectCategory, RegionCategory> {
fn default() -> Self {
Self {
name: String::new(),
label: String::new(),
counts: HashMap::new(),
aabb: None,
levels: Vec::new(),
}
}
}
impl<ObjectCategory, RegionCategory> SemanticScene<ObjectCategory, RegionCategory> {
#[must_use]
pub fn from_parts(
name: impl Into<String>,
label: impl Into<String>,
counts: HashMap<&'static str, usize>,
aabb: Option<Aabb>,
levels: Vec<SemanticLevel<ObjectCategory, RegionCategory>>,
) -> Self {
Self {
name: name.into(),
label: label.into(),
counts,
aabb,
levels,
}
}
#[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()
}
pub(crate) fn count(&self, element: ElementKind) -> Option<usize> {
self.counts.get(element.as_str()).copied()
}
#[must_use]
pub fn levels(&self) -> &[SemanticLevel<ObjectCategory, RegionCategory>] {
&self.levels
}
pub fn regions(&self) -> impl Iterator<Item = &SemanticRegion<ObjectCategory, RegionCategory>> {
self.levels.iter().flat_map(SemanticLevel::regions)
}
pub fn objects(&self) -> impl Iterator<Item = &SemanticObject<ObjectCategory>> {
self.levels.iter().flat_map(SemanticLevel::objects)
}
}
impl<ObjectCategory, RegionCategory> fmt::Display
for SemanticScene<ObjectCategory, RegionCategory>
{
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<(), ()> {
pub fn load<D: Dataset>(
path: impl AsRef<Path>,
options: D::Options,
) -> Result<SemanticScene<D::ObjectCategory, D::RegionCategory>, D::Error>
where
D::Error: From<std::io::Error>,
{
D::from_path(path, options)
}
pub fn from_reader<D: Dataset, R: BufRead>(
reader: R,
options: D::Options,
) -> Result<SemanticScene<D::ObjectCategory, D::RegionCategory>, D::Error> {
D::from_reader(reader, options)
}
pub fn from_str<D: Dataset>(
input: &str,
options: D::Options,
) -> Result<SemanticScene<D::ObjectCategory, D::RegionCategory>, D::Error> {
D::from_str(input, options)
}
}
impl<ObjectCategory, RegionCategory> SemanticScene<ObjectCategory, RegionCategory> {
const fn display_aabb(&self) -> DisplayAabb<'_> {
DisplayAabb(self.aabb.as_ref())
}
const fn display_counts(&self) -> DisplayCounts<'_, ObjectCategory, RegionCategory> {
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, ObjectCategory, RegionCategory>(
&'a SemanticScene<ObjectCategory, RegionCategory>,
);
impl<ObjectCategory, RegionCategory> fmt::Display
for DisplayCounts<'_, ObjectCategory, RegionCategory>
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"levels={}, regions={}, objects={}, categories={}, segments={}",
self.0.levels.len(),
self.0.regions().count(),
self.0.objects().count(),
self.0.count(ElementKind::Categories).unwrap_or(0),
self.0.count(ElementKind::Segments).unwrap_or(0),
)
}
}