mod caching;
mod clipping;
mod processing;
mod transforms;
mod voids;
mod voids_2d;
#[cfg(test)]
mod tests;
use crate::processors::{
AdvancedBrepProcessor, BooleanClippingProcessor, ExtrudedAreaSolidProcessor,
FaceBasedSurfaceModelProcessor, FacetedBrepProcessor, MappedItemProcessor,
PolygonalFaceSetProcessor, RevolvedAreaSolidProcessor, ShellBasedSurfaceModelProcessor,
SweptDiskSolidProcessor, TriangulatedFaceSetProcessor,
};
use crate::{Mesh, Result};
use ifc_lite_core::{DecodedEntity, EntityDecoder, IfcSchema, IfcType};
use nalgebra::Matrix4;
use rustc_hash::FxHashMap;
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::Arc;
pub trait GeometryProcessor {
fn process(
&self,
entity: &DecodedEntity,
decoder: &mut EntityDecoder,
schema: &IfcSchema,
) -> Result<Mesh>;
fn supported_types(&self) -> Vec<IfcType>;
}
pub struct GeometryRouter {
schema: IfcSchema,
processors: HashMap<IfcType, Arc<dyn GeometryProcessor>>,
mapped_item_cache: RefCell<FxHashMap<u32, Arc<Mesh>>>,
faceted_brep_cache: RefCell<FxHashMap<u32, Mesh>>,
geometry_hash_cache: RefCell<FxHashMap<u64, Arc<Mesh>>>,
unit_scale: f64,
rtc_offset: (f64, f64, f64),
}
impl GeometryRouter {
pub fn new() -> Self {
let schema = IfcSchema::new();
let schema_clone = schema.clone();
let mut router = Self {
schema,
processors: HashMap::new(),
mapped_item_cache: RefCell::new(FxHashMap::default()),
faceted_brep_cache: RefCell::new(FxHashMap::default()),
geometry_hash_cache: RefCell::new(FxHashMap::default()),
unit_scale: 1.0, rtc_offset: (0.0, 0.0, 0.0), };
router.register(Box::new(ExtrudedAreaSolidProcessor::new(
schema_clone.clone(),
)));
router.register(Box::new(TriangulatedFaceSetProcessor::new()));
router.register(Box::new(PolygonalFaceSetProcessor::new()));
router.register(Box::new(MappedItemProcessor::new()));
router.register(Box::new(FacetedBrepProcessor::new()));
router.register(Box::new(BooleanClippingProcessor::new()));
router.register(Box::new(SweptDiskSolidProcessor::new(schema_clone.clone())));
router.register(Box::new(RevolvedAreaSolidProcessor::new(
schema_clone.clone(),
)));
router.register(Box::new(AdvancedBrepProcessor::new()));
router.register(Box::new(ShellBasedSurfaceModelProcessor::new()));
router.register(Box::new(FaceBasedSurfaceModelProcessor::new()));
router
}
pub fn with_units(content: &str, decoder: &mut EntityDecoder) -> Self {
let mut scanner = ifc_lite_core::EntityScanner::new(content);
let mut scale = 1.0;
while let Some((id, type_name, _, _)) = scanner.next_entity() {
if type_name == "IFCPROJECT" {
if let Ok(s) = ifc_lite_core::extract_length_unit_scale(decoder, id) {
scale = s;
}
break;
}
}
Self::with_scale(scale)
}
pub fn with_units_and_rtc(
content: &str,
decoder: &mut ifc_lite_core::EntityDecoder,
rtc_offset: (f64, f64, f64),
) -> Self {
let mut scanner = ifc_lite_core::EntityScanner::new(content);
let mut scale = 1.0;
while let Some((id, type_name, _, _)) = scanner.next_entity() {
if type_name == "IFCPROJECT" {
if let Ok(s) = ifc_lite_core::extract_length_unit_scale(decoder, id) {
scale = s;
}
break;
}
}
Self::with_scale_and_rtc(scale, rtc_offset)
}
pub fn with_scale(unit_scale: f64) -> Self {
let mut router = Self::new();
router.unit_scale = unit_scale;
router
}
pub fn with_rtc(rtc_offset: (f64, f64, f64)) -> Self {
let mut router = Self::new();
router.rtc_offset = rtc_offset;
router
}
pub fn with_scale_and_rtc(unit_scale: f64, rtc_offset: (f64, f64, f64)) -> Self {
let mut router = Self::new();
router.unit_scale = unit_scale;
router.rtc_offset = rtc_offset;
router
}
pub fn set_rtc_offset(&mut self, offset: (f64, f64, f64)) {
self.rtc_offset = offset;
}
pub fn rtc_offset(&self) -> (f64, f64, f64) {
self.rtc_offset
}
#[inline]
pub fn has_rtc_offset(&self) -> bool {
self.rtc_offset.0 != 0.0 || self.rtc_offset.1 != 0.0 || self.rtc_offset.2 != 0.0
}
pub fn unit_scale(&self) -> f64 {
self.unit_scale
}
#[inline]
fn scale_mesh(&self, mesh: &mut Mesh) {
if self.unit_scale != 1.0 {
let scale = self.unit_scale as f32;
for pos in mesh.positions.iter_mut() {
*pos *= scale;
}
}
}
#[inline]
fn scale_transform(&self, transform: &mut Matrix4<f64>) {
if self.unit_scale != 1.0 {
transform[(0, 3)] *= self.unit_scale;
transform[(1, 3)] *= self.unit_scale;
transform[(2, 3)] *= self.unit_scale;
}
}
pub fn register(&mut self, processor: Box<dyn GeometryProcessor>) {
let processor_arc: Arc<dyn GeometryProcessor> = Arc::from(processor);
for ifc_type in processor_arc.supported_types() {
self.processors.insert(ifc_type, Arc::clone(&processor_arc));
}
}
pub fn preprocess_faceted_breps(&self, brep_ids: &[u32], decoder: &mut EntityDecoder) {
if brep_ids.is_empty() {
return;
}
let processor = FacetedBrepProcessor::new();
let results = processor.process_batch(brep_ids, decoder);
let mut cache = self.faceted_brep_cache.borrow_mut();
cache.reserve(results.len());
for (brep_idx, mesh) in results {
let brep_id = brep_ids[brep_idx];
cache.insert(brep_id, mesh);
}
}
#[inline]
pub fn take_cached_faceted_brep(&self, brep_id: u32) -> Option<Mesh> {
self.faceted_brep_cache.borrow_mut().remove(&brep_id)
}
pub fn resolve_scaled_placement(
&self,
entity: &DecodedEntity,
decoder: &mut EntityDecoder,
) -> Result<[f64; 16]> {
let mut transform = self.get_placement_transform_from_element(entity, decoder)?;
self.scale_transform(&mut transform);
let mut result = [0.0f64; 16];
result.copy_from_slice(transform.as_slice());
Ok(result)
}
pub fn schema(&self) -> &IfcSchema {
&self.schema
}
}
impl Default for GeometryRouter {
fn default() -> Self {
Self::new()
}
}