ifcfast 0.1.0a2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ifcfast-0.1.0a2/Cargo.lock +239 -0
- ifcfast-0.1.0a2/Cargo.toml +14 -0
- ifcfast-0.1.0a2/LICENSE +21 -0
- ifcfast-0.1.0a2/PKG-INFO +292 -0
- ifcfast-0.1.0a2/README.md +265 -0
- ifcfast-0.1.0a2/crates/core/Cargo.toml +36 -0
- ifcfast-0.1.0a2/crates/core/src/bin/bench.rs +93 -0
- ifcfast-0.1.0a2/crates/core/src/bin/mesh.rs +141 -0
- ifcfast-0.1.0a2/crates/core/src/entity_table.rs +106 -0
- ifcfast-0.1.0a2/crates/core/src/extractors/classifications.rs +175 -0
- ifcfast-0.1.0a2/crates/core/src/extractors/materials.rs +236 -0
- ifcfast-0.1.0a2/crates/core/src/extractors/mod.rs +20 -0
- ifcfast-0.1.0a2/crates/core/src/extractors/psets.rs +270 -0
- ifcfast-0.1.0a2/crates/core/src/extractors/quantities.rs +188 -0
- ifcfast-0.1.0a2/crates/core/src/indexer.rs +767 -0
- ifcfast-0.1.0a2/crates/core/src/lexer.rs +477 -0
- ifcfast-0.1.0a2/crates/core/src/lib.rs +506 -0
- ifcfast-0.1.0a2/crates/core/src/mesh/brep.rs +224 -0
- ifcfast-0.1.0a2/crates/core/src/mesh/extrusion.rs +222 -0
- ifcfast-0.1.0a2/crates/core/src/mesh/faceset.rs +229 -0
- ifcfast-0.1.0a2/crates/core/src/mesh/gltf.rs +349 -0
- ifcfast-0.1.0a2/crates/core/src/mesh/mapped.rs +208 -0
- ifcfast-0.1.0a2/crates/core/src/mesh/mod.rs +421 -0
- ifcfast-0.1.0a2/crates/core/src/mesh/obj.rs +47 -0
- ifcfast-0.1.0a2/crates/core/src/mesh/placement.rs +200 -0
- ifcfast-0.1.0a2/crates/core/src/mesh/profile.rs +480 -0
- ifcfast-0.1.0a2/crates/core/src/mesh/stats.rs +379 -0
- ifcfast-0.1.0a2/pyproject.toml +50 -0
- ifcfast-0.1.0a2/python/ifcfast/__init__.py +47 -0
- ifcfast-0.1.0a2/python/ifcfast/cache.py +436 -0
- ifcfast-0.1.0a2/python/ifcfast/classify.py +207 -0
- ifcfast-0.1.0a2/python/ifcfast/cli.py +127 -0
- ifcfast-0.1.0a2/python/ifcfast/federated_floors.py +378 -0
- ifcfast-0.1.0a2/python/ifcfast/header.py +207 -0
- ifcfast-0.1.0a2/python/ifcfast/model.py +400 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "autocfg"
|
|
7
|
+
version = "1.5.0"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|
10
|
+
|
|
11
|
+
[[package]]
|
|
12
|
+
name = "cfg-if"
|
|
13
|
+
version = "1.0.4"
|
|
14
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
+
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|
16
|
+
|
|
17
|
+
[[package]]
|
|
18
|
+
name = "earcutr"
|
|
19
|
+
version = "0.4.3"
|
|
20
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
21
|
+
checksum = "79127ed59a85d7687c409e9978547cffb7dc79675355ed22da6b66fd5f6ead01"
|
|
22
|
+
dependencies = [
|
|
23
|
+
"itertools",
|
|
24
|
+
"num-traits",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[[package]]
|
|
28
|
+
name = "either"
|
|
29
|
+
version = "1.15.0"
|
|
30
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
31
|
+
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
|
32
|
+
|
|
33
|
+
[[package]]
|
|
34
|
+
name = "glam"
|
|
35
|
+
version = "0.29.3"
|
|
36
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
37
|
+
checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee"
|
|
38
|
+
|
|
39
|
+
[[package]]
|
|
40
|
+
name = "heck"
|
|
41
|
+
version = "0.5.0"
|
|
42
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
43
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
44
|
+
|
|
45
|
+
[[package]]
|
|
46
|
+
name = "ifcfast-core"
|
|
47
|
+
version = "0.1.0"
|
|
48
|
+
dependencies = [
|
|
49
|
+
"earcutr",
|
|
50
|
+
"glam",
|
|
51
|
+
"memchr",
|
|
52
|
+
"memmap2",
|
|
53
|
+
"pyo3",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[[package]]
|
|
57
|
+
name = "indoc"
|
|
58
|
+
version = "2.0.7"
|
|
59
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
60
|
+
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
|
|
61
|
+
dependencies = [
|
|
62
|
+
"rustversion",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[[package]]
|
|
66
|
+
name = "itertools"
|
|
67
|
+
version = "0.11.0"
|
|
68
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
69
|
+
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
|
70
|
+
dependencies = [
|
|
71
|
+
"either",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[[package]]
|
|
75
|
+
name = "libc"
|
|
76
|
+
version = "0.2.186"
|
|
77
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
78
|
+
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|
79
|
+
|
|
80
|
+
[[package]]
|
|
81
|
+
name = "memchr"
|
|
82
|
+
version = "2.8.0"
|
|
83
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
84
|
+
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
|
85
|
+
|
|
86
|
+
[[package]]
|
|
87
|
+
name = "memmap2"
|
|
88
|
+
version = "0.9.10"
|
|
89
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
90
|
+
checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
|
|
91
|
+
dependencies = [
|
|
92
|
+
"libc",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
[[package]]
|
|
96
|
+
name = "memoffset"
|
|
97
|
+
version = "0.9.1"
|
|
98
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
99
|
+
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
|
100
|
+
dependencies = [
|
|
101
|
+
"autocfg",
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
[[package]]
|
|
105
|
+
name = "num-traits"
|
|
106
|
+
version = "0.2.19"
|
|
107
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
108
|
+
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
|
109
|
+
dependencies = [
|
|
110
|
+
"autocfg",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
[[package]]
|
|
114
|
+
name = "once_cell"
|
|
115
|
+
version = "1.21.4"
|
|
116
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
117
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
118
|
+
|
|
119
|
+
[[package]]
|
|
120
|
+
name = "portable-atomic"
|
|
121
|
+
version = "1.13.1"
|
|
122
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
123
|
+
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
|
124
|
+
|
|
125
|
+
[[package]]
|
|
126
|
+
name = "proc-macro2"
|
|
127
|
+
version = "1.0.106"
|
|
128
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
129
|
+
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
130
|
+
dependencies = [
|
|
131
|
+
"unicode-ident",
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
[[package]]
|
|
135
|
+
name = "pyo3"
|
|
136
|
+
version = "0.22.6"
|
|
137
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
138
|
+
checksum = "f402062616ab18202ae8319da13fa4279883a2b8a9d9f83f20dbade813ce1884"
|
|
139
|
+
dependencies = [
|
|
140
|
+
"cfg-if",
|
|
141
|
+
"indoc",
|
|
142
|
+
"libc",
|
|
143
|
+
"memoffset",
|
|
144
|
+
"once_cell",
|
|
145
|
+
"portable-atomic",
|
|
146
|
+
"pyo3-build-config",
|
|
147
|
+
"pyo3-ffi",
|
|
148
|
+
"pyo3-macros",
|
|
149
|
+
"unindent",
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
[[package]]
|
|
153
|
+
name = "pyo3-build-config"
|
|
154
|
+
version = "0.22.6"
|
|
155
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
156
|
+
checksum = "b14b5775b5ff446dd1056212d778012cbe8a0fbffd368029fd9e25b514479c38"
|
|
157
|
+
dependencies = [
|
|
158
|
+
"once_cell",
|
|
159
|
+
"target-lexicon",
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
[[package]]
|
|
163
|
+
name = "pyo3-ffi"
|
|
164
|
+
version = "0.22.6"
|
|
165
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
166
|
+
checksum = "9ab5bcf04a2cdcbb50c7d6105de943f543f9ed92af55818fd17b660390fc8636"
|
|
167
|
+
dependencies = [
|
|
168
|
+
"libc",
|
|
169
|
+
"pyo3-build-config",
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
[[package]]
|
|
173
|
+
name = "pyo3-macros"
|
|
174
|
+
version = "0.22.6"
|
|
175
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
176
|
+
checksum = "0fd24d897903a9e6d80b968368a34e1525aeb719d568dba8b3d4bfa5dc67d453"
|
|
177
|
+
dependencies = [
|
|
178
|
+
"proc-macro2",
|
|
179
|
+
"pyo3-macros-backend",
|
|
180
|
+
"quote",
|
|
181
|
+
"syn",
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
[[package]]
|
|
185
|
+
name = "pyo3-macros-backend"
|
|
186
|
+
version = "0.22.6"
|
|
187
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
188
|
+
checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe"
|
|
189
|
+
dependencies = [
|
|
190
|
+
"heck",
|
|
191
|
+
"proc-macro2",
|
|
192
|
+
"pyo3-build-config",
|
|
193
|
+
"quote",
|
|
194
|
+
"syn",
|
|
195
|
+
]
|
|
196
|
+
|
|
197
|
+
[[package]]
|
|
198
|
+
name = "quote"
|
|
199
|
+
version = "1.0.45"
|
|
200
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
201
|
+
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
|
202
|
+
dependencies = [
|
|
203
|
+
"proc-macro2",
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
[[package]]
|
|
207
|
+
name = "rustversion"
|
|
208
|
+
version = "1.0.22"
|
|
209
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
210
|
+
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
|
211
|
+
|
|
212
|
+
[[package]]
|
|
213
|
+
name = "syn"
|
|
214
|
+
version = "2.0.117"
|
|
215
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
216
|
+
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
|
217
|
+
dependencies = [
|
|
218
|
+
"proc-macro2",
|
|
219
|
+
"quote",
|
|
220
|
+
"unicode-ident",
|
|
221
|
+
]
|
|
222
|
+
|
|
223
|
+
[[package]]
|
|
224
|
+
name = "target-lexicon"
|
|
225
|
+
version = "0.12.16"
|
|
226
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
227
|
+
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|
228
|
+
|
|
229
|
+
[[package]]
|
|
230
|
+
name = "unicode-ident"
|
|
231
|
+
version = "1.0.24"
|
|
232
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
233
|
+
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
234
|
+
|
|
235
|
+
[[package]]
|
|
236
|
+
name = "unindent"
|
|
237
|
+
version = "0.2.4"
|
|
238
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
239
|
+
checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[workspace]
|
|
2
|
+
members = ["crates/core"]
|
|
3
|
+
resolver = "2"
|
|
4
|
+
|
|
5
|
+
[workspace.package]
|
|
6
|
+
version = "0.1.0"
|
|
7
|
+
edition = "2021"
|
|
8
|
+
license = "MIT"
|
|
9
|
+
repository = "https://github.com/EdvardGK/ifcfast"
|
|
10
|
+
|
|
11
|
+
[profile.release]
|
|
12
|
+
lto = "thin"
|
|
13
|
+
codegen-units = 1
|
|
14
|
+
opt-level = 3
|
ifcfast-0.1.0a2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Edvard Granskogen Kjorstad
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ifcfast-0.1.0a2/PKG-INFO
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ifcfast
|
|
3
|
+
Version: 0.1.0a2
|
|
4
|
+
Classifier: Development Status :: 4 - Beta
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Rust
|
|
9
|
+
Classifier: Topic :: Scientific/Engineering
|
|
10
|
+
Requires-Dist: pandas>=2.0.0
|
|
11
|
+
Requires-Dist: pyarrow>=14.0.0
|
|
12
|
+
Requires-Dist: pyyaml>=6.0.0
|
|
13
|
+
Requires-Dist: pytest>=7.4.0 ; extra == 'dev'
|
|
14
|
+
Requires-Dist: openpyxl>=3.1.0 ; extra == 'dev'
|
|
15
|
+
Requires-Dist: ifcopenshell>=0.8.0 ; extra == 'dev'
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Summary: Fast native IFC parsing, data extraction, and geometric analytics
|
|
19
|
+
Keywords: IFC,BIM,QTO,parser,rust
|
|
20
|
+
Author-email: Edvard Granskogen Kjorstad <ed.subscript@gmail.com>
|
|
21
|
+
License: MIT
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
24
|
+
Project-URL: Homepage, https://github.com/EdvardGK/ifcfast
|
|
25
|
+
Project-URL: Issues, https://github.com/EdvardGK/ifcfast/issues
|
|
26
|
+
|
|
27
|
+
# ifcfast
|
|
28
|
+
|
|
29
|
+
Fast native IFC parsing, data extraction and geometric analytics. Python
|
|
30
|
+
on top, Rust underneath, no `ifcopenshell.open()` on the hot path.
|
|
31
|
+
|
|
32
|
+
Aimed at the "open an IFC, get the data out, run QTO / quality
|
|
33
|
+
queries" workflow. Tier-1 parse is byte-identical to `ifcopenshell` and
|
|
34
|
+
~20-27× faster on production files.
|
|
35
|
+
|
|
36
|
+
> `ifcfast` was extracted on 2026-05-13 from the
|
|
37
|
+
> [`EdvardGK/ifc-workbench`](https://github.com/EdvardGK/ifc-workbench)
|
|
38
|
+
> scratch repo. See [`docs/history/origin.md`](docs/history/origin.md)
|
|
39
|
+
> for the trail back and what was renamed.
|
|
40
|
+
|
|
41
|
+
## What it gives you
|
|
42
|
+
|
|
43
|
+
| layer | format | typical latency on 200 MB IFC |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| Products (GUID, type, name, storey, parent, tag) | dict of parallel lists | tier-1 cold: 0.5–2 s |
|
|
46
|
+
| Property sets | long-format `pandas.DataFrame` | 137 ms |
|
|
47
|
+
| Element quantities | long-format `pandas.DataFrame` | 90 ms |
|
|
48
|
+
| Materials (incl. layer sets) | long-format `pandas.DataFrame` | 27 ms |
|
|
49
|
+
| Classifications | long-format `pandas.DataFrame` | 17 ms |
|
|
50
|
+
| All data layers (shared scan) | bundle | 1.3 s |
|
|
51
|
+
| Triangle meshes (extrusion / mapped / face sets / BREP) | OBJ / glTF / CSV | 2.6 s |
|
|
52
|
+
| Placement-vs-mesh drift report | `pandas.DataFrame` | 322 ms |
|
|
53
|
+
| Parquet cache (all of the above) | parquet | 65 ms hot reload |
|
|
54
|
+
|
|
55
|
+
End-to-end cold parse of a 200 MB IFC: under 5 s. Hot reload from cache:
|
|
56
|
+
under 100 ms. Memory peak: under 1 GB resident (mmap-based).
|
|
57
|
+
|
|
58
|
+
Audited at **234,144 products across 5 authoring tools** (Tekla,
|
|
59
|
+
Archicad, Revit IFC4, Revit IFC2X3, MagiCAD, BSProLib) with byte-level
|
|
60
|
+
parity vs `ifcopenshell`. See
|
|
61
|
+
[`docs/history/audit/`](docs/history/audit/).
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
Needs Rust 1.95+ and Python 3.10+.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install maturin
|
|
69
|
+
maturin develop --release # builds the Rust extension, ~30 s first time
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
For production: `maturin build --release` produces a wheel.
|
|
73
|
+
|
|
74
|
+
## Quick start
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
import ifcfast
|
|
78
|
+
|
|
79
|
+
m = ifcfast.open("model.ifc")
|
|
80
|
+
print(len(m), "products,", len(m.storeys), "storeys")
|
|
81
|
+
print(m.authoring_app, "→", m.schema)
|
|
82
|
+
|
|
83
|
+
walls = list(m.filter(entity="IfcWall"))
|
|
84
|
+
|
|
85
|
+
# Long-format data layers (pandas DataFrames, loaded lazily).
|
|
86
|
+
m.psets # 63k+ rows on a 200 MB Archicad file
|
|
87
|
+
m.quantities # author-supplied Qto_*BaseQuantities
|
|
88
|
+
m.materials # (guid, role, layer, name, thickness, category)
|
|
89
|
+
m.classifications # NS 3451 / Uniformat / OmniClass references
|
|
90
|
+
m.drift # placement-vs-mesh drift report
|
|
91
|
+
|
|
92
|
+
# Standard QTO query — external walls.
|
|
93
|
+
external_walls = m.psets[
|
|
94
|
+
(m.psets.pset_name == "Pset_WallCommon")
|
|
95
|
+
& (m.psets.prop_name == "IsExternal")
|
|
96
|
+
& (m.psets.value == "True")
|
|
97
|
+
].guid.unique()
|
|
98
|
+
|
|
99
|
+
# Quality gate — placement bugs.
|
|
100
|
+
suspect = m.drift[m.drift.drift_severity == "error"]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The same model can be re-opened cheaply — the second `ifcfast.open(...)`
|
|
104
|
+
returns from the parquet cache in tens of milliseconds.
|
|
105
|
+
|
|
106
|
+
## CLI
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
ifcfast index model.ifc # tier-1 parse + counts
|
|
110
|
+
ifcfast extract model.ifc # extract data layers (writes cache)
|
|
111
|
+
ifcfast drift model.ifc --top 20 # placement / mesh drift report
|
|
112
|
+
ifcfast cache model.ifc # inspect cache for a file
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The Rust binary `ifcfast-mesh` writes OBJ / glTF / CSV directly:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
cargo build --release --bin ifcfast-mesh --no-default-features --features mesh
|
|
119
|
+
./target/release/ifcfast-mesh model.ifc model.glb
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Cache
|
|
123
|
+
|
|
124
|
+
Parquet files live under `~/.cache/ifcfast/<cache_key>/`, where
|
|
125
|
+
`cache_key` is `sha256(file_size + first 4 MB + last 4 MB)` truncated.
|
|
126
|
+
Any edit to the IFC invalidates the entry automatically.
|
|
127
|
+
|
|
128
|
+
Override with the `IFCFAST_CACHE` environment variable, e.g.
|
|
129
|
+
`IFCFAST_CACHE=/srv/cache ifcfast extract model.ifc`.
|
|
130
|
+
|
|
131
|
+
Disk footprint on a 200 MB Archicad IFC: **2.4 MB total** zstd-compressed.
|
|
132
|
+
|
|
133
|
+
## Data schemas
|
|
134
|
+
|
|
135
|
+
All extractors return long-format (one row per fact, no nested fields).
|
|
136
|
+
Easy to join, easy to filter, easy to flatten to Excel.
|
|
137
|
+
|
|
138
|
+
**Missing values:** string columns use pandas `StringDtype` with `nan`
|
|
139
|
+
as the NULL sentinel (chosen for memory and pyarrow round-trip).
|
|
140
|
+
Cells corresponding to a STEP `$` field hold `float('nan')`, **not**
|
|
141
|
+
Python `None`. Use `.isna()` to test, not `== None` or `is None`:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
m.classifications[m.classifications.identification.isna()] # correct
|
|
145
|
+
m.classifications[m.classifications.identification == None] # always False
|
|
146
|
+
[r for r in m.classifications.itertuples() if r.identification is None] # always False
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
If you're cross-checking against `ifcopenshell` (which returns `None`),
|
|
150
|
+
normalise NaN→None on the comparison side.
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
### psets
|
|
154
|
+
|
|
155
|
+
| column | type | description |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| `guid` | str | `IfcProduct.GlobalId` |
|
|
158
|
+
| `pset_name` | str | e.g. `Pset_WallCommon` |
|
|
159
|
+
| `prop_name` | str | e.g. `IsExternal` |
|
|
160
|
+
| `value` | str \| None | booleans normalised to `True` / `False` / `UNKNOWN` |
|
|
161
|
+
| `value_type` | str \| None | `IfcBoolean`, `IfcText`, `IfcReal`, … |
|
|
162
|
+
|
|
163
|
+
### quantities
|
|
164
|
+
|
|
165
|
+
| column | type | description |
|
|
166
|
+
|---|---|---|
|
|
167
|
+
| `guid` | str | `IfcProduct.GlobalId` |
|
|
168
|
+
| `qto_name` | str | e.g. `Qto_WallBaseQuantities` |
|
|
169
|
+
| `quantity_name` | str | e.g. `NetVolume`, `GrossArea`, `Length` |
|
|
170
|
+
| `value` | str \| None | numeric value as string |
|
|
171
|
+
| `quantity_type` | str | `Area` / `Length` / `Volume` / `Count` / `Weight` / `Time` |
|
|
172
|
+
| `unit_step_id` | int \| None | usually None (project default applies) |
|
|
173
|
+
|
|
174
|
+
### materials
|
|
175
|
+
|
|
176
|
+
| column | type | description |
|
|
177
|
+
|---|---|---|
|
|
178
|
+
| `guid` | str | `IfcProduct.GlobalId` |
|
|
179
|
+
| `role` | str | `direct` / `list` / `layer` / `unknown` |
|
|
180
|
+
| `layer_index` | int | 0-based for layered materials, `-1` otherwise |
|
|
181
|
+
| `material_name` | str \| None | material label |
|
|
182
|
+
| `layer_thickness_mm` | float \| None | only set for `role="layer"` |
|
|
183
|
+
| `category` | str \| None | IFC4 only |
|
|
184
|
+
|
|
185
|
+
### classifications
|
|
186
|
+
|
|
187
|
+
| column | type | description |
|
|
188
|
+
|---|---|---|
|
|
189
|
+
| `guid` | str | `IfcProduct.GlobalId` |
|
|
190
|
+
| `system_name` | str \| None | `NS 3451`, `Uniformat II`, `OmniClass` |
|
|
191
|
+
| `edition` | str \| None | e.g. `2022` |
|
|
192
|
+
| `identification` | str \| None | the actual code |
|
|
193
|
+
| `name` | str \| None | human label |
|
|
194
|
+
| `location` | str \| None | URI to spec (rarely populated) |
|
|
195
|
+
| `source` | str \| None | publisher |
|
|
196
|
+
|
|
197
|
+
### drift
|
|
198
|
+
|
|
199
|
+
| column | type | description |
|
|
200
|
+
|---|---|---|
|
|
201
|
+
| `guid`, `entity`, `source` | str | identification |
|
|
202
|
+
| `triangle_count`, `surface_area`, `volume_abs` | int / float | geometric stats |
|
|
203
|
+
| `placement_x/y/z` | float | what `IfcLocalPlacement` says |
|
|
204
|
+
| `centroid_x/y/z` | float | where the mesh AABB centre actually is |
|
|
205
|
+
| `drift_distance` | float | Euclidean distance, mm |
|
|
206
|
+
| `max_extent` | float | largest AABB dimension |
|
|
207
|
+
| `drift_ratio` | float | `drift_distance / max_extent` |
|
|
208
|
+
| `drift_severity` | str | `ok` / `warn` / `error` |
|
|
209
|
+
|
|
210
|
+
Severity rule: `ok` when `drift_ratio ≤ 2.0` or `drift_distance < 10
|
|
211
|
+
mm`; `error` when `drift_ratio > 10.0` and `drift_distance > 10 mm`.
|
|
212
|
+
|
|
213
|
+
A 100 m wall placed at one end has ratio 0.5 (legitimate). A 50 mm sensor
|
|
214
|
+
100 m from its placement has ratio 2000 (clear authoring bug).
|
|
215
|
+
|
|
216
|
+
## Federated floor synthesis
|
|
217
|
+
|
|
218
|
+
Multi-discipline projects have the same physical floor named differently
|
|
219
|
+
by ARK / RIB / RIV / RIE authors. `ifcfast.federated_floors` clusters by
|
|
220
|
+
elevation across discipline models and applies a project-supplied YAML
|
|
221
|
+
rule.
|
|
222
|
+
|
|
223
|
+
```yaml
|
|
224
|
+
# examples/projects/lbk-building-c.yaml
|
|
225
|
+
prefix: "C - "
|
|
226
|
+
overrides:
|
|
227
|
+
Plan U1: Hav
|
|
228
|
+
C - U1: Hav
|
|
229
|
+
idempotent_labels: [Hav]
|
|
230
|
+
apply_drop_leading_zero: true
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
The module is project-agnostic — project tables live in user config.
|
|
234
|
+
|
|
235
|
+
## Architecture in two paragraphs
|
|
236
|
+
|
|
237
|
+
The Rust core (`crates/core`) does one byte-level pass over the IFC's
|
|
238
|
+
DATA section using a string-aware STEP tokenizer (memchr-accelerated).
|
|
239
|
+
That pass builds an `EntityTable` — a `step_id → byte_range` map of
|
|
240
|
+
every entity in the file. Each PyO3 entry point (`index_ifc`,
|
|
241
|
+
`extract_psets`, etc.) walks the table once, dispatching on entity type
|
|
242
|
+
and extracting only the fields that layer needs.
|
|
243
|
+
|
|
244
|
+
The Python cache (`ifcfast.cache`) writes each extractor's output as
|
|
245
|
+
zstd-compressed parquet, keyed by `sha256(size + 4 MB head + 4 MB tail)`
|
|
246
|
+
so any IFC edit invalidates automatically. Hot reads are pure
|
|
247
|
+
pandas / pyarrow — no Rust call needed. There is no `ifcopenshell.open()`
|
|
248
|
+
anywhere in the data path; `ifcopenshell` is an *optional* dev dep used
|
|
249
|
+
only for cross-checking parity in tests.
|
|
250
|
+
|
|
251
|
+
## What it doesn't do
|
|
252
|
+
|
|
253
|
+
- Write or modify IFCs. Read-only by construction.
|
|
254
|
+
- Schema validation. Trusts the file's syntax. Use
|
|
255
|
+
[bsi-validator](https://github.com/buildingSMART/IFC) for conformance.
|
|
256
|
+
- Tessellate `IfcBooleanClippingResult` (walls with openings render
|
|
257
|
+
without cutouts — gross volume correct, net volume not).
|
|
258
|
+
- NURBS / advanced BREP geometry. ~0.5% of elements in typical exports.
|
|
259
|
+
- Property variants beyond `IfcPropertySingleValue` —
|
|
260
|
+
`IfcPropertyEnumeratedValue`, `IfcPropertyListValue`,
|
|
261
|
+
`IfcPropertyBoundedValue`, `IfcComplexProperty` are skipped. Covers
|
|
262
|
+
~90% of psets seen on Revit / Archicad / Tekla / MagiCAD exports.
|
|
263
|
+
|
|
264
|
+
## Layout
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
crates/core/ Rust extension (PyO3) — tokenizer, indexer, extractors, mesh
|
|
268
|
+
src/
|
|
269
|
+
lib.rs PyO3 entry points
|
|
270
|
+
lexer.rs STEP tokenizer
|
|
271
|
+
indexer.rs tier-1 product / storey index
|
|
272
|
+
entity_table.rs step_id → byte range lookup
|
|
273
|
+
extractors/ psets, quantities, materials, classifications
|
|
274
|
+
mesh/ extrusion, mapped, face sets, BREP, glTF writer
|
|
275
|
+
bin/ ifcfast-bench, ifcfast-mesh CLIs
|
|
276
|
+
python/ifcfast/ Public Python API
|
|
277
|
+
__init__.py ifcfast.open(), Model, header, classify
|
|
278
|
+
header.py STEP header reader (tier-0)
|
|
279
|
+
model.py Model class + native tier-1 driver
|
|
280
|
+
cache.py parquet cache for index + data layers
|
|
281
|
+
classify.py element-mode policy (count / measure / linear / skip)
|
|
282
|
+
federated_floors.py multi-discipline floor synthesiser
|
|
283
|
+
cli.py ifcfast CLI
|
|
284
|
+
docs/history/ origin doc + audit issues from ifc-workbench
|
|
285
|
+
examples/projects/ project YAMLs for federated_floors
|
|
286
|
+
tests/ pytest suite
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
MIT — see [`LICENSE`](LICENSE).
|
|
292
|
+
|