Skip to main content

oxihuman_export/
ifc_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! IFC BIM building model export stub.
6
7/// IFC entity class stub.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum IfcClass {
10    IfcProject,
11    IfcSite,
12    IfcBuilding,
13    IfcBuildingStorey,
14    IfcWall,
15    IfcSlab,
16    IfcColumn,
17}
18
19/// A single IFC entity stub.
20#[derive(Debug, Clone)]
21pub struct IfcEntity {
22    pub id: u32,
23    pub class: IfcClass,
24    pub name: String,
25    pub attributes: Vec<String>,
26}
27
28/// IFC export container.
29#[derive(Debug, Clone, Default)]
30pub struct IfcExport {
31    pub schema: String,
32    pub entities: Vec<IfcEntity>,
33}
34
35/// Create a new IFC export.
36pub fn new_ifc_export(schema: &str) -> IfcExport {
37    IfcExport {
38        schema: schema.to_string(),
39        entities: Vec::new(),
40    }
41}
42
43/// Add an IFC entity; returns its id.
44pub fn add_ifc_entity(export: &mut IfcExport, class: IfcClass, name: &str) -> u32 {
45    let id = export.entities.len() as u32 + 1;
46    export.entities.push(IfcEntity {
47        id,
48        class,
49        name: name.to_string(),
50        attributes: Vec::new(),
51    });
52    id
53}
54
55/// Return entity count.
56pub fn ifc_entity_count(export: &IfcExport) -> usize {
57    export.entities.len()
58}
59
60/// Count entities of a given class.
61pub fn ifc_count_class(export: &IfcExport, class: IfcClass) -> usize {
62    export.entities.iter().filter(|e| e.class == class).count()
63}
64
65/// Render a stub STEP-based IFC header.
66pub fn ifc_header(export: &IfcExport) -> String {
67    format!(
68        "ISO-10303-21;\nHEADER;\nFILE_SCHEMA(('{}'));\nENDSEC;\nDATA;",
69        export.schema
70    )
71}
72
73/// Render a single IFC entity line.
74pub fn ifc_entity_line(entity: &IfcEntity) -> String {
75    let class_name = match entity.class {
76        IfcClass::IfcProject => "IFCPROJECT",
77        IfcClass::IfcSite => "IFCSITE",
78        IfcClass::IfcBuilding => "IFCBUILDING",
79        IfcClass::IfcBuildingStorey => "IFCBUILDINGSTOREY",
80        IfcClass::IfcWall => "IFCWALL",
81        IfcClass::IfcSlab => "IFCSLAB",
82        IfcClass::IfcColumn => "IFCCOLUMN",
83    };
84    format!("#{} = {}('{}');", entity.id, class_name, entity.name)
85}
86
87/// Validate that a project entity exists.
88pub fn validate_ifc(export: &IfcExport) -> bool {
89    export
90        .entities
91        .iter()
92        .any(|e| e.class == IfcClass::IfcProject)
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn test_new_export_empty() {
101        let exp = new_ifc_export("IFC4");
102        assert_eq!(ifc_entity_count(&exp), 0);
103    }
104
105    #[test]
106    fn test_add_entity_returns_id() {
107        let mut exp = new_ifc_export("IFC4");
108        let id = add_ifc_entity(&mut exp, IfcClass::IfcProject, "MyProject");
109        assert_eq!(id, 1);
110    }
111
112    #[test]
113    fn test_entity_count() {
114        let mut exp = new_ifc_export("IFC4");
115        add_ifc_entity(&mut exp, IfcClass::IfcProject, "P");
116        add_ifc_entity(&mut exp, IfcClass::IfcBuilding, "B");
117        assert_eq!(ifc_entity_count(&exp), 2);
118    }
119
120    #[test]
121    fn test_count_class() {
122        let mut exp = new_ifc_export("IFC4");
123        add_ifc_entity(&mut exp, IfcClass::IfcWall, "W1");
124        add_ifc_entity(&mut exp, IfcClass::IfcWall, "W2");
125        add_ifc_entity(&mut exp, IfcClass::IfcSlab, "S1");
126        assert_eq!(ifc_count_class(&exp, IfcClass::IfcWall), 2);
127    }
128
129    #[test]
130    fn test_header_contains_schema() {
131        let exp = new_ifc_export("IFC4");
132        assert!(ifc_header(&exp).contains("IFC4"));
133    }
134
135    #[test]
136    fn test_entity_line_wall() {
137        let mut exp = new_ifc_export("IFC4");
138        add_ifc_entity(&mut exp, IfcClass::IfcWall, "MyWall");
139        let line = ifc_entity_line(&exp.entities[0]);
140        assert!(line.contains("IFCWALL"));
141        assert!(line.contains("MyWall"));
142    }
143
144    #[test]
145    fn test_validate_with_project() {
146        let mut exp = new_ifc_export("IFC4");
147        add_ifc_entity(&mut exp, IfcClass::IfcProject, "Proj");
148        assert!(validate_ifc(&exp));
149    }
150
151    #[test]
152    fn test_validate_without_project() {
153        let mut exp = new_ifc_export("IFC4");
154        add_ifc_entity(&mut exp, IfcClass::IfcWall, "W");
155        assert!(!validate_ifc(&exp));
156    }
157
158    #[test]
159    fn test_schema_stored() {
160        let exp = new_ifc_export("IFC2X3");
161        assert_eq!(exp.schema, "IFC2X3");
162    }
163}