@ifc-lite/viewer 1.17.2 → 1.17.3
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.
- package/.turbo/turbo-build.log +30 -29
- package/.turbo/turbo-typecheck.log +1 -42
- package/CHANGELOG.md +9 -0
- package/dist/assets/arrow-DJf2ErbF.js +20 -0
- package/dist/assets/basketViewActivator-aojwdomq.js +1 -0
- package/dist/assets/bcf-D5-QWGO9.js +281 -0
- package/dist/assets/{browser-BDShTXzi.js → browser-CKs-FY1P.js} +1 -1
- package/dist/assets/drawing-2d-gWfpdfYe.js +257 -0
- package/dist/assets/epsg-index.generated-BjJrt_0S.js +1 -0
- package/dist/assets/exporters-C_6J153K.js +79896 -0
- package/dist/assets/geometry.worker-Nz9_YIqh.js +1 -0
- package/dist/assets/ids-B4jTqB1O.js +1 -0
- package/dist/assets/{ifc-lite_bg-FNRmpSvM.wasm → ifc-lite_bg-eSkBTizQ.wasm} +0 -0
- package/dist/assets/index-jhBr1wbn.js +101666 -0
- package/dist/assets/index-pbE7itQS.css +1 -0
- package/dist/assets/lens-CSASnhAL.js +1 -0
- package/dist/assets/maplibre-gl-BpvwNKKy.js +811 -0
- package/dist/assets/{native-bridge-Crsb7TKz.js → native-bridge-DSIyEYXG.js} +6 -4
- package/dist/assets/{arrow2-bb-jcVEo.js → parquet-CEXmQNRO.js} +2 -2
- package/dist/assets/sandbox-B79eavQ3.js +5933 -0
- package/dist/assets/server-client-D3bUPJJc.js +626 -0
- package/dist/assets/wasm-bridge-B0J07fZZ.js +1 -0
- package/dist/assets/zip-B-jFFAGa.js +12 -0
- package/dist/index.html +11 -2
- package/package.json +24 -19
- package/src/components/viewer/ExportChangesButton.tsx +18 -3
- package/src/components/viewer/ExportDialog.tsx +16 -3
- package/src/components/viewer/HierarchyPanel.tsx +6 -6
- package/src/components/viewer/PropertiesPanel.tsx +96 -60
- package/src/components/viewer/Section2DPanel.tsx +3 -2
- package/src/components/viewer/ViewportContainer.tsx +5 -4
- package/src/components/viewer/hierarchy/treeDataBuilder.ts +2 -1
- package/src/components/viewer/properties/EpsgLookupDialog.tsx +418 -0
- package/src/components/viewer/properties/GeoreferencingPanel.tsx +591 -0
- package/src/components/viewer/properties/LocationMap.tsx +289 -0
- package/src/components/viewer/properties/ModelMetadataPanel.tsx +3 -70
- package/src/hooks/bcfIdLookup.ts +13 -11
- package/src/hooks/ids/idsColorSystem.ts +3 -8
- package/src/hooks/useIDS.ts +31 -16
- package/src/hooks/useIfcFederation.ts +2 -2
- package/src/lib/geo/kmz-exporter.ts +112 -0
- package/src/lib/geo/reproject.ts +244 -0
- package/src/lib/lens/adapter.ts +3 -1
- package/src/main.tsx +1 -0
- package/src/sdk/adapters/export-adapter.ts +14 -1
- package/src/sdk/adapters/viewer-adapter.ts +5 -9
- package/src/sdk/adapters/visibility-adapter.ts +6 -9
- package/src/store/basketVisibleSet.ts +3 -4
- package/src/store/globalId.ts +79 -0
- package/src/store/index.ts +1 -0
- package/src/store/slices/mutationSlice.ts +178 -0
- package/src/store/slices/pinboardSlice.ts +4 -8
- package/vite.config.ts +17 -0
- package/dist/assets/Arrow.dom-BhOg9lpn.js +0 -20
- package/dist/assets/arrow2_bg-BlXl-cSQ.js +0 -1
- package/dist/assets/basketViewActivator-BRG5DBmM.js +0 -1
- package/dist/assets/geometry.worker-kgiT_Qhh.js +0 -1
- package/dist/assets/index-B1Ecw4AU.js +0 -189756
- package/dist/assets/index-Ba4eoTe7.css +0 -1
- package/dist/assets/index-CrgYBjTn.js +0 -229
- package/dist/assets/module-6F3E5H7Y-tx0BadV3.js +0 -6
- package/dist/assets/wasm-bridge-mJUhb7uk.js +0 -1
|
@@ -27,11 +27,12 @@ import { ScrollArea } from '@/components/ui/scroll-area';
|
|
|
27
27
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
|
|
28
28
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
|
29
29
|
import { useViewerStore } from '@/store';
|
|
30
|
+
import { toGlobalIdFromModels } from '@/store/globalId';
|
|
30
31
|
import { useIfc } from '@/hooks/useIfc';
|
|
31
32
|
import { configureMutationView } from '@/utils/configureMutationView';
|
|
32
33
|
import { IfcQuery } from '@ifc-lite/query';
|
|
33
34
|
import { MutablePropertyView } from '@ifc-lite/mutations';
|
|
34
|
-
import { extractClassificationsOnDemand, extractMaterialsOnDemand, extractTypePropertiesOnDemand, extractTypeEntityOwnProperties, extractDocumentsOnDemand, extractRelationshipsOnDemand, type IfcDataStore } from '@ifc-lite/parser';
|
|
35
|
+
import { extractClassificationsOnDemand, extractMaterialsOnDemand, extractTypePropertiesOnDemand, extractTypeEntityOwnProperties, extractDocumentsOnDemand, extractRelationshipsOnDemand, extractGeoreferencingOnDemand, type IfcDataStore } from '@ifc-lite/parser';
|
|
35
36
|
import { EntityFlags, RelationshipType, isSpatialStructureTypeName, isStoreyLikeSpatialTypeName } from '@ifc-lite/data';
|
|
36
37
|
import type { EntityRef, FederatedModel } from '@/store/types';
|
|
37
38
|
|
|
@@ -45,6 +46,7 @@ import { DocumentCard } from './properties/DocumentCard';
|
|
|
45
46
|
import { RelationshipsCard } from './properties/RelationshipsCard';
|
|
46
47
|
import type { PropertySet, QuantitySet } from './properties/encodingUtils';
|
|
47
48
|
import { BsddCard } from './properties/BsddCard';
|
|
49
|
+
import { GeoreferencingPanel } from './properties/GeoreferencingPanel';
|
|
48
50
|
|
|
49
51
|
type DisplayProperty = { name: string; value: unknown; isMutated: boolean };
|
|
50
52
|
type DisplayPropertySet = {
|
|
@@ -247,7 +249,7 @@ export function PropertiesPanel() {
|
|
|
247
249
|
if (!geoResult?.meshes?.length) return null;
|
|
248
250
|
|
|
249
251
|
// In multi-model mode, meshes use globalIds (originalExpressId + idOffset)
|
|
250
|
-
const targetExpressId = selectedEntity.expressId
|
|
252
|
+
const targetExpressId = toGlobalIdFromModels(models, selectedEntity.modelId, selectedEntity.expressId);
|
|
251
253
|
|
|
252
254
|
// Compute bounding box from matching mesh positions
|
|
253
255
|
let minX = Infinity, minY = Infinity, minZ = Infinity;
|
|
@@ -515,6 +517,14 @@ export function PropertiesPanel() {
|
|
|
515
517
|
return totalCount > 0 ? rels : null;
|
|
516
518
|
}, [selectedEntity, model, ifcDataStore]);
|
|
517
519
|
|
|
520
|
+
// Extract georeferencing info for the model (used in coordinates section)
|
|
521
|
+
const georef = useMemo(() => {
|
|
522
|
+
const dataStore = model?.ifcDataStore ?? ifcDataStore;
|
|
523
|
+
if (!dataStore) return null;
|
|
524
|
+
const info = extractGeoreferencingOnDemand(dataStore as IfcDataStore);
|
|
525
|
+
return info?.hasGeoreference ? info : null;
|
|
526
|
+
}, [model, ifcDataStore]);
|
|
527
|
+
|
|
518
528
|
// Extract type-level properties (e.g., from IfcWallType's HasPropertySets)
|
|
519
529
|
const typeProperties = useMemo(() => {
|
|
520
530
|
if (!selectedEntity) return null;
|
|
@@ -644,8 +654,8 @@ export function PropertiesPanel() {
|
|
|
644
654
|
|
|
645
655
|
// Separate occurrence (instance) and inherited type properties.
|
|
646
656
|
// Occurrence properties are displayed first, type properties in a separate section.
|
|
647
|
-
//
|
|
648
|
-
//
|
|
657
|
+
// All type property sets are always shown in the inherited section so users can see
|
|
658
|
+
// what the type defines, even when the same pset exists at occurrence level.
|
|
649
659
|
const { occurrenceProperties, inheritedTypeProperties } = useMemo(() => {
|
|
650
660
|
const occ: PropertySet[] = properties.map(p => ({ ...p, source: 'instance' as const }));
|
|
651
661
|
|
|
@@ -653,23 +663,10 @@ export function PropertiesPanel() {
|
|
|
653
663
|
return { occurrenceProperties: occ, inheritedTypeProperties: [] as PropertySet[] };
|
|
654
664
|
}
|
|
655
665
|
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
if (instanceByName.has(typePset.name)) {
|
|
661
|
-
// Pset exists at instance level - add type-only props that aren't overridden
|
|
662
|
-
const instancePset = properties.find(p => p.name === typePset.name)!;
|
|
663
|
-
const instancePropNames = new Set(instancePset.properties.map(p => p.name));
|
|
664
|
-
const extraProps = typePset.properties.filter(p => !instancePropNames.has(p.name));
|
|
665
|
-
if (extraProps.length > 0) {
|
|
666
|
-
inherited.push({ ...typePset, properties: extraProps, source: 'type' });
|
|
667
|
-
}
|
|
668
|
-
} else {
|
|
669
|
-
// Type-only pset - show fully in inherited section
|
|
670
|
-
inherited.push({ ...typePset, source: 'type' });
|
|
671
|
-
}
|
|
672
|
-
}
|
|
666
|
+
const inherited: PropertySet[] = typeProperties.psets.map(typePset => ({
|
|
667
|
+
...typePset,
|
|
668
|
+
source: 'type' as const,
|
|
669
|
+
}));
|
|
673
670
|
|
|
674
671
|
return { occurrenceProperties: occ, inheritedTypeProperties: inherited };
|
|
675
672
|
}, [properties, typeProperties]);
|
|
@@ -770,6 +767,23 @@ export function PropertiesPanel() {
|
|
|
770
767
|
}
|
|
771
768
|
|
|
772
769
|
if (!selectedEntityId || !modelQuery || !entityNode) {
|
|
770
|
+
// Show model metadata when a single legacy model is loaded and nothing selected
|
|
771
|
+
if (ifcDataStore && models.size === 0 && geometryResult) {
|
|
772
|
+
const legacyModel: FederatedModel = {
|
|
773
|
+
id: '__legacy__',
|
|
774
|
+
name: 'Model',
|
|
775
|
+
ifcDataStore: ifcDataStore as IfcDataStore,
|
|
776
|
+
geometryResult,
|
|
777
|
+
visible: true,
|
|
778
|
+
collapsed: false,
|
|
779
|
+
schemaVersion: ((ifcDataStore as IfcDataStore).schemaVersion ?? 'IFC4') as FederatedModel['schemaVersion'],
|
|
780
|
+
loadedAt: Date.now(),
|
|
781
|
+
fileSize: (ifcDataStore as IfcDataStore).fileSize ?? 0,
|
|
782
|
+
idOffset: 0,
|
|
783
|
+
maxExpressId: (ifcDataStore as IfcDataStore).entityCount ?? 0,
|
|
784
|
+
};
|
|
785
|
+
return <ModelMetadataPanel model={legacyModel} />;
|
|
786
|
+
}
|
|
773
787
|
return (
|
|
774
788
|
<div className="h-full flex flex-col border-l-2 border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-black">
|
|
775
789
|
<div className="p-3 border-b-2 border-zinc-200 dark:border-zinc-800 bg-white dark:bg-black">
|
|
@@ -781,7 +795,7 @@ export function PropertiesPanel() {
|
|
|
781
795
|
</div>
|
|
782
796
|
<p className="font-bold uppercase text-zinc-900 dark:text-zinc-100 mb-2">No Selection</p>
|
|
783
797
|
<p className="text-xs font-mono text-zinc-500 dark:text-zinc-400 max-w-[150px]">
|
|
784
|
-
Select an element to view details
|
|
798
|
+
{models.size > 1 ? 'Select a model or element to view details' : 'Select an element to view details'}
|
|
785
799
|
</p>
|
|
786
800
|
</div>
|
|
787
801
|
</div>
|
|
@@ -808,6 +822,13 @@ export function PropertiesPanel() {
|
|
|
808
822
|
{entityName || `${entityType}`}
|
|
809
823
|
</h3>
|
|
810
824
|
<p className="text-xs font-mono text-zinc-500 dark:text-zinc-400">{entityType}</p>
|
|
825
|
+
{/* Show associated type entity for occurrences */}
|
|
826
|
+
{!isTypeEntity && typeProperties && (
|
|
827
|
+
<p className="text-[11px] font-mono text-indigo-500 dark:text-indigo-400 truncate" title={`${activeDataStore?.entities.getTypeName(typeProperties.typeId) || 'Type'}: ${typeProperties.typeName}`}>
|
|
828
|
+
<Building2 className="inline h-3 w-3 mr-1 -mt-0.5" />
|
|
829
|
+
{activeDataStore?.entities.getTypeName(typeProperties.typeId) || 'Type'}: {typeProperties.typeName}
|
|
830
|
+
</p>
|
|
831
|
+
)}
|
|
811
832
|
</div>
|
|
812
833
|
<div className="flex gap-1 shrink-0">
|
|
813
834
|
<Tooltip>
|
|
@@ -932,55 +953,70 @@ export function PropertiesPanel() {
|
|
|
932
953
|
</div>
|
|
933
954
|
)}
|
|
934
955
|
|
|
935
|
-
{/*
|
|
936
|
-
{entityCoordinates && (
|
|
956
|
+
{/* World coordinates + Georeferencing — single consolidated section */}
|
|
957
|
+
{(entityCoordinates || georef || editMode) && (
|
|
937
958
|
<Collapsible open={coordOpen} onOpenChange={setCoordOpen}>
|
|
938
959
|
<CollapsibleTrigger className="flex items-center gap-2 w-full text-xs border border-teal-500/30 px-2 py-1.5 text-teal-800 dark:text-teal-400 min-w-0 text-left group/coord">
|
|
939
960
|
<Crosshair className="h-3.5 w-3.5 shrink-0" />
|
|
940
961
|
<span className="font-bold uppercase tracking-wide shrink-0">World</span>
|
|
941
962
|
{!coordOpen && (
|
|
942
963
|
<>
|
|
943
|
-
|
|
944
|
-
<
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
964
|
+
{entityCoordinates && (
|
|
965
|
+
<span className="font-mono text-[10px] text-teal-600/70 dark:text-teal-500/70 truncate min-w-0 flex-1 tabular-nums">
|
|
966
|
+
<CoordVal axis="E" value={entityCoordinates.worldZup.center.x} />{' '}
|
|
967
|
+
<CoordVal axis="N" value={entityCoordinates.worldZup.center.y} />{' '}
|
|
968
|
+
<CoordVal axis="Z" value={entityCoordinates.worldZup.center.z} />
|
|
969
|
+
</span>
|
|
970
|
+
)}
|
|
971
|
+
{georef?.projectedCRS?.name && (
|
|
972
|
+
<span className="font-mono text-[9px] text-teal-500/60 shrink-0">{georef.projectedCRS.name}</span>
|
|
973
|
+
)}
|
|
948
974
|
<span className="text-[9px] text-teal-500/0 group-hover/coord:text-teal-500/40 transition-colors shrink-0">details</span>
|
|
949
975
|
</>
|
|
950
976
|
)}
|
|
951
977
|
</CollapsibleTrigger>
|
|
952
978
|
<CollapsibleContent>
|
|
953
|
-
|
|
954
|
-
<
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
{
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
{
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
<
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
979
|
+
{entityCoordinates && (
|
|
980
|
+
<div className="px-2 py-1.5 space-y-0.5">
|
|
981
|
+
<CoordRow
|
|
982
|
+
label=""
|
|
983
|
+
values={[
|
|
984
|
+
{ axis: 'E', value: entityCoordinates.worldZup.center.x },
|
|
985
|
+
{ axis: 'N', value: entityCoordinates.worldZup.center.y },
|
|
986
|
+
{ axis: 'Z', value: entityCoordinates.worldZup.center.z },
|
|
987
|
+
]}
|
|
988
|
+
primary
|
|
989
|
+
copyLabel="world"
|
|
990
|
+
coordCopied={coordCopied}
|
|
991
|
+
onCopy={copyCoords}
|
|
992
|
+
/>
|
|
993
|
+
<CoordRow
|
|
994
|
+
label="Local"
|
|
995
|
+
values={[
|
|
996
|
+
{ axis: 'X', value: entityCoordinates.local.center.x },
|
|
997
|
+
{ axis: 'Y', value: entityCoordinates.local.center.y },
|
|
998
|
+
{ axis: 'Z', value: entityCoordinates.local.center.z },
|
|
999
|
+
]}
|
|
1000
|
+
copyLabel="local"
|
|
1001
|
+
coordCopied={coordCopied}
|
|
1002
|
+
onCopy={copyCoords}
|
|
1003
|
+
/>
|
|
1004
|
+
<div className="flex items-start gap-1.5">
|
|
1005
|
+
<span className="text-[9px] font-medium text-muted-foreground/50 uppercase tracking-wider w-[34px] shrink-0 pt-px">Size</span>
|
|
1006
|
+
<span className="font-mono text-[10px] text-muted-foreground/50 tabular-nums">
|
|
1007
|
+
{(entityCoordinates.local.max.x - entityCoordinates.local.min.x).toFixed(2)} x {(entityCoordinates.local.max.y - entityCoordinates.local.min.y).toFixed(2)} x {(entityCoordinates.local.max.z - entityCoordinates.local.min.z).toFixed(2)}
|
|
1008
|
+
</span>
|
|
1009
|
+
</div>
|
|
982
1010
|
</div>
|
|
983
|
-
|
|
1011
|
+
)}
|
|
1012
|
+
<GeoreferencingPanel
|
|
1013
|
+
georef={georef}
|
|
1014
|
+
modelId={selectedEntity?.modelId === 'legacy' ? '__legacy__' : (model?.id ?? selectedEntity?.modelId)}
|
|
1015
|
+
enableEditing
|
|
1016
|
+
schemaVersion={activeDataStore?.schemaVersion}
|
|
1017
|
+
coordinateInfo={(model?.geometryResult ?? geometryResult)?.coordinateInfo}
|
|
1018
|
+
geometryResult={model?.geometryResult ?? geometryResult}
|
|
1019
|
+
/>
|
|
984
1020
|
</CollapsibleContent>
|
|
985
1021
|
</Collapsible>
|
|
986
1022
|
)}
|
|
@@ -1131,7 +1167,7 @@ export function PropertiesPanel() {
|
|
|
1131
1167
|
)}
|
|
1132
1168
|
<div className="flex items-center gap-2 px-1 pb-0.5 text-[11px] text-indigo-600/70 dark:text-indigo-400/60 uppercase tracking-wider font-semibold">
|
|
1133
1169
|
<Building2 className="h-3 w-3 shrink-0" />
|
|
1134
|
-
<span className="truncate">
|
|
1170
|
+
<span className="truncate">Type Properties ({typeProperties.typeName})</span>
|
|
1135
1171
|
</div>
|
|
1136
1172
|
{inheritedTypeProperties.map((pset: PropertySet) => (
|
|
1137
1173
|
<PropertySetCard
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
DropdownMenuTrigger,
|
|
23
23
|
} from '@/components/ui/dropdown-menu';
|
|
24
24
|
import { useViewerStore } from '@/store';
|
|
25
|
+
import { toGlobalIdFromModels } from '@/store/globalId';
|
|
25
26
|
import { useIfc } from '@/hooks/useIfc';
|
|
26
27
|
import { GraphicOverrideEngine } from '@ifc-lite/drawing-2d';
|
|
27
28
|
import { type GeometryResult } from '@ifc-lite/geometry';
|
|
@@ -224,7 +225,7 @@ export function Section2DPanel({
|
|
|
224
225
|
const model = models.get(modelId);
|
|
225
226
|
if (model && model.idOffset !== undefined) {
|
|
226
227
|
for (const localId of localHiddenIds) {
|
|
227
|
-
globalHiddenIds.add(
|
|
228
|
+
globalHiddenIds.add(toGlobalIdFromModels(models, model.id, localId));
|
|
228
229
|
}
|
|
229
230
|
}
|
|
230
231
|
}
|
|
@@ -245,7 +246,7 @@ export function Section2DPanel({
|
|
|
245
246
|
const model = models.get(modelId);
|
|
246
247
|
if (model && model.idOffset !== undefined) {
|
|
247
248
|
for (const localId of localIsolatedIds) {
|
|
248
|
-
globalIsolatedIds.add(
|
|
249
|
+
globalIsolatedIds.add(toGlobalIdFromModels(models, model.id, localId));
|
|
249
250
|
}
|
|
250
251
|
}
|
|
251
252
|
}
|
|
@@ -10,6 +10,7 @@ import { Section2DPanel } from './Section2DPanel';
|
|
|
10
10
|
import { BasketPresentationDock } from './BasketPresentationDock';
|
|
11
11
|
import { BCFOverlay } from './bcf/BCFOverlay';
|
|
12
12
|
import { useViewerStore } from '@/store';
|
|
13
|
+
import { toGlobalIdFromModels } from '@/store/globalId';
|
|
13
14
|
import { collectIfcBuildingStoreyElementsWithIfcSpace } from '@/store/basketVisibleSet';
|
|
14
15
|
import { useIfc } from '@/hooks/useIfc';
|
|
15
16
|
import { useWebGPU } from '@/hooks/useWebGPU';
|
|
@@ -265,14 +266,14 @@ export function ViewportContainer() {
|
|
|
265
266
|
const hierarchy = model.ifcDataStore?.spatialHierarchy;
|
|
266
267
|
if (!hierarchy) continue;
|
|
267
268
|
|
|
268
|
-
const offset = model.idOffset ?? 0;
|
|
269
|
-
|
|
270
269
|
for (const storeyId of selectedStoreys) {
|
|
271
|
-
const localStoreyId = hierarchy.byStorey.has(storeyId)
|
|
270
|
+
const localStoreyId = hierarchy.byStorey.has(storeyId)
|
|
271
|
+
? storeyId
|
|
272
|
+
: storeyId - (model.idOffset ?? 0);
|
|
272
273
|
const storeyElementIds = collectIfcBuildingStoreyElementsWithIfcSpace(hierarchy, localStoreyId);
|
|
273
274
|
if (storeyElementIds) {
|
|
274
275
|
for (const originalExpressId of storeyElementIds) {
|
|
275
|
-
combinedGlobalIds.add(
|
|
276
|
+
combinedGlobalIds.add(toGlobalIdFromModels(storeModels, model.id, originalExpressId));
|
|
276
277
|
}
|
|
277
278
|
}
|
|
278
279
|
}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from '@ifc-lite/data';
|
|
14
14
|
import type { IfcDataStore } from '@ifc-lite/parser';
|
|
15
15
|
import { useViewerStore, type FederatedModel } from '@/store';
|
|
16
|
+
import { toGlobalIdFromModels } from '@/store/globalId';
|
|
16
17
|
import type { TreeNode, NodeType, StoreyData, UnifiedStorey } from './types';
|
|
17
18
|
|
|
18
19
|
/** Helper to create elevation key (with 0.5m tolerance for matching) */
|
|
@@ -300,7 +301,7 @@ export function buildTreeData(
|
|
|
300
301
|
nodes.push({
|
|
301
302
|
id: storeyNodeId,
|
|
302
303
|
expressIds: allStoreyIds,
|
|
303
|
-
globalIds: unified.storeys.map((s) =>
|
|
304
|
+
globalIds: unified.storeys.map((s) => toGlobalIdFromModels(models, s.modelId, s.storeyId)),
|
|
304
305
|
modelIds: unified.storeys.map(s => s.modelId),
|
|
305
306
|
name: unified.name,
|
|
306
307
|
type: 'unified-storey',
|