@ifc-lite/viewer 1.25.2 → 1.27.0

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.
Files changed (116) hide show
  1. package/.turbo/turbo-build.log +40 -30
  2. package/CHANGELOG.md +110 -0
  3. package/dist/assets/{basketViewActivator-CTgyKI3U.js → basketViewActivator-B3CdrLsb.js} +7 -7
  4. package/dist/assets/{bcf-7jQby1qi.js → bcf-QeHK_Aud.js} +5 -5
  5. package/dist/assets/{browser-DXS29_v9.js → browser-BIoDDfBW.js} +1 -1
  6. package/dist/assets/{cesium-BoVuJvTC.js → cesium-CzZn5yVA.js} +319 -319
  7. package/dist/assets/{deflate-Cfp9t1Df.js → deflate-B-d0SYQM.js} +1 -1
  8. package/dist/assets/exceljs.min-DsuzKYnj.js +29 -0
  9. package/dist/assets/{exporters-DfSvJPi4.js → exporters-B4LbZFeT.js} +1434 -1179
  10. package/dist/assets/geometry.worker-BdH-E6NB.js +1 -0
  11. package/dist/assets/{geotiff-xZoE8BkO.js → geotiff-CrVtDRFq.js} +10 -10
  12. package/dist/assets/html2canvas.esm-Ge7aVWlp.js +5 -0
  13. package/dist/assets/{ids-Cu73hD0Y.js → ids-DjsGFN10.js} +21 -21
  14. package/dist/assets/ifc-lite_bg-DsYUIHm3.wasm +0 -0
  15. package/dist/assets/{index-WSbA5iy6.js → index-COYokSKc.js} +44122 -38782
  16. package/dist/assets/index-ajK6D32J.css +1 -0
  17. package/dist/assets/index.es-CY202jA3.js +6866 -0
  18. package/dist/assets/{jpeg-DhwFEbqb.js → jpeg-D4wOkf5h.js} +1 -1
  19. package/dist/assets/jspdf.es.min-DIGb9BHN.js +19571 -0
  20. package/dist/assets/jspdf.plugin.autotable-BBLUVd7n.js +2 -0
  21. package/dist/assets/{lerc-Dz6BXOVb.js → lerc-DmW0_tgf.js} +1 -1
  22. package/dist/assets/{lzw-C9z0fG2o.js → lzw-oWetY-d6.js} +1 -1
  23. package/dist/assets/{maplibre-gl-Do6O5tDc.js → maplibre-gl-BF3Z0idw.js} +1 -1
  24. package/dist/assets/{native-bridge-RvDmzO-2.js → native-bridge-BX8_tHXE.js} +1 -1
  25. package/dist/assets/{packbits-jfwifz7C.js → packbits-F8Nkp4NY.js} +1 -1
  26. package/dist/assets/{pako.esm-Cram60i4.js → pako.esm-n3Pgozwg.js} +1 -1
  27. package/dist/assets/{parser.worker-C594dWxH.js → parser.worker-D591Zu_-.js} +3 -3
  28. package/dist/assets/pdf-Dsh3HPZB.js +135 -0
  29. package/dist/assets/raw-D9iw0tmc.js +1 -0
  30. package/dist/assets/{sandbox-DDSZ7rek.js → sandbox-BAC3a-eN.js} +4235 -2716
  31. package/dist/assets/server-client-Cjwnm7il.js +706 -0
  32. package/dist/assets/{webimage-XFHVyVtC.js → webimage-BLV1dgmd.js} +1 -1
  33. package/dist/assets/xlsx-Bc2HTrjC.js +142 -0
  34. package/dist/assets/{zip-BJqVbRkU.js → zip-DFgP-l20.js} +1 -1
  35. package/dist/assets/{zstd-3q5qcl5V.js → zstd-C_1HxVrA.js} +1 -1
  36. package/dist/index.html +8 -8
  37. package/package.json +13 -9
  38. package/src/components/extensions/FlavorDialog.tsx +18 -2
  39. package/src/components/extensions/FlavorListView.tsx +12 -3
  40. package/src/components/mcp/PlaygroundChat.tsx +1 -0
  41. package/src/components/mcp/data.ts +6 -0
  42. package/src/components/mcp/playground-dispatcher.ts +277 -0
  43. package/src/components/mcp/types.ts +2 -1
  44. package/src/components/ui/combo-input.tsx +163 -0
  45. package/src/components/ui/tabs.tsx +1 -1
  46. package/src/components/viewer/ClashBcfExportDialog.tsx +271 -0
  47. package/src/components/viewer/ClashPanel.tsx +370 -0
  48. package/src/components/viewer/ClashSettingsDialog.tsx +407 -0
  49. package/src/components/viewer/CommandPalette.tsx +14 -15
  50. package/src/components/viewer/MainToolbar.tsx +155 -175
  51. package/src/components/viewer/PropertiesPanel.tsx +13 -6
  52. package/src/components/viewer/SearchInline.tsx +62 -2
  53. package/src/components/viewer/SearchModal.filter.builder.tsx +24 -393
  54. package/src/components/viewer/SearchModal.filter.editors.tsx +503 -0
  55. package/src/components/viewer/SearchModal.filter.tsx +64 -1
  56. package/src/components/viewer/SearchModal.tsx +19 -6
  57. package/src/components/viewer/ViewerLayout.tsx +5 -0
  58. package/src/components/viewer/Viewport.tsx +64 -9
  59. package/src/components/viewer/ViewportContainer.tsx +45 -3
  60. package/src/components/viewer/bcf/BCFOverlay.tsx +5 -4
  61. package/src/components/viewer/lists/ColumnHeaderMenu.tsx +84 -0
  62. package/src/components/viewer/lists/ListBuilder.tsx +789 -280
  63. package/src/components/viewer/lists/ListGroupingBar.tsx +72 -0
  64. package/src/components/viewer/lists/ListPanel.tsx +49 -5
  65. package/src/components/viewer/lists/ListResultsTable.tsx +270 -176
  66. package/src/components/viewer/lists/list-table-utils.ts +123 -0
  67. package/src/components/viewer/useGeometryStreaming.ts +21 -1
  68. package/src/generated/mcp-catalog.json +4 -0
  69. package/src/hooks/ingest/streamCleanup.test.ts +41 -0
  70. package/src/hooks/ingest/streamCleanup.ts +45 -0
  71. package/src/hooks/ingest/viewerModelIngest.ts +64 -42
  72. package/src/hooks/ingest/watchedGeometryStream.test.ts +78 -0
  73. package/src/hooks/ingest/watchedGeometryStream.ts +76 -0
  74. package/src/hooks/source-key.ts +35 -0
  75. package/src/hooks/useAlignmentLines3D.ts +139 -0
  76. package/src/hooks/useClash.ts +420 -0
  77. package/src/hooks/useGridLines3D.ts +140 -0
  78. package/src/hooks/useIfcFederation.ts +16 -2
  79. package/src/hooks/useIfcLoader.ts +5 -7
  80. package/src/lib/clash/persistence.ts +308 -0
  81. package/src/lib/geo/effective-georef.test.ts +66 -0
  82. package/src/lib/length-unit-scale.ts +41 -0
  83. package/src/lib/lists/adapter.ts +136 -11
  84. package/src/lib/lists/export/csv.ts +47 -0
  85. package/src/lib/lists/export/index.ts +49 -0
  86. package/src/lib/lists/export/model.ts +111 -0
  87. package/src/lib/lists/export/pdf.ts +67 -0
  88. package/src/lib/lists/export/xlsx.ts +83 -0
  89. package/src/lib/lists/index.ts +2 -0
  90. package/src/lib/search/filter-evaluate.test.ts +81 -0
  91. package/src/lib/search/filter-evaluate.ts +59 -87
  92. package/src/lib/search/filter-match.ts +167 -0
  93. package/src/lib/search/filter-rules.test.ts +25 -0
  94. package/src/lib/search/filter-rules.ts +75 -2
  95. package/src/lib/search/filter-schema.ts +0 -0
  96. package/src/lib/slab-edit.test.ts +72 -0
  97. package/src/lib/slab-edit.ts +159 -19
  98. package/src/sdk/adapters/export-adapter.ts +3 -3
  99. package/src/sdk/adapters/query-adapter.ts +3 -3
  100. package/src/services/extensions/host.ts +13 -0
  101. package/src/store/constants.ts +33 -25
  102. package/src/store/index.ts +29 -8
  103. package/src/store/slices/clashSlice.ts +251 -0
  104. package/src/store/slices/listSlice.ts +6 -0
  105. package/src/store/slices/mutationSlice.ts +14 -6
  106. package/src/store/slices/searchSlice.ts +29 -3
  107. package/src/store/slices/visibilitySlice.test.ts +23 -5
  108. package/src/store/slices/visibilitySlice.ts +18 -8
  109. package/src/utils/nativeSpatialDataStore.ts +6 -0
  110. package/src/utils/serverDataModel.test.ts +6 -0
  111. package/src/utils/serverDataModel.ts +7 -0
  112. package/dist/assets/geometry.worker-Cyn5BybV.js +0 -1
  113. package/dist/assets/ifc-lite_bg-ksLBP5cA.wasm +0 -0
  114. package/dist/assets/index-Bws3UAkj.css +0 -1
  115. package/dist/assets/raw-R2QfzPAR.js +0 -1
  116. package/dist/assets/server-client-Ctk8_Bof.js +0 -626
