Skip to main content

bimifc_model/
types.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//! Core types for IFC data representation
6//!
7//! This module defines the fundamental types used throughout the IFC parsing system.
8
9use serde::{Deserialize, Serialize};
10use std::fmt;
11use std::str::FromStr;
12
13/// Type-safe entity identifier
14///
15/// Wraps the raw IFC entity ID (e.g., #123 becomes EntityId(123))
16#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Default)]
17pub struct EntityId(pub u32);
18
19impl fmt::Display for EntityId {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        write!(f, "#{}", self.0)
22    }
23}
24
25impl From<u32> for EntityId {
26    fn from(id: u32) -> Self {
27        EntityId(id)
28    }
29}
30
31impl From<EntityId> for u32 {
32    fn from(id: EntityId) -> Self {
33        id.0
34    }
35}
36
37impl From<EntityId> for u64 {
38    fn from(id: EntityId) -> Self {
39        id.0 as u64
40    }
41}
42
43/// IFC entity type enumeration
44///
45/// Covers all common IFC entity types. Unknown types are captured with their
46/// original string representation.
47#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
48#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
49pub enum IfcType {
50    // ========================================================================
51    // Abstract parents (inheritance graph)
52    // ========================================================================
53    // These rarely appear as concrete entity instances, but are required so
54    // `IfcType::is_subtype_of(IfcProduct)` resolves correctly via parent().
55    // See schema_helpers::has_geometry_by_name.
56    IfcRoot,
57    IfcObjectDefinition,
58    IfcObject,
59    IfcProduct,
60    IfcElement,
61    IfcBuiltElement,
62    IfcSpatialElement,
63    IfcSpatialStructureElement,
64    IfcExternalSpatialStructureElement,
65    IfcExternalSpatialElement,
66    IfcSpatialZone,
67    IfcCivilElement,
68    IfcGeographicElement,
69    IfcAnnotation,
70    IfcPort,
71    IfcFeatureElement,
72    IfcFeatureElementAddition,
73    IfcFeatureElementSubtraction,
74    IfcGeotechnicalAssembly,
75
76    // ========================================================================
77    // Spatial Structure
78    // ========================================================================
79    IfcProject,
80    IfcSite,
81    IfcBuilding,
82    IfcBuildingStorey,
83    IfcSpace,
84
85    // ========================================================================
86    // Building Elements
87    // ========================================================================
88    IfcWall,
89    IfcWallStandardCase,
90    IfcCurtainWall,
91    IfcSlab,
92    IfcRoof,
93    IfcBeam,
94    IfcColumn,
95    IfcDoor,
96    IfcWindow,
97    IfcStair,
98    IfcStairFlight,
99    IfcRamp,
100    IfcRampFlight,
101    IfcRailing,
102    IfcCovering,
103    IfcPlate,
104    IfcMember,
105    IfcFooting,
106    IfcPile,
107    IfcBuildingElementProxy,
108    IfcElementAssembly,
109
110    // ========================================================================
111    // Distribution Elements (MEP)
112    // ========================================================================
113    IfcDistributionElement,
114    IfcDistributionFlowElement,
115    IfcFlowTerminal,
116    IfcFlowSegment,
117    IfcFlowFitting,
118    IfcFlowController,
119    IfcFlowMovingDevice,
120    IfcFlowStorageDevice,
121    IfcFlowTreatmentDevice,
122    IfcEnergyConversionDevice,
123    IfcDistributionControlElement,
124
125    // Concrete MEP subtypes
126    // Electrical
127    IfcCableSegment,
128    IfcCableCarrierSegment,
129    IfcCableCarrierFitting,
130    // Plumbing
131    IfcPipeSegment,
132    IfcPipeFitting,
133    // HVAC
134    IfcSpaceHeater,
135    IfcAirTerminal,
136
137    // ========================================================================
138    // Furnishing and Equipment
139    // ========================================================================
140    IfcFurnishingElement,
141    IfcFurniture,
142    IfcSystemFurnitureElement,
143
144    // ========================================================================
145    // Openings and Features
146    // ========================================================================
147    IfcOpeningElement,
148    IfcOpeningStandardCase,
149    IfcVoidingFeature,
150    IfcProjectionElement,
151
152    // ========================================================================
153    // Geometry Representations
154    // ========================================================================
155    // Swept solids
156    IfcExtrudedAreaSolid,
157    IfcExtrudedAreaSolidTapered,
158    IfcRevolvedAreaSolid,
159    IfcRevolvedAreaSolidTapered,
160    IfcSweptDiskSolid,
161    IfcSweptDiskSolidPolygonal,
162    IfcSurfaceCurveSweptAreaSolid,
163    IfcFixedReferenceSweptAreaSolid,
164
165    // Boundary representations
166    IfcFacetedBrep,
167    IfcFacetedBrepWithVoids,
168    IfcAdvancedBrep,
169    IfcAdvancedBrepWithVoids,
170
171    // Tessellated geometry (IFC4+)
172    IfcTriangulatedFaceSet,
173    IfcPolygonalFaceSet,
174    IfcTessellatedFaceSet,
175
176    // Boolean operations
177    IfcBooleanResult,
178    IfcBooleanClippingResult,
179
180    // Mapped items (instancing)
181    IfcMappedItem,
182    IfcRepresentationMap,
183
184    // CSG primitives
185    IfcBlock,
186    IfcRectangularPyramid,
187    IfcRightCircularCone,
188    IfcRightCircularCylinder,
189    IfcSphere,
190
191    // Half-space solids
192    IfcHalfSpaceSolid,
193    IfcPolygonalBoundedHalfSpace,
194    IfcBoxedHalfSpace,
195
196    // ========================================================================
197    // Profiles (2D cross-sections)
198    // ========================================================================
199    IfcArbitraryClosedProfileDef,
200    IfcArbitraryProfileDefWithVoids,
201    IfcRectangleProfileDef,
202    IfcRectangleHollowProfileDef,
203    IfcCircleProfileDef,
204    IfcCircleHollowProfileDef,
205    IfcEllipseProfileDef,
206    IfcIShapeProfileDef,
207    IfcLShapeProfileDef,
208    IfcTShapeProfileDef,
209    IfcUShapeProfileDef,
210    IfcCShapeProfileDef,
211    IfcZShapeProfileDef,
212    IfcAsymmetricIShapeProfileDef,
213    IfcTrapeziumProfileDef,
214    IfcCompositeProfileDef,
215    IfcDerivedProfileDef,
216    IfcCenterLineProfileDef,
217
218    // ========================================================================
219    // Curves
220    // ========================================================================
221    IfcPolyline,
222    IfcCompositeCurve,
223    IfcCompositeCurveSegment,
224    IfcTrimmedCurve,
225    IfcCircle,
226    IfcEllipse,
227    IfcLine,
228    IfcBSplineCurve,
229    IfcBSplineCurveWithKnots,
230    IfcRationalBSplineCurveWithKnots,
231    IfcIndexedPolyCurve,
232
233    // ========================================================================
234    // Surfaces
235    // ========================================================================
236    IfcPlane,
237    IfcCurveBoundedPlane,
238    IfcCylindricalSurface,
239    IfcBSplineSurface,
240    IfcBSplineSurfaceWithKnots,
241    IfcRationalBSplineSurfaceWithKnots,
242
243    // ========================================================================
244    // Points and Directions
245    // ========================================================================
246    IfcCartesianPoint,
247    IfcDirection,
248    IfcVector,
249    IfcCartesianPointList2D,
250    IfcCartesianPointList3D,
251
252    // ========================================================================
253    // Placement and Transforms
254    // ========================================================================
255    IfcAxis2Placement2D,
256    IfcAxis2Placement3D,
257    IfcLocalPlacement,
258    IfcCartesianTransformationOperator3D,
259    IfcCartesianTransformationOperator3DnonUniform,
260
261    // ========================================================================
262    // Representations and Contexts
263    // ========================================================================
264    IfcShapeRepresentation,
265    IfcProductDefinitionShape,
266    IfcGeometricRepresentationContext,
267    IfcGeometricRepresentationSubContext,
268
269    // ========================================================================
270    // Topology
271    // ========================================================================
272    IfcClosedShell,
273    IfcOpenShell,
274    IfcFace,
275    IfcFaceBound,
276    IfcFaceOuterBound,
277    IfcPolyLoop,
278    IfcEdgeLoop,
279    IfcOrientedEdge,
280    IfcEdgeCurve,
281    IfcVertexPoint,
282    IfcConnectedFaceSet,
283
284    // ========================================================================
285    // Relationships
286    // ========================================================================
287    IfcRelContainedInSpatialStructure,
288    IfcRelAggregates,
289    IfcRelDefinesByProperties,
290    IfcRelDefinesByType,
291    IfcRelAssociatesMaterial,
292    IfcRelVoidsElement,
293    IfcRelFillsElement,
294    IfcRelConnectsPathElements,
295    IfcRelSpaceBoundary,
296    IfcRelAssignsToGroup,
297
298    // ========================================================================
299    // Properties
300    // ========================================================================
301    IfcPropertySet,
302    IfcPropertySingleValue,
303    IfcPropertyEnumeratedValue,
304    IfcPropertyBoundedValue,
305    IfcPropertyListValue,
306    IfcPropertyTableValue,
307    IfcComplexProperty,
308    IfcElementQuantity,
309    IfcQuantityLength,
310    IfcQuantityArea,
311    IfcQuantityVolume,
312    IfcQuantityCount,
313    IfcQuantityWeight,
314    IfcQuantityTime,
315
316    // ========================================================================
317    // Materials
318    // ========================================================================
319    IfcMaterial,
320    IfcMaterialLayer,
321    IfcMaterialLayerSet,
322    IfcMaterialLayerSetUsage,
323    IfcMaterialList,
324    IfcMaterialConstituentSet,
325    IfcMaterialConstituent,
326    IfcMaterialProfile,
327    IfcMaterialProfileSet,
328    IfcMaterialProfileSetUsage,
329
330    // ========================================================================
331    // Presentation (styling)
332    // ========================================================================
333    IfcStyledItem,
334    IfcSurfaceStyle,
335    IfcSurfaceStyleRendering,
336    IfcColourRgb,
337    IfcPresentationLayerAssignment,
338
339    // ========================================================================
340    // Lighting
341    // ========================================================================
342    IfcLightFixture,
343    IfcLightFixtureType,
344    IfcLightSource,
345    IfcLightSourceAmbient,
346    IfcLightSourceDirectional,
347    IfcLightSourceGoniometric,
348    IfcLightSourcePositional,
349    IfcLightSourceSpot,
350    IfcLightIntensityDistribution,
351    IfcLightDistributionData,
352
353    // ========================================================================
354    // Units
355    // ========================================================================
356    IfcUnitAssignment,
357    IfcSIUnit,
358    IfcConversionBasedUnit,
359    IfcDerivedUnit,
360    IfcMeasureWithUnit,
361
362    // ========================================================================
363    // Type definitions
364    // ========================================================================
365    IfcWallType,
366    IfcSlabType,
367    IfcBeamType,
368    IfcColumnType,
369    IfcDoorType,
370    IfcWindowType,
371    IfcCoveringType,
372    IfcRailingType,
373    IfcStairType,
374    IfcStairFlightType,
375    IfcRampType,
376    IfcRampFlightType,
377    IfcRoofType,
378    IfcMemberType,
379    IfcPlateType,
380    IfcFootingType,
381    IfcPileType,
382    IfcBuildingElementProxyType,
383
384    // ========================================================================
385    // IFC4x3 Additions (Infrastructure)
386    // ========================================================================
387    IfcAlignment,
388    IfcAlignmentCant,
389    IfcAlignmentHorizontal,
390    IfcAlignmentVertical,
391    IfcAlignmentSegment,
392    IfcRoad,
393    IfcRoadPart,
394    IfcBridge,
395    IfcBridgePart,
396    IfcRailway,
397    IfcRailwayPart,
398    IfcFacility,
399    IfcFacilityPart,
400    IfcGeotechnicalElement,
401    IfcBorehole,
402    IfcGeomodel,
403    IfcGeoslice,
404    IfcSolidStratum,
405    IfcVoidStratum,
406    IfcWaterStratum,
407    IfcEarthworksCut,
408    IfcEarthworksFill,
409    IfcEarthworksElement,
410    IfcPavement,
411    IfcCourse,
412    IfcKerb,
413    IfcDeepFoundation,
414
415    /// Unknown type - stores the original type name string
416    Unknown(String),
417}
418
419impl FromStr for IfcType {
420    type Err = std::convert::Infallible;
421
422    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
423        Ok(Self::parse(s))
424    }
425}
426
427impl IfcType {
428    /// Parse a type name string into an IfcType
429    pub fn parse(s: &str) -> Self {
430        // Convert to uppercase for matching
431        match s.to_uppercase().as_str() {
432            // Spatial structure
433            "IFCPROJECT" => IfcType::IfcProject,
434            "IFCSITE" => IfcType::IfcSite,
435            "IFCBUILDING" => IfcType::IfcBuilding,
436            "IFCBUILDINGSTOREY" => IfcType::IfcBuildingStorey,
437            "IFCSPACE" => IfcType::IfcSpace,
438
439            // Building elements
440            "IFCWALL" => IfcType::IfcWall,
441            "IFCWALLSTANDARDCASE" => IfcType::IfcWallStandardCase,
442            "IFCCURTAINWALL" => IfcType::IfcCurtainWall,
443            "IFCSLAB" => IfcType::IfcSlab,
444            "IFCROOF" => IfcType::IfcRoof,
445            "IFCBEAM" => IfcType::IfcBeam,
446            "IFCCOLUMN" => IfcType::IfcColumn,
447            "IFCDOOR" => IfcType::IfcDoor,
448            "IFCWINDOW" => IfcType::IfcWindow,
449            "IFCSTAIR" => IfcType::IfcStair,
450            "IFCSTAIRFLIGHT" => IfcType::IfcStairFlight,
451            "IFCRAMP" => IfcType::IfcRamp,
452            "IFCRAMPFLIGHT" => IfcType::IfcRampFlight,
453            "IFCRAILING" => IfcType::IfcRailing,
454            "IFCCOVERING" => IfcType::IfcCovering,
455            "IFCPLATE" => IfcType::IfcPlate,
456            "IFCMEMBER" => IfcType::IfcMember,
457            "IFCFOOTING" => IfcType::IfcFooting,
458            "IFCPILE" => IfcType::IfcPile,
459            "IFCBUILDINGELEMENTPROXY" => IfcType::IfcBuildingElementProxy,
460            "IFCELEMENTASSEMBLY" => IfcType::IfcElementAssembly,
461
462            // Distribution elements
463            "IFCDISTRIBUTIONELEMENT" => IfcType::IfcDistributionElement,
464            "IFCDISTRIBUTIONFLOWELEMENT" => IfcType::IfcDistributionFlowElement,
465            "IFCFLOWTERMINAL" => IfcType::IfcFlowTerminal,
466            "IFCFLOWSEGMENT" => IfcType::IfcFlowSegment,
467            "IFCFLOWFITTING" => IfcType::IfcFlowFitting,
468            "IFCFLOWCONTROLLER" => IfcType::IfcFlowController,
469            "IFCFLOWMOVINGDEVICE" => IfcType::IfcFlowMovingDevice,
470            "IFCFLOWSTORAGEDEVICE" => IfcType::IfcFlowStorageDevice,
471            "IFCFLOWTREATMENTDEVICE" => IfcType::IfcFlowTreatmentDevice,
472            "IFCENERGYCONVERSIONDEVICE" => IfcType::IfcEnergyConversionDevice,
473            "IFCDISTRIBUTIONCONTROLELEMENT" => IfcType::IfcDistributionControlElement,
474
475            // Concrete MEP subtypes
476            "IFCCABLESEGMENT" => IfcType::IfcCableSegment,
477            "IFCCABLECARRIERSEGMENT" => IfcType::IfcCableCarrierSegment,
478            "IFCCABLECARRIERFITTING" => IfcType::IfcCableCarrierFitting,
479            "IFCPIPESEGMENT" => IfcType::IfcPipeSegment,
480            "IFCPIPEFITTING" => IfcType::IfcPipeFitting,
481            "IFCSPACEHEATER" => IfcType::IfcSpaceHeater,
482            "IFCAIRTERMINAL" => IfcType::IfcAirTerminal,
483
484            // Furnishing
485            "IFCFURNISHINGELEMENT" => IfcType::IfcFurnishingElement,
486            "IFCFURNITURE" => IfcType::IfcFurniture,
487            "IFCSYSTEMFURNITUREELEMENT" => IfcType::IfcSystemFurnitureElement,
488
489            // Openings
490            "IFCOPENINGELEMENT" => IfcType::IfcOpeningElement,
491            "IFCOPENINGSTANDARDCASE" => IfcType::IfcOpeningStandardCase,
492            "IFCVOIDINGFEATURE" => IfcType::IfcVoidingFeature,
493            "IFCPROJECTIONELEMENT" => IfcType::IfcProjectionElement,
494
495            // Geometry - Swept solids
496            "IFCEXTRUDEDAREASOLID" => IfcType::IfcExtrudedAreaSolid,
497            "IFCEXTRUDEDAREASOLIDTAPERED" => IfcType::IfcExtrudedAreaSolidTapered,
498            "IFCREVOLVEDAREASOLID" => IfcType::IfcRevolvedAreaSolid,
499            "IFCREVOLVEDAREASOLIDTAPERED" => IfcType::IfcRevolvedAreaSolidTapered,
500            "IFCSWEPTDISKSOLID" => IfcType::IfcSweptDiskSolid,
501            "IFCSWEPTDISKSOLIDPOLYGONAL" => IfcType::IfcSweptDiskSolidPolygonal,
502            "IFCSURFACECURVESWEPTAREASOLID" => IfcType::IfcSurfaceCurveSweptAreaSolid,
503            "IFCFIXEDREFERENCESWEPTAREASOLID" => IfcType::IfcFixedReferenceSweptAreaSolid,
504
505            // Geometry - BREPs
506            "IFCFACETEDBREP" => IfcType::IfcFacetedBrep,
507            "IFCFACETEDBREPWITHVOIDS" => IfcType::IfcFacetedBrepWithVoids,
508            "IFCADVANCEDBREP" => IfcType::IfcAdvancedBrep,
509            "IFCADVANCEDBREPWITHVOIDS" => IfcType::IfcAdvancedBrepWithVoids,
510
511            // Geometry - Tessellated
512            "IFCTRIANGULATEDFACESET" => IfcType::IfcTriangulatedFaceSet,
513            "IFCPOLYGONALFACESET" => IfcType::IfcPolygonalFaceSet,
514            "IFCTESSELLATEDFACESET" => IfcType::IfcTessellatedFaceSet,
515
516            // Geometry - Boolean
517            "IFCBOOLEANRESULT" => IfcType::IfcBooleanResult,
518            "IFCBOOLEANCLIPPINGRESULT" => IfcType::IfcBooleanClippingResult,
519
520            // Geometry - Mapped items
521            "IFCMAPPEDITEM" => IfcType::IfcMappedItem,
522            "IFCREPRESENTATIONMAP" => IfcType::IfcRepresentationMap,
523
524            // Geometry - CSG primitives
525            "IFCBLOCK" => IfcType::IfcBlock,
526            "IFCRECTANGULARPYRAMID" => IfcType::IfcRectangularPyramid,
527            "IFCRIGHTCIRCULARCONE" => IfcType::IfcRightCircularCone,
528            "IFCRIGHTCIRCULARCYLINDER" => IfcType::IfcRightCircularCylinder,
529            "IFCSPHERE" => IfcType::IfcSphere,
530
531            // Geometry - Half-space
532            "IFCHALFSPACESOLID" => IfcType::IfcHalfSpaceSolid,
533            "IFCPOLYGONALBOUNDEDHALFSPACE" => IfcType::IfcPolygonalBoundedHalfSpace,
534            "IFCBOXEDHALFSPACE" => IfcType::IfcBoxedHalfSpace,
535
536            // Profiles
537            "IFCARBITRARYCLOSEDPROFILEDEF" => IfcType::IfcArbitraryClosedProfileDef,
538            "IFCARBITRARYPROFILEDEFWITHVOIDS" => IfcType::IfcArbitraryProfileDefWithVoids,
539            "IFCRECTANGLEPROFILEDEF" => IfcType::IfcRectangleProfileDef,
540            "IFCRECTANGLEHOLLOWPROFILEDEF" => IfcType::IfcRectangleHollowProfileDef,
541            "IFCCIRCLEPROFILEDEF" => IfcType::IfcCircleProfileDef,
542            "IFCCIRCLEHOLLOWPROFILEDEF" => IfcType::IfcCircleHollowProfileDef,
543            "IFCELLIPSEPROFILEDEF" => IfcType::IfcEllipseProfileDef,
544            "IFCISHAPEPROFILEDEF" => IfcType::IfcIShapeProfileDef,
545            "IFCLSHAPEPROFILEDEF" => IfcType::IfcLShapeProfileDef,
546            "IFCTSHAPEPROFILEDEF" => IfcType::IfcTShapeProfileDef,
547            "IFCUSHAPEPROFILEDEF" => IfcType::IfcUShapeProfileDef,
548            "IFCCSHAPEPROFILEDEF" => IfcType::IfcCShapeProfileDef,
549            "IFCZSHAPEPROFILEDEF" => IfcType::IfcZShapeProfileDef,
550            "IFCASYMMETRICISHAPEPROFILEDEF" => IfcType::IfcAsymmetricIShapeProfileDef,
551            "IFCTRAPEZIUMPROFILEDEF" => IfcType::IfcTrapeziumProfileDef,
552            "IFCCOMPOSITEPROFILEDEF" => IfcType::IfcCompositeProfileDef,
553            "IFCDERIVEDPROFILEDEF" => IfcType::IfcDerivedProfileDef,
554            "IFCCENTERLINEPROFILEDEF" => IfcType::IfcCenterLineProfileDef,
555
556            // Curves
557            "IFCPOLYLINE" => IfcType::IfcPolyline,
558            "IFCCOMPOSITECURVE" => IfcType::IfcCompositeCurve,
559            "IFCCOMPOSITECURVESEGMENT" => IfcType::IfcCompositeCurveSegment,
560            "IFCTRIMMEDCURVE" => IfcType::IfcTrimmedCurve,
561            "IFCCIRCLE" => IfcType::IfcCircle,
562            "IFCELLIPSE" => IfcType::IfcEllipse,
563            "IFCLINE" => IfcType::IfcLine,
564            "IFCBSPLINECURVE" => IfcType::IfcBSplineCurve,
565            "IFCBSPLINECURVEWITHKNOTS" => IfcType::IfcBSplineCurveWithKnots,
566            "IFCRATIONALBSPLINECURVEWITHKNOTS" => IfcType::IfcRationalBSplineCurveWithKnots,
567            "IFCINDEXEDPOLYCURVE" => IfcType::IfcIndexedPolyCurve,
568
569            // Surfaces
570            "IFCPLANE" => IfcType::IfcPlane,
571            "IFCCURVEBOUNDEDPLANE" => IfcType::IfcCurveBoundedPlane,
572            "IFCCYLINDRICALSURFACE" => IfcType::IfcCylindricalSurface,
573            "IFCBSPLINESURFACE" => IfcType::IfcBSplineSurface,
574            "IFCBSPLINESURFACEWITHKNOTS" => IfcType::IfcBSplineSurfaceWithKnots,
575            "IFCRATIONALBSPLINESURFACEWITHKNOTS" => IfcType::IfcRationalBSplineSurfaceWithKnots,
576
577            // Points and directions
578            "IFCCARTESIANPOINT" => IfcType::IfcCartesianPoint,
579            "IFCDIRECTION" => IfcType::IfcDirection,
580            "IFCVECTOR" => IfcType::IfcVector,
581            "IFCCARTESIANPOINTLIST2D" => IfcType::IfcCartesianPointList2D,
582            "IFCCARTESIANPOINTLIST3D" => IfcType::IfcCartesianPointList3D,
583
584            // Placement
585            "IFCAXIS2PLACEMENT2D" => IfcType::IfcAxis2Placement2D,
586            "IFCAXIS2PLACEMENT3D" => IfcType::IfcAxis2Placement3D,
587            "IFCLOCALPLACEMENT" => IfcType::IfcLocalPlacement,
588            "IFCCARTESIANTRANSFORMATIONOPERATOR3D" => IfcType::IfcCartesianTransformationOperator3D,
589            "IFCCARTESIANTRANSFORMATIONOPERATOR3DNONUNIFORM" => {
590                IfcType::IfcCartesianTransformationOperator3DnonUniform
591            }
592
593            // Representations
594            "IFCSHAPEREPRESENTATION" => IfcType::IfcShapeRepresentation,
595            "IFCPRODUCTDEFINITIONSHAPE" => IfcType::IfcProductDefinitionShape,
596            "IFCGEOMETRICREPRESENTATIONCONTEXT" => IfcType::IfcGeometricRepresentationContext,
597            "IFCGEOMETRICREPRESENTATIONSUBCONTEXT" => IfcType::IfcGeometricRepresentationSubContext,
598
599            // Topology
600            "IFCCLOSEDSHELL" => IfcType::IfcClosedShell,
601            "IFCOPENSHELL" => IfcType::IfcOpenShell,
602            "IFCFACE" => IfcType::IfcFace,
603            "IFCFACEBOUND" => IfcType::IfcFaceBound,
604            "IFCFACEOUTERBOUND" => IfcType::IfcFaceOuterBound,
605            "IFCPOLYLOOP" => IfcType::IfcPolyLoop,
606            "IFCEDGELOOP" => IfcType::IfcEdgeLoop,
607            "IFCORIENTEDEDGE" => IfcType::IfcOrientedEdge,
608            "IFCEDGECURVE" => IfcType::IfcEdgeCurve,
609            "IFCVERTEXPOINT" => IfcType::IfcVertexPoint,
610            "IFCCONNECTEDFACESET" => IfcType::IfcConnectedFaceSet,
611
612            // Relationships
613            "IFCRELCONTAINEDINSPATIALSTRUCTURE" => IfcType::IfcRelContainedInSpatialStructure,
614            "IFCRELAGGREGATES" => IfcType::IfcRelAggregates,
615            "IFCRELDEFINESBYPROPERTIES" => IfcType::IfcRelDefinesByProperties,
616            "IFCRELDEFINESBYTYPE" => IfcType::IfcRelDefinesByType,
617            "IFCRELASSOCIATESMATERIAL" => IfcType::IfcRelAssociatesMaterial,
618            "IFCRELVOIDSELEMENT" => IfcType::IfcRelVoidsElement,
619            "IFCRELFILLSELEMENT" => IfcType::IfcRelFillsElement,
620            "IFCRELCONNECTSPATHELEMENTS" => IfcType::IfcRelConnectsPathElements,
621            "IFCRELSPACEBOUNDARY" => IfcType::IfcRelSpaceBoundary,
622            "IFCRELASSIGNSTOGROUP" => IfcType::IfcRelAssignsToGroup,
623
624            // Properties
625            "IFCPROPERTYSET" => IfcType::IfcPropertySet,
626            "IFCPROPERTYSINGLEVALUE" => IfcType::IfcPropertySingleValue,
627            "IFCPROPERTYENUMERATEDVALUE" => IfcType::IfcPropertyEnumeratedValue,
628            "IFCPROPERTYBOUNDEDVALUE" => IfcType::IfcPropertyBoundedValue,
629            "IFCPROPERTYLISTVALUE" => IfcType::IfcPropertyListValue,
630            "IFCPROPERTYTABLEVALUE" => IfcType::IfcPropertyTableValue,
631            "IFCCOMPLEXPROPERTY" => IfcType::IfcComplexProperty,
632            "IFCELEMENTQUANTITY" => IfcType::IfcElementQuantity,
633            "IFCQUANTITYLENGTH" => IfcType::IfcQuantityLength,
634            "IFCQUANTITYAREA" => IfcType::IfcQuantityArea,
635            "IFCQUANTITYVOLUME" => IfcType::IfcQuantityVolume,
636            "IFCQUANTITYCOUNT" => IfcType::IfcQuantityCount,
637            "IFCQUANTITYWEIGHT" => IfcType::IfcQuantityWeight,
638            "IFCQUANTITYTIME" => IfcType::IfcQuantityTime,
639
640            // Materials
641            "IFCMATERIAL" => IfcType::IfcMaterial,
642            "IFCMATERIALLAYER" => IfcType::IfcMaterialLayer,
643            "IFCMATERIALLAYERSET" => IfcType::IfcMaterialLayerSet,
644            "IFCMATERIALLAYERSETUSAGE" => IfcType::IfcMaterialLayerSetUsage,
645            "IFCMATERIALLIST" => IfcType::IfcMaterialList,
646            "IFCMATERIALCONSTITUENTSET" => IfcType::IfcMaterialConstituentSet,
647            "IFCMATERIALCONSTITUENT" => IfcType::IfcMaterialConstituent,
648            "IFCMATERIALPROFILE" => IfcType::IfcMaterialProfile,
649            "IFCMATERIALPROFILESET" => IfcType::IfcMaterialProfileSet,
650            "IFCMATERIALPROFILESETUSAGE" => IfcType::IfcMaterialProfileSetUsage,
651
652            // Presentation
653            "IFCSTYLEDITEM" => IfcType::IfcStyledItem,
654            "IFCSURFACESTYLE" => IfcType::IfcSurfaceStyle,
655            "IFCSURFACESTYLERENDERING" => IfcType::IfcSurfaceStyleRendering,
656            "IFCCOLOURRGB" => IfcType::IfcColourRgb,
657            "IFCPRESENTATIONLAYERASSIGNMENT" => IfcType::IfcPresentationLayerAssignment,
658
659            // Lighting
660            "IFCLIGHTFIXTURE" => IfcType::IfcLightFixture,
661            "IFCLIGHTFIXTURETYPE" => IfcType::IfcLightFixtureType,
662            "IFCLIGHTSOURCE" => IfcType::IfcLightSource,
663            "IFCLIGHTSOURCEAMBIENT" => IfcType::IfcLightSourceAmbient,
664            "IFCLIGHTSOURCEDIRECTIONAL" => IfcType::IfcLightSourceDirectional,
665            "IFCLIGHTSOURCEGONIOMETRIC" => IfcType::IfcLightSourceGoniometric,
666            "IFCLIGHTSOURCEPOSITIONAL" => IfcType::IfcLightSourcePositional,
667            "IFCLIGHTSOURCESPOT" => IfcType::IfcLightSourceSpot,
668            "IFCLIGHTINTENSITYDISTRIBUTION" => IfcType::IfcLightIntensityDistribution,
669            "IFCLIGHTDISTRIBUTIONDATA" => IfcType::IfcLightDistributionData,
670
671            // Units
672            "IFCUNITASSIGNMENT" => IfcType::IfcUnitAssignment,
673            "IFCSIUNIT" => IfcType::IfcSIUnit,
674            "IFCCONVERSIONBASEDUNIT" => IfcType::IfcConversionBasedUnit,
675            "IFCDERIVEDUNIT" => IfcType::IfcDerivedUnit,
676            "IFCMEASUREWITHUNIT" => IfcType::IfcMeasureWithUnit,
677
678            // Type definitions
679            "IFCWALLTYPE" => IfcType::IfcWallType,
680            "IFCSLABTYPE" => IfcType::IfcSlabType,
681            "IFCBEAMTYPE" => IfcType::IfcBeamType,
682            "IFCCOLUMNTYPE" => IfcType::IfcColumnType,
683            "IFCDOORTYPE" => IfcType::IfcDoorType,
684            "IFCWINDOWTYPE" => IfcType::IfcWindowType,
685            "IFCCOVERINGTYPE" => IfcType::IfcCoveringType,
686            "IFCRAILINGTYPE" => IfcType::IfcRailingType,
687            "IFCSTAIRTYPE" => IfcType::IfcStairType,
688            "IFCSTAIRFLIGHTTYPE" => IfcType::IfcStairFlightType,
689            "IFCRAMPTYPE" => IfcType::IfcRampType,
690            "IFCRAMPFLIGHTTYPE" => IfcType::IfcRampFlightType,
691            "IFCROOFTYPE" => IfcType::IfcRoofType,
692            "IFCMEMBERTYPE" => IfcType::IfcMemberType,
693            "IFCPLATETYPE" => IfcType::IfcPlateType,
694            "IFCFOOTINGTYPE" => IfcType::IfcFootingType,
695            "IFCPILETYPE" => IfcType::IfcPileType,
696            "IFCBUILDINGELEMENTPROXYTYPE" => IfcType::IfcBuildingElementProxyType,
697
698            // IFC4x3 Infrastructure
699            "IFCALIGNMENT" => IfcType::IfcAlignment,
700            "IFCALIGNMENTCANT" => IfcType::IfcAlignmentCant,
701            "IFCALIGNMENTHORIZONTAL" => IfcType::IfcAlignmentHorizontal,
702            "IFCALIGNMENTVERTICAL" => IfcType::IfcAlignmentVertical,
703            "IFCALIGNMENTSEGMENT" => IfcType::IfcAlignmentSegment,
704            "IFCROAD" => IfcType::IfcRoad,
705            "IFCROADPART" => IfcType::IfcRoadPart,
706            "IFCBRIDGE" => IfcType::IfcBridge,
707            "IFCBRIDGEPART" => IfcType::IfcBridgePart,
708            "IFCRAILWAY" => IfcType::IfcRailway,
709            "IFCRAILWAYPART" => IfcType::IfcRailwayPart,
710            "IFCFACILITY" => IfcType::IfcFacility,
711            "IFCFACILITYPART" => IfcType::IfcFacilityPart,
712            "IFCGEOTECHNICALELEMENT" => IfcType::IfcGeotechnicalElement,
713            "IFCBOREHOLE" => IfcType::IfcBorehole,
714            "IFCGEOMODEL" => IfcType::IfcGeomodel,
715            "IFCGEOSLICE" => IfcType::IfcGeoslice,
716            "IFCSOLIDSTRATUM" => IfcType::IfcSolidStratum,
717            "IFCVOIDSTRATUM" => IfcType::IfcVoidStratum,
718            "IFCWATERSTRATUM" => IfcType::IfcWaterStratum,
719            "IFCEARTHWORKSCUT" => IfcType::IfcEarthworksCut,
720            "IFCEARTHWORKSFILL" => IfcType::IfcEarthworksFill,
721            "IFCEARTHWORKSELEMENT" => IfcType::IfcEarthworksElement,
722            "IFCPAVEMENT" => IfcType::IfcPavement,
723            "IFCCOURSE" => IfcType::IfcCourse,
724            "IFCKERB" => IfcType::IfcKerb,
725            "IFCDEEPFOUNDATION" => IfcType::IfcDeepFoundation,
726
727            // Unknown
728            _ => IfcType::Unknown(s.to_string()),
729        }
730    }
731
732    /// Get the type name as a string
733    pub fn name(&self) -> &str {
734        match self {
735            IfcType::Unknown(s) => s,
736            _ => {
737                // For known types, return the variant name
738                // This uses the debug representation which includes the type name
739                // A more elegant solution would use a macro, but this works
740                match self {
741                    IfcType::IfcProject => "IFCPROJECT",
742                    IfcType::IfcSite => "IFCSITE",
743                    IfcType::IfcBuilding => "IFCBUILDING",
744                    IfcType::IfcBuildingStorey => "IFCBUILDINGSTOREY",
745                    IfcType::IfcSpace => "IFCSPACE",
746                    IfcType::IfcWall => "IFCWALL",
747                    IfcType::IfcWallStandardCase => "IFCWALLSTANDARDCASE",
748                    IfcType::IfcCurtainWall => "IFCCURTAINWALL",
749                    IfcType::IfcSlab => "IFCSLAB",
750                    IfcType::IfcRoof => "IFCROOF",
751                    IfcType::IfcBeam => "IFCBEAM",
752                    IfcType::IfcColumn => "IFCCOLUMN",
753                    IfcType::IfcDoor => "IFCDOOR",
754                    IfcType::IfcWindow => "IFCWINDOW",
755                    IfcType::IfcStair => "IFCSTAIR",
756                    IfcType::IfcStairFlight => "IFCSTAIRFLIGHT",
757                    IfcType::IfcRamp => "IFCRAMP",
758                    IfcType::IfcRampFlight => "IFCRAMPFLIGHT",
759                    IfcType::IfcRailing => "IFCRAILING",
760                    IfcType::IfcCovering => "IFCCOVERING",
761                    IfcType::IfcPlate => "IFCPLATE",
762                    IfcType::IfcMember => "IFCMEMBER",
763                    IfcType::IfcFooting => "IFCFOOTING",
764                    IfcType::IfcPile => "IFCPILE",
765                    IfcType::IfcBuildingElementProxy => "IFCBUILDINGELEMENTPROXY",
766                    IfcType::IfcElementAssembly => "IFCELEMENTASSEMBLY",
767                    IfcType::IfcExtrudedAreaSolid => "IFCEXTRUDEDAREASOLID",
768                    IfcType::IfcFacetedBrep => "IFCFACETEDBREP",
769                    IfcType::IfcTriangulatedFaceSet => "IFCTRIANGULATEDFACESET",
770                    IfcType::IfcMappedItem => "IFCMAPPEDITEM",
771                    IfcType::IfcBooleanClippingResult => "IFCBOOLEANCLIPPINGRESULT",
772                    IfcType::IfcFurnishingElement => "IFCFURNISHINGELEMENT",
773                    IfcType::IfcFurniture => "IFCFURNITURE",
774                    IfcType::IfcFlowTerminal => "IFCFLOWTERMINAL",
775                    IfcType::IfcFlowSegment => "IFCFLOWSEGMENT",
776                    IfcType::IfcFlowFitting => "IFCFLOWFITTING",
777                    IfcType::IfcFlowController => "IFCFLOWCONTROLLER",
778                    IfcType::IfcCableSegment => "IFCCABLESEGMENT",
779                    IfcType::IfcCableCarrierSegment => "IFCCABLECARRIERSEGMENT",
780                    IfcType::IfcCableCarrierFitting => "IFCCABLECARRIERFITTING",
781                    IfcType::IfcPipeSegment => "IFCPIPESEGMENT",
782                    IfcType::IfcPipeFitting => "IFCPIPEFITTING",
783                    IfcType::IfcSpaceHeater => "IFCSPACEHEATER",
784                    IfcType::IfcAirTerminal => "IFCAIRTERMINAL",
785                    IfcType::IfcDistributionElement => "IFCDISTRIBUTIONELEMENT",
786                    IfcType::IfcOpeningElement => "IFCOPENINGELEMENT",
787                    IfcType::IfcLightFixture => "IFCLIGHTFIXTURE",
788                    IfcType::IfcLightFixtureType => "IFCLIGHTFIXTURETYPE",
789                    IfcType::IfcLightSourceGoniometric => "IFCLIGHTSOURCEGONIOMETRIC",
790                    IfcType::IfcLightSourcePositional => "IFCLIGHTSOURCEPOSITIONAL",
791                    IfcType::IfcLightSourceSpot => "IFCLIGHTSOURCESPOT",
792                    IfcType::IfcLightSourceDirectional => "IFCLIGHTSOURCEDIRECTIONAL",
793                    IfcType::IfcLightSourceAmbient => "IFCLIGHTSOURCEAMBIENT",
794                    _ => "UNKNOWN",
795                }
796            }
797        }
798    }
799
800    /// IFC inheritance: direct parent in the EXPRESS type hierarchy.
801    ///
802    /// Only the branches needed for geometry-eligibility decisions are
803    /// populated — `IfcRoot` and its `IfcObjectDefinition`/`IfcObject`/
804    /// `IfcProduct`/`IfcElement` descendants. Types unrelated to that
805    /// subtree (representation items, profiles, relationships, units, …)
806    /// return `None`; callers should treat that as "not a product".
807    ///
808    /// This is a hand-maintained subset of upstream `@ifc-lite/codegen`'s
809    /// generated `parent()` table, ported from upstream PR #596 / #585 but
810    /// scoped to the types the bimifc enum actually carries. When a new
811    /// `IfcType` variant is added, give it a parent arm here and the rest
812    /// of the system (has_geometry, future is_subtype_of callers) picks it
813    /// up without further edits.
814    pub fn parent(&self) -> Option<Self> {
815        use IfcType::*;
816        Some(match self {
817            // ── Root chain ────────────────────────────────────────────
818            IfcObjectDefinition => IfcRoot,
819            IfcObject => IfcObjectDefinition,
820            IfcProduct => IfcObject,
821
822            // ── Spatial elements ──────────────────────────────────────
823            IfcSpatialElement => IfcProduct,
824            IfcSpatialStructureElement => IfcSpatialElement,
825            IfcExternalSpatialStructureElement => IfcSpatialElement,
826            IfcExternalSpatialElement => IfcExternalSpatialStructureElement,
827            IfcSpatialZone => IfcSpatialElement,
828            IfcSite => IfcSpatialStructureElement,
829            IfcBuilding => IfcSpatialStructureElement,
830            IfcBuildingStorey => IfcSpatialStructureElement,
831            IfcSpace => IfcSpatialStructureElement,
832            IfcFacility => IfcSpatialStructureElement,
833            IfcFacilityPart => IfcSpatialStructureElement,
834            IfcBridge => IfcFacility,
835            IfcBridgePart => IfcFacilityPart,
836            IfcRoad => IfcFacility,
837            IfcRoadPart => IfcFacilityPart,
838            IfcRailway => IfcFacility,
839            IfcRailwayPart => IfcFacilityPart,
840
841            // ── Elements & built elements ─────────────────────────────
842            IfcElement => IfcProduct,
843            IfcBuiltElement => IfcElement,
844            IfcCivilElement => IfcElement,
845            IfcGeographicElement => IfcElement,
846            IfcAnnotation => IfcProduct,
847            IfcPort => IfcProduct,
848            IfcElementAssembly => IfcElement,
849            IfcFurnishingElement => IfcElement,
850            IfcFurniture => IfcFurnishingElement,
851            IfcSystemFurnitureElement => IfcFurnishingElement,
852            IfcBuildingElementProxy => IfcBuiltElement,
853
854            // ── Built element concrete classes ────────────────────────
855            IfcWall => IfcBuiltElement,
856            IfcWallStandardCase => IfcWall,
857            IfcCurtainWall => IfcBuiltElement,
858            IfcSlab => IfcBuiltElement,
859            IfcRoof => IfcBuiltElement,
860            IfcBeam => IfcBuiltElement,
861            IfcColumn => IfcBuiltElement,
862            IfcDoor => IfcBuiltElement,
863            IfcWindow => IfcBuiltElement,
864            IfcStair => IfcBuiltElement,
865            IfcStairFlight => IfcBuiltElement,
866            IfcRamp => IfcBuiltElement,
867            IfcRampFlight => IfcBuiltElement,
868            IfcRailing => IfcBuiltElement,
869            IfcCovering => IfcBuiltElement,
870            IfcPlate => IfcBuiltElement,
871            IfcMember => IfcBuiltElement,
872            IfcFooting => IfcBuiltElement,
873            IfcPile => IfcBuiltElement,
874            IfcDeepFoundation => IfcBuiltElement,
875
876            // ── Feature elements (openings, voids, projections) ───────
877            IfcFeatureElement => IfcElement,
878            IfcFeatureElementSubtraction => IfcFeatureElement,
879            IfcFeatureElementAddition => IfcFeatureElement,
880            IfcOpeningElement => IfcFeatureElementSubtraction,
881            IfcOpeningStandardCase => IfcOpeningElement,
882            IfcVoidingFeature => IfcFeatureElementSubtraction,
883            IfcProjectionElement => IfcFeatureElementAddition,
884
885            // ── Distribution elements (MEP) ───────────────────────────
886            IfcDistributionElement => IfcElement,
887            IfcDistributionFlowElement => IfcDistributionElement,
888            IfcDistributionControlElement => IfcDistributionElement,
889            IfcFlowSegment => IfcDistributionFlowElement,
890            IfcFlowFitting => IfcDistributionFlowElement,
891            IfcFlowTerminal => IfcDistributionFlowElement,
892            IfcFlowController => IfcDistributionFlowElement,
893            IfcFlowMovingDevice => IfcDistributionFlowElement,
894            IfcFlowStorageDevice => IfcDistributionFlowElement,
895            IfcFlowTreatmentDevice => IfcDistributionFlowElement,
896            IfcEnergyConversionDevice => IfcDistributionFlowElement,
897            IfcCableSegment => IfcFlowSegment,
898            IfcCableCarrierSegment => IfcFlowSegment,
899            IfcCableCarrierFitting => IfcFlowFitting,
900            IfcPipeSegment => IfcFlowSegment,
901            IfcPipeFitting => IfcFlowFitting,
902            IfcSpaceHeater => IfcEnergyConversionDevice,
903            IfcAirTerminal => IfcFlowTerminal,
904            IfcLightFixture => IfcFlowTerminal,
905
906            // ── Infrastructure / geotechnical ─────────────────────────
907            IfcGeotechnicalElement => IfcElement,
908            IfcGeotechnicalAssembly => IfcGeotechnicalElement,
909            IfcBorehole => IfcGeotechnicalAssembly,
910            IfcGeomodel => IfcGeotechnicalAssembly,
911            IfcGeoslice => IfcGeotechnicalAssembly,
912            IfcSolidStratum => IfcGeotechnicalElement,
913            IfcVoidStratum => IfcGeotechnicalElement,
914            IfcWaterStratum => IfcGeotechnicalElement,
915            IfcEarthworksElement => IfcElement,
916            IfcEarthworksCut => IfcFeatureElementSubtraction,
917            IfcEarthworksFill => IfcEarthworksElement,
918            IfcPavement => IfcBuiltElement,
919            IfcCourse => IfcBuiltElement,
920            IfcKerb => IfcBuiltElement,
921
922            // ── IfcProject is itself a context, not a product ─────────
923            // (left unmapped on purpose so is_subtype_of(IfcProduct) is false)
924            _ => return None,
925        })
926    }
927
928    /// True if this type equals `parent` or any of its ancestors equals `parent`.
929    pub fn is_subtype_of(&self, parent: IfcType) -> bool {
930        // `IfcType` carries an `Unknown(String)` variant so it isn't `Copy`.
931        // Walking the chain only needs the named variants — `Unknown` has no
932        // parent and is never equal to a named `parent` argument, so we can
933        // short-circuit it.
934        if matches!(self, IfcType::Unknown(_)) {
935            return false;
936        }
937        let mut current = Some(self.clone());
938        while let Some(t) = current {
939            if t == parent {
940                return true;
941            }
942            current = t.parent();
943        }
944        false
945    }
946
947    /// Check if this type represents a product that can carry geometry.
948    ///
949    /// Inheritance-based: anything under `IfcProduct` is renderable, *except*
950    /// spatial-container subclasses of `IfcSpatialElement` (with `IfcSpace`
951    /// and `IfcSite` kept — their boundary representations are rendered).
952    /// Adding a new concrete subtype now only requires wiring up `parent()`.
953    ///
954    /// Ported from upstream ifc-lite PR #596 (`schema_helpers::has_geometry_by_name`),
955    /// scoped to the bimifc `IfcType` enum.
956    pub fn has_geometry(&self) -> bool {
957        if !self.is_subtype_of(IfcType::IfcProduct) {
958            return false;
959        }
960        !is_non_geometric_spatial(self)
961    }
962}
963
964/// Spatial containers that exist only to group children, not to render.
965/// `IfcSpace` and `IfcSite` are deliberately exempt — their boundary
966/// representations are consumed by the renderer.
967fn is_non_geometric_spatial(t: &IfcType) -> bool {
968    if matches!(t, IfcType::IfcSpace | IfcType::IfcSite) {
969        return false;
970    }
971    t.is_subtype_of(IfcType::IfcSpatialElement)
972}
973
974impl IfcType {
975
976    /// Check if this type is a spatial structure element
977    pub fn is_spatial(&self) -> bool {
978        matches!(
979            self,
980            IfcType::IfcProject
981                | IfcType::IfcSite
982                | IfcType::IfcBuilding
983                | IfcType::IfcBuildingStorey
984                | IfcType::IfcSpace
985                | IfcType::IfcFacility
986                | IfcType::IfcFacilityPart
987        )
988    }
989}
990
991impl Default for IfcType {
992    fn default() -> Self {
993        IfcType::Unknown(String::new())
994    }
995}
996
997impl fmt::Display for IfcType {
998    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
999        write!(f, "{}", self.name())
1000    }
1001}
1002
1003/// Decoded attribute value
1004///
1005/// Represents any value that can appear in an IFC entity's attribute list.
1006#[derive(Clone, Debug, PartialEq, Default)]
1007pub enum AttributeValue {
1008    /// Null value ($)
1009    #[default]
1010    Null,
1011    /// Derived value (*)
1012    Derived,
1013    /// Entity reference (#123)
1014    EntityRef(EntityId),
1015    /// Boolean value
1016    Bool(bool),
1017    /// Integer value
1018    Integer(i64),
1019    /// Floating point value
1020    Float(f64),
1021    /// String value
1022    String(String),
1023    /// Enumeration value (.VALUE.)
1024    Enum(String),
1025    /// List of values
1026    List(Vec<AttributeValue>),
1027    /// Typed value like IFCLABEL('text')
1028    TypedValue(String, Vec<AttributeValue>),
1029}
1030
1031impl AttributeValue {
1032    /// Try to get as entity reference
1033    pub fn as_entity_ref(&self) -> Option<EntityId> {
1034        match self {
1035            AttributeValue::EntityRef(id) => Some(*id),
1036            _ => None,
1037        }
1038    }
1039
1040    /// Try to get as string
1041    pub fn as_string(&self) -> Option<&str> {
1042        match self {
1043            AttributeValue::String(s) => Some(s),
1044            AttributeValue::TypedValue(_, args) if !args.is_empty() => args[0].as_string(),
1045            _ => None,
1046        }
1047    }
1048
1049    /// Try to get as float
1050    pub fn as_float(&self) -> Option<f64> {
1051        match self {
1052            AttributeValue::Float(f) => Some(*f),
1053            AttributeValue::Integer(i) => Some(*i as f64),
1054            AttributeValue::TypedValue(_, args) if !args.is_empty() => args[0].as_float(),
1055            _ => None,
1056        }
1057    }
1058
1059    /// Try to get as integer
1060    pub fn as_integer(&self) -> Option<i64> {
1061        match self {
1062            AttributeValue::Integer(i) => Some(*i),
1063            _ => None,
1064        }
1065    }
1066
1067    /// Try to get as boolean
1068    pub fn as_bool(&self) -> Option<bool> {
1069        match self {
1070            AttributeValue::Bool(b) => Some(*b),
1071            AttributeValue::Enum(s) => match s.to_uppercase().as_str() {
1072                "TRUE" | "T" => Some(true),
1073                "FALSE" | "F" => Some(false),
1074                _ => None,
1075            },
1076            _ => None,
1077        }
1078    }
1079
1080    /// Try to get as enum string
1081    pub fn as_enum(&self) -> Option<&str> {
1082        match self {
1083            AttributeValue::Enum(s) => Some(s),
1084            _ => None,
1085        }
1086    }
1087
1088    /// Try to get as list
1089    pub fn as_list(&self) -> Option<&[AttributeValue]> {
1090        match self {
1091            AttributeValue::List(list) => Some(list),
1092            _ => None,
1093        }
1094    }
1095
1096    /// Check if this is a null value
1097    pub fn is_null(&self) -> bool {
1098        matches!(self, AttributeValue::Null)
1099    }
1100
1101    /// Check if this is a derived value
1102    pub fn is_derived(&self) -> bool {
1103        matches!(self, AttributeValue::Derived)
1104    }
1105}
1106
1107/// Decoded IFC entity
1108///
1109/// Represents a fully decoded IFC entity with its ID, type, and attribute values.
1110#[derive(Clone, Debug)]
1111pub struct DecodedEntity {
1112    /// Entity ID
1113    pub id: EntityId,
1114    /// Entity type
1115    pub ifc_type: IfcType,
1116    /// Attribute values in order
1117    pub attributes: Vec<AttributeValue>,
1118}
1119
1120impl DecodedEntity {
1121    /// Get attribute at index
1122    pub fn get(&self, index: usize) -> Option<&AttributeValue> {
1123        self.attributes.get(index)
1124    }
1125
1126    /// Get entity reference at index
1127    pub fn get_ref(&self, index: usize) -> Option<EntityId> {
1128        self.get(index).and_then(|v| v.as_entity_ref())
1129    }
1130
1131    /// Get string at index
1132    pub fn get_string(&self, index: usize) -> Option<&str> {
1133        self.get(index).and_then(|v| v.as_string())
1134    }
1135
1136    /// Get float at index
1137    pub fn get_float(&self, index: usize) -> Option<f64> {
1138        self.get(index).and_then(|v| v.as_float())
1139    }
1140
1141    /// Get integer at index
1142    pub fn get_integer(&self, index: usize) -> Option<i64> {
1143        self.get(index).and_then(|v| v.as_integer())
1144    }
1145
1146    /// Get list at index
1147    pub fn get_list(&self, index: usize) -> Option<&[AttributeValue]> {
1148        self.get(index).and_then(|v| v.as_list())
1149    }
1150
1151    /// Get boolean at index
1152    pub fn get_bool(&self, index: usize) -> Option<bool> {
1153        self.get(index).and_then(|v| v.as_bool())
1154    }
1155
1156    /// Get enum string at index
1157    pub fn get_enum(&self, index: usize) -> Option<&str> {
1158        self.get(index).and_then(|v| v.as_enum())
1159    }
1160
1161    /// Get list of entity references at index
1162    pub fn get_refs(&self, index: usize) -> Option<Vec<EntityId>> {
1163        self.get_list(index)
1164            .map(|list| list.iter().filter_map(|v| v.as_entity_ref()).collect())
1165    }
1166}
1167
1168/// GPU-ready mesh data
1169///
1170/// Contains flattened vertex data suitable for GPU rendering.
1171#[derive(Clone, Debug, Default)]
1172pub struct MeshData {
1173    /// Vertex positions as flattened [x, y, z, x, y, z, ...]
1174    pub positions: Vec<f32>,
1175    /// Vertex normals as flattened [nx, ny, nz, nx, ny, nz, ...]
1176    pub normals: Vec<f32>,
1177    /// Triangle indices
1178    pub indices: Vec<u32>,
1179}
1180
1181impl MeshData {
1182    /// Create a new empty mesh
1183    pub fn new() -> Self {
1184        Self::default()
1185    }
1186
1187    /// Create mesh with pre-allocated capacity
1188    pub fn with_capacity(vertex_count: usize, index_count: usize) -> Self {
1189        Self {
1190            positions: Vec::with_capacity(vertex_count * 3),
1191            normals: Vec::with_capacity(vertex_count * 3),
1192            indices: Vec::with_capacity(index_count),
1193        }
1194    }
1195
1196    /// Check if mesh is empty
1197    pub fn is_empty(&self) -> bool {
1198        self.positions.is_empty()
1199    }
1200
1201    /// Get vertex count
1202    pub fn vertex_count(&self) -> usize {
1203        self.positions.len() / 3
1204    }
1205
1206    /// Get triangle count
1207    pub fn triangle_count(&self) -> usize {
1208        self.indices.len() / 3
1209    }
1210
1211    /// Merge another mesh into this one
1212    pub fn merge(&mut self, other: &MeshData) {
1213        let vertex_offset = self.vertex_count() as u32;
1214
1215        self.positions.extend_from_slice(&other.positions);
1216        self.normals.extend_from_slice(&other.normals);
1217        self.indices
1218            .extend(other.indices.iter().map(|i| i + vertex_offset));
1219    }
1220}
1221
1222/// Model metadata extracted from IFC header
1223#[derive(Clone, Debug, Default)]
1224pub struct ModelMetadata {
1225    /// IFC schema version (e.g., "IFC2X3", "IFC4", "IFC4X3")
1226    pub schema_version: String,
1227    /// Originating system (CAD application)
1228    pub originating_system: Option<String>,
1229    /// Preprocessor version
1230    pub preprocessor_version: Option<String>,
1231    /// File name from header
1232    pub file_name: Option<String>,
1233    /// File description
1234    pub file_description: Option<String>,
1235    /// Author
1236    pub author: Option<String>,
1237    /// Organization
1238    pub organization: Option<String>,
1239    /// Timestamp
1240    pub timestamp: Option<String>,
1241}
1242
1243#[cfg(test)]
1244mod inheritance_tests {
1245    //! Regression tests for the inheritance-graph based `has_geometry`,
1246    //! adapted from upstream ifc-lite `rust/core/src/schema_helpers.rs`
1247    //! (PR #596 / #585). Each test that names a specific IFC type is
1248    //! a single source of truth: if a new variant is added to `IfcType`
1249    //! and missed in `parent()`, the relevant assertion fails here
1250    //! instead of silently dropping geometry at render time.
1251    use super::IfcType;
1252
1253    #[test]
1254    fn building_elements_have_geometry() {
1255        for t in [
1256            IfcType::IfcWall,
1257            IfcType::IfcWallStandardCase,
1258            IfcType::IfcSlab,
1259            IfcType::IfcBeam,
1260            IfcType::IfcColumn,
1261            IfcType::IfcDoor,
1262            IfcType::IfcWindow,
1263            IfcType::IfcRoof,
1264            IfcType::IfcStair,
1265        ] {
1266            assert!(t.has_geometry(), "{t:?} should have geometry");
1267        }
1268    }
1269
1270    #[test]
1271    fn mep_elements_have_geometry() {
1272        for t in [
1273            IfcType::IfcFlowSegment,
1274            IfcType::IfcFlowFitting,
1275            IfcType::IfcEnergyConversionDevice,
1276            IfcType::IfcFlowTreatmentDevice,
1277            IfcType::IfcCableSegment,
1278            IfcType::IfcCableCarrierSegment,
1279            IfcType::IfcCableCarrierFitting,
1280            IfcType::IfcPipeSegment,
1281            IfcType::IfcPipeFitting,
1282            IfcType::IfcSpaceHeater,
1283            IfcType::IfcAirTerminal,
1284            IfcType::IfcLightFixture,
1285        ] {
1286            assert!(t.has_geometry(), "{t:?} should have geometry");
1287        }
1288    }
1289
1290    #[test]
1291    fn space_and_site_have_geometry() {
1292        // Containers in general are excluded, but IfcSpace and IfcSite are
1293        // exempt because their boundary representations are rendered.
1294        assert!(IfcType::IfcSpace.has_geometry());
1295        assert!(IfcType::IfcSite.has_geometry());
1296        assert!(IfcType::IfcOpeningElement.has_geometry());
1297    }
1298
1299    #[test]
1300    fn non_geometric_spatial_excluded() {
1301        // Pure spatial containers — present in this enum but never rendered.
1302        for t in [
1303            IfcType::IfcBuilding,
1304            IfcType::IfcBuildingStorey,
1305            IfcType::IfcFacility,
1306            IfcType::IfcFacilityPart,
1307            IfcType::IfcSpatialElement,
1308            IfcType::IfcSpatialStructureElement,
1309            IfcType::IfcBridge,
1310            IfcType::IfcRoad,
1311            IfcType::IfcRailway,
1312            IfcType::IfcBridgePart,
1313            IfcType::IfcSpatialZone,
1314            IfcType::IfcExternalSpatialElement,
1315            IfcType::IfcExternalSpatialStructureElement,
1316        ] {
1317            assert!(!t.has_geometry(), "{t:?} should NOT have geometry");
1318        }
1319    }
1320
1321    #[test]
1322    fn non_products_excluded() {
1323        // Project, materials, properties, rels, geometry items — none are
1324        // IfcProduct subtypes, so parent() returns None for all of them.
1325        for t in [
1326            IfcType::IfcProject,
1327            IfcType::IfcMaterial,
1328            IfcType::IfcPropertySet,
1329            IfcType::IfcRelAggregates,
1330            IfcType::IfcSurfaceStyleRendering,
1331            IfcType::IfcCartesianPoint,
1332            IfcType::IfcExtrudedAreaSolid,
1333        ] {
1334            assert!(!t.has_geometry(), "{t:?} should NOT have geometry");
1335        }
1336    }
1337
1338    #[test]
1339    fn is_subtype_of_walks_chain() {
1340        // Direct relationship.
1341        assert!(IfcType::IfcWall.is_subtype_of(IfcType::IfcBuiltElement));
1342        // Multi-hop: IfcCableSegment → IfcFlowSegment → IfcDistributionFlowElement → IfcDistributionElement → IfcElement → IfcProduct
1343        assert!(IfcType::IfcCableSegment.is_subtype_of(IfcType::IfcElement));
1344        assert!(IfcType::IfcCableSegment.is_subtype_of(IfcType::IfcProduct));
1345        // A type is its own subtype.
1346        assert!(IfcType::IfcWall.is_subtype_of(IfcType::IfcWall));
1347        // Negative: not in the same subtree.
1348        assert!(!IfcType::IfcWall.is_subtype_of(IfcType::IfcDistributionElement));
1349        // Unknown variant never matches anything.
1350        assert!(!IfcType::Unknown("FOO".into()).is_subtype_of(IfcType::IfcProduct));
1351    }
1352
1353    /// MEP types we just added (concrete subclasses) — these are the exact
1354    /// types whose manual enumeration motivated this port. They must inherit
1355    /// geometry eligibility from their parents without any leaf-level edits.
1356    #[test]
1357    fn mep_concrete_types_inherit_geometry() {
1358        for t in [
1359            IfcType::IfcCableSegment,
1360            IfcType::IfcCableCarrierSegment,
1361            IfcType::IfcCableCarrierFitting,
1362            IfcType::IfcPipeSegment,
1363            IfcType::IfcPipeFitting,
1364            IfcType::IfcSpaceHeater,
1365            IfcType::IfcAirTerminal,
1366        ] {
1367            assert!(
1368                t.has_geometry(),
1369                "{t:?} should inherit geometry via parent() chain"
1370            );
1371        }
1372    }
1373}