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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! Hand-maintained schema helpers built on top of the auto-generated
//! `IfcType` enum.
//!
//! These helpers used to live appended to `generated/schema.rs` despite that
//! file's "DO NOT EDIT" header. Moving them here keeps them safe from a
//! re-run of `@ifc-lite/codegen` and lets us derive answers from the EXPRESS
//! inheritance graph instead of maintaining a leaf-level allow-list that has
//! to be amended every time a new IFC4X3 subtype shows up (see PR #585 for
//! `IfcSolarDevice`, which inherits from `IfcEnergyConversionDevice` and was
//! therefore already covered conceptually by the old whitelist's parent
//! entry, but missed in practice because the whitelist was only checked by
//! string match).
//!
//! Co-authored with Geronimo <gerald.stampfel+geronimo@gmail.com> (PR #585).
//!
//! Both helpers are on the hot path during scene construction, where the
//! same ~50–100 distinct type names are queried thousands of times per file.
//! We memoise per-name behind a `RwLock<FxHashMap<String, bool>>`: the first
//! call for a name pays the full `IfcType::from_str` (a ~1300-arm match) +
//! `is_subtype_of` traversal cost; subsequent calls take a read-lock and a
//! single hash lookup.
use ;
use FxHashMap;
use crateIfcType;
use crateget_legacy_entity_info;
/// Normalise to uppercase ASCII without allocating when the input is already
/// uppercase (the common case — STEP type tokens are emitted uppercase).
/// Look up a cached bool, or compute via `f` and insert.
/// Check if a type name (UPPERCASE STEP string) represents an `IfcProduct`
/// subtype that can bear geometry (has `ObjectPlacement` + `Representation`).
///
/// Implementation:
/// 1. Modern names go through `IfcType::from_str` and are accepted iff they
/// inherit from `IfcProduct`, with a small block-list for abstract spatial
/// containers (`IfcBuildingStorey`, `IfcFacility`, `IfcFacilityPart`,
/// `IfcSpatialElement`, `IfcSpatialStructureElement`) that don't carry
/// geometry directly. `IfcSpace`, `IfcSite`, `IfcSpatialZone` and
/// `IfcBuilding` (and any concrete subtype of those) are intentionally
/// kept — they have boundary representations the renderer consumes. See
/// [`is_non_geometric_spatial`] for how that exempt set is maintained.
/// 2. Legacy IFC2x3 / removed-in-IFC4x3 names that aren't in the generated
/// enum (e.g. `IFCSLABELEMENTEDCASE`, `IFCBUILDINGELEMENT`, `IFCPROXY`,
/// `IFCEQUIPMENTELEMENT`, `IFCELECTRICALDISTRIBUTIONPOINT`) resolve through
/// `legacy_entities::get_legacy_entity_info`, which carries a
/// `has_geometry` flag.
/// 3. Reinforcement variants not covered above fall back to a substring
/// match (`REINFORCING…` / `REINFORCED…`).
/// Subtypes of `IfcProduct` that exist solely as spatial containers and
/// aren't rendered directly. `IfcSpace`/`IfcSite`/`IfcSpatialZone`/`IfcBuilding`
/// and their concrete subtypes are deliberately exempt — their boundary
/// representations are consumed by the renderer when present.
///
/// The exempt set grows as exporters are found that attach a body to a
/// container. `IfcSpatialZone` was unblocked for Revit Family geometry authored
/// via Dynamo (issue #1075); `IfcBuilding` for terrain/DGM exports that hang an
/// `IfcShellBasedSurfaceModel` straight off the building (issue #1910). In both
/// cases the class was blocked, so the entity never became a geometry job and
/// the model rendered nothing at all. **The gate only *permits* meshing; a
/// container with no representation still produces nothing**, so exempting a
/// class costs one abandoned job per instance and is the safe direction.
/// `IfcBuildingStorey` and the `IfcFacility`/`IfcFacilityPart` families stay
/// blocked only because no exporter has been observed giving them a body; the
/// same one-line exemption applies if one is.
///
/// We block by inheritance, not by exact match, so IFC4X3 facility
/// subclasses like `IfcBridge`/`IfcRoad`/`IfcRailway`/`IfcMarineFacility`
/// (under `IfcFacility`), their `*Part` variants (under `IfcFacilityPart`),
/// and any future concrete spatial container all collapse to the same answer
/// without the whitelist needing to enumerate them.
/// Check if an IFC entity class is "simple" geometry (processed first for
/// fast first frame). Driven off the EXPRESS inheritance graph rather than
/// a leaf-level blacklist, so new IFC4X3 subtypes (e.g. `IfcSolarDevice`
/// under `IfcEnergyConversionDevice`) are categorised correctly without
/// code changes — see PR #585.
///
/// Returns `true` for "simple" elements (load first), `false` for
/// "secondary/complex" (openings, doors, windows, furniture, MEP/distribution
/// elements, spaces, sites, annotations, virtual/proxy entities).
/// Resolve a STEP keyword to its `IfcType`, **legacy-aware**: a removed/renamed
/// entity (`IFCPROXY`, `IFCSOLIDSTRATUM`, …) maps to its modern base type via the
/// hand-maintained legacy table, exactly as `has_geometry_by_name` does. Any pass
/// that *classifies* or *labels* an entity must use this rather than a bare
/// `IfcType::from_str`; otherwise it disagrees with the geometry pass (which meshes
/// legacy entities), leaving a rendered node with no attribute row — the
/// geometry/attribute product-set divergence (#1496).