@ifc-lite/viewer 1.22.0 → 1.22.1
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 +71 -44
- package/CHANGELOG.md +23 -0
- package/dist/assets/__vite-browser-external-B1O5LaIO.js +1 -0
- package/dist/assets/{arrow-fie-E7fe.js → arrow-CXWhTnNT.js} +1 -1
- package/dist/assets/{basketViewActivator-EHAhHlwN.js → basketViewActivator--cFpU2Q9.js} +10 -10
- package/dist/assets/{bcf-Bhx-K17f.js → bcf-Ba2CjHib.js} +2 -2
- package/dist/assets/browser-DXS29_v9.js +695 -0
- package/dist/assets/{cesium-B4ZIU9jS.js → cesium-BoVuJvTC.js} +5838 -5730
- package/dist/assets/{decode-worker-CYqSjk1n.js → decode-worker-CgM1iNSK.js} +1 -1
- package/dist/assets/deflate-DCLbV4UE.js +1 -0
- package/dist/assets/{drawing-2d-Bjy8YPrg.js → drawing-2d-C71b8Ugx.js} +1 -1
- package/dist/assets/emscripten-module-B1g2L2eS.wasm +0 -0
- package/dist/assets/emscripten-module-DHbYPfAp.wasm +0 -0
- package/dist/assets/emscripten-module-ZrHFMo7O.wasm +0 -0
- package/dist/assets/emscripten-module-uFzwHH0Y.wasm +0 -0
- package/dist/assets/emscripten-module.browser-BLJD5hhE.js +1 -0
- package/dist/assets/{esbuild-Cpd5nU_H.wasm → esbuild-CzsZLPr0.wasm} +0 -0
- package/dist/assets/esbuild-FgU11_Eg.js +1 -0
- package/dist/assets/event-B0kAzHa-.js +1 -0
- package/dist/assets/{exporters-KTio0Tdm.js → exporters-Bf6PTtdW.js} +1011 -1011
- package/dist/assets/ffi-Boa1QuFa.js +1 -0
- package/dist/assets/{geometry-controller.worker-Cm2P_EJr.js → geometry-controller.worker-CEr00X3X.js} +2 -2
- package/dist/assets/{geometry.worker-DchLBqZ8.js → geometry.worker-B4VPDkmL.js} +1 -1
- package/dist/assets/geotiff-BN4J8Vt9.js +3354 -0
- package/dist/assets/{ids-CS7VCFin.js → ids-XwxE1tK3.js} +6 -6
- package/dist/assets/{ifc-lite-C6wEhXa6.js → ifc-lite-DNzkEkIb.js} +2 -2
- package/dist/assets/ifc-lite_bg-1IiJN0Zg.wasm +0 -0
- package/dist/assets/ifc-lite_bg-B_eUD1Wy.wasm +0 -0
- package/dist/assets/index-DMho-JA0.js +6 -0
- package/dist/assets/index-DS_xJQfP.css +1 -0
- package/dist/assets/{index-8k9h-ANq.js → index-j2x5R7fb.js} +66047 -55202
- package/dist/assets/jpeg-BUTmr0Bp.js +1 -0
- package/dist/assets/{laz-perf-DnSyzVYH.wasm → laz-perf-CFJp03W6.wasm} +0 -0
- package/dist/assets/laz-perf-DgUOSLeU.js +1 -0
- package/dist/assets/{laz-source-jj3xI5Y4.js → laz-source-BWjza0Iw.js} +2 -2
- package/dist/assets/{lens-CSASnhAL.js → lens-CpjUdqpw.js} +1 -1
- package/dist/assets/lerc-DmzRHXn3.js +1 -0
- package/dist/assets/lzw-CgyIIzii.js +1 -0
- package/dist/assets/maplibre-gl-Do6O5tDc.js +800 -0
- package/dist/assets/{native-bridge-DNrEhx2R.js → native-bridge-Q5ACp4QY.js} +3 -3
- package/dist/assets/packbits-C1r4AzHj.js +1 -0
- package/dist/assets/pako.esm-Cram60i4.js +1 -0
- package/dist/assets/parquet_wasm_bg-DcKVfvto.wasm +0 -0
- package/dist/assets/{parser.worker-BcjkIo89.js → parser.worker-Cl6XQcXA.js} +2 -2
- package/dist/assets/raw-ZqLh7kVQ.js +1 -0
- package/dist/assets/{sandbox-BSn5MyEJ.js → sandbox-Bju6ZKJK.js} +1664 -1542
- package/dist/assets/{server-client-D-kU2XAF.js → server-client-B8wi3CGx.js} +4 -4
- package/dist/assets/three-CQBzFWY2.js +4104 -0
- package/dist/assets/wasm-bridge-X-mWRA9Z.js +1 -0
- package/dist/assets/webimage-D0MbRMkU.js +1 -0
- package/dist/assets/{workerHelpers-pUUnk9Wc.js → workerHelpers-DnNedVRr.js} +1 -1
- package/dist/assets/zstd-DA4VQ-ji.js +1 -0
- package/dist/cesium/{Workers/chunk-V7QEYVP3.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-236YIEYT.js} +2 -2
- package/dist/cesium/{Workers/chunk-5TJMAQVL.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-2ZYB3DYT.js} +2 -2
- package/dist/cesium/{Workers/chunk-UBOGZS7F.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-4M56RRIL.js} +2 -2
- package/dist/cesium/{Workers/chunk-OCWJRAXS.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-5BC2Q3QW.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-5XHUDY37.js +26 -0
- package/dist/cesium/{Workers/chunk-Z3QF2EHT.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-6WMLAJJP.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-72KUXMWU.js +26 -0
- package/dist/cesium/{Workers/chunk-EQ4YRVWL.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-7NQYTTAU.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-A35GG5WJ.js +26 -0
- package/dist/cesium/{Workers/chunk-FC4ZZ65J.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-AXNBHUAG.js} +2 -2
- package/dist/cesium/{Workers/chunk-BTSYJ5XU.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-DC3K7YTH.js} +2 -2
- package/dist/cesium/{Workers/chunk-SLT4J352.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-DRBPXGI7.js} +2 -2
- package/dist/cesium/{Workers/chunk-2MJIIVP4.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-EARRZPMO.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-EHC3BDVP.js +26 -0
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-EYZUSGKM.js +26 -0
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-EZSKHVA2.js +26 -0
- package/dist/cesium/{Workers/chunk-ICALLYLG.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-F3WJIFOO.js} +2 -2
- package/dist/cesium/{Workers/chunk-LSLE2RL4.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-FB7UV5BI.js} +2 -2
- package/dist/cesium/{Workers/chunk-CUUSNIVQ.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-FC6IYMYF.js} +2 -2
- package/dist/cesium/{Workers/chunk-TNSUQXWK.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-GF67PEXE.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-GXEQRH2R.js +26 -0
- package/dist/cesium/{Workers/chunk-M4HLDBCG.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-I5NKQIWE.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-IH7GXIUB.js +26 -0
- package/dist/cesium/{Workers/chunk-OIT7J4IC.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-IPP3UFGH.js} +2 -2
- package/dist/cesium/{Workers/chunk-WWWZVEEH.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-IYRGNBSH.js} +2 -2
- package/dist/cesium/{Workers/chunk-WPMZLB3Y.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-J6BM74AD.js} +2 -2
- package/dist/cesium/{Workers/chunk-QFM5DCMQ.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-KG2GJUJT.js} +1 -1
- package/dist/cesium/{Workers/chunk-XQHLGIO7.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-L7UE5MMF.js} +2 -2
- package/dist/cesium/{Workers/chunk-EFBN7QNX.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-LBZ34MHQ.js} +2 -2
- package/dist/cesium/{Workers/chunk-YP7I5QBZ.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-LOQDTQMX.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-LYLRYC4L.js +29 -0
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-MGPRMLLW.js +26 -0
- package/dist/cesium/{Workers/chunk-LI2ZSORM.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-NP26LKQA.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-OMUAZ3NM.js +26 -0
- package/dist/cesium/{Workers/chunk-S44JILQT.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-PPFUDJN4.js} +2 -2
- package/dist/cesium/{Workers/chunk-EDVBB7SS.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-PQ3V63XF.js} +2 -2
- package/dist/cesium/{Workers/chunk-Q5BPHJQF.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-PWBQN4GK.js} +2 -2
- package/dist/cesium/{Workers/chunk-E7KYDCM5.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-QOTMLO2T.js} +2 -2
- package/dist/cesium/{Workers/chunk-XUSCFAVF.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-SP35IT73.js} +2 -2
- package/dist/cesium/{Workers/chunk-6BD4U3VO.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-T3ZGSZKA.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-TM6SYYHO.js +28 -0
- package/dist/cesium/{Workers/chunk-VUKYSU4H.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-TSGIJVWH.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-U3YGOX3C.js +63 -0
- package/dist/cesium/{Workers/chunk-7TVGLKQF.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-VBYOXOSM.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-VCOHJNKB.js +26 -0
- package/dist/cesium/{Workers/chunk-WBOV35NL.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-VXAZXMUX.js} +2 -2
- package/dist/cesium/{Workers/chunk-IX4VMHEV.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-VXCJOT4W.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-WPD3MB6X.js +26 -0
- package/dist/cesium/{Workers/chunk-V3OSTMM6.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-X4D5KUN5.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-XEC656IT.js +26 -0
- package/dist/cesium/{Workers/chunk-MJHHSGEH.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-XR53QRQS.js} +2 -2
- package/dist/cesium/{Workers/chunk-XFIQ5DEQ.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-XR7MN4PJ.js} +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-XU6O4MRS.js +26 -0
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-XZBHEBLF.js +29 -0
- package/dist/cesium/{Workers/chunk-OLZ3FYUM.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-Z2M4BF4E.js} +2 -2
- package/dist/cesium/{Workers/chunk-2ZBHLJST.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-Z4ERBZFB.js} +2 -2
- package/dist/cesium/{Workers/chunk-W37FE5GR.js → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/chunk-ZY2KCIWI.js} +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/combineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createBoxGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createBoxOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createCircleGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createCircleOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createCoplanarPolygonGeometry.js +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/createCoplanarPolygonOutlineGeometry.js +26 -0
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createCorridorGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createCorridorOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createCylinderGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createCylinderOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createEllipseGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createEllipseOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createEllipsoidGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createEllipsoidOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createFrustumGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createFrustumOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createGeometry.js +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/createGroundPolylineGeometry.js +26 -0
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createPlaneGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createPlaneOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createPolygonGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createPolygonOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createPolylineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createPolylineVolumeGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createPolylineVolumeOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createRectangleGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createRectangleOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createSimplePolylineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createSphereGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createSphereOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createTaskProcessorWorker.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createVectorTileClampedPolylines.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createVectorTileGeometries.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createVectorTilePoints.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createVectorTilePolygons.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createVectorTilePolylines.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createVerticesFromCesium3DTilesTerrain.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createVerticesFromGoogleEarthEnterpriseBuffer.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createVerticesFromHeightmap.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createVerticesFromQuantizedTerrainMesh.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createWallGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/createWallOutlineGeometry.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/decodeDraco.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/decodeGoogleEarthEnterprisePacket.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/decodeI3S.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/gaussianSplatSorter.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/gaussianSplatTextureGenerator.js +2 -2
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/incrementallyBuildTerrainPicker.js +2 -2
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/transcodeKTX2.js +56 -0
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/transferTypedArrayTest.js +1 -1
- package/dist/cesium/node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers/upsampleQuantizedTerrainMesh.js +26 -0
- package/dist/cesium/{Workers → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Workers}/upsampleVerticesFromCesium3DTilesTerrain.js +2 -2
- package/dist/index.html +11 -11
- package/package.json +52 -45
- package/src/components/mcp/McpLanding.tsx +1 -1
- package/src/components/mcp/McpPlayground.tsx +1 -1
- package/src/components/viewer/AddElementPanel.tsx +2 -2
- package/src/components/viewer/BasepointOverlay.tsx +239 -0
- package/src/components/viewer/CesiumOverlay.tsx +15 -59
- package/src/components/viewer/CesiumPlacementEditor.tsx +16 -1
- package/src/components/viewer/CommandPalette.tsx +25 -0
- package/src/components/viewer/GeometryAxisRow.tsx +54 -0
- package/src/components/viewer/GeometryEditCard.tsx +392 -0
- package/src/components/viewer/HierarchyPanel.tsx +2 -2
- package/src/components/viewer/IDSAuditSummary.tsx +2 -2
- package/src/components/viewer/KeyboardShortcutsDialog.tsx +58 -4
- package/src/components/viewer/MainToolbar.tsx +275 -4
- package/src/components/viewer/PropertiesPanel.tsx +28 -31
- package/src/components/viewer/StatusBar.tsx +12 -0
- package/src/components/viewer/ToolOverlays.tsx +36 -0
- package/src/components/viewer/ViewerLayout.tsx +27 -0
- package/src/components/viewer/Viewport.tsx +49 -4
- package/src/components/viewer/ViewportContainer.tsx +88 -17
- package/src/components/viewer/ViewportOverlays.tsx +50 -11
- package/src/components/viewer/chat/ByokKeyModal.tsx +1 -1
- package/src/components/viewer/properties/FederationAlignmentControls.tsx +180 -0
- package/src/components/viewer/properties/GeoreferencingPanel.tsx +6 -0
- package/src/components/viewer/properties/PrecisionGridBadge.tsx +125 -0
- package/src/components/viewer/properties/raw-step-format.ts +5 -3
- package/src/components/viewer/selectionHandlers.ts +301 -10
- package/src/components/viewer/tools/GizmoOverlay.tsx +322 -0
- package/src/components/viewer/tools/SplitNumericInput.tsx +225 -0
- package/src/components/viewer/tools/SplitOverlay.tsx +242 -0
- package/src/components/viewer/tools/WallEndpointOverlay.tsx +252 -0
- package/src/components/viewer/useGeometryStreaming.ts +100 -1
- package/src/components/viewer/useMouseControls.ts +8 -1
- package/src/hooks/useBCF.ts +6 -6
- package/src/hooks/useCameraTickSubscription.ts +62 -0
- package/src/hooks/useIfc.ts +4 -0
- package/src/hooks/useIfcFederation.ts +368 -20
- package/src/hooks/useKeyboardShortcuts.ts +86 -0
- package/src/hooks/useLevelDisplayEffect.ts +160 -0
- package/src/hooks/useViewerSelectors.ts +8 -0
- package/src/lib/__test__/stubs.ts +110 -0
- package/src/lib/geo/cesium-bridge.ts +3 -3
- package/src/lib/geo/cesium-placement.test.ts +28 -12
- package/src/lib/geo/cesium-placement.ts +16 -10
- package/src/lib/geo/effective-georef.test.ts +23 -7
- package/src/lib/geo/geo-scale.ts +58 -2
- package/src/lib/geo/ifc-origin.test.ts +176 -0
- package/src/lib/geo/ifc-origin.ts +144 -0
- package/src/lib/geo/precision-grids.ts +444 -0
- package/src/lib/geo/reproject.test.ts +88 -0
- package/src/lib/geo/reproject.ts +168 -36
- package/src/lib/level-offsets.test.ts +153 -0
- package/src/lib/level-offsets.ts +140 -0
- package/src/lib/linear-element-edit.test.ts +220 -0
- package/src/lib/linear-element-edit.ts +327 -0
- package/src/lib/metadata-clone.test.ts +173 -0
- package/src/lib/metadata-clone.ts +124 -0
- package/src/lib/placement-core.ts +340 -0
- package/src/lib/placement-edit.boot.ts +21 -0
- package/src/lib/placement-edit.test.ts +464 -0
- package/src/lib/placement-edit.ts +47 -0
- package/src/lib/polygon-clip.test.ts +193 -0
- package/src/lib/polygon-clip.ts +199 -0
- package/src/lib/slab-edit.test.ts +169 -0
- package/src/lib/slab-edit.ts +312 -0
- package/src/lib/wall-edit.ts +342 -0
- package/src/lib/wall-opening-reassign.test.ts +291 -0
- package/src/lib/wall-opening-reassign.ts +241 -0
- package/src/main.tsx +4 -0
- package/src/store/index.ts +7 -0
- package/src/store/slices/cesiumSlice.ts +61 -8
- package/src/store/slices/dataSlice.ts +80 -0
- package/src/store/slices/levelDisplaySlice.ts +105 -0
- package/src/store/slices/modelSlice.test.ts +19 -0
- package/src/store/slices/mutationSlice.ts +1138 -1
- package/src/store/slices/splitToolSlice.ts +165 -0
- package/src/store/slices/uiSlice.edit-mode.test.ts +210 -0
- package/src/store/slices/uiSlice.ts +78 -1
- package/src/store/types.ts +57 -2
- package/src/utils/createBlankIfc.ts +37 -0
- package/tsconfig.json +1 -0
- package/.turbo/turbo-typecheck.log +0 -4
- package/dist/assets/arrow2_bg-BoXCojjR.wasm +0 -0
- package/dist/assets/browser-CVf8ATeW.js +0 -694
- package/dist/assets/emscripten-module-BTRCZGcB.wasm +0 -0
- package/dist/assets/emscripten-module-CGIn_cMh.wasm +0 -0
- package/dist/assets/emscripten-module-DYvzWiHh.wasm +0 -0
- package/dist/assets/emscripten-module-NWak2PoB.wasm +0 -0
- package/dist/assets/emscripten-module.browser-DcFZLAUx.js +0 -1
- package/dist/assets/esbuild-COv63sf-.js +0 -1
- package/dist/assets/event-DIOks52T.js +0 -1
- package/dist/assets/ffi-DlhRHxHv.js +0 -1
- package/dist/assets/ifc-lite_bg-CSeT3fNI.wasm +0 -0
- package/dist/assets/ifc-lite_bg-ns4cSnX2.wasm +0 -0
- package/dist/assets/index-BZC2YaOP.css +0 -1
- package/dist/assets/index-HqAIQkr6.js +0 -22
- package/dist/assets/laz-perf-Cvr_Lepg.js +0 -1
- package/dist/assets/maplibre-gl-C4LXKM6c.js +0 -808
- package/dist/assets/three-DwNDHx9-.js +0 -4049
- package/dist/assets/wasm-bridge-Cha08LdC.js +0 -1
- package/dist/cesium/Workers/chunk-23ZQ2IVV.js +0 -29
- package/dist/cesium/Workers/chunk-2EQO3Q56.js +0 -26
- package/dist/cesium/Workers/chunk-2TE5NTVD.js +0 -26
- package/dist/cesium/Workers/chunk-BXMEEOCS.js +0 -63
- package/dist/cesium/Workers/chunk-BYLCY7GP.js +0 -29
- package/dist/cesium/Workers/chunk-CTHM3W6I.js +0 -26
- package/dist/cesium/Workers/chunk-E3JOOS3S.js +0 -26
- package/dist/cesium/Workers/chunk-F6PRE7D6.js +0 -26
- package/dist/cesium/Workers/chunk-FFBVWF2L.js +0 -26
- package/dist/cesium/Workers/chunk-GBAA6GVX.js +0 -26
- package/dist/cesium/Workers/chunk-ILRYTWTP.js +0 -26
- package/dist/cesium/Workers/chunk-IRNLBSEJ.js +0 -26
- package/dist/cesium/Workers/chunk-L6QHHACZ.js +0 -26
- package/dist/cesium/Workers/chunk-NMVKML6W.js +0 -26
- package/dist/cesium/Workers/chunk-OIRKANTH.js +0 -26
- package/dist/cesium/Workers/chunk-QKUIYMGC.js +0 -28
- package/dist/cesium/Workers/chunk-SQMIIXB7.js +0 -26
- package/dist/cesium/Workers/chunk-TJ4XLGBQ.js +0 -26
- package/dist/cesium/Workers/createCoplanarPolygonOutlineGeometry.js +0 -26
- package/dist/cesium/Workers/createGroundPolylineGeometry.js +0 -26
- package/dist/cesium/Workers/transcodeKTX2.js +0 -56
- package/dist/cesium/Workers/upsampleQuantizedTerrainMesh.js +0 -26
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_0.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_1.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_10.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_11.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_12.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_13.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_14.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_15.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_16.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_17.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_18.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_19.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_2.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_20.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_21.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_22.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_23.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_24.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_25.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_26.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_27.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_3.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_4.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_5.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_6.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_7.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_8.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/IAU2006_XYS/IAU2006_XYS_9.json +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Images/bing_maps_credit.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Images/cesium_credit.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Images/google_earth_credit.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Images/ion-credit.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/LensFlare/DirtMask.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/LensFlare/StarBurst.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/0/0/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/0/1/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/1/0/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/1/0/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/1/1/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/1/1/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/1/2/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/1/2/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/1/3/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/1/3/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/0/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/0/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/0/2.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/0/3.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/1/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/1/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/1/2.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/1/3.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/2/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/2/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/2/2.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/2/3.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/3/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/3/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/3/2.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/3/3.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/4/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/4/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/4/2.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/4/3.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/5/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/5/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/5/2.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/5/3.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/6/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/6/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/6/2.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/6/3.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/7/0.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/7/1.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/7/2.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/2/7/3.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/NaturalEarthII/tilemapresource.xml +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/SkyBox/tycho2t3_80_mx.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/SkyBox/tycho2t3_80_my.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/SkyBox/tycho2t3_80_mz.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/SkyBox/tycho2t3_80_px.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/SkyBox/tycho2t3_80_py.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/SkyBox/tycho2t3_80_pz.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/airfield.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/airport.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/alcohol-shop.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/america-football.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/art-gallery.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/bakery.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/bank.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/bar.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/baseball.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/basketball.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/beer.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/bicycle.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/building.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/bus.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/cafe.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/camera.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/campsite.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/car.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/cemetery.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/cesium.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/chemist.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/cinema.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/circle-stroked.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/circle.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/city.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/clothing-store.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/college.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/commercial.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/cricket.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/cross.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/dam.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/danger.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/disability.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/dog-park.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/embassy.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/emergency-telephone.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/entrance.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/farm.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/fast-food.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/ferry.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/fire-station.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/fuel.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/garden.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/gift.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/golf.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/grocery.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/hairdresser.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/harbor.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/heart.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/heliport.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/hospital.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/ice-cream.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/industrial.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/land-use.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/laundry.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/library.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/lighthouse.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/lodging.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/logging.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/london-underground.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/marker-stroked.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/marker.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/minefield.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/mobilephone.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/monument.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/museum.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/music.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/oil-well.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/park.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/park2.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/parking-garage.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/parking.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/pharmacy.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/pitch.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/place-of-worship.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/playground.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/police.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/polling-place.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/post.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/prison.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/rail-above.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/rail-light.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/rail-metro.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/rail-underground.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/rail.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/religious-christian.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/religious-jewish.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/religious-muslim.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/restaurant.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/roadblock.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/rocket.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/school.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/scooter.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/shop.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/skiing.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/slaughterhouse.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/soccer.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/square-stroked.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/square.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/star-stroked.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/star.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/suitcase.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/swimming.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/telephone.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/tennis.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/theatre.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/toilets.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/town-hall.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/town.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/triangle-stroked.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/triangle.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/village.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/warehouse.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/waste-basket.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/water.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/wetland.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/maki/zoo.png +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/moonSmall.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/pin.svg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/waterNormals.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/Textures/waterNormalsSmall.jpg +0 -0
- /package/dist/cesium/{Assets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Assets}/approximateTerrainHeights.json +0 -0
- /package/dist/cesium/{ThirdParty → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/ThirdParty}/Workers/package.json +0 -0
- /package/dist/cesium/{ThirdParty → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/ThirdParty}/Workers/zip-web-worker.js +0 -0
- /package/dist/cesium/{ThirdParty → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/ThirdParty}/basis_transcoder.wasm +0 -0
- /package/dist/cesium/{ThirdParty → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/ThirdParty}/draco_decoder.wasm +0 -0
- /package/dist/cesium/{ThirdParty → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/ThirdParty}/google-earth-dbroot-parser.js +0 -0
- /package/dist/cesium/{ThirdParty → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/ThirdParty}/wasm_splats_bg.wasm +0 -0
- /package/dist/cesium/{ThirdParty → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/ThirdParty}/zip-module.wasm +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Animation/Animation.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Animation/lighter.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/BaseLayerPicker/BaseLayerPicker.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/BaseLayerPicker/lighter.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Cesium3DTilesInspector/Cesium3DTilesInspector.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/CesiumInspector/CesiumInspector.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/CesiumWidget/CesiumWidget.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/CesiumWidget/lighter.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/FullscreenButton/FullscreenButton.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Geocoder/Geocoder.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Geocoder/lighter.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/I3SBuildingSceneLayerExplorer/I3SBuildingSceneLayerExplorer.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/ArcGisMapServiceWorldHillshade.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/ArcGisMapServiceWorldImagery.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/ArcGisMapServiceWorldOcean.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/azureAerial.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/azureRoads.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/bingAerial.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/bingAerialLabels.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/bingRoads.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/blueMarble.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/earthAtNight.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/googleContour.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/googleRoadmap.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/googleSatellite.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/googleSatelliteLabels.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/mapQuestOpenStreetMap.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/mapboxSatellite.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/mapboxStreets.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/mapboxTerrain.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/naturalEarthII.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/openStreetMap.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/sentinel-2.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/stadiaAlidadeSmooth.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/stadiaAlidadeSmoothDark.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/stamenToner.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/ImageryProviders/stamenWatercolor.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/NavigationHelp/Mouse.svg +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/NavigationHelp/MouseLeft.svg +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/NavigationHelp/MouseMiddle.svg +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/NavigationHelp/MouseRight.svg +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/NavigationHelp/Touch.svg +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/NavigationHelp/TouchDrag.svg +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/NavigationHelp/TouchRotate.svg +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/NavigationHelp/TouchTilt.svg +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/NavigationHelp/TouchZoom.svg +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/TerrainProviders/CesiumWorldTerrain.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/TerrainProviders/Ellipsoid.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/TimelineIcons.png +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Images/info-loading.gif +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/InfoBox/InfoBox.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/InfoBox/InfoBoxDescription.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/NavigationHelpButton/NavigationHelpButton.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/NavigationHelpButton/lighter.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/PerformanceWatchdog/PerformanceWatchdog.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/ProjectionPicker/ProjectionPicker.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/SceneModePicker/SceneModePicker.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/SelectionIndicator/SelectionIndicator.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Timeline/Timeline.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Timeline/lighter.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/VRButton/VRButton.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/Viewer/Viewer.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/VoxelInspector/VoxelInspector.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/lighter.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/lighterShared.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/shared.css +0 -0
- /package/dist/cesium/{Widgets → node_modules/.pnpm/cesium@1.141.0/node_modules/cesium/Build/Cesium/Widgets}/widgets.css +0 -0
|
@@ -41,12 +41,35 @@ import {
|
|
|
41
41
|
type WallInStoreParams,
|
|
42
42
|
type WindowInStoreParams,
|
|
43
43
|
} from '@ifc-lite/create';
|
|
44
|
-
import type
|
|
44
|
+
import { EntityExtractor, type MapConversion, type ProjectedCRS } from '@ifc-lite/parser';
|
|
45
45
|
import type { MeshData } from '@ifc-lite/geometry';
|
|
46
46
|
import { getEntityBounds } from '@/utils/viewportUtils';
|
|
47
47
|
import { toGlobalIdFromModels } from '../globalId.js';
|
|
48
48
|
import { buildElementMesh, type ElementMeshPayload } from './addElementMeshes.js';
|
|
49
49
|
import type { AddElementType } from './addElementSlice.js';
|
|
50
|
+
import {
|
|
51
|
+
resolvePlacementChain,
|
|
52
|
+
resolveRotationState,
|
|
53
|
+
rotateProductYaw,
|
|
54
|
+
resolveWallEditChain,
|
|
55
|
+
resizeRectangleWall,
|
|
56
|
+
computeWallSplitGeometry,
|
|
57
|
+
projectOntoWallAxis,
|
|
58
|
+
} from '@/lib/placement-edit.js';
|
|
59
|
+
import { cloneElementMetadata } from '@/lib/metadata-clone.js';
|
|
60
|
+
import {
|
|
61
|
+
resolveLinearElementChain,
|
|
62
|
+
computeLinearElementSplitGeometry,
|
|
63
|
+
projectOntoLinearAxis,
|
|
64
|
+
type LinearElementType,
|
|
65
|
+
} from '@/lib/linear-element-edit.js';
|
|
66
|
+
import { reassignWallOpenings } from '@/lib/wall-opening-reassign.js';
|
|
67
|
+
import {
|
|
68
|
+
resolveSlabEditChain,
|
|
69
|
+
computeSlabSplitGeometry,
|
|
70
|
+
type SlabLikeType,
|
|
71
|
+
} from '@/lib/slab-edit.js';
|
|
72
|
+
import type { Point2D } from '@/lib/polygon-clip.js';
|
|
50
73
|
|
|
51
74
|
/**
|
|
52
75
|
* IFC-space directions for {@link MutationSlice.duplicateEntity}.
|
|
@@ -167,6 +190,35 @@ export interface MutationSlice {
|
|
|
167
190
|
undoStacks: Map<string, Mutation[]>;
|
|
168
191
|
/** Redo stack per model */
|
|
169
192
|
redoStacks: Map<string, Mutation[]>;
|
|
193
|
+
/**
|
|
194
|
+
* Maps mutationId → batchId. Mutations created via
|
|
195
|
+
* `setPositionalAttributesBatch` share a single batchId so the
|
|
196
|
+
* undo / redo handlers can pop / push them as one atomic
|
|
197
|
+
* step — important for compound operations like `resizeWall`
|
|
198
|
+
* (4 positional writes) where the user expects one Ctrl+Z to
|
|
199
|
+
* undo the whole resize, not unwind through inconsistent
|
|
200
|
+
* intermediate states.
|
|
201
|
+
*
|
|
202
|
+
* Stored as a side-channel on the slice (vs an extra field on
|
|
203
|
+
* the published `Mutation` interface) so the batching is a
|
|
204
|
+
* viewer-local concern and doesn't ripple through @ifc-lite/
|
|
205
|
+
* mutations consumers.
|
|
206
|
+
*/
|
|
207
|
+
mutationBatchTags: Map<string, string>;
|
|
208
|
+
/**
|
|
209
|
+
* Maps mutationId → the renderer-frame mesh translation that
|
|
210
|
+
* accompanied a placement-move mutation (`translateEntity` /
|
|
211
|
+
* `setEntityPosition`). The mutation itself only records the
|
|
212
|
+
* IfcCartesianPoint coordinate change; the rendered mesh moves
|
|
213
|
+
* via a separate `setPendingMeshTranslations` call. Undo / redo
|
|
214
|
+
* of the IFC value alone would leave the 3D mesh stranded at the
|
|
215
|
+
* moved position, so the handlers replay (redo) or negate (undo)
|
|
216
|
+
* the translation recorded here.
|
|
217
|
+
*
|
|
218
|
+
* Side-channel for the same reason as `mutationBatchTags`: keeps
|
|
219
|
+
* the renderer coupling out of the published Mutation interface.
|
|
220
|
+
*/
|
|
221
|
+
mutationMeshTranslations: Map<string, { globalId: number; rendererDelta: [number, number, number] }>;
|
|
170
222
|
/** Models with unsaved changes */
|
|
171
223
|
dirtyModels: Set<string>;
|
|
172
224
|
/** Version counter to trigger re-renders when mutations change */
|
|
@@ -272,11 +324,215 @@ export interface MutationSlice {
|
|
|
272
324
|
index: number,
|
|
273
325
|
value: IfcAttributeValue
|
|
274
326
|
) => Mutation | null;
|
|
327
|
+
/**
|
|
328
|
+
* Atomic batch of positional writes — undo / redo treat the
|
|
329
|
+
* whole list as one operation. Each entry produces a primitive
|
|
330
|
+
* `UPDATE_POSITIONAL_ATTRIBUTE` mutation under the hood (same
|
|
331
|
+
* shape as `setPositionalAttribute` so the undo handler stays
|
|
332
|
+
* uniform), but all entries share a batchId via
|
|
333
|
+
* `mutationBatchTags` so a single Ctrl+Z reverts the entire
|
|
334
|
+
* batch.
|
|
335
|
+
*
|
|
336
|
+
* Used by compound operations like `resizeWall` (4 coordinated
|
|
337
|
+
* positional writes) so the user doesn't have to press Ctrl+Z
|
|
338
|
+
* four times to undo one resize. Returns the batchId so callers
|
|
339
|
+
* can correlate; empty input is a no-op (returns null).
|
|
340
|
+
*/
|
|
341
|
+
setPositionalAttributesBatch: (
|
|
342
|
+
modelId: string,
|
|
343
|
+
updates: Array<{ entityId: number; index: number; value: IfcAttributeValue }>,
|
|
344
|
+
) => string | null;
|
|
275
345
|
/**
|
|
276
346
|
* Tombstone an entity (existing source entity) or forget it (overlay-only).
|
|
277
347
|
* Returns true if the entity was known to the store or overlay.
|
|
278
348
|
*/
|
|
279
349
|
removeEntity: (modelId: string, expressId: number) => boolean;
|
|
350
|
+
/**
|
|
351
|
+
* Translate an IfcProduct by a storey-local delta (IFC Z-up). Walks
|
|
352
|
+
* the placement chain to the terminal `IfcCartesianPoint` and writes
|
|
353
|
+
* the new coordinates via `setPositionalAttribute` so the edit
|
|
354
|
+
* stacks with other overlay mutations and undoes cleanly.
|
|
355
|
+
*
|
|
356
|
+
* Returns `{ ok: false }` for entities whose placement isn't a
|
|
357
|
+
* simple `IfcLocalPlacement → IfcAxis2Placement3D → IfcCartesianPoint`
|
|
358
|
+
* chain (mapped representations, 2D placements, non-product
|
|
359
|
+
* entities). The viewer surfaces the reason as a toast.
|
|
360
|
+
*
|
|
361
|
+
* `batchId` (optional) tags the mutation so a drag that emits
|
|
362
|
+
* many per-frame `translateEntity` calls collapses to one undo
|
|
363
|
+
* step. The gizmo passes one id per drag; omit it for a
|
|
364
|
+
* standalone move (e.g. a single numeric-input commit).
|
|
365
|
+
*/
|
|
366
|
+
translateEntity: (
|
|
367
|
+
modelId: string,
|
|
368
|
+
expressId: number,
|
|
369
|
+
deltaIfc: [number, number, number],
|
|
370
|
+
batchId?: string,
|
|
371
|
+
) => { ok: true; newCoordinates: [number, number, number] } | { ok: false; reason: string };
|
|
372
|
+
/**
|
|
373
|
+
* Absolute version of `translateEntity` — replaces the entity's
|
|
374
|
+
* storey-local position instead of adding a delta. Same chain
|
|
375
|
+
* requirements apply.
|
|
376
|
+
*/
|
|
377
|
+
setEntityPosition: (
|
|
378
|
+
modelId: string,
|
|
379
|
+
expressId: number,
|
|
380
|
+
position: [number, number, number],
|
|
381
|
+
) => { ok: true; newCoordinates: [number, number, number] } | { ok: false; reason: string };
|
|
382
|
+
/**
|
|
383
|
+
* Rotate an IfcProduct about the storey-up Z axis by `deltaYaw`
|
|
384
|
+
* radians. Updates RefDirection on the placement's
|
|
385
|
+
* IfcAxis2Placement3D when one already exists.
|
|
386
|
+
*
|
|
387
|
+
* Refuses with `{ ok: false }` when the entity's placement has
|
|
388
|
+
* no explicit RefDirection (the implicit `[1, 0, 0]` STEP
|
|
389
|
+
* default). Materialising a fresh IfcDirection there would
|
|
390
|
+
* require a multi-mutation atomic undo entry to avoid orphans
|
|
391
|
+
* on undo, which the store doesn't have yet. Every entity
|
|
392
|
+
* emitted by `@ifc-lite/create`'s in-store builders carries an
|
|
393
|
+
* explicit RefDirection, so the refusal only trips on
|
|
394
|
+
* hand-rolled source-buffer entities.
|
|
395
|
+
*/
|
|
396
|
+
rotateEntity: (
|
|
397
|
+
modelId: string,
|
|
398
|
+
expressId: number,
|
|
399
|
+
deltaYaw: number,
|
|
400
|
+
) => { ok: true; newYawZ: number } | { ok: false; reason: string };
|
|
401
|
+
/**
|
|
402
|
+
* Snapshot of the placement's current yaw about Z (radians) plus
|
|
403
|
+
* the metadata the UI needs to render a rotation gizmo. Returns
|
|
404
|
+
* null when the placement chain isn't translatable.
|
|
405
|
+
*/
|
|
406
|
+
readEntityRotation: (
|
|
407
|
+
modelId: string,
|
|
408
|
+
expressId: number,
|
|
409
|
+
) => { yawZ: number; refDirection: [number, number, number] } | null;
|
|
410
|
+
/**
|
|
411
|
+
* Read the entity's storey-local placement coordinates. Returns
|
|
412
|
+
* null when the placement chain isn't a simple
|
|
413
|
+
* `IfcLocalPlacement → IfcAxis2Placement3D → IfcCartesianPoint`
|
|
414
|
+
* (i.e. when `translateEntity` / `setEntityPosition` wouldn't work
|
|
415
|
+
* either). The action lazily creates the `StoreEditor` on first
|
|
416
|
+
* call so it works on a freshly-loaded model that hasn't seen any
|
|
417
|
+
* mutations yet — `MutablePropertyView` is the only thing
|
|
418
|
+
* `PropertiesPanel` registers up front, and the editor is a thin
|
|
419
|
+
* facade we can build on demand. Pairing the gate condition with
|
|
420
|
+
* the existing read-actions keeps "is this entity movable?" and
|
|
421
|
+
* "what are its coords?" answered by the same code path.
|
|
422
|
+
*/
|
|
423
|
+
readEntityPosition: (
|
|
424
|
+
modelId: string,
|
|
425
|
+
expressId: number,
|
|
426
|
+
) => [number, number, number] | null;
|
|
427
|
+
/**
|
|
428
|
+
* Resize a rectangular-profile wall by setting new start AND end
|
|
429
|
+
* points. Atomically updates the placement origin, RefDirection,
|
|
430
|
+
* profile length, and profile origin. Returns null for walls that
|
|
431
|
+
* don't follow the `addWallToStore` shape.
|
|
432
|
+
*/
|
|
433
|
+
resizeWall: (
|
|
434
|
+
modelId: string,
|
|
435
|
+
expressId: number,
|
|
436
|
+
newStart: [number, number, number],
|
|
437
|
+
newEnd: [number, number, number],
|
|
438
|
+
) => { ok: true; newLength: number } | { ok: false; reason: string };
|
|
439
|
+
/**
|
|
440
|
+
* Read a wall's current start/end so the UI can render endpoint
|
|
441
|
+
* handles. Returns null for non-rectangle walls.
|
|
442
|
+
*/
|
|
443
|
+
readWallEndpoints: (
|
|
444
|
+
modelId: string,
|
|
445
|
+
expressId: number,
|
|
446
|
+
) => { start: [number, number, number]; end: [number, number, number]; thickness: number } | null;
|
|
447
|
+
/**
|
|
448
|
+
* Split a rectangle-profile wall into two walls at `distance`
|
|
449
|
+
* metres along its axis (measured from the wall's start). Produces
|
|
450
|
+
* two new walls inheriting the source's Pset / Qto / classification
|
|
451
|
+
* / material / type relationships, then tombstones the source.
|
|
452
|
+
*
|
|
453
|
+
* Returns the two new walls' express ids and federation global
|
|
454
|
+
* ids on success. On failure (non-rectangle wall, distance too
|
|
455
|
+
* close to an end, missing storey, etc.) returns a descriptive
|
|
456
|
+
* reason for the UI to surface.
|
|
457
|
+
*
|
|
458
|
+
* Undo posture: the action lands as three primitive mutations on
|
|
459
|
+
* the model's undo stack (one per new wall create, one for the
|
|
460
|
+
* source delete), so a full revert needs three Ctrl+Z presses
|
|
461
|
+
* today. A batched-mutation primitive that collapses this to one
|
|
462
|
+
* step is on the follow-up list from PR #723.
|
|
463
|
+
*/
|
|
464
|
+
splitWallAtDistance: (
|
|
465
|
+
modelId: string,
|
|
466
|
+
expressId: number,
|
|
467
|
+
distanceFromStart: number,
|
|
468
|
+
) => { ok: true; left: { expressId: number; globalId: number }; right: { expressId: number; globalId: number }; openings: { toLeft: number; toRight: number; skipped: number } } | { ok: false; reason: string };
|
|
469
|
+
/**
|
|
470
|
+
* Read-only helper for the Split-tool live preview: projects an
|
|
471
|
+
* arbitrary storey-local 3D cursor onto the wall axis and returns
|
|
472
|
+
* how far along the wall (in metres from start) it lands, plus
|
|
473
|
+
* the wall's total length so the UI can show "1.42 m / 3.50 m".
|
|
474
|
+
*
|
|
475
|
+
* Returns null when the entity isn't a resizable wall.
|
|
476
|
+
*/
|
|
477
|
+
readWallSplitProjection: (
|
|
478
|
+
modelId: string,
|
|
479
|
+
expressId: number,
|
|
480
|
+
cursorStoreyLocal: [number, number, number],
|
|
481
|
+
) => { distance: number; length: number; cutPoint: [number, number, number]; axis: [number, number, number] } | null;
|
|
482
|
+
/**
|
|
483
|
+
* Split a linear element (`IfcBeam` / `IfcColumn` / `IfcMember`)
|
|
484
|
+
* at `distance` metres from start. Unlike walls, the source's
|
|
485
|
+
* extrusion is shrunk in place so the "left" half keeps the
|
|
486
|
+
* source's GlobalId and Pset rels — the choice is forced by the
|
|
487
|
+
* IFC representation (length lives on the extrusion `Depth`, not
|
|
488
|
+
* on the profile XDim), so one positional write covers it. A new
|
|
489
|
+
* element is added at the cut point to carry the "right" half.
|
|
490
|
+
*/
|
|
491
|
+
splitLinearElementAtDistance: (
|
|
492
|
+
modelId: string,
|
|
493
|
+
expressId: number,
|
|
494
|
+
distanceFromStart: number,
|
|
495
|
+
) => { ok: true; source: { expressId: number; globalId: number }; right: { expressId: number; globalId: number } } | { ok: false; reason: string };
|
|
496
|
+
/**
|
|
497
|
+
* Linear-element analogue of `readWallSplitProjection`. Returns
|
|
498
|
+
* null when the entity isn't an `addBeam` / `addColumn` /
|
|
499
|
+
* `addMember` -shaped element.
|
|
500
|
+
*/
|
|
501
|
+
readLinearElementSplitProjection: (
|
|
502
|
+
modelId: string,
|
|
503
|
+
expressId: number,
|
|
504
|
+
cursorStoreyLocal: [number, number, number],
|
|
505
|
+
) => { distance: number; length: number; cutPoint: [number, number, number]; axis: [number, number, number]; elementType: LinearElementType } | null;
|
|
506
|
+
/**
|
|
507
|
+
* Read a slab-like element's storey-local footprint polygon so
|
|
508
|
+
* the Split overlay can render the live cut-line preview. The
|
|
509
|
+
* footprint comes back in storey-local 2D (XY) with the
|
|
510
|
+
* placement origin already added. Returns null for non-slab
|
|
511
|
+
* selections or representations the chain resolver doesn't
|
|
512
|
+
* support (mapped shapes, tessellated faces, etc).
|
|
513
|
+
*/
|
|
514
|
+
readSlabFootprint: (
|
|
515
|
+
modelId: string,
|
|
516
|
+
expressId: number,
|
|
517
|
+
) => { footprint: Point2D[]; elementType: SlabLikeType; storeyElevation: number; thickness: number } | null;
|
|
518
|
+
/**
|
|
519
|
+
* Split a slab-like element (IfcSlab / IfcRoof / IfcPlate /
|
|
520
|
+
* IfcSpace) along a cut line defined by two storey-local 2D
|
|
521
|
+
* points. Builds two fresh elements with the clipped footprints
|
|
522
|
+
* (polygon-mode `IfcArbitraryClosedProfileDef` even when the
|
|
523
|
+
* source was a rectangle — most cuts produce non-rectangular
|
|
524
|
+
* halves), clones metadata onto both, then tombstones the
|
|
525
|
+
* source.
|
|
526
|
+
*
|
|
527
|
+
* Selection moves to whichever half contains the second click,
|
|
528
|
+
* so the user can keep editing the new piece immediately.
|
|
529
|
+
*/
|
|
530
|
+
splitSlabByLine: (
|
|
531
|
+
modelId: string,
|
|
532
|
+
expressId: number,
|
|
533
|
+
cutA: [number, number],
|
|
534
|
+
cutB: [number, number],
|
|
535
|
+
) => { ok: true; left: { expressId: number; globalId: number }; right: { expressId: number; globalId: number } } | { ok: false; reason: string };
|
|
280
536
|
/**
|
|
281
537
|
* Add a fully-anchored IfcColumn (and its sub-graph) to a parsed model.
|
|
282
538
|
* Returns the new column's expressId, or null if the model can't be
|
|
@@ -441,6 +697,160 @@ function getOrCreateStoreEditor(
|
|
|
441
697
|
return editor;
|
|
442
698
|
}
|
|
443
699
|
|
|
700
|
+
/**
|
|
701
|
+
* IfcBuildingStorey.ObjectPlacement is optional in the schema —
|
|
702
|
+
* some authoring tools leave it null when the file was never
|
|
703
|
+
* meant to host geometry. Authoring actions need a placement to
|
|
704
|
+
* anchor their new entities against, so we materialise a default
|
|
705
|
+
* IfcLocalPlacement at the storey's elevation when one's missing
|
|
706
|
+
* and patch the storey's attribute via the overlay.
|
|
707
|
+
*
|
|
708
|
+
* Idempotent: if the storey already has a placement (number or
|
|
709
|
+
* `#X` string ref), this is a no-op. Returns true when a
|
|
710
|
+
* placement was created.
|
|
711
|
+
*/
|
|
712
|
+
function ensureStoreyPlacement(
|
|
713
|
+
dataStore: import('@ifc-lite/parser').IfcDataStore,
|
|
714
|
+
editor: StoreEditor,
|
|
715
|
+
storeyExpressId: number,
|
|
716
|
+
): boolean {
|
|
717
|
+
// Pull the storey's current attributes (overlay overrides + source).
|
|
718
|
+
const overlay = editor.getNewEntity(storeyExpressId);
|
|
719
|
+
let attrs: unknown[];
|
|
720
|
+
if (overlay) {
|
|
721
|
+
attrs = overlay.attributes.slice();
|
|
722
|
+
} else {
|
|
723
|
+
const ref = dataStore.entityIndex.byId.get(storeyExpressId);
|
|
724
|
+
if (!ref) return false;
|
|
725
|
+
const extractor = new EntityExtractor(dataStore.source);
|
|
726
|
+
const entity = extractor.extractEntity(ref);
|
|
727
|
+
if (!entity) return false;
|
|
728
|
+
attrs = entity.attributes.slice();
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// IfcProduct.ObjectPlacement is at index 5 across IFC2X3 / IFC4.
|
|
732
|
+
// Accept both number refs and `#X` strings as "already present".
|
|
733
|
+
const existing = attrs[5];
|
|
734
|
+
if (typeof existing === 'number' && Number.isFinite(existing)) return false;
|
|
735
|
+
if (typeof existing === 'string' && existing.startsWith('#')) return false;
|
|
736
|
+
|
|
737
|
+
// Build a fresh placement at world origin. The storey's elevation
|
|
738
|
+
// (if any) carries through the geometry pipeline elsewhere; this
|
|
739
|
+
// placement gives the IFC graph what resolveSpatialAnchor needs.
|
|
740
|
+
const elevation = dataStore.spatialHierarchy?.storeyElevations?.get(storeyExpressId) ?? 0;
|
|
741
|
+
const originPt = editor.addEntity('IfcCartesianPoint', [[0, 0, elevation]]).expressId;
|
|
742
|
+
const axisPlacement = editor.addEntity('IfcAxis2Placement3D', [`#${originPt}`, null, null]).expressId;
|
|
743
|
+
const localPlacement = editor.addEntity('IfcLocalPlacement', [null, `#${axisPlacement}`]).expressId;
|
|
744
|
+
|
|
745
|
+
editor.setPositionalAttribute(storeyExpressId, 5, `#${localPlacement}`);
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Resolve the (view, editor, dataStore, storey) tuple that every
|
|
751
|
+
* splitWall / splitLinearElement / splitSlab action needs. Returns
|
|
752
|
+
* an error result with a stable message when any piece is missing
|
|
753
|
+
* so each action's preamble collapses to a single early-return.
|
|
754
|
+
*
|
|
755
|
+
* Pass `requireStorey: false` when the caller resolves storey from
|
|
756
|
+
* a different source (none currently — but the flag keeps the
|
|
757
|
+
* helper reusable for non-storey-bound split-like flows).
|
|
758
|
+
*/
|
|
759
|
+
type SplitContext = {
|
|
760
|
+
view: MutablePropertyView;
|
|
761
|
+
editor: StoreEditor;
|
|
762
|
+
dataStore: import('@ifc-lite/parser').IfcDataStore;
|
|
763
|
+
storeyExpressId: number;
|
|
764
|
+
};
|
|
765
|
+
function resolveSplitContext(
|
|
766
|
+
get: () => ViewerState,
|
|
767
|
+
set: (partial: Partial<ViewerState> | ((s: ViewerState) => Partial<ViewerState>)) => void,
|
|
768
|
+
modelId: string,
|
|
769
|
+
expressId: number,
|
|
770
|
+
notInStoreyMessage: string,
|
|
771
|
+
): SplitContext | { ok: false; reason: string } {
|
|
772
|
+
const state = get();
|
|
773
|
+
const view = state.mutationViews.get(modelId);
|
|
774
|
+
if (!view) return { ok: false, reason: 'Model has no editable mutation view yet' };
|
|
775
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
776
|
+
if (!editor) return { ok: false, reason: 'Failed to resolve store editor' };
|
|
777
|
+
const dataStore = state.models.get(modelId)?.ifcDataStore;
|
|
778
|
+
if (!dataStore) return { ok: false, reason: `No model loaded for id "${modelId}"` };
|
|
779
|
+
const storeyExpressId = dataStore.spatialHierarchy?.elementToStorey.get(expressId);
|
|
780
|
+
if (storeyExpressId === undefined) return { ok: false, reason: notInStoreyMessage };
|
|
781
|
+
return { view, editor, dataStore, storeyExpressId };
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Rollback helper for failed atomic operations (e.g. split where
|
|
786
|
+
* the left half was created but the right half's builder threw).
|
|
787
|
+
*
|
|
788
|
+
* Pops the most recent CREATE_ENTITY mutation for `expressId` off
|
|
789
|
+
* the model's undo stack, removes the overlay record via
|
|
790
|
+
* `view.deleteEntity`, and queues the renderer mesh for removal.
|
|
791
|
+
* No DELETE_ENTITY mutation is recorded — the operation never
|
|
792
|
+
* happened from the user's perspective, so the undo history is
|
|
793
|
+
* left clean (Ctrl+Z after a failed split shouldn't bring back
|
|
794
|
+
* the orphan half).
|
|
795
|
+
*
|
|
796
|
+
* Returns true when at least one undo entry was popped.
|
|
797
|
+
*/
|
|
798
|
+
function rollbackOverlayCreate(
|
|
799
|
+
get: () => ViewerState,
|
|
800
|
+
set: (partial: Partial<ViewerState> | ((s: ViewerState) => Partial<ViewerState>)) => void,
|
|
801
|
+
modelId: string,
|
|
802
|
+
expressId: number,
|
|
803
|
+
): boolean {
|
|
804
|
+
const state = get();
|
|
805
|
+
const view = state.mutationViews.get(modelId);
|
|
806
|
+
const editor = state.storeEditors.get(modelId);
|
|
807
|
+
if (!view || !editor) return false;
|
|
808
|
+
|
|
809
|
+
// Drop the entity from the overlay. The view.deleteEntity call
|
|
810
|
+
// is silent for already-gone entities — safe even if the caller
|
|
811
|
+
// gets the rollback path wrong.
|
|
812
|
+
editor.removeEntity(expressId);
|
|
813
|
+
|
|
814
|
+
// Pop the matching CREATE_ENTITY entry off the undo stack. The
|
|
815
|
+
// split flow always rolls back immediately after the failed
|
|
816
|
+
// create, so the entry is at top-of-stack — fast-path that case
|
|
817
|
+
// with a single `pop()`-style slice and only fall back to the
|
|
818
|
+
// linear scan if a follow-up mutation slipped in between.
|
|
819
|
+
set((s) => {
|
|
820
|
+
const stacks = new Map(s.undoStacks);
|
|
821
|
+
const stack = stacks.get(modelId);
|
|
822
|
+
if (!stack || stack.length === 0) return {};
|
|
823
|
+
const top = stack[stack.length - 1];
|
|
824
|
+
if (top.type === 'CREATE_ENTITY' && top.entityId === expressId) {
|
|
825
|
+
stacks.set(modelId, stack.slice(0, -1));
|
|
826
|
+
return {
|
|
827
|
+
undoStacks: stacks,
|
|
828
|
+
mutationVersion: s.mutationVersion + 1,
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
for (let i = stack.length - 2; i >= 0; i--) {
|
|
832
|
+
const m = stack[i];
|
|
833
|
+
if (m.type === 'CREATE_ENTITY' && m.entityId === expressId) {
|
|
834
|
+
const next = stack.slice();
|
|
835
|
+
next.splice(i, 1);
|
|
836
|
+
stacks.set(modelId, next);
|
|
837
|
+
return {
|
|
838
|
+
undoStacks: stacks,
|
|
839
|
+
mutationVersion: s.mutationVersion + 1,
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
return {};
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
// Drop the entity's mesh from the renderer so the user doesn't
|
|
847
|
+
// see a phantom half-element after the failed split. Uses the
|
|
848
|
+
// existing pendingMeshRemovals channel (same as Phase A).
|
|
849
|
+
const globalId = toGlobalIdFromModels(state.models, modelId, expressId);
|
|
850
|
+
state.setPendingMeshRemovals(new Set([globalId]));
|
|
851
|
+
return true;
|
|
852
|
+
}
|
|
853
|
+
|
|
444
854
|
/**
|
|
445
855
|
* Shared dispatcher for the wall/slab/beam in-store builders. Mirrors the
|
|
446
856
|
* structure of `addColumn` (resolve store/view/editor/anchor → run the
|
|
@@ -468,6 +878,15 @@ function runInStoreElementBuilder(
|
|
|
468
878
|
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
469
879
|
if (!editor) return { error: 'Failed to create store editor' };
|
|
470
880
|
|
|
881
|
+
// Some source IFC files leave IfcBuildingStorey.ObjectPlacement
|
|
882
|
+
// null (it's optional in the schema). Without a placement,
|
|
883
|
+
// resolveSpatialAnchor throws "storey #N has no resolvable
|
|
884
|
+
// IfcLocalPlacement" — but a fresh IfcLocalPlacement at the
|
|
885
|
+
// origin is a valid default. Materialise one before the anchor
|
|
886
|
+
// walk so the user's authoring action doesn't get blocked by
|
|
887
|
+
// missing-but-recoverable IFC structure.
|
|
888
|
+
ensureStoreyPlacement(dataStore, editor, storeyExpressId);
|
|
889
|
+
|
|
471
890
|
let entityId: number;
|
|
472
891
|
try {
|
|
473
892
|
const anchor = resolveSpatialAnchor(dataStore, storeyExpressId);
|
|
@@ -575,6 +994,8 @@ export const createMutationSlice: StateCreator<
|
|
|
575
994
|
activeChangeSetId: null,
|
|
576
995
|
undoStacks: new Map(),
|
|
577
996
|
redoStacks: new Map(),
|
|
997
|
+
mutationBatchTags: new Map(),
|
|
998
|
+
mutationMeshTranslations: new Map(),
|
|
578
999
|
dirtyModels: new Set(),
|
|
579
1000
|
mutationVersion: 0,
|
|
580
1001
|
georefMutations: new Map(),
|
|
@@ -921,6 +1342,653 @@ export const createMutationSlice: StateCreator<
|
|
|
921
1342
|
return stack ? stack[stack.length - 1] : null;
|
|
922
1343
|
},
|
|
923
1344
|
|
|
1345
|
+
setPositionalAttributesBatch: (modelId, updates) => {
|
|
1346
|
+
if (updates.length === 0) return null;
|
|
1347
|
+
// Generate the batch id once; every mutation created below
|
|
1348
|
+
// gets tagged with it so the undo / redo handlers can group
|
|
1349
|
+
// them. `crypto.randomUUID` is available in every browser the
|
|
1350
|
+
// viewer supports and avoids the collision risk of
|
|
1351
|
+
// Date.now() + Math.random concatenation.
|
|
1352
|
+
const batchId = `batch_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
1353
|
+
const tags = new Map(get().mutationBatchTags);
|
|
1354
|
+
for (const { entityId, index, value } of updates) {
|
|
1355
|
+
const mutation = get().setPositionalAttribute(modelId, entityId, index, value);
|
|
1356
|
+
if (mutation) tags.set(mutation.id, batchId);
|
|
1357
|
+
}
|
|
1358
|
+
set({ mutationBatchTags: tags });
|
|
1359
|
+
return batchId;
|
|
1360
|
+
},
|
|
1361
|
+
|
|
1362
|
+
translateEntity: (modelId, expressId, delta, batchId) => {
|
|
1363
|
+
// Read the existing placement chain WITHOUT committing the edit
|
|
1364
|
+
// yet — we'll route the actual write through `setPositionalAttribute`
|
|
1365
|
+
// below so undo/redo + dirty-tracking come for free.
|
|
1366
|
+
const view = get().mutationViews.get(modelId);
|
|
1367
|
+
if (!view) return { ok: false, reason: 'Model has no editable mutation view yet' };
|
|
1368
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
1369
|
+
if (!editor) return { ok: false, reason: 'Failed to resolve store editor' };
|
|
1370
|
+
const dataStore = get().models.get(modelId)?.ifcDataStore;
|
|
1371
|
+
if (!dataStore) return { ok: false, reason: `No model loaded for id "${modelId}"` };
|
|
1372
|
+
|
|
1373
|
+
const chain = resolvePlacementChain(dataStore, view, editor, expressId);
|
|
1374
|
+
if (!chain) {
|
|
1375
|
+
return {
|
|
1376
|
+
ok: false,
|
|
1377
|
+
reason:
|
|
1378
|
+
'Entity placement is not a simple IfcLocalPlacement → IfcAxis2Placement3D → IfcCartesianPoint chain',
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
const [x, y, z] = chain.coordinates;
|
|
1382
|
+
const next: [number, number, number] = [x + delta[0], y + delta[1], z + delta[2]];
|
|
1383
|
+
// Go through the slice's own `setPositionalAttribute` action so
|
|
1384
|
+
// the mutation lands on the undo stack with the standard envelope.
|
|
1385
|
+
const mutation = get().setPositionalAttribute(modelId, chain.cartesianPointId, 0, next);
|
|
1386
|
+
|
|
1387
|
+
// Push the renderer-frame delta so the visible mesh follows
|
|
1388
|
+
// the IFC mutation. IFC is Z-up; renderer is Y-up. Conversion:
|
|
1389
|
+
// renderer.x = ifc.x
|
|
1390
|
+
// renderer.y = ifc.z
|
|
1391
|
+
// renderer.z = -ifc.y
|
|
1392
|
+
const globalId = toGlobalIdFromModels(get().models, modelId, expressId);
|
|
1393
|
+
const rendererDelta: [number, number, number] = [delta[0], delta[2], -delta[1]];
|
|
1394
|
+
get().setPendingMeshTranslations(new Map([[globalId, rendererDelta]]));
|
|
1395
|
+
|
|
1396
|
+
// Record the mesh translation against the mutation id so undo /
|
|
1397
|
+
// redo can move the rendered mesh back / forward — the mutation
|
|
1398
|
+
// alone only carries the IfcCartesianPoint coordinate change.
|
|
1399
|
+
// When a `batchId` is supplied (gizmo drag), tag the mutation so
|
|
1400
|
+
// all the drag's per-frame translates collapse to one undo step.
|
|
1401
|
+
if (mutation) {
|
|
1402
|
+
const meshTags = new Map(get().mutationMeshTranslations);
|
|
1403
|
+
meshTags.set(mutation.id, { globalId, rendererDelta });
|
|
1404
|
+
if (batchId) {
|
|
1405
|
+
const batchTags = new Map(get().mutationBatchTags);
|
|
1406
|
+
batchTags.set(mutation.id, batchId);
|
|
1407
|
+
set({ mutationMeshTranslations: meshTags, mutationBatchTags: batchTags });
|
|
1408
|
+
} else {
|
|
1409
|
+
set({ mutationMeshTranslations: meshTags });
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
return { ok: true, newCoordinates: next };
|
|
1414
|
+
},
|
|
1415
|
+
|
|
1416
|
+
setEntityPosition: (modelId, expressId, position) => {
|
|
1417
|
+
const view = get().mutationViews.get(modelId);
|
|
1418
|
+
if (!view) return { ok: false, reason: 'Model has no editable mutation view yet' };
|
|
1419
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
1420
|
+
if (!editor) return { ok: false, reason: 'Failed to resolve store editor' };
|
|
1421
|
+
const dataStore = get().models.get(modelId)?.ifcDataStore;
|
|
1422
|
+
if (!dataStore) return { ok: false, reason: `No model loaded for id "${modelId}"` };
|
|
1423
|
+
|
|
1424
|
+
const chain = resolvePlacementChain(dataStore, view, editor, expressId);
|
|
1425
|
+
if (!chain) {
|
|
1426
|
+
return {
|
|
1427
|
+
ok: false,
|
|
1428
|
+
reason:
|
|
1429
|
+
'Entity placement is not a simple IfcLocalPlacement → IfcAxis2Placement3D → IfcCartesianPoint chain',
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
// Push the IFC → renderer delta for the rendered mesh. Same
|
|
1433
|
+
// Z-up → Y-up conversion as `translateEntity` above.
|
|
1434
|
+
const [oldX, oldY, oldZ] = chain.coordinates;
|
|
1435
|
+
const dx = position[0] - oldX;
|
|
1436
|
+
const dy = position[1] - oldY;
|
|
1437
|
+
const dz = position[2] - oldZ;
|
|
1438
|
+
const mutation = get().setPositionalAttribute(modelId, chain.cartesianPointId, 0, position);
|
|
1439
|
+
if (dx !== 0 || dy !== 0 || dz !== 0) {
|
|
1440
|
+
const globalId = toGlobalIdFromModels(get().models, modelId, expressId);
|
|
1441
|
+
const rendererDelta: [number, number, number] = [dx, dz, -dy];
|
|
1442
|
+
get().setPendingMeshTranslations(new Map([[globalId, rendererDelta]]));
|
|
1443
|
+
// Record so undo / redo can move the rendered mesh — see the
|
|
1444
|
+
// matching note in `translateEntity`.
|
|
1445
|
+
if (mutation) {
|
|
1446
|
+
const tags = new Map(get().mutationMeshTranslations);
|
|
1447
|
+
tags.set(mutation.id, { globalId, rendererDelta });
|
|
1448
|
+
set({ mutationMeshTranslations: tags });
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
return { ok: true, newCoordinates: position };
|
|
1452
|
+
},
|
|
1453
|
+
|
|
1454
|
+
rotateEntity: (modelId, expressId, deltaYaw) => {
|
|
1455
|
+
const view = get().mutationViews.get(modelId);
|
|
1456
|
+
if (!view) return { ok: false, reason: 'Model has no editable mutation view yet' };
|
|
1457
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
1458
|
+
if (!editor) return { ok: false, reason: 'Failed to resolve store editor' };
|
|
1459
|
+
const dataStore = get().models.get(modelId)?.ifcDataStore;
|
|
1460
|
+
if (!dataStore) return { ok: false, reason: `No model loaded for id "${modelId}"` };
|
|
1461
|
+
|
|
1462
|
+
// resolveRotationState gives us both the current angle and
|
|
1463
|
+
// whether RefDirection is explicit. When it's null we refuse
|
|
1464
|
+
// — see the interface comment above for why; materialising
|
|
1465
|
+
// would require multi-mutation atomic undo to avoid orphans.
|
|
1466
|
+
// Every in-store builder emits an explicit RefDirection, so
|
|
1467
|
+
// this only trips on hand-rolled source-buffer entities.
|
|
1468
|
+
const state = resolveRotationState(dataStore, view, editor, expressId);
|
|
1469
|
+
if (!state) {
|
|
1470
|
+
return {
|
|
1471
|
+
ok: false,
|
|
1472
|
+
reason:
|
|
1473
|
+
'Entity placement is not a simple IfcLocalPlacement → IfcAxis2Placement3D chain',
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
if (state.refDirectionId === null) {
|
|
1477
|
+
// Implicit RefDirection means the axis placement points at no
|
|
1478
|
+
// IfcDirection — STEP `$` slot. Materialising a fresh
|
|
1479
|
+
// IfcDirection here would require a multi-mutation atomic undo
|
|
1480
|
+
// entry to avoid orphans; we don't have that primitive yet.
|
|
1481
|
+
// In practice every entity our in-store builders emit
|
|
1482
|
+
// (addColumn / addWall / addSlab / …) carries an explicit
|
|
1483
|
+
// RefDirection, so this branch only trips on hand-rolled
|
|
1484
|
+
// source-buffer entities. Surface a clear refusal so the UI
|
|
1485
|
+
// can show "rotate not supported for this entity" rather than
|
|
1486
|
+
// silently leaking entities.
|
|
1487
|
+
return {
|
|
1488
|
+
ok: false,
|
|
1489
|
+
reason:
|
|
1490
|
+
'Entity has an implicit reference direction (no IfcDirection on its axis placement). Rotation would require materialising a new IfcDirection, which isn\'t undoable yet.',
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
const newYaw = state.yawZ + deltaYaw;
|
|
1494
|
+
const newRatios: [number, number, number] = [
|
|
1495
|
+
Math.cos(newYaw),
|
|
1496
|
+
Math.sin(newYaw),
|
|
1497
|
+
state.refDirection[2],
|
|
1498
|
+
];
|
|
1499
|
+
get().setPositionalAttribute(modelId, state.refDirectionId, 0, newRatios);
|
|
1500
|
+
return { ok: true, newYawZ: newYaw };
|
|
1501
|
+
},
|
|
1502
|
+
|
|
1503
|
+
readEntityRotation: (modelId, expressId) => {
|
|
1504
|
+
// Lazy editor creation — see the note on `readEntityPosition`
|
|
1505
|
+
// below. A freshly-loaded model has a mutation view but no
|
|
1506
|
+
// cached editor; building one on read so the rotation UI lights
|
|
1507
|
+
// up on first selection, not after the first unrelated edit.
|
|
1508
|
+
const view = get().mutationViews.get(modelId);
|
|
1509
|
+
if (!view) return null;
|
|
1510
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
1511
|
+
if (!editor) return null;
|
|
1512
|
+
const dataStore = get().models.get(modelId)?.ifcDataStore;
|
|
1513
|
+
if (!dataStore) return null;
|
|
1514
|
+
const state = resolveRotationState(dataStore, view, editor, expressId);
|
|
1515
|
+
if (!state) return null;
|
|
1516
|
+
return { yawZ: state.yawZ, refDirection: state.refDirection };
|
|
1517
|
+
},
|
|
1518
|
+
|
|
1519
|
+
readEntityPosition: (modelId, expressId) => {
|
|
1520
|
+
// Mirror of `readEntityRotation`'s lazy-create pattern. Used by
|
|
1521
|
+
// `GeometryEditCard` to seed its inputs AND by `GizmoOverlay`
|
|
1522
|
+
// as its "is this entity movable?" gate — one code path means
|
|
1523
|
+
// the controls and the visual gizmo agree on availability.
|
|
1524
|
+
const view = get().mutationViews.get(modelId);
|
|
1525
|
+
if (!view) return null;
|
|
1526
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
1527
|
+
if (!editor) return null;
|
|
1528
|
+
const dataStore = get().models.get(modelId)?.ifcDataStore;
|
|
1529
|
+
if (!dataStore) return null;
|
|
1530
|
+
const chain = resolvePlacementChain(dataStore, view, editor, expressId);
|
|
1531
|
+
return chain ? chain.coordinates : null;
|
|
1532
|
+
},
|
|
1533
|
+
|
|
1534
|
+
resizeWall: (modelId, expressId, newStart, newEnd) => {
|
|
1535
|
+
const view = get().mutationViews.get(modelId);
|
|
1536
|
+
if (!view) return { ok: false, reason: 'Model has no editable mutation view yet' };
|
|
1537
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
1538
|
+
if (!editor) return { ok: false, reason: 'Failed to resolve store editor' };
|
|
1539
|
+
const dataStore = get().models.get(modelId)?.ifcDataStore;
|
|
1540
|
+
if (!dataStore) return { ok: false, reason: `No model loaded for id "${modelId}"` };
|
|
1541
|
+
|
|
1542
|
+
// resolveWallEditChain reads all four ids without mutating.
|
|
1543
|
+
// The four writes are then committed as a single atomic batch
|
|
1544
|
+
// via setPositionalAttributesBatch — one Ctrl+Z reverts the
|
|
1545
|
+
// whole resize, no walking through inconsistent intermediate
|
|
1546
|
+
// wall states.
|
|
1547
|
+
const chain = resolveWallEditChain(dataStore, view, editor, expressId);
|
|
1548
|
+
if (!chain) {
|
|
1549
|
+
return {
|
|
1550
|
+
ok: false,
|
|
1551
|
+
reason:
|
|
1552
|
+
'Wall does not have a simple IfcRectangleProfileDef → IfcExtrudedAreaSolid representation',
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
const dx = newEnd[0] - newStart[0];
|
|
1556
|
+
const dy = newEnd[1] - newStart[1];
|
|
1557
|
+
const dz = newEnd[2] - newStart[2];
|
|
1558
|
+
const length = Math.hypot(dx, dy);
|
|
1559
|
+
if (length < 1e-6) return { ok: false, reason: 'Wall length must be greater than zero' };
|
|
1560
|
+
if (Math.abs(dz) > Math.max(1e-6 * length, 1e-9)) {
|
|
1561
|
+
return { ok: false, reason: 'Start and end must lie on the same storey plane' };
|
|
1562
|
+
}
|
|
1563
|
+
const dir: [number, number, number] = [dx / length, dy / length, 0];
|
|
1564
|
+
|
|
1565
|
+
get().setPositionalAttributesBatch(modelId, [
|
|
1566
|
+
{ entityId: chain.startPointId, index: 0, value: newStart },
|
|
1567
|
+
{ entityId: chain.refDirectionId, index: 0, value: dir },
|
|
1568
|
+
{ entityId: chain.profileId, index: 3, value: length },
|
|
1569
|
+
{ entityId: chain.profileOriginPointId, index: 0, value: [length / 2, 0] },
|
|
1570
|
+
]);
|
|
1571
|
+
|
|
1572
|
+
return { ok: true, newLength: length };
|
|
1573
|
+
},
|
|
1574
|
+
|
|
1575
|
+
readWallEndpoints: (modelId, expressId) => {
|
|
1576
|
+
// Same lazy-create pattern as `readEntityRotation` /
|
|
1577
|
+
// `readEntityPosition` — handles need to surface on first
|
|
1578
|
+
// selection, not after an unrelated mutation has primed the
|
|
1579
|
+
// editor cache.
|
|
1580
|
+
const view = get().mutationViews.get(modelId);
|
|
1581
|
+
if (!view) return null;
|
|
1582
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
1583
|
+
if (!editor) return null;
|
|
1584
|
+
const dataStore = get().models.get(modelId)?.ifcDataStore;
|
|
1585
|
+
if (!dataStore) return null;
|
|
1586
|
+
const chain = resolveWallEditChain(dataStore, view, editor, expressId);
|
|
1587
|
+
if (!chain) return null;
|
|
1588
|
+
const [sx, sy, sz] = chain.startCoordinates;
|
|
1589
|
+
const [dx, dy, dz] = chain.refDirection;
|
|
1590
|
+
const end: [number, number, number] = [
|
|
1591
|
+
sx + dx * chain.wallLength,
|
|
1592
|
+
sy + dy * chain.wallLength,
|
|
1593
|
+
sz + dz * chain.wallLength,
|
|
1594
|
+
];
|
|
1595
|
+
return { start: [sx, sy, sz], end, thickness: chain.thickness };
|
|
1596
|
+
},
|
|
1597
|
+
|
|
1598
|
+
readWallSplitProjection: (modelId, expressId, cursorStoreyLocal) => {
|
|
1599
|
+
const view = get().mutationViews.get(modelId);
|
|
1600
|
+
if (!view) return null;
|
|
1601
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
1602
|
+
if (!editor) return null;
|
|
1603
|
+
const dataStore = get().models.get(modelId)?.ifcDataStore;
|
|
1604
|
+
if (!dataStore) return null;
|
|
1605
|
+
const chain = resolveWallEditChain(dataStore, view, editor, expressId);
|
|
1606
|
+
if (!chain) return null;
|
|
1607
|
+
const distance = projectOntoWallAxis(chain, cursorStoreyLocal);
|
|
1608
|
+
const [sx, sy, sz] = chain.startCoordinates;
|
|
1609
|
+
const [dx, dy, dz] = chain.refDirection;
|
|
1610
|
+
const cutPoint: [number, number, number] = [
|
|
1611
|
+
sx + dx * distance,
|
|
1612
|
+
sy + dy * distance,
|
|
1613
|
+
sz + dz * distance,
|
|
1614
|
+
];
|
|
1615
|
+
// Walls always lie on a storey plane (refDirection.z === 0 by
|
|
1616
|
+
// the builder's contract) but the type lets us carry whatever
|
|
1617
|
+
// the IFC actually says, so we surface it as-is.
|
|
1618
|
+
return { distance, length: chain.wallLength, cutPoint, axis: [dx, dy, dz] };
|
|
1619
|
+
},
|
|
1620
|
+
|
|
1621
|
+
splitWallAtDistance: (modelId, expressId, distanceFromStart) => {
|
|
1622
|
+
const ctx = resolveSplitContext(get, set, modelId, expressId, 'Wall is not contained in a building storey');
|
|
1623
|
+
if ('ok' in ctx) return ctx;
|
|
1624
|
+
const { view, editor, dataStore, storeyExpressId } = ctx;
|
|
1625
|
+
const state = get();
|
|
1626
|
+
|
|
1627
|
+
const chain = resolveWallEditChain(dataStore, view, editor, expressId);
|
|
1628
|
+
if (!chain) {
|
|
1629
|
+
return {
|
|
1630
|
+
ok: false,
|
|
1631
|
+
reason:
|
|
1632
|
+
'Wall does not have a simple IfcRectangleProfileDef → IfcExtrudedAreaSolid representation. Split supports walls built by addWallToStore.',
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
if (!Number.isFinite(chain.height) || chain.height <= 0) {
|
|
1636
|
+
return {
|
|
1637
|
+
ok: false,
|
|
1638
|
+
reason: 'Wall has no readable extrusion height',
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
const geo = computeWallSplitGeometry(chain, distanceFromStart, chain.height);
|
|
1643
|
+
if (!geo.ok) return geo;
|
|
1644
|
+
|
|
1645
|
+
// Build the two halves. Each `addWall` call already pushes a
|
|
1646
|
+
// CREATE_ENTITY mutation onto the undo stack AND emits a fresh
|
|
1647
|
+
// mesh via appendGeometryBatch, so the new walls appear in 3D
|
|
1648
|
+
// immediately. The source's mesh stays in the geometry result
|
|
1649
|
+
// but is tombstoned in the IFC overlay — for v1 we mark it
|
|
1650
|
+
// hidden via the existing hiddenEntities mechanism so the user
|
|
1651
|
+
// sees the split take effect.
|
|
1652
|
+
const left = state.addWall(modelId, storeyExpressId, {
|
|
1653
|
+
Start: geo.geometry.left.Start,
|
|
1654
|
+
End: geo.geometry.left.End,
|
|
1655
|
+
Thickness: geo.geometry.left.Thickness,
|
|
1656
|
+
Height: geo.geometry.left.Height,
|
|
1657
|
+
Name: 'Wall (split L)',
|
|
1658
|
+
});
|
|
1659
|
+
if ('error' in left) {
|
|
1660
|
+
return { ok: false, reason: `Couldn't build left half: ${left.error}` };
|
|
1661
|
+
}
|
|
1662
|
+
const right = state.addWall(modelId, storeyExpressId, {
|
|
1663
|
+
Start: geo.geometry.right.Start,
|
|
1664
|
+
End: geo.geometry.right.End,
|
|
1665
|
+
Thickness: geo.geometry.right.Thickness,
|
|
1666
|
+
Height: geo.geometry.right.Height,
|
|
1667
|
+
Name: 'Wall (split R)',
|
|
1668
|
+
});
|
|
1669
|
+
if ('error' in right) {
|
|
1670
|
+
// Roll back the left half via the no-history helper so the
|
|
1671
|
+
// failed split doesn't leave a phantom CREATE+DELETE pair on
|
|
1672
|
+
// the undo stack. `rollbackOverlayCreate` pops the orphan
|
|
1673
|
+
// CREATE_ENTITY entry, drops the overlay record, and removes
|
|
1674
|
+
// the renderer mesh.
|
|
1675
|
+
rollbackOverlayCreate(get, set, modelId, left.expressId);
|
|
1676
|
+
return { ok: false, reason: `Couldn't build right half: ${right.error}` };
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
// Carry Pset / Qto / classification / material / type rels
|
|
1680
|
+
// from the source onto both new walls. Done AFTER the new walls
|
|
1681
|
+
// exist so the rels' RelatedObjects lists can include them.
|
|
1682
|
+
cloneElementMetadata(dataStore, view, editor, expressId, [left.expressId, right.expressId]);
|
|
1683
|
+
|
|
1684
|
+
// Reassign hosted openings (doors / windows / generic voids)
|
|
1685
|
+
// to whichever new half they geometrically belong to. The
|
|
1686
|
+
// canonical IFC convention places the opening's
|
|
1687
|
+
// ObjectPlacement relative to the wall's placement, with
|
|
1688
|
+
// local-X = distance along the wall axis — so we read each
|
|
1689
|
+
// opening's local-X to decide left vs right, and offset
|
|
1690
|
+
// right-half openings by -splitDistance so their world
|
|
1691
|
+
// positions stay fixed across the reparent.
|
|
1692
|
+
//
|
|
1693
|
+
// We resolve each new half's IfcLocalPlacement id by
|
|
1694
|
+
// re-walking the placement chain (it's the entity addWall
|
|
1695
|
+
// created internally; the action's return value only carries
|
|
1696
|
+
// the wall id).
|
|
1697
|
+
const leftChain = resolvePlacementChain(dataStore, view, editor, left.expressId);
|
|
1698
|
+
const rightChain = resolvePlacementChain(dataStore, view, editor, right.expressId);
|
|
1699
|
+
let openingSummary: { toLeft: number; toRight: number; skipped: number } = { toLeft: 0, toRight: 0, skipped: 0 };
|
|
1700
|
+
if (leftChain && rightChain) {
|
|
1701
|
+
const s = reassignWallOpenings(
|
|
1702
|
+
dataStore,
|
|
1703
|
+
view,
|
|
1704
|
+
editor,
|
|
1705
|
+
expressId,
|
|
1706
|
+
left.expressId,
|
|
1707
|
+
right.expressId,
|
|
1708
|
+
distanceFromStart,
|
|
1709
|
+
leftChain.localPlacementId,
|
|
1710
|
+
rightChain.localPlacementId,
|
|
1711
|
+
);
|
|
1712
|
+
openingSummary = { toLeft: s.toLeft, toRight: s.toRight, skipped: s.skipped };
|
|
1713
|
+
}
|
|
1714
|
+
void openingSummary; // surfaced as a toast hint by the caller (selectionHandlers)
|
|
1715
|
+
|
|
1716
|
+
// Tombstone the source. `removeEntity` returns false if the
|
|
1717
|
+
// entity wasn't known — shouldn't happen here (we just
|
|
1718
|
+
// resolved its chain), but defend anyway.
|
|
1719
|
+
const removed = state.removeEntity(modelId, expressId);
|
|
1720
|
+
if (!removed) {
|
|
1721
|
+
return {
|
|
1722
|
+
ok: false,
|
|
1723
|
+
reason: 'Wall was unexpectedly removed before split completed',
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
// Drop the source's mesh from the rendered scene. The entity
|
|
1728
|
+
// is tombstoned in the IFC overlay so it won't export; this
|
|
1729
|
+
// also clears its GPU buffers and bounding-box entry so picks
|
|
1730
|
+
// / bounds stop finding it. The two new walls already have
|
|
1731
|
+
// their meshes in the geometry (addWall emits them via
|
|
1732
|
+
// appendGeometryBatch).
|
|
1733
|
+
const sourceGlobalId = toGlobalIdFromModels(state.models, modelId, expressId);
|
|
1734
|
+
state.setPendingMeshRemovals(new Set([sourceGlobalId]));
|
|
1735
|
+
|
|
1736
|
+
const leftGlobalId = toGlobalIdFromModels(state.models, modelId, left.expressId);
|
|
1737
|
+
const rightGlobalId = toGlobalIdFromModels(state.models, modelId, right.expressId);
|
|
1738
|
+
|
|
1739
|
+
return {
|
|
1740
|
+
ok: true,
|
|
1741
|
+
left: { expressId: left.expressId, globalId: leftGlobalId },
|
|
1742
|
+
right: { expressId: right.expressId, globalId: rightGlobalId },
|
|
1743
|
+
openings: openingSummary,
|
|
1744
|
+
};
|
|
1745
|
+
},
|
|
1746
|
+
|
|
1747
|
+
readLinearElementSplitProjection: (modelId, expressId, cursorStoreyLocal) => {
|
|
1748
|
+
const view = get().mutationViews.get(modelId);
|
|
1749
|
+
if (!view) return null;
|
|
1750
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
1751
|
+
if (!editor) return null;
|
|
1752
|
+
const dataStore = get().models.get(modelId)?.ifcDataStore;
|
|
1753
|
+
if (!dataStore) return null;
|
|
1754
|
+
const chain = resolveLinearElementChain(dataStore, view, editor, expressId);
|
|
1755
|
+
if (!chain) return null;
|
|
1756
|
+
const distance = projectOntoLinearAxis(chain, cursorStoreyLocal);
|
|
1757
|
+
const [sx, sy, sz] = chain.startCoordinates;
|
|
1758
|
+
const [dx, dy, dz] = chain.axisDirection;
|
|
1759
|
+
const cutPoint: [number, number, number] = [
|
|
1760
|
+
sx + dx * distance,
|
|
1761
|
+
sy + dy * distance,
|
|
1762
|
+
sz + dz * distance,
|
|
1763
|
+
];
|
|
1764
|
+
return {
|
|
1765
|
+
distance,
|
|
1766
|
+
length: chain.depth,
|
|
1767
|
+
cutPoint,
|
|
1768
|
+
axis: chain.axisDirection,
|
|
1769
|
+
elementType: chain.elementType,
|
|
1770
|
+
};
|
|
1771
|
+
},
|
|
1772
|
+
|
|
1773
|
+
splitLinearElementAtDistance: (modelId, expressId, distanceFromStart) => {
|
|
1774
|
+
const ctx = resolveSplitContext(get, set, modelId, expressId, 'Element is not contained in a building storey');
|
|
1775
|
+
if ('ok' in ctx) return ctx;
|
|
1776
|
+
const { view, editor, dataStore, storeyExpressId } = ctx;
|
|
1777
|
+
const state = get();
|
|
1778
|
+
|
|
1779
|
+
const chain = resolveLinearElementChain(dataStore, view, editor, expressId);
|
|
1780
|
+
if (!chain) {
|
|
1781
|
+
return {
|
|
1782
|
+
ok: false,
|
|
1783
|
+
reason:
|
|
1784
|
+
'Element is not a rectangular-profile beam / column / member built by the in-store builders.',
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
const geo = computeLinearElementSplitGeometry(chain, distanceFromStart);
|
|
1788
|
+
if (!geo.ok) return geo;
|
|
1789
|
+
|
|
1790
|
+
// Add the "right" half FIRST so a builder failure leaves the
|
|
1791
|
+
// source untouched (no partial-commit state). The source's
|
|
1792
|
+
// extrusion shrink happens only after the new half lands.
|
|
1793
|
+
// The dispatch is one-to-one with the chain's resolved
|
|
1794
|
+
// element type.
|
|
1795
|
+
let addResult: { expressId: number } | { error: string };
|
|
1796
|
+
if (chain.elementType === 'IfcBeam') {
|
|
1797
|
+
addResult = state.addBeam(modelId, storeyExpressId, {
|
|
1798
|
+
Start: geo.geometry.cutPoint,
|
|
1799
|
+
End: geo.geometry.endPoint,
|
|
1800
|
+
Width: geo.geometry.width,
|
|
1801
|
+
Height: geo.geometry.height,
|
|
1802
|
+
Name: 'Beam (split)',
|
|
1803
|
+
});
|
|
1804
|
+
} else if (chain.elementType === 'IfcColumn') {
|
|
1805
|
+
// Columns take a Position + Width + Depth + Height (extrusion
|
|
1806
|
+
// is along +Z). Width/Depth come from the cross-section
|
|
1807
|
+
// (profile XDim / YDim). Height is the right half's length.
|
|
1808
|
+
addResult = state.addColumn(modelId, storeyExpressId, {
|
|
1809
|
+
Position: geo.geometry.cutPoint,
|
|
1810
|
+
Width: geo.geometry.width,
|
|
1811
|
+
Depth: geo.geometry.height,
|
|
1812
|
+
Height: geo.geometry.rightDepth,
|
|
1813
|
+
Name: 'Column (split)',
|
|
1814
|
+
});
|
|
1815
|
+
} else {
|
|
1816
|
+
addResult = state.addMember(modelId, storeyExpressId, {
|
|
1817
|
+
Start: geo.geometry.cutPoint,
|
|
1818
|
+
End: geo.geometry.endPoint,
|
|
1819
|
+
Width: geo.geometry.width,
|
|
1820
|
+
Height: geo.geometry.height,
|
|
1821
|
+
Name: 'Member (split)',
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
if ('error' in addResult) {
|
|
1825
|
+
return { ok: false, reason: `Couldn't build right half: ${addResult.error}` };
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
// Right half built — now shrink the source's extrusion to the
|
|
1829
|
+
// "left" length. One write, one undo entry, identity
|
|
1830
|
+
// preserved. Goes through the slice's own
|
|
1831
|
+
// setPositionalAttribute action so undo recovers it.
|
|
1832
|
+
state.setPositionalAttribute(modelId, chain.extrudedSolidId, 3, geo.geometry.leftDepth);
|
|
1833
|
+
|
|
1834
|
+
// Carry Pset / classification / material rels onto the new
|
|
1835
|
+
// right half so it inherits the source's metadata. The source
|
|
1836
|
+
// keeps its own rels natively (we didn't tombstone it).
|
|
1837
|
+
cloneElementMetadata(dataStore, view, editor, expressId, [addResult.expressId]);
|
|
1838
|
+
|
|
1839
|
+
// Hide / re-show the source's mesh so the renderer reflects
|
|
1840
|
+
// the new shorter length. The new mesh for the right half
|
|
1841
|
+
// already came via the addElement pipeline's appendGeometryBatch.
|
|
1842
|
+
// For the source, the easiest visual update is to nudge the
|
|
1843
|
+
// geometryUpdateTick so consumers re-derive bounds — the
|
|
1844
|
+
// existing mesh data lingers at full length until the next
|
|
1845
|
+
// full reload (deferred mesh-update from PR #723). Users see
|
|
1846
|
+
// the new wall appear; the source mesh stays visually unchanged
|
|
1847
|
+
// for now. Documented as a known limitation.
|
|
1848
|
+
const sourceGlobalId = toGlobalIdFromModels(state.models, modelId, expressId);
|
|
1849
|
+
const rightGlobalId = toGlobalIdFromModels(state.models, modelId, addResult.expressId);
|
|
1850
|
+
|
|
1851
|
+
return {
|
|
1852
|
+
ok: true,
|
|
1853
|
+
source: { expressId, globalId: sourceGlobalId },
|
|
1854
|
+
right: { expressId: addResult.expressId, globalId: rightGlobalId },
|
|
1855
|
+
};
|
|
1856
|
+
},
|
|
1857
|
+
|
|
1858
|
+
readSlabFootprint: (modelId, expressId) => {
|
|
1859
|
+
const view = get().mutationViews.get(modelId);
|
|
1860
|
+
if (!view) return null;
|
|
1861
|
+
const editor = getOrCreateStoreEditor(get, set, modelId);
|
|
1862
|
+
if (!editor) return null;
|
|
1863
|
+
const dataStore = get().models.get(modelId)?.ifcDataStore;
|
|
1864
|
+
if (!dataStore) return null;
|
|
1865
|
+
const chain = resolveSlabEditChain(dataStore, view, editor, expressId);
|
|
1866
|
+
if (!chain) return null;
|
|
1867
|
+
const storeyId = dataStore.spatialHierarchy?.elementToStorey.get(expressId);
|
|
1868
|
+
const storeyElevation =
|
|
1869
|
+
(storeyId !== undefined
|
|
1870
|
+
? dataStore.spatialHierarchy?.storeyElevations?.get(storeyId)
|
|
1871
|
+
: undefined) ?? 0;
|
|
1872
|
+
return {
|
|
1873
|
+
footprint: chain.footprint,
|
|
1874
|
+
elementType: chain.elementType,
|
|
1875
|
+
storeyElevation,
|
|
1876
|
+
thickness: chain.thickness,
|
|
1877
|
+
};
|
|
1878
|
+
},
|
|
1879
|
+
|
|
1880
|
+
splitSlabByLine: (modelId, expressId, cutA, cutB) => {
|
|
1881
|
+
const ctx = resolveSplitContext(get, set, modelId, expressId, 'Slab is not contained in a building storey');
|
|
1882
|
+
if ('ok' in ctx) return ctx;
|
|
1883
|
+
const { view, editor, dataStore, storeyExpressId } = ctx;
|
|
1884
|
+
const state = get();
|
|
1885
|
+
|
|
1886
|
+
const chain = resolveSlabEditChain(dataStore, view, editor, expressId);
|
|
1887
|
+
if (!chain) {
|
|
1888
|
+
return {
|
|
1889
|
+
ok: false,
|
|
1890
|
+
reason:
|
|
1891
|
+
'Element representation is not a rectangle / polygon profile extruded along Z. Split supports slab-like elements built by addSlab / addRoof / addPlate / addSpace.',
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
const geo = computeSlabSplitGeometry(chain, cutA, cutB);
|
|
1895
|
+
if (!geo.ok) return geo;
|
|
1896
|
+
|
|
1897
|
+
// The clipped footprints are in storey-local XY (placement
|
|
1898
|
+
// origin already added). The builders expect an `OuterCurve`
|
|
1899
|
+
// in *profile-local* 2D + a `Position` in storey-local 3D.
|
|
1900
|
+
// Easiest mapping: keep `Position` at `[0, 0, 0]` and pass the
|
|
1901
|
+
// clipped polygon verbatim — the builders fold profile-origin
|
|
1902
|
+
// and placement-origin into one identity.
|
|
1903
|
+
//
|
|
1904
|
+
// IfcSlab / IfcRoof / IfcPlate carry their extrusion depth on
|
|
1905
|
+
// a `Thickness` param; IfcSpace uses `Height`. Same chain
|
|
1906
|
+
// resolver feeds both because the underlying STEP shape is
|
|
1907
|
+
// identical (IfcExtrudedAreaSolid.Depth) — the divergence is
|
|
1908
|
+
// only in the in-store builder's parameter naming.
|
|
1909
|
+
const buildHalf = (outline: Point2D[], label: string) => {
|
|
1910
|
+
const name = `${chain.elementType.replace(/^Ifc/, '')} (split ${label})`;
|
|
1911
|
+
switch (chain.elementType) {
|
|
1912
|
+
case 'IfcSlab':
|
|
1913
|
+
return state.addSlab(modelId, storeyExpressId, {
|
|
1914
|
+
Profile: 'polygon',
|
|
1915
|
+
Position: [0, 0, 0],
|
|
1916
|
+
OuterCurve: outline,
|
|
1917
|
+
Thickness: geo.thickness,
|
|
1918
|
+
Name: name,
|
|
1919
|
+
});
|
|
1920
|
+
case 'IfcRoof':
|
|
1921
|
+
return state.addRoof(modelId, storeyExpressId, {
|
|
1922
|
+
Profile: 'polygon',
|
|
1923
|
+
Position: [0, 0, 0],
|
|
1924
|
+
OuterCurve: outline,
|
|
1925
|
+
Thickness: geo.thickness,
|
|
1926
|
+
Name: name,
|
|
1927
|
+
});
|
|
1928
|
+
case 'IfcPlate':
|
|
1929
|
+
return state.addPlate(modelId, storeyExpressId, {
|
|
1930
|
+
Profile: 'polygon',
|
|
1931
|
+
Position: [0, 0, 0],
|
|
1932
|
+
OuterCurve: outline,
|
|
1933
|
+
Thickness: geo.thickness,
|
|
1934
|
+
Name: name,
|
|
1935
|
+
});
|
|
1936
|
+
case 'IfcSpace':
|
|
1937
|
+
return state.addSpace(modelId, storeyExpressId, {
|
|
1938
|
+
Profile: 'polygon',
|
|
1939
|
+
Position: [0, 0, 0],
|
|
1940
|
+
OuterCurve: outline,
|
|
1941
|
+
Height: geo.thickness,
|
|
1942
|
+
Name: name,
|
|
1943
|
+
});
|
|
1944
|
+
default: {
|
|
1945
|
+
// Exhaustive switch — compile error here if a new
|
|
1946
|
+
// SlabLikeType lands without a builder dispatch.
|
|
1947
|
+
const exhaust: never = chain.elementType;
|
|
1948
|
+
throw new Error(`Unhandled slab-like type: ${String(exhaust)}`);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
};
|
|
1952
|
+
|
|
1953
|
+
const left = buildHalf(geo.leftFootprint, 'L');
|
|
1954
|
+
if ('error' in left) {
|
|
1955
|
+
return { ok: false, reason: `Couldn't build left half: ${left.error}` };
|
|
1956
|
+
}
|
|
1957
|
+
const right = buildHalf(geo.rightFootprint, 'R');
|
|
1958
|
+
if ('error' in right) {
|
|
1959
|
+
// Roll back the left half via the no-history helper — same
|
|
1960
|
+
// reasoning as the wall-split rollback above.
|
|
1961
|
+
rollbackOverlayCreate(get, set, modelId, left.expressId);
|
|
1962
|
+
return { ok: false, reason: `Couldn't build right half: ${right.error}` };
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
cloneElementMetadata(dataStore, view, editor, expressId, [left.expressId, right.expressId]);
|
|
1966
|
+
|
|
1967
|
+
const removed = state.removeEntity(modelId, expressId);
|
|
1968
|
+
if (!removed) {
|
|
1969
|
+
return {
|
|
1970
|
+
ok: false,
|
|
1971
|
+
reason: 'Slab was unexpectedly removed before split completed',
|
|
1972
|
+
};
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
// Hide source mesh so the user sees the cut take effect; the
|
|
1976
|
+
// two new halves already have meshes via addSlab's
|
|
1977
|
+
// appendGeometryBatch. The source's mesh is dropped from GPU
|
|
1978
|
+
// buffers + bbox map via setPendingMeshRemovals — the
|
|
1979
|
+
// streaming hook drains it on the next frame.
|
|
1980
|
+
const sourceGlobalId = toGlobalIdFromModels(state.models, modelId, expressId);
|
|
1981
|
+
state.setPendingMeshRemovals(new Set([sourceGlobalId]));
|
|
1982
|
+
|
|
1983
|
+
const leftGlobalId = toGlobalIdFromModels(state.models, modelId, left.expressId);
|
|
1984
|
+
const rightGlobalId = toGlobalIdFromModels(state.models, modelId, right.expressId);
|
|
1985
|
+
return {
|
|
1986
|
+
ok: true,
|
|
1987
|
+
left: { expressId: left.expressId, globalId: leftGlobalId },
|
|
1988
|
+
right: { expressId: right.expressId, globalId: rightGlobalId },
|
|
1989
|
+
};
|
|
1990
|
+
},
|
|
1991
|
+
|
|
924
1992
|
removeEntity: (modelId, expressId) => {
|
|
925
1993
|
const view = get().mutationViews.get(modelId);
|
|
926
1994
|
if (!view) return false;
|
|
@@ -934,6 +2002,19 @@ export const createMutationSlice: StateCreator<
|
|
|
934
2002
|
const removed = editor.removeEntity(expressId);
|
|
935
2003
|
if (!removed) return false;
|
|
936
2004
|
|
|
2005
|
+
// Hide the entity's mesh — the IFC tombstone is what governs
|
|
2006
|
+
// exports; the renderer just needs the visual gone. We use
|
|
2007
|
+
// hideEntities (visibility set) rather than the harder
|
|
2008
|
+
// pendingMeshRemovals path so the undo handler can flip
|
|
2009
|
+
// visibility back without needing to re-materialise GPU
|
|
2010
|
+
// buffers (the mesh data stays in memory + buckets).
|
|
2011
|
+
//
|
|
2012
|
+
// The split-source removal path also flows through here; on
|
|
2013
|
+
// undo of a split, the source's mesh comes back via
|
|
2014
|
+
// `showEntities` in the DELETE_ENTITY undo branch.
|
|
2015
|
+
const globalIdForMesh = toGlobalIdFromModels(get().models, modelId, expressId);
|
|
2016
|
+
get().hideEntities([globalIdForMesh]);
|
|
2017
|
+
|
|
937
2018
|
set((state) => {
|
|
938
2019
|
const newRemoved = new Map(state.removedNewEntities);
|
|
939
2020
|
if (overlayRecord) {
|
|
@@ -1275,6 +2356,13 @@ export const createMutationSlice: StateCreator<
|
|
|
1275
2356
|
if (undoStack.length === 0) return;
|
|
1276
2357
|
|
|
1277
2358
|
const mutation = undoStack[undoStack.length - 1];
|
|
2359
|
+
// Batch awareness: if the mutation we're about to undo was
|
|
2360
|
+
// tagged as part of a batch (via setPositionalAttributesBatch),
|
|
2361
|
+
// we want one Ctrl+Z to undo every mutation in that batch.
|
|
2362
|
+
// The tail-recurse at the end of this action handles that —
|
|
2363
|
+
// capture the batchId here, undo this single mutation, then
|
|
2364
|
+
// if the next top still shares the batchId, recurse.
|
|
2365
|
+
const batchId = state.mutationBatchTags.get(mutation.id);
|
|
1278
2366
|
|
|
1279
2367
|
// Handle georef mutations directly on georefMutations map
|
|
1280
2368
|
if (mutation.type === 'UPDATE_ATTRIBUTE' && mutation.attributeName?.startsWith('georef.')) {
|
|
@@ -1381,6 +2469,18 @@ export const createMutationSlice: StateCreator<
|
|
|
1381
2469
|
view.setPositionalAttribute(mutation.entityId, index, mutation.oldValue as IfcAttributeValue, true);
|
|
1382
2470
|
}
|
|
1383
2471
|
}
|
|
2472
|
+
// If this mutation carried a mesh translation (gizmo / numeric
|
|
2473
|
+
// move), reverse it so the rendered mesh follows the undo.
|
|
2474
|
+
const meshMove = get().mutationMeshTranslations.get(mutation.id);
|
|
2475
|
+
if (meshMove) {
|
|
2476
|
+
get().setPendingMeshTranslations(
|
|
2477
|
+
new Map([[meshMove.globalId, [
|
|
2478
|
+
-meshMove.rendererDelta[0],
|
|
2479
|
+
-meshMove.rendererDelta[1],
|
|
2480
|
+
-meshMove.rendererDelta[2],
|
|
2481
|
+
]]]),
|
|
2482
|
+
);
|
|
2483
|
+
}
|
|
1384
2484
|
} else if (mutation.type === 'CREATE_ENTITY') {
|
|
1385
2485
|
// Undo of a create: stash the NewEntity payload so a subsequent redo
|
|
1386
2486
|
// can restore it. Without this, redo finds an empty stash and becomes
|
|
@@ -1433,6 +2533,20 @@ export const createMutationSlice: StateCreator<
|
|
|
1433
2533
|
mutationVersion: s.mutationVersion + 1,
|
|
1434
2534
|
};
|
|
1435
2535
|
});
|
|
2536
|
+
|
|
2537
|
+
// Tail-recurse for the rest of the batch (if any). Reading
|
|
2538
|
+
// the stack via get() picks up the just-set state. Stops as
|
|
2539
|
+
// soon as the next top mutation either doesn't exist or
|
|
2540
|
+
// belongs to a different batch.
|
|
2541
|
+
if (batchId !== undefined) {
|
|
2542
|
+
const nextStack = get().undoStacks.get(modelId) || [];
|
|
2543
|
+
if (nextStack.length > 0) {
|
|
2544
|
+
const nextBatchId = get().mutationBatchTags.get(nextStack[nextStack.length - 1].id);
|
|
2545
|
+
if (nextBatchId === batchId) {
|
|
2546
|
+
get().undo(modelId);
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
1436
2550
|
},
|
|
1437
2551
|
|
|
1438
2552
|
redo: (modelId) => {
|
|
@@ -1441,6 +2555,7 @@ export const createMutationSlice: StateCreator<
|
|
|
1441
2555
|
if (redoStack.length === 0) return;
|
|
1442
2556
|
|
|
1443
2557
|
const mutation = redoStack[redoStack.length - 1];
|
|
2558
|
+
const batchId = state.mutationBatchTags.get(mutation.id);
|
|
1444
2559
|
|
|
1445
2560
|
// Handle georef mutations directly
|
|
1446
2561
|
if (mutation.type === 'UPDATE_ATTRIBUTE' && mutation.attributeName?.startsWith('georef.')) {
|
|
@@ -1524,6 +2639,14 @@ export const createMutationSlice: StateCreator<
|
|
|
1524
2639
|
if (index !== null && mutation.newValue !== undefined) {
|
|
1525
2640
|
view.setPositionalAttribute(mutation.entityId, index, mutation.newValue as IfcAttributeValue, true);
|
|
1526
2641
|
}
|
|
2642
|
+
// Replay the mesh translation forward so the rendered mesh
|
|
2643
|
+
// follows the redo — mirror of the undo reversal above.
|
|
2644
|
+
const meshMove = get().mutationMeshTranslations.get(mutation.id);
|
|
2645
|
+
if (meshMove) {
|
|
2646
|
+
get().setPendingMeshTranslations(
|
|
2647
|
+
new Map([[meshMove.globalId, meshMove.rendererDelta]]),
|
|
2648
|
+
);
|
|
2649
|
+
}
|
|
1527
2650
|
} else if (mutation.type === 'CREATE_ENTITY') {
|
|
1528
2651
|
// Redo of a create: replay from the stashed NewEntity. Symmetrical to
|
|
1529
2652
|
// DELETE_ENTITY's undo — same map, same key.
|
|
@@ -1577,6 +2700,20 @@ export const createMutationSlice: StateCreator<
|
|
|
1577
2700
|
mutationVersion: s.mutationVersion + 1,
|
|
1578
2701
|
};
|
|
1579
2702
|
});
|
|
2703
|
+
|
|
2704
|
+
// Tail-recurse for the rest of the batch — mirror of the
|
|
2705
|
+
// undo handler's batch tail. Stops as soon as the next top
|
|
2706
|
+
// of the redo stack either doesn't exist or belongs to a
|
|
2707
|
+
// different batch.
|
|
2708
|
+
if (batchId !== undefined) {
|
|
2709
|
+
const nextStack = get().redoStacks.get(modelId) || [];
|
|
2710
|
+
if (nextStack.length > 0) {
|
|
2711
|
+
const nextBatchId = get().mutationBatchTags.get(nextStack[nextStack.length - 1].id);
|
|
2712
|
+
if (nextBatchId === batchId) {
|
|
2713
|
+
get().redo(modelId);
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
1580
2717
|
},
|
|
1581
2718
|
|
|
1582
2719
|
canUndo: (modelId) => {
|