semantic-scene 0.1.0

Rust parser for Habitat-Sim `SemanticScene` descriptors.
Documentation
//! Semantic object model.

use std::fmt;

use crate::{Aabb, Obb, SemanticScene};

/// Represents a distinct semantically annotated object.
///
/// The source index is also the object's semantic id, matching Habitat-Sim's
/// `SemanticObject::semanticID()`.
#[derive(Debug, Clone, PartialEq)]
pub struct SemanticObject {
    index: i32,
    region_index: Option<usize>,
    category_index: Option<usize>,
    obb: Obb,
}

impl SemanticObject {
    #[must_use]
    pub(crate) const fn new(
        index: i32,
        region_index: Option<usize>,
        category_index: Option<usize>,
        obb: Obb,
    ) -> Self {
        Self {
            index,
            region_index,
            category_index,
            obb,
        }
    }

    /// Returns the Habitat-Sim-style object id.
    ///
    /// If the object has a parent region, the form is
    /// `<level_id>_<region_id>_<object_id>`. Otherwise, the form is
    /// `_<object_id>`.
    #[must_use]
    pub fn id(&self, scene: &SemanticScene) -> String {
        self.region_index.map_or_else(
            || format!("_{}", self.index),
            |region_index| format!("{}_{}", scene.regions()[region_index].id(scene), self.index),
        )
    }

    /// Returns the source descriptor index.
    #[must_use]
    pub const fn index(&self) -> i32 {
        self.index
    }

    /// Returns the unique semantic id corresponding to this object.
    #[must_use]
    pub const fn semantic_id(&self) -> i32 {
        self.index
    }

    /// Returns the index of this object's parent region in `SemanticScene::regions`.
    #[must_use]
    pub const fn region_index(&self) -> Option<usize> {
        self.region_index
    }

    /// Returns the index of this object's category in `SemanticScene::categories`.
    #[must_use]
    pub const fn category_index(&self) -> Option<usize> {
        self.category_index
    }

    /// Returns the axis-aligned bounding box enclosing this object.
    #[must_use]
    pub fn aabb(&self) -> Aabb {
        self.obb.to_aabb()
    }

    /// Returns the object's oriented bounding box.
    #[must_use]
    pub const fn obb(&self) -> &Obb {
        &self.obb
    }
}

impl fmt::Display for SemanticObject {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        let region = self
            .region_index
            .map_or_else(|| "none".to_string(), |index| index.to_string());
        let category = self
            .category_index
            .map_or_else(|| "none".to_string(), |index| index.to_string());
        write!(
            formatter,
            "object {}: region={}, category={}, {}",
            self.index, region, category, self.obb
        )
    }
}