1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! Which openings void a host element (`IfcRelVoidsElement`).
//!
//! # Why this is geometry input and not a spatial query
//!
//! `ifc-spatial` indexes the relation for navigation, but only this crate
//! needs it to decide what a product's NET shape is: the Body representation
//! of a wall is the gross wall, and the file never authors the net one. So
//! the relation is read here, as a kernel-free slot read, and `lower` turns it
//! into boolean differences.
//!
//! # The slots are stable
//!
//! `RelatingBuildingElement` is slot 4 and `RelatedOpeningElement` slot 5 in
//! IFC2X3 (under `IfcRelConnects`), IFC4 and IFC4X3 (under
//! `IfcRelDecomposes`): both supertypes contribute exactly the four
//! `IfcRoot` attributes. `tests/context_slots.rs` asserts that against the
//! shipped schemas, following ADR 0008.
use ;
use crateSlots;
/// Absolute slots on `IfcRelVoidsElement`.
/// The type name the relation is stored under. It has no subtypes.
const VOIDS_ELEMENT: &str = "IFCRELVOIDSELEMENT";
/// One voiding: the relation entity and the opening it names.
pub
/// Every voiding of `host`, one per opening, in ascending opening id.
///
/// Ordered by the opening rather than by the relation so the result is a
/// property of the model's content, not of which relation an exporter wrote
/// first. An opening named by two relations is subtracted once: removing the
/// same body twice changes nothing but the cost.
///
/// Scans the relations on each call. That is O(relations), which is a few
/// hundred on a real building; a caller netting every product of a large model
/// pays O(products x relations), still well under the boolean cost.
pub
/// The openings voiding `host`, in ascending id.
///
/// Kernel-free: answering which openings a wall has is a slot read, so this
/// works under `--no-default-features` exactly as with the kernel linked. A
/// relation with a missing or non-reference end is skipped rather than
/// guessed at; it names no opening this function could return.
///
/// ```
/// use ifc_geometry::openings_of;
/// use ifc_model::{EntityId, Model};
///
/// // A model with no relations has no openings anywhere.
/// assert!(openings_of(&Model::new(), EntityId(1)).is_empty());
/// ```