Skip to main content

gldf_rs/ifc/
types.rs

1//! IFC type definitions for lighting entities
2
3use serde::{Deserialize, Serialize};
4
5/// Light fixture type enum matching IFC IfcLightFixtureTypeEnum
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7pub enum LightFixtureTypeEnum {
8    /// Point light source
9    PointSource,
10    /// Directional light source
11    DirectionSource,
12    /// Security/emergency lighting
13    SecurityLighting,
14    /// User-defined type
15    UserDefined,
16    /// Not defined
17    #[default]
18    NotDefined,
19}
20
21impl LightFixtureTypeEnum {
22    /// Convert to IFC STEP enum string
23    pub fn to_step(&self) -> &'static str {
24        match self {
25            Self::PointSource => ".POINTSOURCE.",
26            Self::DirectionSource => ".DIRECTIONSOURCE.",
27            Self::SecurityLighting => ".SECURITYLIGHTING.",
28            Self::UserDefined => ".USERDEFINED.",
29            Self::NotDefined => ".NOTDEFINED.",
30        }
31    }
32}
33
34/// Light emission source enum matching IFC IfcLightEmissionSourceEnum
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
36pub enum LightEmissionSourceEnum {
37    CompactFluorescent,
38    Fluorescent,
39    HighPressureMercury,
40    HighPressureSodium,
41    Led,
42    LightEmittingDiode,
43    LowPressureSodium,
44    LowVoltageHalogen,
45    MainVoltageHalogen,
46    MetalHalide,
47    TungstenFilament,
48    #[default]
49    NotDefined,
50}
51
52impl LightEmissionSourceEnum {
53    /// Convert to IFC STEP enum string
54    pub fn to_step(&self) -> &'static str {
55        match self {
56            Self::CompactFluorescent => ".COMPACTFLUORESCENT.",
57            Self::Fluorescent => ".FLUORESCENT.",
58            Self::HighPressureMercury => ".HIGHPRESSUREMERCURY.",
59            Self::HighPressureSodium => ".HIGHPRESSURESODIUM.",
60            Self::Led => ".LED.",
61            Self::LightEmittingDiode => ".LIGHTEMITTINGDIODE.",
62            Self::LowPressureSodium => ".LOWPRESSURESODIUM.",
63            Self::LowVoltageHalogen => ".LOWVOLTAGEHALOGEN.",
64            Self::MainVoltageHalogen => ".MAINVOLTAGEHALOGEN.",
65            Self::MetalHalide => ".METALHALIDE.",
66            Self::TungstenFilament => ".TUNGSTENFILAMENT.",
67            Self::NotDefined => ".NOTDEFINED.",
68        }
69    }
70}
71
72/// Entity reference in IFC STEP format (e.g., #123)
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub struct EntityRef(pub u64);
75
76impl EntityRef {
77    pub fn new(id: u64) -> Self {
78        Self(id)
79    }
80}
81
82impl std::fmt::Display for EntityRef {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        write!(f, "#{}", self.0)
85    }
86}
87
88/// Optional entity reference ($ for null)
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum OptionalRef {
91    Some(EntityRef),
92    None,
93}
94
95impl std::fmt::Display for OptionalRef {
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        match self {
98            Self::Some(r) => write!(f, "{}", r),
99            Self::None => write!(f, "$"),
100        }
101    }
102}
103
104impl From<EntityRef> for OptionalRef {
105    fn from(r: EntityRef) -> Self {
106        Self::Some(r)
107    }
108}
109
110impl From<Option<EntityRef>> for OptionalRef {
111    fn from(opt: Option<EntityRef>) -> Self {
112        match opt {
113            Some(r) => Self::Some(r),
114            None => Self::None,
115        }
116    }
117}
118
119// ============================================================================
120// Electrical MVD Types (SPARKIE / Electrical Information Exchange)
121// ============================================================================
122
123/// Conductor function enum for electrical phase identification (IEC 60446)
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
125#[allow(non_camel_case_types)]
126pub enum ConductorFunctionEnum {
127    /// Phase L1
128    PHASE_L1,
129    /// Phase L2
130    PHASE_L2,
131    /// Phase L3
132    PHASE_L3,
133    /// Neutral
134    Neutral,
135    /// Protective Earth
136    ProtectiveEarth,
137    /// Protective Earth and Neutral combined
138    ProtectiveEarthNeutral,
139    #[default]
140    NotDefined,
141}
142
143impl ConductorFunctionEnum {
144    pub fn to_step(&self) -> &'static str {
145        match self {
146            Self::PHASE_L1 => ".PHASE_L1.",
147            Self::PHASE_L2 => ".PHASE_L2.",
148            Self::PHASE_L3 => ".PHASE_L3.",
149            Self::Neutral => ".NEUTRAL.",
150            Self::ProtectiveEarth => ".PROTECTIVEEARTH.",
151            Self::ProtectiveEarthNeutral => ".PROTECTIVEEARTHNEUTRAL.",
152            Self::NotDefined => ".NOTDEFINED.",
153        }
154    }
155}
156
157/// Insulation standard class for electrical safety (IEC 61140)
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
159pub enum InsulationStandardClass {
160    /// Class 0 - Basic insulation, no earth
161    Class0,
162    /// Class I - Basic insulation + protective earth
163    ClassI,
164    /// Class II - Double/reinforced insulation
165    ClassII,
166    /// Class III - Safety extra-low voltage (SELV)
167    ClassIII,
168    #[default]
169    NotDefined,
170}
171
172impl InsulationStandardClass {
173    pub fn to_step(&self) -> &'static str {
174        match self {
175            Self::Class0 => ".CLASS0.",
176            Self::ClassI => ".CLASSI.",
177            Self::ClassII => ".CLASSII.",
178            Self::ClassIII => ".CLASSIII.",
179            Self::NotDefined => ".NOTDEFINED.",
180        }
181    }
182
183    /// Convert from GLDF electrical safety class string
184    pub fn from_gldf_safety_class(s: &str) -> Self {
185        match s.to_uppercase().as_str() {
186            "I" | "CLASS I" | "CLASSI" | "1" => Self::ClassI,
187            "II" | "CLASS II" | "CLASSII" | "2" => Self::ClassII,
188            "III" | "CLASS III" | "CLASSIII" | "3" => Self::ClassIII,
189            "0" | "CLASS 0" | "CLASS0" => Self::Class0,
190            _ => Self::NotDefined,
191        }
192    }
193}
194
195/// Comprehensive electrical device properties for Pset_ElectricalDeviceCommon
196///
197/// Based on IFC4.3 specification and SPARKIE MVD requirements.
198/// See: <https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/Pset_ElectricalDeviceCommon.htm>
199#[derive(Debug, Clone, Default)]
200pub struct ElectricalDeviceProperties {
201    /// Rated current in Amperes (A)
202    pub rated_current: Option<f64>,
203    /// Rated voltage in Volts (V) - can be range (min, max)
204    pub rated_voltage: Option<f64>,
205    /// Maximum rated voltage (for bounded value)
206    pub rated_voltage_max: Option<f64>,
207    /// Nominal frequency range in Hz (min, max)
208    pub nominal_frequency_min: Option<f64>,
209    pub nominal_frequency_max: Option<f64>,
210    /// Power factor (cos φ), normalized ratio 0.0-1.0
211    pub power_factor: Option<f64>,
212    /// Conductor function (phase line identification)
213    pub conductor_function: Option<ConductorFunctionEnum>,
214    /// Number of poles (live lines)
215    pub number_of_poles: Option<i32>,
216    /// Has protective earth connection
217    pub has_protective_earth: Option<bool>,
218    /// Insulation standard class (IEC 61140)
219    pub insulation_standard_class: Option<InsulationStandardClass>,
220    /// IP Code (IEC 60529) - e.g., "IP65"
221    pub ip_code: Option<String>,
222    /// IK Code (IEC 62262) - mechanical impact protection, e.g., "IK08"
223    pub ik_code: Option<String>,
224    /// Earthing style description
225    pub earthing_style: Option<String>,
226    /// Heat dissipation in Watts
227    pub heat_dissipation: Option<f64>,
228    /// Actual power output in Watts
229    pub power: Option<f64>,
230    /// Nominal power consumption in Watts
231    pub nominal_power_consumption: Option<f64>,
232    /// Number of power supply ports
233    pub number_of_power_supply_ports: Option<i32>,
234}
235
236/// Light fixture common properties for Pset_LightFixtureTypeCommon
237#[derive(Debug, Clone, Default)]
238pub struct LightFixtureCommonProperties {
239    /// Reference identifier
240    pub reference: Option<String>,
241    /// Status (NEW, EXISTING, DEMOLISH, TEMPORARY)
242    pub status: Option<String>,
243    /// Number of light sources
244    pub number_of_sources: Option<i32>,
245    /// Total wattage in Watts
246    pub total_wattage: Option<f64>,
247    /// Mounting type (SURFACE, RECESSED, SUSPENDED, POLE, etc.)
248    pub mounting_type: Option<String>,
249    /// Placing type (CEILING, FLOOR, WALL, etc.)
250    pub placing_type: Option<String>,
251    /// Maintenance factor (0.0-1.0)
252    pub maintenance_factor: Option<f64>,
253    /// Maximum plenum sensible load in Watts
254    pub max_plenum_sensible_load: Option<f64>,
255    /// Maximum space sensible load in Watts
256    pub max_space_sensible_load: Option<f64>,
257    /// Ratio of sensible load to radiant (0.0-1.0)
258    pub sensible_load_to_radiant: Option<f64>,
259}
260
261/// COBie manufacturer type information for Pset_ManufacturerTypeInformation
262#[derive(Debug, Clone, Default)]
263pub struct ManufacturerTypeInfo {
264    /// Global trade item number (GTIN/EAN/UPC)
265    pub global_trade_item_number: Option<String>,
266    /// Article number / product code
267    pub article_number: Option<String>,
268    /// Model reference
269    pub model_reference: Option<String>,
270    /// Model label
271    pub model_label: Option<String>,
272    /// Manufacturer name
273    pub manufacturer: Option<String>,
274    /// Production year
275    pub production_year: Option<i32>,
276    /// Assembly place
277    pub assembly_place: Option<String>,
278}
279
280/// COBie warranty information for Pset_Warranty
281#[derive(Debug, Clone, Default)]
282pub struct WarrantyInfo {
283    /// Warranty identifier
284    pub warranty_identifier: Option<String>,
285    /// Warranty start date (ISO 8601)
286    pub warranty_start_date: Option<String>,
287    /// Warranty end date (ISO 8601)
288    pub warranty_end_date: Option<String>,
289    /// Warranty period in years
290    pub warranty_period: Option<f64>,
291    /// Point of contact
292    pub point_of_contact: Option<String>,
293    /// Terms and conditions
294    pub terms_and_conditions: Option<String>,
295    /// Exclusions
296    pub exclusions: Option<String>,
297}
298
299/// COBie service life information for Pset_ServiceLife
300#[derive(Debug, Clone, Default)]
301pub struct ServiceLifeInfo {
302    /// Service life duration in years
303    pub service_life_duration: Option<f64>,
304    /// Service life type (ACTUALSERVICELIFE, EXPECTEDSERVICELIFE, etc.)
305    pub service_life_type: Option<String>,
306    /// Mean time between failures in hours
307    pub mean_time_between_failure: Option<f64>,
308}
309
310/// Distribution port flow direction
311#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
312pub enum FlowDirectionEnum {
313    /// Incoming flow (power input)
314    Source,
315    /// Outgoing flow (power output)
316    Sink,
317    /// Bidirectional flow
318    SourceAndSink,
319    #[default]
320    NotDefined,
321}
322
323impl FlowDirectionEnum {
324    pub fn to_step(&self) -> &'static str {
325        match self {
326            Self::Source => ".SOURCE.",
327            Self::Sink => ".SINK.",
328            Self::SourceAndSink => ".SOURCEANDSINK.",
329            Self::NotDefined => ".NOTDEFINED.",
330        }
331    }
332}
333
334/// Distribution system type for electrical systems
335#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
336pub enum DistributionSystemEnum {
337    Electrical,
338    Lighting,
339    LightningProtection,
340    PowerGeneration,
341    #[default]
342    NotDefined,
343}
344
345impl DistributionSystemEnum {
346    pub fn to_step(&self) -> &'static str {
347        match self {
348            Self::Electrical => ".ELECTRICAL.",
349            Self::Lighting => ".LIGHTING.",
350            Self::LightningProtection => ".LIGHTNINGPROTECTION.",
351            Self::PowerGeneration => ".POWERGENERATION.",
352            Self::NotDefined => ".NOTDEFINED.",
353        }
354    }
355}