ifc_rs/objects/wall/
mod.rs

1mod deserialize;
2mod serialize;
3
4use std::ops::{Deref, DerefMut};
5
6use ifc_rs_verify_derive::IfcVerify;
7
8use crate::{
9    id::{IdOr, TypedId},
10    ifc_type::{IfcType, IfcVerify},
11    parser::{label::Label, optional::OptionalParameter},
12    prelude::*,
13    relations::rel_associates_material::MaterialRelatable,
14};
15
16use super::StructureType;
17
18/// The wall represents a vertical construction that may bound or
19/// subdivide spaces. Wall are usually vertical, or nearly vertical,
20/// planar elements, often designed to bear structural loads.
21/// A wall is however not required to be load bearing.
22///
23/// https://standards.buildingsmart.org/IFC/DEV/IFC4_2/FINAL/HTML/link/ifcwall.htm
24#[derive(IfcVerify)]
25pub struct Wall {
26    #[inherited]
27    element: Element,
28
29    /// Predefined generic type for a wall that is specified in an
30    /// enumeration. There may be a property set given specifically
31    /// for the predefined types.
32    pub predefined_type: OptionalParameter<IdOr<WallType>>,
33}
34
35impl Wall {
36    pub fn new(name: impl Into<Label>) -> Self {
37        Self {
38            element: Element::new(Product::new(Object::new(Root::new(name.into())))),
39            predefined_type: OptionalParameter::omitted(),
40        }
41    }
42
43    pub fn predefined_type(
44        mut self,
45        predefined_type: impl Into<IdOr<WallType>>,
46        ifc: &mut IFC,
47    ) -> Self {
48        let id_or: IdOr<_> = predefined_type.into();
49        let id_or: IdOr<_> = id_or.or_insert(ifc).into();
50        self.predefined_type = id_or.into();
51        self
52    }
53}
54
55impl RootBuilder for Wall {
56    fn root_mut(&mut self) -> &mut Root {
57        &mut self.element
58    }
59}
60
61impl ObjectBuilder for Wall {
62    fn object_mut(&mut self) -> &mut Object {
63        &mut self.element
64    }
65}
66
67impl ProductBuilder for Wall {
68    fn product_mut(&mut self) -> &mut Product {
69        &mut self.element
70    }
71}
72
73impl ElementBuilder for Wall {
74    fn element_mut(&mut self) -> &mut Element {
75        &mut self.element
76    }
77}
78
79impl Deref for Wall {
80    type Target = Element;
81
82    fn deref(&self) -> &Self::Target {
83        &self.element
84    }
85}
86
87impl DerefMut for Wall {
88    fn deref_mut(&mut self) -> &mut Self::Target {
89        &mut self.element
90    }
91}
92
93impl IfcType for Wall {
94    fn to_structure(&self) -> Option<&dyn Structure> {
95        Some(self)
96    }
97}
98impl Structure for Wall {
99    fn structure_type(&self) -> Option<StructureType<'_>> {
100        Some(StructureType::Wall(self))
101    }
102}
103impl MaterialRelatable for Wall {}
104
105impl TransformableType for Wall {
106    fn shape(&self) -> Option<TypedId<ProductDefinitionShape>> {
107        self.representation.custom().cloned()
108    }
109}
110
111#[cfg(test)]
112pub mod test {
113    use glam::DVec3;
114    use winnow::Parser;
115
116    use crate::geometry::axis::Axis3D;
117    use crate::geometry::local_placement::LocalPlacement;
118    use crate::geometry::point::Point3D;
119    use crate::geometry::product_definition_shape::test::new_product_definition_shape;
120    use crate::geometry::product_definition_shape::ProductDefinitionShape;
121    use crate::geometry::representation_context::GeometricRepresentationContext;
122    use crate::geometry::representation_subcontext::GeometricRepresentationSubContext;
123    use crate::geometry::shape_representation::ShapeRepresentation;
124    use crate::id::IdOr;
125    use crate::objects::application::Application;
126    use crate::objects::change_action::ChangeAction;
127    use crate::objects::organization::Organization;
128    use crate::objects::owner_history::OwnerHistory;
129    use crate::objects::person::Person;
130    use crate::objects::person_and_org::PersonAndOrganization;
131    use crate::objects::shared::{product::ProductBuilder, root::RootBuilder};
132    use crate::objects::wall::Wall;
133    use crate::parser::timestamp::IfcTimestamp;
134    use crate::parser::IFCParse;
135    use crate::IFC;
136
137    #[test]
138    fn wall_round_trip() {
139        let example = "IFCWALL('0DWgwt6o1FOx7466fPk$jl',#2,$,$,$,#33,#25,$,$);";
140
141        let wall: Wall = Wall::parse().parse(example).unwrap();
142        let str_wall = wall.to_string();
143
144        assert_eq!(example, str_wall);
145    }
146
147    pub fn print_wall_hierarchy(ifc: &IFC) {
148        use crate::objects::wall::Wall;
149
150        for (_, wall) in ifc.data.find_all_of_type::<Wall>() {
151            println!("wall: {wall}");
152
153            if let Some(owner_history) = wall
154                .owner_history
155                .custom()
156                .map(|&id| ifc.data.get_untyped(id))
157            {
158                println!("\towner_history: {owner_history}");
159            }
160
161            if let Some(id) = wall.object_placement.custom() {
162                println!("\tpoint3d: {}", ifc.data.get_untyped(*id));
163            }
164
165            if let Some(representation) = wall
166                .representation
167                .custom()
168                .map(|&id| ifc.data.get_untyped(id))
169            {
170                println!("\trepresentation: {representation}");
171
172                for repr in representation
173                    .downcast_ref::<ProductDefinitionShape>()
174                    .unwrap()
175                    .representations
176                    .iter()
177                {
178                    let shape = ifc.data.get::<ShapeRepresentation>(*repr);
179                    println!("\t\tshape_representation: {shape}");
180
181                    let sub_context = ifc
182                        .data
183                        .get::<GeometricRepresentationSubContext>(shape.context_of_items);
184
185                    println!("\t\t\tsub context: {sub_context}");
186
187                    let parent_context = ifc
188                        .data
189                        .get::<GeometricRepresentationContext>(sub_context.parent_context);
190
191                    println!("\t\t\t\tcontext: {parent_context}");
192                    println!(
193                        "\t\t\t\t\tcoord_dims: {}",
194                        parent_context.coord_space_dimension
195                    );
196
197                    let world_coord_system = ifc
198                        .data
199                        .get::<Axis3D>(parent_context.world_coord_system.into());
200
201                    println!("\t\t\t\t\tworld_coord_system: {world_coord_system}");
202                    println!(
203                        "\t\t\t\t\t\tcoord_system_point: {}",
204                        ifc.data.get_untyped(world_coord_system.location)
205                    );
206
207                    for (index, item) in shape.items(ifc).enumerate() {
208                        println!("\t\t\titem {index}: {item}");
209                    }
210                }
211            }
212
213            if let Some(id_or) = wall.predefined_type.custom() {
214                match id_or {
215                    IdOr::Id(id) => println!("\twall_type: {}", ifc.data.get_untyped(*id)),
216                    IdOr::Custom(wall_type) => println!("\twall_type: {}", wall_type),
217                }
218            }
219        }
220    }
221
222    #[test]
223    fn create_wall() {
224        let mut ifc = IFC::default();
225
226        let person_id = ifc.data.insert_new(Person::empty());
227        let application =
228            Application::new(person_id, "0.0.1", "create_wall_test", "IFC4", &mut ifc);
229        let application_id = ifc.data.insert_new(application);
230
231        let person_and_org = PersonAndOrganization::new(
232            person_id,
233            Organization::new(None, "organization_name", None),
234            &mut ifc,
235        );
236
237        let owner_history = OwnerHistory::new(ChangeAction::Added, IfcTimestamp::now())
238            .owning_user(person_and_org, &mut ifc)
239            .owning_application(application_id, &mut ifc);
240
241        let axis = Axis3D::new(Point3D::from(DVec3::new(0.0, 0.0, 0.0)), &mut ifc);
242        let axis_id = ifc.data.insert_new(axis);
243        let local_placement = LocalPlacement::new(axis_id, &mut ifc);
244
245        let representation = new_product_definition_shape(&mut ifc, axis_id.into());
246
247        let wall = Wall::new("global_id_example")
248            .owner_history(owner_history, &mut ifc)
249            .object_placement(local_placement, &mut ifc)
250            .representation(representation, &mut ifc);
251
252        ifc.data.insert_new(wall);
253
254        println!("{}", ifc.data);
255        println!();
256        print_wall_hierarchy(&ifc);
257    }
258}