Skip to main content

ifc_lite_geometry/processors/
mapped.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! MappedItem processor - geometry instancing.
6
7use crate::{Error, Mesh, Result};
8use ifc_lite_core::{DecodedEntity, EntityDecoder, IfcSchema, IfcType};
9
10use crate::router::GeometryProcessor;
11use super::extrusion::ExtrudedAreaSolidProcessor;
12use super::tessellated::TriangulatedFaceSetProcessor;
13use super::brep::FacetedBrepProcessor;
14use super::boolean::BooleanClippingProcessor;
15use super::swept::{SweptDiskSolidProcessor, RevolvedAreaSolidProcessor};
16
17/// MappedItem processor (P0)
18/// Handles IfcMappedItem - geometry instancing
19pub struct MappedItemProcessor;
20
21impl MappedItemProcessor {
22    pub fn new() -> Self {
23        Self
24    }
25}
26
27impl GeometryProcessor for MappedItemProcessor {
28    fn process(
29        &self,
30        entity: &DecodedEntity,
31        decoder: &mut EntityDecoder,
32        schema: &IfcSchema,
33    ) -> Result<Mesh> {
34        // IfcMappedItem attributes:
35        // 0: MappingSource (IfcRepresentationMap)
36        // 1: MappingTarget (IfcCartesianTransformationOperator)
37
38        // Get mapping source
39        let source_attr = entity
40            .get(0)
41            .ok_or_else(|| Error::geometry("MappedItem missing MappingSource".to_string()))?;
42
43        let source_entity = decoder
44            .resolve_ref(source_attr)?
45            .ok_or_else(|| Error::geometry("Failed to resolve MappingSource".to_string()))?;
46
47        // IfcRepresentationMap has:
48        // 0: MappingOrigin (IfcAxis2Placement)
49        // 1: MappedRepresentation (IfcRepresentation)
50
51        let mapped_rep_attr = source_entity.get(1).ok_or_else(|| {
52            Error::geometry("RepresentationMap missing MappedRepresentation".to_string())
53        })?;
54
55        let mapped_rep = decoder
56            .resolve_ref(mapped_rep_attr)?
57            .ok_or_else(|| Error::geometry("Failed to resolve MappedRepresentation".to_string()))?;
58
59        // Get representation items
60        let items_attr = mapped_rep
61            .get(3)
62            .ok_or_else(|| Error::geometry("Representation missing Items".to_string()))?;
63
64        let items = decoder.resolve_ref_list(items_attr)?;
65
66        // Process all items and merge
67        let mut mesh = Mesh::new();
68        for item in items {
69            let item_mesh = match item.ifc_type {
70                IfcType::IfcExtrudedAreaSolid => {
71                    let processor = ExtrudedAreaSolidProcessor::new(schema.clone());
72                    processor.process(&item, decoder, schema)?
73                }
74                IfcType::IfcTriangulatedFaceSet => {
75                    let processor = TriangulatedFaceSetProcessor::new();
76                    processor.process(&item, decoder, schema)?
77                }
78                IfcType::IfcFacetedBrep => {
79                    let processor = FacetedBrepProcessor::new();
80                    processor.process(&item, decoder, schema)?
81                }
82                IfcType::IfcSweptDiskSolid => {
83                    let processor = SweptDiskSolidProcessor::new(schema.clone());
84                    processor.process(&item, decoder, schema)?
85                }
86                IfcType::IfcBooleanClippingResult | IfcType::IfcBooleanResult => {
87                    let processor = BooleanClippingProcessor::new();
88                    processor.process(&item, decoder, schema)?
89                }
90                IfcType::IfcRevolvedAreaSolid => {
91                    let processor = RevolvedAreaSolidProcessor::new(schema.clone());
92                    processor.process(&item, decoder, schema)?
93                }
94                _ => continue, // Skip unsupported types
95            };
96            mesh.merge(&item_mesh);
97        }
98
99        // Note: MappingTarget transformation is applied by the router's process_mapped_item_cached
100        // when MappedItem is encountered through process_representation_item. This processor
101        // is a fallback that doesn't have access to the router's transformation logic.
102
103        Ok(mesh)
104    }
105
106    fn supported_types(&self) -> Vec<IfcType> {
107        vec![IfcType::IfcMappedItem]
108    }
109}
110
111impl Default for MappedItemProcessor {
112    fn default() -> Self {
113        Self::new()
114    }
115}