@@ -0,0 +1,251 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+
5
+ /**
6
+ * Clash detection panel state (Phase 1). Detection itself lives in
7
+ * `@ifc-lite/clash`; this slice holds the panel's UI state, the last result,
8
+ * and the user's persisted detection settings + rule presets (see
9
+ * `lib/clash/persistence.ts`, modeled on the lens slice). Orchestration
10
+ * (gathering elements, running the engine, applying colors / selection /
11
+ * camera, BCF export) lives in the `useClash` hook.
12
+ */
13
+
14
+ import type { StateCreator } from 'zustand';
15
+ import type { ClashResult, ClashGroup, ClashMode, ClashProgress } from '@ifc-lite/clash';
16
+ import {
17
+ buildInitialPresets,
18
+ defaultPresets,
19
+ loadSettings,
20
+ savePresets,
21
+ saveSettings,
22
+ validatePresetName,
23
+ validateSelector,
24
+ CLASH_BOUNDS,
25
+ clampToBounds,
26
+ DEFAULT_CLASH_SETTINGS,
27
+ type ClashPreset,
28
+ type ClashGlobalSettings,
29
+ type ClashSettingsGroupBy,
30
+ type SaveResult,
31
+ } from '@/lib/clash/persistence';
32
+
33
+ export type ClashGroupBy = ClashSettingsGroupBy;
34
+ export type { ClashPreset, ClashGlobalSettings, SaveResult };
35
+
36
+ /** Fields a user supplies when adding a custom rule (id/flags filled in here). */
37
+ export type NewClashPreset = {
38
+ name: string;
39
+ description?: string;
40
+ severity: ClashPreset['severity'];
41
+ selectorA: string;
42
+ selectorB: string;
43
+ };
44
+
45
+ export interface ClashSlice {
46
+ clashPanelVisible: boolean;
47
+ clashResult: ClashResult | null;
48
+ clashGroups: ClashGroup[] | null;
49
+ clashRunning: boolean;
50
+ clashError: string | null;
51
+ /** Live detection progress for the running rule (null when idle). */
52
+ clashProgress: ClashProgress | null;
53
+ /** Detection settings (persisted). */
54
+ clashMode: ClashMode;
55
+ clashTolerance: number;
56
+ clashClearance: number;
57
+ clashClusterEpsilon: number;
58
+ clashReportTouch: boolean;
59
+ /** How the result list is organized (persisted). */
60
+ clashGroupBy: ClashGroupBy;
61
+ /** Built-in + custom rule presets (persisted). */
62
+ clashPresets: ClashPreset[];
63
+ /** Currently focused clash id (for highlight in the list). */
64
+ clashSelectedId: string | null;
65
+
66
+ setClashPanelVisible: (visible: boolean) => void;
67
+ toggleClashPanel: () => void;
68
+ setClashResult: (result: ClashResult | null) => void;
69
+ setClashGroups: (groups: ClashGroup[] | null) => void;
70
+ setClashRunning: (running: boolean) => void;
71
+ setClashError: (error: string | null) => void;
72
+ setClashProgress: (progress: ClashProgress | null) => void;
73
+ setClashMode: (mode: ClashMode) => void;
74
+ setClashTolerance: (tolerance: number) => void;
75
+ setClashClearance: (clearance: number) => void;
76
+ setClashClusterEpsilon: (epsilon: number) => void;
77
+ setClashReportTouch: (reportTouch: boolean) => void;
78
+ setClashGroupBy: (groupBy: ClashGroupBy) => void;
79
+ resetClashSettings: () => void;
80
+ setClashSelectedId: (id: string | null) => void;
81
+ // Preset CRUD (persisted). create/update/import return a SaveResult so the UI
82
+ // can surface quota / cap failures; the rest are best-effort.
83
+ createClashPreset: (input: NewClashPreset) => SaveResult;
84
+ updateClashPreset: (id: string, patch: Partial<Omit<ClashPreset, 'id' | 'builtin'>>) => SaveResult;
85
+ deleteClashPreset: (id: string) => void;
86
+ setClashPresetEnabled: (id: string, enabled: boolean) => void;
87
+ resetClashPresets: () => void;
88
+ importClashPresets: (presets: ClashPreset[]) => SaveResult;
89
+ /**
90
+ * Replace the entire clash config (presets + detection settings) and persist.
91
+ * Used when activating a flavor/profile so each one carries its own rule-set.
92
+ */
93
+ applyClashFlavorConfig: (config: { presets: ClashPreset[]; settings: ClashGlobalSettings }) => void;
94
+ clearClash: () => void;
95
+ }
96
+
97
+ /** Build the persisted settings blob from current slice state. */
98
+ function snapshotSettings(s: ClashSlice): ClashGlobalSettings {
99
+ return {
100
+ mode: s.clashMode,
101
+ tolerance: s.clashTolerance,
102
+ clearance: s.clashClearance,
103
+ clusterEpsilon: s.clashClusterEpsilon,
104
+ reportTouch: s.clashReportTouch,
105
+ groupBy: s.clashGroupBy,
106
+ };
107
+ }
108
+
109
+ export const createClashSlice: StateCreator<ClashSlice, [], [], ClashSlice> = (set, get) => {
110
+ const initial = loadSettings();
111
+ // Persist the current settings snapshot after a state change.
112
+ const persistSettings = () => saveSettings(snapshotSettings(get()));
113
+
114
+ return {
115
+ clashPanelVisible: false,
116
+ clashResult: null,
117
+ clashGroups: null,
118
+ clashRunning: false,
119
+ clashError: null,
120
+ clashProgress: null,
121
+ clashMode: initial.mode,
122
+ clashTolerance: initial.tolerance,
123
+ clashClearance: initial.clearance,
124
+ clashClusterEpsilon: initial.clusterEpsilon,
125
+ clashReportTouch: initial.reportTouch,
126
+ clashGroupBy: initial.groupBy,
127
+ clashPresets: buildInitialPresets(),
128
+ clashSelectedId: null,
129
+
130
+ setClashPanelVisible: (clashPanelVisible) => set({ clashPanelVisible }),
131
+ toggleClashPanel: () => set((s) => ({ clashPanelVisible: !s.clashPanelVisible })),
132
+ setClashResult: (clashResult) => set({ clashResult }),
133
+ setClashGroups: (clashGroups) => set({ clashGroups }),
134
+ setClashRunning: (clashRunning) => set({ clashRunning }),
135
+ setClashError: (clashError) => set({ clashError }),
136
+ setClashProgress: (clashProgress) => set({ clashProgress }),
137
+
138
+ setClashMode: (clashMode) => { set({ clashMode }); persistSettings(); },
139
+ setClashTolerance: (clashTolerance) => {
140
+ set({ clashTolerance: clampToBounds(clashTolerance, CLASH_BOUNDS.tolerance, DEFAULT_CLASH_SETTINGS.tolerance) });
141
+ persistSettings();
142
+ },
143
+ setClashClearance: (clashClearance) => {
144
+ set({ clashClearance: clampToBounds(clashClearance, CLASH_BOUNDS.clearance, DEFAULT_CLASH_SETTINGS.clearance) });
145
+ persistSettings();
146
+ },
147
+ setClashClusterEpsilon: (clashClusterEpsilon) => {
148
+ set({ clashClusterEpsilon: clampToBounds(clashClusterEpsilon, CLASH_BOUNDS.clusterEpsilon, DEFAULT_CLASH_SETTINGS.clusterEpsilon) });
149
+ persistSettings();
150
+ },
151
+ setClashReportTouch: (clashReportTouch) => { set({ clashReportTouch }); persistSettings(); },
152
+ setClashGroupBy: (clashGroupBy) => { set({ clashGroupBy }); persistSettings(); },
153
+ resetClashSettings: () => {
154
+ set({
155
+ clashMode: DEFAULT_CLASH_SETTINGS.mode,
156
+ clashTolerance: DEFAULT_CLASH_SETTINGS.tolerance,
157
+ clashClearance: DEFAULT_CLASH_SETTINGS.clearance,
158
+ clashClusterEpsilon: DEFAULT_CLASH_SETTINGS.clusterEpsilon,
159
+ clashReportTouch: DEFAULT_CLASH_SETTINGS.reportTouch,
160
+ clashGroupBy: DEFAULT_CLASH_SETTINGS.groupBy,
161
+ });
162
+ persistSettings();
163
+ },
164
+
165
+ setClashSelectedId: (clashSelectedId) => set({ clashSelectedId }),
166
+
167
+ createClashPreset: (input) => {
168
+ const name = validatePresetName(input.name);
169
+ const selectorA = validateSelector(input.selectorA);
170
+ const selectorB = validateSelector(input.selectorB);
171
+ if (!name || !selectorA || !selectorB) {
172
+ return { ok: false, reason: 'serialize', message: 'Name and both selectors are required.' };
173
+ }
174
+ const preset: ClashPreset = {
175
+ id: `custom-${crypto.randomUUID()}`,
176
+ name,
177
+ description: input.description?.trim() ?? '',
178
+ severity: input.severity,
179
+ selectorA,
180
+ selectorB,
181
+ enabled: true,
182
+ builtin: false,
183
+ };
184
+ const next = [...get().clashPresets, preset];
185
+ const result = savePresets(next);
186
+ if (result.ok) set({ clashPresets: next });
187
+ return result;
188
+ },
189
+
190
+ updateClashPreset: (id, patch) => {
191
+ const next = get().clashPresets.map((p) => (p.id === id ? { ...p, ...patch } : p));
192
+ const result = savePresets(next);
193
+ if (result.ok) set({ clashPresets: next });
194
+ return result;
195
+ },
196
+
197
+ deleteClashPreset: (id) => {
198
+ const target = get().clashPresets.find((p) => p.id === id);
199
+ if (!target || target.builtin) return; // built-ins are reset, never deleted
200
+ const next = get().clashPresets.filter((p) => p.id !== id);
201
+ savePresets(next);
202
+ set({ clashPresets: next });
203
+ },
204
+
205
+ setClashPresetEnabled: (id, enabled) => {
206
+ const next = get().clashPresets.map((p) => (p.id === id ? { ...p, enabled } : p));
207
+ savePresets(next);
208
+ set({ clashPresets: next });
209
+ },
210
+
211
+ resetClashPresets: () => {
212
+ const next = defaultPresets(); // drops all overrides + customs
213
+ savePresets(next);
214
+ set({ clashPresets: next });
215
+ },
216
+
217
+ importClashPresets: (presets) => {
218
+ const next = [...get().clashPresets, ...presets.filter((p) => !p.builtin)];
219
+ const result = savePresets(next);
220
+ if (result.ok) set({ clashPresets: next });
221
+ return result;
222
+ },
223
+
224
+ applyClashFlavorConfig: ({ presets, settings }) => {
225
+ set({
226
+ clashPresets: presets,
227
+ clashMode: settings.mode,
228
+ clashTolerance: settings.tolerance,
229
+ clashClearance: settings.clearance,
230
+ clashClusterEpsilon: settings.clusterEpsilon,
231
+ clashReportTouch: settings.reportTouch,
232
+ clashGroupBy: settings.groupBy,
233
+ });
234
+ // Persist so the activated flavor's config becomes the working set on reload.
235
+ savePresets(presets);
236
+ saveSettings(settings);
237
+ },
238
+
239
+ clearClash: () =>
240
+ // Keep presets + settings (workspace prefs, like saved lenses): only the
241
+ // run result/panel state is cleared.
242
+ set({
243
+ clashResult: null,
244
+ clashGroups: null,
245
+ clashRunning: false,
246
+ clashError: null,
247
+ clashProgress: null,
248
+ clashSelectedId: null,
249
+ }),
250
+ };
251
+ };
@@ -17,6 +17,9 @@ export interface ListSlice {
17
17
  listResult: ListResult | null;
18
18
  listPanelVisible: boolean;
19
19
  listExecuting: boolean;
20
+ /** A list definition handed off from elsewhere (e.g. "Create list" in the
21
+ * search filter) for the ListPanel to open straight into the builder. */
22
+ pendingListDraft: ListDefinition | null;
20
23
 
21
24
  // Actions
22
25
  setListDefinitions: (definitions: ListDefinition[]) => void;
@@ -28,6 +31,7 @@ export interface ListSlice {
28
31
  setListPanelVisible: (visible: boolean) => void;
29
32
  toggleListPanel: () => void;
30
33
  setListExecuting: (executing: boolean) => void;
34
+ setPendingListDraft: (definition: ListDefinition | null) => void;
31
35
  }
32
36
 
33
37
  export const createListSlice: StateCreator<ListSlice, [], [], ListSlice> = (set, get) => ({
@@ -37,6 +41,7 @@ export const createListSlice: StateCreator<ListSlice, [], [], ListSlice> = (set,
37
41
  listResult: null,
38
42
  listPanelVisible: false,
39
43
  listExecuting: false,
44
+ pendingListDraft: null,
40
45
 
41
46
  // Actions
42
47
  setListDefinitions: (listDefinitions) => {
@@ -71,4 +76,5 @@ export const createListSlice: StateCreator<ListSlice, [], [], ListSlice> = (set,
71
76
  setListPanelVisible: (listPanelVisible) => set({ listPanelVisible }),
72
77
  toggleListPanel: () => set((state) => ({ listPanelVisible: !state.listPanelVisible })),
73
78
  setListExecuting: (listExecuting) => set({ listExecuting }),
79
+ setPendingListDraft: (pendingListDraft) => set({ pendingListDraft }),
74
80
  });
@@ -69,6 +69,7 @@ import {
69
69
  computeSlabSplitGeometry,
70
70
  type SlabLikeType,
71
71
  } from '@/lib/slab-edit.js';
72
+ import { getModelLengthUnitScale } from '@/lib/length-unit-scale.js';
72
73
  import type { Point2D } from '@/lib/polygon-clip.js';
73
74
 
74
75
  /**
@@ -676,7 +677,9 @@ function generateChangeSetId(): string {
676
677
  */
677
678
  function getOrCreateStoreEditor(
678
679
  get: () => ViewerState,
679
- set: (partial: Partial<ViewerState>) => void,
680
+ // Editors are cached in-place on the (non-reactive) `storeEditors`
681
+ // Map below, so the Zustand setter is intentionally unused here.
682
+ _set: (partial: Partial<ViewerState>) => void,
680
683
  modelId: string,
681
684
  ): StoreEditor | null {
682
685
  const state = get();
@@ -691,9 +694,14 @@ function getOrCreateStoreEditor(
691
694
  if (!dataStore) return null;
692
695
 
693
696
  const editor = new StoreEditor(dataStore, view);
694
- const next = new Map(state.storeEditors);
695
- next.set(modelId, editor);
696
- set({ storeEditors: next });
697
+ // `storeEditors` is an internal, non-reactive cache (no component
698
+ // subscribes to it). Mutate the existing Map in place rather than
699
+ // `set({...})` the read functions (readSlabFootprint, etc.) call
700
+ // this during render via GeometryEditCard's `splittable` memo, and a
701
+ // reactive `set()` there triggers React's "cannot update a component
702
+ // while rendering a different component" warning. In-place caching
703
+ // keeps the editor memoised without scheduling a render-phase update.
704
+ state.storeEditors.set(modelId, editor);
697
705
  return editor;
698
706
  }
699
707
 
@@ -1862,7 +1870,7 @@ export const createMutationSlice: StateCreator<
1862
1870
  if (!editor) return null;
1863
1871
  const dataStore = get().models.get(modelId)?.ifcDataStore;
1864
1872
  if (!dataStore) return null;
1865
- const chain = resolveSlabEditChain(dataStore, view, editor, expressId);
1873
+ const chain = resolveSlabEditChain(dataStore, view, editor, expressId, getModelLengthUnitScale(dataStore));
1866
1874
  if (!chain) return null;
1867
1875
  const storeyId = dataStore.spatialHierarchy?.elementToStorey.get(expressId);
1868
1876
  const storeyElevation =
@@ -1883,7 +1891,7 @@ export const createMutationSlice: StateCreator<
1883
1891
  const { view, editor, dataStore, storeyExpressId } = ctx;
1884
1892
  const state = get();
1885
1893
 
1886
- const chain = resolveSlabEditChain(dataStore, view, editor, expressId);
1894
+ const chain = resolveSlabEditChain(dataStore, view, editor, expressId, getModelLengthUnitScale(dataStore));
1887
1895
  if (!chain) {
1888
1896
  return {
1889
1897
  ok: false,
@@ -24,7 +24,7 @@ import type { StateCreator } from 'zustand';
24
24
  import type { Tier1Index } from '@/lib/search/tier1-index';
25
25
  import type { SearchResult, MatchField } from '@/lib/search/tier0-scan';
26
26
  import type { FilterRule, Combinator } from '@/lib/search/filter-rules';
27
- import type { FilterSchema, PsetQtoSchema } from '@/lib/search/filter-schema';
27
+ import type { FilterSchema, PsetQtoSchema, FilterValueSchema } from '@/lib/search/filter-schema';
28
28
 
29
29
  /** Index lifecycle state for a single model. */
30
30
  export type Tier1IndexStatus = 'pending' | 'building' | 'ready' | 'error';
@@ -60,6 +60,10 @@ export interface SearchVimCycleState {
60
60
  */
61
61
  export type SearchFieldFilter = MatchField | 'all';
62
62
 
63
+ /** Which tab the advanced modal renders. Lets callers (e.g. the inline
64
+ * filter button) open straight to the Filter builder. */
65
+ export type SearchModalTab = 'search' | 'filter';
66
+
63
67
  /**
64
68
  * Tabular result from a Filter run. Flat snapshot so the modal can
65
69
  * re-render rows without holding live evaluator state.
@@ -94,6 +98,9 @@ export interface FilterSchemaCacheEntry {
94
98
  basic: FilterSchema;
95
99
  /** Expensive pass — pset / qto names. Lazy; null until first request. */
96
100
  psetQto: PsetQtoSchema | null;
101
+ /** Expensive pass — distinct material / classification / property values
102
+ * for chip value suggestions. Lazy; null until first request. */
103
+ values: FilterValueSchema | null;
97
104
  }
98
105
 
99
106
  export interface SearchSlice {
@@ -109,6 +116,8 @@ export interface SearchSlice {
109
116
  searchVimCycle: SearchVimCycleState | null;
110
117
  /** Advanced search modal (⌘⇧F) is open. */
111
118
  searchModalOpen: boolean;
119
+ /** Which tab the advanced modal shows. Remembered across opens. */
120
+ searchModalTab: SearchModalTab;
112
121
  /** Field chip filter active inside the modal. Defaults to 'all'. */
113
122
  searchFieldFilter: SearchFieldFilter;
114
123
  /** Per-modelId include filter inside the modal. `null` means all models included. */
@@ -147,6 +156,7 @@ export interface SearchSlice {
147
156
 
148
157
  setSearchModalOpen: (open: boolean) => void;
149
158
  toggleSearchModal: () => void;
159
+ setSearchModalTab: (tab: SearchModalTab) => void;
150
160
  setSearchFieldFilter: (filter: SearchFieldFilter) => void;
151
161
  /** Toggle a model in/out of the include filter. If the filter is null,
152
162
  * the first toggle materialises it as "all models except this one". */
@@ -177,6 +187,7 @@ export interface SearchSlice {
177
187
  // ── Schema cache actions ──────────────────────────────────────────
178
188
  setFilterSchema: (modelId: string, basic: FilterSchema) => void;
179
189
  setFilterPsetQtoSchema: (modelId: string, psetQto: PsetQtoSchema) => void;
190
+ setFilterValueSchema: (modelId: string, values: FilterValueSchema) => void;
180
191
  removeFilterSchema: (modelId: string) => void;
181
192
  }
182
193
 
@@ -187,6 +198,7 @@ export const createSearchSlice: StateCreator<SearchSlice, [], [], SearchSlice> =
187
198
  searchIndexes: new Map(),
188
199
  searchVimCycle: null,
189
200
  searchModalOpen: false,
201
+ searchModalTab: 'search',
190
202
  searchFieldFilter: 'all',
191
203
  searchModelFilter: null,
192
204
  searchFilterResult: null,
@@ -239,6 +251,7 @@ export const createSearchSlice: StateCreator<SearchSlice, [], [], SearchSlice> =
239
251
 
240
252
  setSearchModalOpen: (searchModalOpen) => set({ searchModalOpen }),
241
253
  toggleSearchModal: () => set((state) => ({ searchModalOpen: !state.searchModalOpen })),
254
+ setSearchModalTab: (searchModalTab) => set({ searchModalTab }),
242
255
  setSearchFieldFilter: (searchFieldFilter) => set({ searchFieldFilter }),
243
256
 
244
257
  toggleSearchModelFilter: (modelId, availableModelIds) =>
@@ -316,7 +329,11 @@ export const createSearchSlice: StateCreator<SearchSlice, [], [], SearchSlice> =
316
329
  set((state) => {
317
330
  const next = new Map(state.searchFilterSchema);
318
331
  const existing = next.get(modelId);
319
- next.set(modelId, { basic, psetQto: existing?.psetQto ?? null });
332
+ next.set(modelId, {
333
+ basic,
334
+ psetQto: existing?.psetQto ?? null,
335
+ values: existing?.values ?? null,
336
+ });
320
337
  return { searchFilterSchema: next };
321
338
  }),
322
339
 
@@ -327,7 +344,16 @@ export const createSearchSlice: StateCreator<SearchSlice, [], [], SearchSlice> =
327
344
  // Only meaningful once a basic schema has been set — the modal
328
345
  // calls discoverFilterSchema first then queues the heavy pass.
329
346
  if (!existing) return {};
330
- next.set(modelId, { basic: existing.basic, psetQto });
347
+ next.set(modelId, { ...existing, psetQto });
348
+ return { searchFilterSchema: next };
349
+ }),
350
+
351
+ setFilterValueSchema: (modelId, values) =>
352
+ set((state) => {
353
+ const next = new Map(state.searchFilterSchema);
354
+ const existing = next.get(modelId);
355
+ if (!existing) return {};
356
+ next.set(modelId, { ...existing, values });
331
357
  return { searchFilterSchema: next };
332
358
  }),
333
359
 
@@ -5,7 +5,7 @@
5
5
  import { describe, it, beforeEach } from 'node:test';
6
6
  import assert from 'node:assert';
7
7
  import { createVisibilitySlice, type VisibilitySlice } from './visibilitySlice.js';
8
- import { TYPE_VISIBILITY_DEFAULTS } from '../constants.js';
8
+ import { getPersistedTypeVisibility } from '../constants.js';
9
9
 
10
10
  describe('VisibilitySlice', () => {
11
11
  let state: VisibilitySlice;
@@ -33,10 +33,13 @@ describe('VisibilitySlice', () => {
33
33
  assert.strictEqual(state.isolatedEntitiesByModel.size, 0);
34
34
  });
35
35
 
36
- it('should have default type visibility', () => {
37
- assert.strictEqual(state.typeVisibility.spaces, TYPE_VISIBILITY_DEFAULTS.SPACES);
38
- assert.strictEqual(state.typeVisibility.openings, TYPE_VISIBILITY_DEFAULTS.OPENINGS);
39
- assert.strictEqual(state.typeVisibility.site, TYPE_VISIBILITY_DEFAULTS.SITE);
36
+ it('should initialise type visibility from persisted preferences', () => {
37
+ const persisted = getPersistedTypeVisibility();
38
+ assert.strictEqual(state.typeVisibility.spaces, persisted.spaces);
39
+ assert.strictEqual(state.typeVisibility.openings, persisted.openings);
40
+ assert.strictEqual(state.typeVisibility.site, persisted.site);
41
+ assert.strictEqual(state.typeVisibility.ifcAnnotations, persisted.ifcAnnotations);
42
+ assert.strictEqual(state.typeVisibility.ifcGrid, persisted.ifcGrid);
40
43
  });
41
44
  });
42
45
 
@@ -306,5 +309,20 @@ describe('VisibilitySlice', () => {
306
309
  state.toggleTypeVisibility('ifcAnnotations');
307
310
  assert.strictEqual(state.typeVisibility.ifcAnnotations, !initial);
308
311
  });
312
+
313
+ it('resetTypeVisibility restores semantic defaults', () => {
314
+ // Flip everything away from defaults first.
315
+ state.toggleTypeVisibility('spaces'); // false -> true
316
+ state.toggleTypeVisibility('site'); // true -> false
317
+ state.toggleTypeVisibility('ifcGrid'); // true -> false
318
+ state.resetTypeVisibility();
319
+ assert.deepStrictEqual(state.typeVisibility, {
320
+ spaces: false,
321
+ openings: false,
322
+ site: true,
323
+ ifcAnnotations: true,
324
+ ifcGrid: true,
325
+ });
326
+ });
309
327
  });
310
328
  });
@@ -11,7 +11,7 @@
11
11
 
12
12
  import type { StateCreator } from 'zustand';
13
13
  import type { TypeVisibility, EntityRef } from '../types.js';
14
- import { TYPE_VISIBILITY_DEFAULTS, TYPE_VISIBILITY_STORAGE_KEYS } from '../constants.js';
14
+ import { getPersistedTypeVisibility, TYPE_VISIBILITY_STORAGE_KEYS, TYPE_VISIBILITY_SEMANTIC_DEFAULTS } from '../constants.js';
15
15
 
16
16
  export interface VisibilitySlice {
17
17
  // State (legacy - single model)
@@ -44,6 +44,8 @@ export interface VisibilitySlice {
44
44
  showAll: () => void;
45
45
  isEntityVisible: (id: number) => boolean;
46
46
  toggleTypeVisibility: (type: 'spaces' | 'openings' | 'site' | 'ifcAnnotations' | 'ifcGrid') => void;
47
+ /** Restore every type-visibility toggle to its semantic default (and persist). */
48
+ resetTypeVisibility: () => void;
47
49
  /** Set all hidden entities at once (for BCF viewpoint application) */
48
50
  setHiddenEntities: (ids: Set<number>) => void;
49
51
  /** Set all isolated entities at once (for BCF viewpoint with defaultVisibility=false) */
@@ -75,13 +77,8 @@ export const createVisibilitySlice: StateCreator<VisibilitySlice, [], [], Visibi
75
77
  hiddenEntities: new Set(),
76
78
  isolatedEntities: null,
77
79
  classFilter: null,
78
- typeVisibility: {
79
- spaces: TYPE_VISIBILITY_DEFAULTS.SPACES,
80
- openings: TYPE_VISIBILITY_DEFAULTS.OPENINGS,
81
- site: TYPE_VISIBILITY_DEFAULTS.SITE,
82
- ifcAnnotations: TYPE_VISIBILITY_DEFAULTS.IFC_ANNOTATIONS,
83
- ifcGrid: TYPE_VISIBILITY_DEFAULTS.IFC_GRID,
84
- },
80
+ // Read persisted toggles fresh so the user's choices survive reloads.
81
+ typeVisibility: getPersistedTypeVisibility(),
85
82
 
86
83
  // Initial state (multi-model)
87
84
  hiddenEntitiesByModel: new Map(),
@@ -211,6 +208,19 @@ export const createVisibilitySlice: StateCreator<VisibilitySlice, [], [], Visibi
211
208
  };
212
209
  }),
213
210
 
211
+ resetTypeVisibility: () => set(() => {
212
+ // Restore semantic defaults and persist them per-key (same storage
213
+ // pattern as toggleTypeVisibility) so the reset survives reloads.
214
+ if (typeof window !== 'undefined') {
215
+ (Object.keys(TYPE_VISIBILITY_STORAGE_KEYS) as (keyof typeof TYPE_VISIBILITY_STORAGE_KEYS)[])
216
+ .forEach((key) => {
217
+ try { localStorage.setItem(TYPE_VISIBILITY_STORAGE_KEYS[key], String(TYPE_VISIBILITY_SEMANTIC_DEFAULTS[key])); }
218
+ catch { /* private-mode storage rejection — non-fatal */ }
219
+ });
220
+ }
221
+ return { typeVisibility: { ...TYPE_VISIBILITY_SEMANTIC_DEFAULTS } };
222
+ }),
223
+
214
224
  // Actions (multi-model)
215
225
  hideEntityInModel: (modelId, expressId) => set((state) => {
216
226
  const newMap = new Map(state.hiddenEntitiesByModel);
@@ -267,5 +267,11 @@ export function buildIfcDataStoreFromNativeMetadata(snapshot: NativeMetadataSnap
267
267
  quantities: undefined as unknown as IfcDataStore['quantities'],
268
268
  relationships: undefined as unknown as IfcDataStore['relationships'],
269
269
  spatialHierarchy: hierarchy,
270
+ // Native spatial snapshots are metadata-only (no source buffer / property
271
+ // or quantity tables), so the IfcStoreBase accessors return empties.
272
+ getEntity: () => null,
273
+ getEntitiesByType: () => [],
274
+ getProperties: () => [],
275
+ getQuantities: () => [],
270
276
  } as IfcDataStore;
271
277
  }
@@ -38,6 +38,9 @@ describe('convertServerDataModel', () => {
38
38
  { rel_type: 'IFCRELAGGREGATES', relating_id: 2, related_id: 3 },
39
39
  { rel_type: 'IFCRELCONTAINEDINSPATIALSTRUCTURE', relating_id: 3, related_id: 4 },
40
40
  ],
41
+ classifications: [],
42
+ materials: [],
43
+ documents: [],
41
44
  spatialHierarchy: {
42
45
  nodes: [
43
46
  {
@@ -101,6 +104,9 @@ describe('convertServerDataModel', () => {
101
104
  { rel_type: 'IFCRELNESTS', relating_id: 1, related_id: 2 },
102
105
  { rel_type: 'IFCRELASSOCIATESDOCUMENT', relating_id: 3, related_id: 2 },
103
106
  ],
107
+ classifications: [],
108
+ materials: [],
109
+ documents: [],
104
110
  spatialHierarchy: {
105
111
  nodes: [
106
112
  {
@@ -711,5 +711,12 @@ export function convertServerDataModel(
711
711
  relationships,
712
712
  spatialHierarchy,
713
713
  spatialIndex,
714
+ // IfcStoreBase accessors: server-parsed models carry pre-built property/
715
+ // quantity tables but no source buffer, so entity extraction is unavailable
716
+ // (the `entities` table remains the primary path for basic attributes).
717
+ getEntity: () => null,
718
+ getEntitiesByType: () => [],
719
+ getProperties: (expressId: number) => properties.getForEntity(expressId),
720
+ getQuantities: (expressId: number) => quantities.getForEntity(expressId),
714
721
  };
715
722
  }
@@ -1 +0,0 @@
1
- let n;function l(e){P===w.length&&w.push(w.length+1);const t=P;return P=w[t],w[t]=e,t}function Yt(e){if(X==1)throw new Error("out of js stack");return w[--X]=e,X}const nt=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>e.dtor(e.a,e.b));function Dt(e){e<132||(w[e]=P,P=e)}function Q(e,t){return e=e>>>0,Xt().subarray(e/4,e/4+t)}function Vt(e,t){return e=e>>>0,Gt().subarray(e/8,e/8+t)}function ht(e,t){return e=e>>>0,mt().subarray(e/4,e/4+t)}let v=null;function o(){return(v===null||v.buffer.detached===!0||v.buffer.detached===void 0&&v.buffer!==n.memory.buffer)&&(v=new DataView(n.memory.buffer)),v}let F=null;function Xt(){return(F===null||F.byteLength===0)&&(F=new Float32Array(n.memory.buffer)),F}let k=null;function Gt(){return(k===null||k.byteLength===0)&&(k=new Float64Array(n.memory.buffer)),k}function b(e,t){return e=e>>>0,$t(e,t)}let M=null;function mt(){return(M===null||M.byteLength===0)&&(M=new Uint32Array(n.memory.buffer)),M}let C=null;function j(){return(C===null||C.byteLength===0)&&(C=new Uint8Array(n.memory.buffer)),C}function g(e){return w[e]}function N(e,t){try{return e.apply(this,t)}catch(r){n.__wbindgen_export(l(r))}}let w=new Array(128).fill(void 0);w.push(void 0,null,!0,!1);let P=w.length;function V(e){return e==null}function Zt(e,t,r,_){const i={a:e,b:t,cnt:1,dtor:r},s=(...c)=>{i.cnt++;const a=i.a;i.a=0;try{return _(a,i.b,...c)}finally{i.a=a,s._wbg_cb_unref()}};return s._wbg_cb_unref=()=>{--i.cnt===0&&(i.dtor(i.a,i.b),i.a=0,nt.unregister(i))},nt.register(s,i,i),s}function h(e,t){const r=t(e.length*4,4)>>>0;return mt().set(e,r/4),d=e.length,r}function x(e,t){const r=t(e.length*1,1)>>>0;return j().set(e,r/1),d=e.length,r}function I(e,t,r){if(r===void 0){const a=E.encode(e),p=t(a.length,1)>>>0;return j().subarray(p,p+a.length).set(a),d=a.length,p}let _=e.length,i=t(_,1)>>>0;const s=j();let c=0;for(;c<_;c++){const a=e.charCodeAt(c);if(a>127)break;s[i+c]=a}if(c!==_){c!==0&&(e=e.slice(c)),i=r(i,_,_=c+e.length*3,1)>>>0;const a=j().subarray(i+c,i+_),p=E.encodeInto(e,a);c+=p.written,i=r(i,_,c,1)>>>0}return d=c,i}let X=128;function f(e){const t=g(e);return Dt(e),t}let G=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});G.decode();const Kt=2146435072;let J=0;function $t(e,t){return J+=t,J>=Kt&&(G=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0}),G.decode(),J=t),G.decode(j().subarray(e,e+t))}const E=new TextEncoder;"encodeInto"in E||(E.encodeInto=function(e,t){const r=E.encode(e);return t.set(r),{read:e.length,written:r.length}});let d=0;function qt(e,t,r){n.__wasm_bindgen_func_elem_1685(e,t,l(r))}function Ht(e,t,r,_){n.__wasm_bindgen_func_elem_1832(e,t,l(r),l(_))}const _t=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>n.__wbg_ifcapi_free(e>>>0,1)),it=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>n.__wbg_meshcollection_free(e>>>0,1)),st=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>n.__wbg_meshdatajs_free(e>>>0,1)),ot=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>n.__wbg_profilecollection_free(e>>>0,1)),at=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>n.__wbg_profileentryjs_free(e>>>0,1)),ct=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>n.__wbg_symboliccircle_free(e>>>0,1)),lt=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>n.__wbg_symbolicfillarea_free(e>>>0,1)),gt=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>n.__wbg_symbolicpolyline_free(e>>>0,1)),dt=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>n.__wbg_symbolicrepresentationcollection_free(e>>>0,1)),ft=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>n.__wbg_symbolictext_free(e>>>0,1));class K{__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,_t.unregister(this),t}free(){const t=this.__destroy_into_raw();n.__wbg_ifcapi_free(t,0)}buildPrePassFast(t){const r=x(t,n.__wbindgen_export3),_=d,i=n.ifcapi_buildPrePassFast(this.__wbg_ptr,r,_);return f(i)}buildPrePassOnce(t){const r=x(t,n.__wbindgen_export3),_=d,i=n.ifcapi_buildPrePassOnce(this.__wbg_ptr,r,_);return f(i)}processGeometryBatch(t,r,_,i,s,c,a,p,m,$,q,H){const A=x(t,n.__wbindgen_export3),kt=d,Mt=h(r,n.__wbindgen_export3),Ct=d,jt=h(p,n.__wbindgen_export3),Pt=d,Et=h(m,n.__wbindgen_export3),Rt=d,Bt=h($,n.__wbindgen_export3),Tt=d,Ot=h(q,n.__wbindgen_export3),zt=d,Wt=x(H,n.__wbindgen_export3),Lt=d,Ut=n.ifcapi_processGeometryBatch(this.__wbg_ptr,A,kt,Mt,Ct,_,i,s,c,a,jt,Pt,Et,Rt,Bt,Tt,Ot,zt,Wt,Lt);return R.__wrap(Ut)}buildPrePassStreaming(t,r,_){try{const a=n.__wbindgen_add_to_stack_pointer(-16),p=x(t,n.__wbindgen_export3),m=d;n.ifcapi_buildPrePassStreaming(a,this.__wbg_ptr,p,m,Yt(r),_);var i=o().getInt32(a+0,!0),s=o().getInt32(a+4,!0),c=o().getInt32(a+8,!0);if(c)throw f(s);return f(i)}finally{n.__wbindgen_add_to_stack_pointer(16),w[X++]=void 0}}extractProfiles(t,r){const _=I(t,n.__wbindgen_export3,n.__wbindgen_export4),i=d,s=n.ifcapi_extractProfiles(this.__wbg_ptr,_,i,r);return T.__wrap(s)}getMemory(){const t=n.ifcapi_getMemory(this.__wbg_ptr);return f(t)}setEntityIndex(t,r,_){const i=h(t,n.__wbindgen_export3),s=d,c=h(r,n.__wbindgen_export3),a=d,p=h(_,n.__wbindgen_export3),m=d;n.ifcapi_setEntityIndex(this.__wbg_ptr,i,s,c,a,p,m)}setMergeLayers(t){n.ifcapi_setMergeLayers(this.__wbg_ptr,t)}clearPrePassCache(){n.ifcapi_clearPrePassCache(this.__wbg_ptr)}constructor(){const t=n.ifcapi_new();return this.__wbg_ptr=t>>>0,_t.register(this,this.__wbg_ptr,this),this}get version(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.ifcapi_version(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get is_ready(){return n.ifcapi_is_ready(this.__wbg_ptr)!==0}parseStreaming(t,r){const _=I(t,n.__wbindgen_export3,n.__wbindgen_export4),i=d,s=n.ifcapi_parseStreaming(this.__wbg_ptr,_,i,l(r));return f(s)}scanEntitiesFast(t){const r=I(t,n.__wbindgen_export3,n.__wbindgen_export4),_=d,i=n.ifcapi_scanEntitiesFast(this.__wbg_ptr,r,_);return f(i)}scanEntitiesFastBytes(t){const r=x(t,n.__wbindgen_export3),_=d,i=n.ifcapi_scanEntitiesFastBytes(this.__wbg_ptr,r,_);return f(i)}scanGeometryEntitiesFast(t){const r=I(t,n.__wbindgen_export3,n.__wbindgen_export4),_=d,i=n.ifcapi_scanGeometryEntitiesFast(this.__wbg_ptr,r,_);return f(i)}scanRelevantEntitiesFastBytes(t){const r=x(t,n.__wbindgen_export3),_=d,i=n.ifcapi_scanRelevantEntitiesFastBytes(this.__wbg_ptr,r,_);return f(i)}parse(t){const r=I(t,n.__wbindgen_export3,n.__wbindgen_export4),_=d,i=n.ifcapi_parse(this.__wbg_ptr,r,_);return f(i)}parseSymbolicRepresentations(t){const r=I(t,n.__wbindgen_export3,n.__wbindgen_export4),_=d,i=n.ifcapi_parseSymbolicRepresentations(this.__wbg_ptr,r,_);return U.__wrap(i)}}Symbol.dispose&&(K.prototype[Symbol.dispose]=K.prototype.free);class R{static __wrap(t){t=t>>>0;const r=Object.create(R.prototype);return r.__wbg_ptr=t,it.register(r,r.__wbg_ptr,r),r}__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,it.unregister(this),t}free(){const t=this.__destroy_into_raw();n.__wbg_meshcollection_free(t,0)}get rtcOffsetX(){return n.meshcollection_rtcOffsetX(this.__wbg_ptr)}get rtcOffsetY(){return n.meshcollection_rtcOffsetY(this.__wbg_ptr)}get rtcOffsetZ(){return n.meshcollection_rtcOffsetZ(this.__wbg_ptr)}hasRtcOffset(){return n.meshcollection_hasRtcOffset(this.__wbg_ptr)!==0}localToWorld(t,r,_){try{const a=n.__wbindgen_add_to_stack_pointer(-16);n.meshcollection_localToWorld(a,this.__wbg_ptr,t,r,_);var i=o().getInt32(a+0,!0),s=o().getInt32(a+4,!0),c=Vt(i,s).slice();return n.__wbindgen_export2(i,s*8,8),c}finally{n.__wbindgen_add_to_stack_pointer(16)}}get totalVertices(){return n.meshcollection_totalVertices(this.__wbg_ptr)>>>0}get totalTriangles(){return n.meshcollection_totalTriangles(this.__wbg_ptr)>>>0}get buildingRotation(){try{const _=n.__wbindgen_add_to_stack_pointer(-16);n.meshcollection_buildingRotation(_,this.__wbg_ptr);var t=o().getInt32(_+0,!0),r=o().getFloat64(_+8,!0);return t===0?void 0:r}finally{n.__wbindgen_add_to_stack_pointer(16)}}get(t){const r=n.meshcollection_get(this.__wbg_ptr,t);return r===0?void 0:B.__wrap(r)}get length(){return n.meshcollection_length(this.__wbg_ptr)>>>0}}Symbol.dispose&&(R.prototype[Symbol.dispose]=R.prototype.free);class B{static __wrap(t){t=t>>>0;const r=Object.create(B.prototype);return r.__wbg_ptr=t,st.register(r,r.__wbg_ptr,r),r}__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,st.unregister(this),t}free(){const t=this.__destroy_into_raw();n.__wbg_meshdatajs_free(t,0)}get expressId(){return n.meshdatajs_expressId(this.__wbg_ptr)>>>0}get vertexCount(){return n.meshdatajs_vertexCount(this.__wbg_ptr)>>>0}get shadingColor(){try{const _=n.__wbindgen_add_to_stack_pointer(-16);n.meshdatajs_shadingColor(_,this.__wbg_ptr);var t=o().getInt32(_+0,!0),r=o().getInt32(_+4,!0);let i;return t!==0&&(i=Q(t,r).slice(),n.__wbindgen_export2(t,r*4,4)),i}finally{n.__wbindgen_add_to_stack_pointer(16)}}get triangleCount(){return n.meshdatajs_triangleCount(this.__wbg_ptr)>>>0}get color(){try{const i=n.__wbindgen_add_to_stack_pointer(-16);n.meshdatajs_color(i,this.__wbg_ptr);var t=o().getInt32(i+0,!0),r=o().getInt32(i+4,!0),_=Q(t,r).slice();return n.__wbindgen_export2(t,r*4,4),_}finally{n.__wbindgen_add_to_stack_pointer(16)}}get indices(){const t=n.meshdatajs_indices(this.__wbg_ptr);return f(t)}get normals(){const t=n.meshdatajs_normals(this.__wbg_ptr);return f(t)}get ifcType(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.meshdatajs_ifcType(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get positions(){const t=n.meshdatajs_positions(this.__wbg_ptr);return f(t)}}Symbol.dispose&&(B.prototype[Symbol.dispose]=B.prototype.free);class T{static __wrap(t){t=t>>>0;const r=Object.create(T.prototype);return r.__wbg_ptr=t,ot.register(r,r.__wbg_ptr,r),r}__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,ot.unregister(this),t}free(){const t=this.__destroy_into_raw();n.__wbg_profilecollection_free(t,0)}get(t){const r=n.profilecollection_get(this.__wbg_ptr,t);return r===0?void 0:O.__wrap(r)}get length(){return n.profilecollection_length(this.__wbg_ptr)>>>0}}Symbol.dispose&&(T.prototype[Symbol.dispose]=T.prototype.free);class O{static __wrap(t){t=t>>>0;const r=Object.create(O.prototype);return r.__wbg_ptr=t,at.register(r,r.__wbg_ptr,r),r}__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,at.unregister(this),t}free(){const t=this.__destroy_into_raw();n.__wbg_profileentryjs_free(t,0)}get expressId(){return n.profileentryjs_expressId(this.__wbg_ptr)>>>0}get holeCounts(){const t=n.profileentryjs_holeCounts(this.__wbg_ptr);return f(t)}get holePoints(){const t=n.profileentryjs_holePoints(this.__wbg_ptr);return f(t)}get modelIndex(){return n.profileentryjs_modelIndex(this.__wbg_ptr)>>>0}get outerPoints(){const t=n.profileentryjs_outerPoints(this.__wbg_ptr);return f(t)}get extrusionDir(){const t=n.profileentryjs_extrusionDir(this.__wbg_ptr);return f(t)}get extrusionDepth(){return n.profileentryjs_extrusionDepth(this.__wbg_ptr)}get ifcType(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.profileentryjs_ifcType(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get transform(){const t=n.profileentryjs_transform(this.__wbg_ptr);return f(t)}}Symbol.dispose&&(O.prototype[Symbol.dispose]=O.prototype.free);class z{static __wrap(t){t=t>>>0;const r=Object.create(z.prototype);return r.__wbg_ptr=t,ct.register(r,r.__wbg_ptr,r),r}__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,ct.unregister(this),t}free(){const t=this.__destroy_into_raw();n.__wbg_symboliccircle_free(t,0)}get expressId(){return n.symboliccircle_expressId(this.__wbg_ptr)>>>0}get startAngle(){return n.symboliccircle_startAngle(this.__wbg_ptr)}get isFullCircle(){return n.symboliccircle_isFullCircle(this.__wbg_ptr)!==0}get repIdentifier(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.symboliccircle_repIdentifier(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get radius(){return n.symboliccircle_radius(this.__wbg_ptr)}get worldY(){return n.symboliccircle_worldY(this.__wbg_ptr)}get centerX(){return n.symboliccircle_centerX(this.__wbg_ptr)}get centerY(){return n.symboliccircle_centerY(this.__wbg_ptr)}get ifcType(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.symboliccircle_ifcType(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get endAngle(){return n.symboliccircle_endAngle(this.__wbg_ptr)}}Symbol.dispose&&(z.prototype[Symbol.dispose]=z.prototype.free);class W{static __wrap(t){t=t>>>0;const r=Object.create(W.prototype);return r.__wbg_ptr=t,lt.register(r,r.__wbg_ptr,r),r}__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,lt.unregister(this),t}free(){const t=this.__destroy_into_raw();n.__wbg_symbolicfillarea_free(t,0)}get expressId(){return n.profileentryjs_expressId(this.__wbg_ptr)>>>0}get holeCount(){return n.symbolicfillarea_holeCount(this.__wbg_ptr)>>>0}get hatchAngle(){return n.symbolicfillarea_hatchAngle(this.__wbg_ptr)}get pointCount(){return n.symbolicfillarea_pointCount(this.__wbg_ptr)>>>0}get hasHatching(){return n.symbolicfillarea_hasHatching(this.__wbg_ptr)!==0}get hatchSpacing(){return n.symbolicfillarea_hatchSpacing(this.__wbg_ptr)}get holesOffsets(){const t=n.symbolicfillarea_holesOffsets(this.__wbg_ptr);return f(t)}get repIdentifier(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.symbolicfillarea_repIdentifier(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get hatchLineWidth(){return n.symbolicfillarea_hatchLineWidth(this.__wbg_ptr)}get hatchAngleSecondary(){return n.symbolicfillarea_hatchAngleSecondary(this.__wbg_ptr)}get fillA(){return n.symbolicfillarea_fillA(this.__wbg_ptr)}get fillB(){return n.symbolicfillarea_fillB(this.__wbg_ptr)}get fillG(){return n.symbolicfillarea_fillG(this.__wbg_ptr)}get fillR(){return n.symbolicfillarea_fillR(this.__wbg_ptr)}get points(){const t=n.symbolicfillarea_points(this.__wbg_ptr);return f(t)}get worldY(){return n.symbolicfillarea_worldY(this.__wbg_ptr)}get ifcType(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.symbolicfillarea_ifcType(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}}Symbol.dispose&&(W.prototype[Symbol.dispose]=W.prototype.free);class L{static __wrap(t){t=t>>>0;const r=Object.create(L.prototype);return r.__wbg_ptr=t,gt.register(r,r.__wbg_ptr,r),r}__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,gt.unregister(this),t}free(){const t=this.__destroy_into_raw();n.__wbg_symbolicpolyline_free(t,0)}get expressId(){return n.symbolicpolyline_expressId(this.__wbg_ptr)>>>0}get pointCount(){return n.symbolicfillarea_pointCount(this.__wbg_ptr)>>>0}get repIdentifier(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.symbolicpolyline_repIdentifier(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get points(){const t=n.symbolicpolyline_points(this.__wbg_ptr);return f(t)}get worldY(){return n.symboliccircle_worldY(this.__wbg_ptr)}get ifcType(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.symbolicpolyline_ifcType(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get isClosed(){return n.symbolicpolyline_isClosed(this.__wbg_ptr)!==0}}Symbol.dispose&&(L.prototype[Symbol.dispose]=L.prototype.free);class U{static __wrap(t){t=t>>>0;const r=Object.create(U.prototype);return r.__wbg_ptr=t,dt.register(r,r.__wbg_ptr,r),r}__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,dt.unregister(this),t}free(){const t=this.__destroy_into_raw();n.__wbg_symbolicrepresentationcollection_free(t,0)}get fillCount(){return n.symbolicrepresentationcollection_fillCount(this.__wbg_ptr)>>>0}getCircle(t){const r=n.symbolicrepresentationcollection_getCircle(this.__wbg_ptr,t);return r===0?void 0:z.__wrap(r)}get textCount(){return n.symbolicrepresentationcollection_textCount(this.__wbg_ptr)>>>0}get totalCount(){return n.symbolicrepresentationcollection_totalCount(this.__wbg_ptr)>>>0}get circleCount(){return n.symbolicrepresentationcollection_circleCount(this.__wbg_ptr)>>>0}getPolyline(t){const r=n.symbolicrepresentationcollection_getPolyline(this.__wbg_ptr,t);return r===0?void 0:L.__wrap(r)}get polylineCount(){return n.symbolicrepresentationcollection_polylineCount(this.__wbg_ptr)>>>0}getExpressIds(){try{const i=n.__wbindgen_add_to_stack_pointer(-16);n.symbolicrepresentationcollection_getExpressIds(i,this.__wbg_ptr);var t=o().getInt32(i+0,!0),r=o().getInt32(i+4,!0),_=ht(t,r).slice();return n.__wbindgen_export2(t,r*4,4),_}finally{n.__wbindgen_add_to_stack_pointer(16)}}getFill(t){const r=n.symbolicrepresentationcollection_getFill(this.__wbg_ptr,t);return r===0?void 0:W.__wrap(r)}getText(t){const r=n.symbolicrepresentationcollection_getText(this.__wbg_ptr,t);return r===0?void 0:Y.__wrap(r)}get isEmpty(){return n.symbolicrepresentationcollection_isEmpty(this.__wbg_ptr)!==0}}Symbol.dispose&&(U.prototype[Symbol.dispose]=U.prototype.free);class Y{static __wrap(t){t=t>>>0;const r=Object.create(Y.prototype);return r.__wbg_ptr=t,ft.register(r,r.__wbg_ptr,r),r}__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,ft.unregister(this),t}free(){const t=this.__destroy_into_raw();n.__wbg_symbolictext_free(t,0)}get expressId(){return n.profileentryjs_expressId(this.__wbg_ptr)>>>0}get repIdentifier(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.symbolictext_repIdentifier(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get x(){return n.symbolicfillarea_fillR(this.__wbg_ptr)}get y(){return n.symbolicfillarea_fillG(this.__wbg_ptr)}get dirX(){return n.symbolicfillarea_fillB(this.__wbg_ptr)}get dirY(){return n.symbolicfillarea_fillA(this.__wbg_ptr)}get height(){return n.symbolicfillarea_hatchSpacing(this.__wbg_ptr)}get colorA(){return n.symbolictext_colorA(this.__wbg_ptr)}get colorB(){return n.symbolicfillarea_worldY(this.__wbg_ptr)}get colorG(){return n.symbolicfillarea_hatchLineWidth(this.__wbg_ptr)}get colorR(){return n.symbolicfillarea_hatchAngleSecondary(this.__wbg_ptr)}get content(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.symbolictext_content(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get worldY(){return n.symbolicfillarea_hatchAngle(this.__wbg_ptr)}get ifcType(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.symbolictext_ifcType(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get alignment(){let t,r;try{const s=n.__wbindgen_add_to_stack_pointer(-16);n.symbolictext_alignment(s,this.__wbg_ptr);var _=o().getInt32(s+0,!0),i=o().getInt32(s+4,!0);return t=_,r=i,b(_,i)}finally{n.__wbindgen_add_to_stack_pointer(16),n.__wbindgen_export2(t,r,1)}}get targetPx(){return n.symbolictext_targetPx(this.__wbg_ptr)}}Symbol.dispose&&(Y.prototype[Symbol.dispose]=Y.prototype.free);const Nt=new Set(["basic","cors","default"]);async function Jt(e,t){if(typeof Response=="function"&&e instanceof Response){if(typeof WebAssembly.instantiateStreaming=="function")try{return await WebAssembly.instantiateStreaming(e,t)}catch(_){if(e.ok&&Nt.has(e.type)&&e.headers.get("Content-Type")!=="application/wasm")console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",_);else throw _}const r=await e.arrayBuffer();return await WebAssembly.instantiate(r,t)}else{const r=await WebAssembly.instantiate(e,t);return r instanceof WebAssembly.Instance?{instance:r,module:e}:r}}function xt(){const e={};return e.wbg={},e.wbg.__wbg_Error_52673b7de5a0ca89=function(t,r){const _=Error(b(t,r));return l(_)},e.wbg.__wbg___wbindgen_is_function_8d400b8b1af978cd=function(t){return typeof g(t)=="function"},e.wbg.__wbg___wbindgen_is_undefined_f6b95eab589e0269=function(t){return g(t)===void 0},e.wbg.__wbg___wbindgen_memory_a342e963fbcabd68=function(){const t=n.memory;return l(t)},e.wbg.__wbg___wbindgen_throw_dd24417ed36fc46e=function(t,r){throw new Error(b(t,r))},e.wbg.__wbg__wbg_cb_unref_87dfb5aaa0cbcea7=function(t){g(t)._wbg_cb_unref()},e.wbg.__wbg_call_3020136f7a2d6e44=function(){return N(function(t,r,_){const i=g(t).call(g(r),g(_));return l(i)},arguments)},e.wbg.__wbg_call_abb4ff46ce38be40=function(){return N(function(t,r){const _=g(t).call(g(r));return l(_)},arguments)},e.wbg.__wbg_error_7534b8e9a36f1ab4=function(t,r){let _,i;try{_=t,i=r,console.error(b(t,r))}finally{n.__wbindgen_export2(_,i,1)}},e.wbg.__wbg_info_ce6bcc489c22f6f0=function(t){console.info(g(t))},e.wbg.__wbg_new_1ba21ce319a06297=function(){const t=new Object;return l(t)},e.wbg.__wbg_new_25f239778d6112b9=function(){const t=new Array;return l(t)},e.wbg.__wbg_new_8a6f238a6ece86ea=function(){const t=new Error;return l(t)},e.wbg.__wbg_new_ff12d2b041fb48f1=function(t,r){try{var _={a:t,b:r},i=(c,a)=>{const p=_.a;_.a=0;try{return Ht(p,_.b,c,a)}finally{_.a=p}};const s=new Promise(i);return l(s)}finally{_.a=_.b=0}},e.wbg.__wbg_new_from_slice_41e2764a343e3cb1=function(t,r){const _=new Float32Array(Q(t,r));return l(_)},e.wbg.__wbg_new_from_slice_db0691b69e9d3891=function(t,r){const _=new Uint32Array(ht(t,r));return l(_)},e.wbg.__wbg_new_no_args_cb138f77cf6151ee=function(t,r){const _=new Function(b(t,r));return l(_)},e.wbg.__wbg_new_with_length_202b3db94ba5fc86=function(t){const r=new Uint32Array(t>>>0);return l(r)},e.wbg.__wbg_new_with_length_806b9e5b8290af7c=function(t){const r=new Float64Array(t>>>0);return l(r)},e.wbg.__wbg_new_with_length_aa5eaf41d35235e5=function(t){const r=new Uint8Array(t>>>0);return l(r)},e.wbg.__wbg_queueMicrotask_9b549dfce8865860=function(t){const r=g(t).queueMicrotask;return l(r)},e.wbg.__wbg_queueMicrotask_fca69f5bfad613a5=function(t){queueMicrotask(g(t))},e.wbg.__wbg_resolve_fd5bfbaa4ce36e1e=function(t){const r=Promise.resolve(g(t));return l(r)},e.wbg.__wbg_set_3f1d0b984ed272ed=function(t,r,_){g(t)[f(r)]=f(_)},e.wbg.__wbg_set_781438a03c0c3c81=function(){return N(function(t,r,_){return Reflect.set(g(t),g(r),g(_))},arguments)},e.wbg.__wbg_set_7df433eea03a5c14=function(t,r,_){g(t)[r>>>0]=f(_)},e.wbg.__wbg_set_index_021489b2916af13e=function(t,r,_){g(t)[r>>>0]=_},e.wbg.__wbg_set_index_04c4b93e64d08a52=function(t,r,_){g(t)[r>>>0]=_},e.wbg.__wbg_set_index_42abe35f117e614e=function(t,r,_){g(t)[r>>>0]=_>>>0},e.wbg.__wbg_stack_0ed75d68575b0f3c=function(t,r){const _=g(r).stack,i=I(_,n.__wbindgen_export3,n.__wbindgen_export4),s=d;o().setInt32(t+4,s,!0),o().setInt32(t+0,i,!0)},e.wbg.__wbg_static_accessor_GLOBAL_769e6b65d6557335=function(){const t=typeof global>"u"?null:global;return V(t)?0:l(t)},e.wbg.__wbg_static_accessor_GLOBAL_THIS_60cf02db4de8e1c1=function(){const t=typeof globalThis>"u"?null:globalThis;return V(t)?0:l(t)},e.wbg.__wbg_static_accessor_SELF_08f5a74c69739274=function(){const t=typeof self>"u"?null:self;return V(t)?0:l(t)},e.wbg.__wbg_static_accessor_WINDOW_a8924b26aa92d024=function(){const t=typeof window>"u"?null:window;return V(t)?0:l(t)},e.wbg.__wbg_then_4f95312d68691235=function(t,r){const _=g(t).then(g(r));return l(_)},e.wbg.__wbg_warn_6e567d0d926ff881=function(t){console.warn(g(t))},e.wbg.__wbindgen_cast_2241b6af4c4b2941=function(t,r){const _=b(t,r);return l(_)},e.wbg.__wbindgen_cast_4625c577ab2ec9ee=function(t){const r=BigInt.asUintN(64,t);return l(r)},e.wbg.__wbindgen_cast_89b0435615caf0ab=function(t,r){const _=Zt(t,r,n.__wasm_bindgen_func_elem_1684,qt);return l(_)},e.wbg.__wbindgen_cast_d6cd19b81560fd6e=function(t){return l(t)},e.wbg.__wbindgen_object_clone_ref=function(t){const r=g(t);return l(r)},e.wbg.__wbindgen_object_drop_ref=function(t){f(t)},e}function vt(e,t){return n=e.exports,It.__wbindgen_wasm_module=t,v=null,F=null,k=null,M=null,C=null,n.__wbindgen_start(),n}function Qt(e){if(n!==void 0)return n;typeof e<"u"&&(Object.getPrototypeOf(e)===Object.prototype?{module:e}=e:console.warn("using deprecated parameters for `initSync()`; pass a single object instead"));const t=xt();e instanceof WebAssembly.Module||(e=new WebAssembly.Module(e));const r=new WebAssembly.Instance(e,t);return vt(r,e)}async function It(e){if(n!==void 0)return n;typeof e<"u"&&(Object.getPrototypeOf(e)===Object.prototype?{module_or_path:e}=e:console.warn("using deprecated parameters for the initialization function; pass a single object instead")),typeof e>"u"&&(e=new URL("/assets/ifc-lite_bg-ksLBP5cA.wasm",import.meta.url));const t=xt();(typeof e=="string"||typeof Request=="function"&&e instanceof Request||typeof URL=="function"&&e instanceof URL)&&(e=fetch(e));const{instance:r,module:_}=await Jt(await e,t);return vt(r,_)}let y=null,St;async function S(){return y||(await It(St),y=new K,D=!1,tt(),y)}let At=!1,D=!1;function tt(){if(!y||D)return;const e=y;typeof e.setMergeLayers=="function"&&e.setMergeLayers(At),D=!0}function et(e){return new Uint8Array(e)}function rt(e){const t=new Uint8Array(e.byteLength);return t.set(new Uint8Array(e)),t}let u=null;const pt=1e6;function bt(e){return{sharedBuffer:e.sharedBuffer,localBytes:et(e.sharedBuffer),sabFallbackTaken:!1,unitScale:e.unitScale,rtcX:e.rtcX,rtcY:e.rtcY,rtcZ:e.rtcZ,needsShift:e.needsShift,voidKeys:e.voidKeys,voidCounts:e.voidCounts,voidValues:e.voidValues,styleIds:e.styleIds,styleColors:e.styleColors,pendingMeshes:[],pendingTransfers:[],totalMeshesEmitted:0,cumulativeMeshBytes:0}}function Ft(e){if(e.pendingMeshes.length===0)return;const t=e.pendingMeshes,r=e.pendingTransfers;e.pendingMeshes=[],e.pendingTransfers=[],e.totalMeshesEmitted+=t.length,self.postMessage({type:"batch",meshes:t},r)}function te(e,t){for(let r=0;r<t.length;r++){const _=t.get(r);if(!_)continue;const i=new Float32Array(_.positions),s=new Float32Array(_.normals),c=new Uint32Array(_.indices);e.pendingMeshes.push({expressId:_.expressId,ifcType:_.ifcType,positions:i,normals:s,indices:c,color:[_.color[0],_.color[1],_.color[2],_.color[3]]}),e.pendingTransfers.push(i.buffer,s.buffer,c.buffer),e.cumulativeMeshBytes+=i.byteLength+s.byteLength+c.byteLength,_.free()}t.free()}async function Z(e,t){const r=Math.floor(t.length/3);if(r!==0)try{const i=(await S()).processGeometryBatch(e.localBytes,t,e.unitScale,e.rtcX,e.rtcY,e.rtcZ,e.needsShift,e.voidKeys,e.voidCounts,e.voidValues,e.styleIds,e.styleColors);te(e,i)}catch(_){const i=_.message;if(!e.sabFallbackTaken&&e.localBytes.buffer instanceof SharedArrayBuffer){e.sabFallbackTaken=!0,console.warn(`[Worker] processGeometryBatch rejected SAB view (${i}), falling back to copy`),e.localBytes=rt(e.sharedBuffer),await Z(e,t);return}if(r===1){console.warn(`[Worker] Skipping entity #${t[0]}: ${i}`),y=null;return}console.warn(`[Worker] Batch of ${r} entities failed (${i}), splitting…`),y=null;const s=Math.floor(r/2)*3;await Z(e,t.slice(0,s)),await Z(e,t.slice(s))}}async function ut(e,t){const r=Math.floor(t.length/3);for(let _=0;_<r;_+=pt){const i=_*3,s=Math.min(i+pt*3,t.length);await Z(e,t.subarray(i,s)),Ft(e)}}function wt(e){Ft(e);let t=0;try{t=y?.getMemory()?.buffer?.byteLength??0}catch{}self.postMessage({type:"memory",meshBytes:e.cumulativeMeshBytes,wasmHeapBytes:t}),self.postMessage({type:"complete",totalMeshes:e.totalMeshesEmitted})}let yt=Promise.resolve();self.onmessage=e=>{yt=yt.then(()=>ee(e)).catch(t=>{self.postMessage({type:"error",message:t instanceof Error?t.message:String(t)})})};async function ee(e){try{if(e.data.type==="prepass-streaming"){const t=await S();self.postMessage({type:"prepass-progress",phase:"parsing"});const r=e.data.sharedBuffer,_=e.data.chunkSize??5e4;let i=et(r),s=!1;const c=a=>{self.postMessage({type:"prepass-stream",event:a})};try{t.buildPrePassStreaming(i,c,_)}catch(a){const p=a instanceof Error?a.message:String(a);if(!s)s=!0,console.warn(`[Worker] Streaming prepass with SAB view failed (${p}), retrying with copy`),i=rt(r),t.buildPrePassStreaming(i,c,_);else throw a}return}if(e.data.type==="prepass"||e.data.type==="prepass-fast"){const t=await S();self.postMessage({type:"prepass-progress",phase:"parsing"});const r=e.data.sharedBuffer,_=e.data.type==="prepass-fast";let i;try{const s=et(r);i=_?t.buildPrePassFast(s):t.buildPrePassOnce(s)}catch(s){const c=s instanceof Error?s.message:String(s);console.warn(`[Worker] Prepass with SAB view failed (${c}), retrying with copy`);const a=rt(r);i=_?t.buildPrePassFast(a):t.buildPrePassOnce(a)}self.postMessage({type:"prepass-result",result:i});return}if(e.data.type==="init"){e.data.wasmUrl&&(St=e.data.wasmUrl),e.data.wasmModule?(Qt({module_or_path:e.data.wasmModule}),y=new K,D=!1,tt()):await S(),self.postMessage({type:"ready"});return}if(e.data.type==="process"){await S();const{sharedBuffer:t,jobsFlat:r,unitScale:_,rtcX:i,rtcY:s,rtcZ:c,needsShift:a,voidKeys:p,voidCounts:m,voidValues:$,styleIds:q,styleColors:H}=e.data,A=bt({sharedBuffer:t,unitScale:_,rtcX:i,rtcY:s,rtcZ:c,needsShift:a,voidKeys:p,voidCounts:m,voidValues:$,styleIds:q,styleColors:H});u=A,await ut(A,r),wt(A),u=null;return}if(e.data.type==="stream-start"){await S(),u=bt({sharedBuffer:e.data.sharedBuffer,unitScale:e.data.unitScale,rtcX:e.data.rtcX,rtcY:e.data.rtcY,rtcZ:e.data.rtcZ,needsShift:e.data.needsShift,voidKeys:e.data.voidKeys,voidCounts:e.data.voidCounts,voidValues:e.data.voidValues,styleIds:e.data.styleIds,styleColors:e.data.styleColors});return}if(e.data.type==="stream-chunk"){if(!u)throw new Error("stream-chunk received before stream-start");await ut(u,e.data.jobsFlat);return}if(e.data.type==="set-styles"){if(!u)return;u.styleIds=e.data.styleIds,u.styleColors=e.data.styleColors,u.voidKeys=e.data.voidKeys,u.voidCounts=e.data.voidCounts,u.voidValues=e.data.voidValues;return}if(e.data.type==="set-entity-index"){(await S()).setEntityIndex(e.data.ids,e.data.starts,e.data.lengths);return}if(e.data.type==="set-merge-layers"){At=e.data.enabled===!0,D=!1,tt();return}if(e.data.type==="stream-end"){if(!u)throw new Error("stream-end received before stream-start");wt(u),u=null;return}}catch(t){self.postMessage({type:"error",message:t instanceof Error?t.message:String(t)})}}