use std::fmt;
use crate::{Aabb, SemanticScene, Vec2, Vec3};
use super::RegionCategory;
#[derive(Debug, Clone, PartialEq)]
pub struct SemanticRegion {
index: i32,
level_index: Option<usize>,
category: RegionCategory,
position: Vec3,
aabb: Aabb,
object_indices: Vec<usize>,
poly_loop_points: Vec<Vec2>,
volume_edges: Vec<Vec<Vec3>>,
floor_height: f64,
extrusion_height: f64,
area: f64,
}
impl SemanticRegion {
#[must_use]
pub(crate) fn new(
index: i32,
level_index: Option<usize>,
category: RegionCategory,
position: Vec3,
aabb: Aabb,
) -> Self {
Self {
index,
level_index,
category,
position,
aabb,
object_indices: Vec::new(),
poly_loop_points: Vec::new(),
volume_edges: Vec::new(),
floor_height: f64::from(aabb.min.1),
extrusion_height: f64::from(aabb.max.1 - aabb.min.1),
area: f64::from((aabb.max.0 - aabb.min.0).abs() * (aabb.max.2 - aabb.min.2).abs()),
}
}
#[must_use]
pub fn id(&self, scene: &SemanticScene) -> String {
self.level_index.map_or_else(
|| format!("_{}", self.index),
|level_index| format!("{}_{}", scene.levels()[level_index].id(), self.index),
)
}
#[must_use]
pub const fn index(&self) -> i32 {
self.index
}
#[must_use]
pub const fn level_index(&self) -> Option<usize> {
self.level_index
}
#[must_use]
pub const fn category(&self) -> &RegionCategory {
&self.category
}
#[must_use]
pub const fn position(&self) -> Vec3 {
self.position
}
#[must_use]
pub const fn aabb(&self) -> &Aabb {
&self.aabb
}
#[must_use]
pub fn object_indices(&self) -> &[usize] {
&self.object_indices
}
#[must_use]
pub fn contains(&self, point: Vec3) -> bool {
self.aabb.contains(point)
}
#[must_use]
pub fn poly_loop_points(&self) -> &[Vec2] {
&self.poly_loop_points
}
#[must_use]
pub fn volume_edges(&self) -> &[Vec<Vec3>] {
&self.volume_edges
}
#[must_use]
pub const fn floor_height(&self) -> f64 {
self.floor_height
}
#[must_use]
pub const fn extrusion_height(&self) -> f64 {
self.extrusion_height
}
#[must_use]
pub const fn area(&self) -> f64 {
self.area
}
#[must_use]
pub const fn volume(&self) -> f64 {
self.area * self.extrusion_height
}
pub(crate) fn add_object(&mut self, object_index: usize) {
self.object_indices.push(object_index);
}
}
impl fmt::Display for SemanticRegion {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let level = self
.level_index
.map_or_else(|| "none".to_string(), |index| index.to_string());
write!(
formatter,
"region {}: level={}, category={}, objects={}, bounds=[{}]",
self.index,
level,
self.category,
self.object_indices.len(),
self.aabb
)
}
}