use crate::{EntityId, IfcType, MeshData};
use std::sync::Arc;
#[derive(Clone, Debug)]
pub struct EntityGeometry {
pub mesh: Arc<MeshData>,
pub color: [f32; 4],
pub transform: [f32; 16],
}
impl EntityGeometry {
pub fn new(mesh: Arc<MeshData>, color: [f32; 4], transform: [f32; 16]) -> Self {
Self {
mesh,
color,
transform,
}
}
pub fn with_identity_transform(mesh: Arc<MeshData>, color: [f32; 4]) -> Self {
Self {
mesh,
color,
transform: [
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
],
}
}
pub fn is_empty(&self) -> bool {
self.mesh.is_empty()
}
pub fn triangle_count(&self) -> usize {
self.mesh.triangle_count()
}
}
impl Default for EntityGeometry {
fn default() -> Self {
Self {
mesh: Arc::new(MeshData::default()),
color: [0.8, 0.8, 0.8, 1.0], transform: [
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
],
}
}
}
pub trait GeometrySource: Send + Sync {
fn entities_with_geometry(&self) -> Vec<EntityId>;
fn has_geometry(&self, id: EntityId) -> bool;
fn get_geometry(&self, id: EntityId) -> Option<EntityGeometry>;
fn batch_geometry(&self, ids: &[EntityId]) -> Vec<(EntityId, EntityGeometry)> {
ids.iter()
.filter_map(|id| self.get_geometry(*id).map(|g| (*id, g)))
.collect()
}
fn default_color(&self, ifc_type: &IfcType) -> [f32; 4] {
get_default_color(ifc_type)
}
fn total_triangle_count(&self) -> usize {
self.entities_with_geometry()
.iter()
.filter_map(|id| self.get_geometry(*id))
.map(|g| g.triangle_count())
.sum()
}
}
pub fn get_default_color(ifc_type: &IfcType) -> [f32; 4] {
match ifc_type {
IfcType::IfcWall | IfcType::IfcWallStandardCase => [0.85, 0.80, 0.70, 1.0],
IfcType::IfcCurtainWall => [0.6, 0.7, 0.8, 0.7],
IfcType::IfcSlab => [0.75, 0.75, 0.75, 1.0],
IfcType::IfcRoof => [0.72, 0.45, 0.35, 1.0],
IfcType::IfcBeam => [0.55, 0.60, 0.65, 1.0],
IfcType::IfcColumn => [0.60, 0.60, 0.60, 1.0],
IfcType::IfcDoor => [0.55, 0.40, 0.25, 1.0],
IfcType::IfcWindow => [0.7, 0.85, 0.95, 0.5],
IfcType::IfcStair | IfcType::IfcStairFlight => [0.70, 0.68, 0.65, 1.0],
IfcType::IfcRamp | IfcType::IfcRampFlight => [0.70, 0.68, 0.65, 1.0],
IfcType::IfcRailing => [0.50, 0.50, 0.55, 1.0],
IfcType::IfcCovering => [0.95, 0.95, 0.95, 1.0],
IfcType::IfcPlate => [0.60, 0.65, 0.70, 1.0],
IfcType::IfcMember => [0.58, 0.58, 0.58, 1.0],
IfcType::IfcFooting => [0.65, 0.65, 0.65, 1.0],
IfcType::IfcPile => [0.55, 0.55, 0.55, 1.0],
IfcType::IfcFurnishingElement | IfcType::IfcFurniture => [0.65, 0.50, 0.35, 1.0],
IfcType::IfcDistributionElement | IfcType::IfcDistributionFlowElement => {
[0.5, 0.7, 0.5, 1.0]
}
IfcType::IfcFlowTerminal => [0.7, 0.7, 0.5, 1.0],
IfcType::IfcFlowSegment => [0.5, 0.5, 0.7, 1.0],
IfcType::IfcFlowFitting => [0.6, 0.5, 0.6, 1.0],
IfcType::IfcCableSegment => [0.95, 0.55, 0.15, 1.0],
IfcType::IfcCableCarrierSegment => [0.85, 0.45, 0.10, 1.0],
IfcType::IfcCableCarrierFitting => [0.75, 0.40, 0.10, 1.0],
IfcType::IfcPipeSegment => [0.20, 0.50, 0.85, 1.0],
IfcType::IfcPipeFitting => [0.15, 0.40, 0.70, 1.0],
IfcType::IfcAirTerminal => [0.30, 0.75, 0.80, 1.0],
IfcType::IfcSpaceHeater => [0.85, 0.35, 0.35, 1.0],
IfcType::IfcOpeningElement | IfcType::IfcOpeningStandardCase => [1.0, 0.3, 0.3, 0.3],
IfcType::IfcLightFixture => [1.0, 0.9, 0.3, 1.0],
IfcType::IfcElementAssembly => [0.6, 0.7, 0.85, 1.0],
IfcType::IfcBuildingElementProxy => [0.7, 0.5, 0.8, 1.0],
IfcType::IfcRoad | IfcType::IfcRoadPart => [0.4, 0.4, 0.4, 1.0],
IfcType::IfcBridge | IfcType::IfcBridgePart => [0.6, 0.6, 0.55, 1.0],
IfcType::IfcRailway | IfcType::IfcRailwayPart => [0.5, 0.45, 0.4, 1.0],
IfcType::IfcPavement => [0.35, 0.35, 0.35, 1.0],
_ => [0.7, 0.7, 0.7, 1.0],
}
}
#[derive(Clone, Debug, Default)]
pub struct GeometryOptions {
pub compute_normals: bool,
pub deduplicate: bool,
pub merge_small_meshes: bool,
pub merge_threshold: usize,
}
impl GeometryOptions {
pub fn fast() -> Self {
Self {
compute_normals: true,
deduplicate: false,
merge_small_meshes: false,
merge_threshold: 0,
}
}
pub fn optimized() -> Self {
Self {
compute_normals: true,
deduplicate: true,
merge_small_meshes: true,
merge_threshold: 100,
}
}
}