@ifc-lite/create 4.0.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/dist/in-store/align-boxes.d.ts +38 -0
- package/dist/in-store/align-boxes.d.ts.map +1 -0
- package/dist/in-store/align-boxes.js +97 -0
- package/dist/in-store/align-boxes.js.map +1 -0
- package/dist/in-store/anchor.d.ts.map +1 -1
- package/dist/in-store/anchor.js +13 -2
- package/dist/in-store/anchor.js.map +1 -1
- package/dist/in-store/beam.d.ts.map +1 -1
- package/dist/in-store/beam.js +3 -10
- package/dist/in-store/beam.js.map +1 -1
- package/dist/in-store/copy-array.d.ts +17 -0
- package/dist/in-store/copy-array.d.ts.map +1 -0
- package/dist/in-store/copy-array.js +47 -0
- package/dist/in-store/copy-array.js.map +1 -0
- package/dist/in-store/copy-batch.d.ts +27 -0
- package/dist/in-store/copy-batch.d.ts.map +1 -0
- package/dist/in-store/copy-batch.js +101 -0
- package/dist/in-store/copy-batch.js.map +1 -0
- package/dist/in-store/copy-dependent-walk.d.ts +27 -0
- package/dist/in-store/copy-dependent-walk.d.ts.map +1 -0
- package/dist/in-store/copy-dependent-walk.js +61 -0
- package/dist/in-store/copy-dependent-walk.js.map +1 -0
- package/dist/in-store/copy-frame.d.ts +4 -3
- package/dist/in-store/copy-frame.d.ts.map +1 -1
- package/dist/in-store/copy-frame.js +14 -1
- package/dist/in-store/copy-frame.js.map +1 -1
- package/dist/in-store/copy-product.d.ts +0 -20
- package/dist/in-store/copy-product.d.ts.map +1 -1
- package/dist/in-store/copy-product.js +35 -35
- package/dist/in-store/copy-product.js.map +1 -1
- package/dist/in-store/edit/effective-mutation-view.d.ts +6 -0
- package/dist/in-store/edit/effective-mutation-view.d.ts.map +1 -0
- package/dist/in-store/edit/effective-mutation-view.js +45 -0
- package/dist/in-store/edit/effective-mutation-view.js.map +1 -0
- package/dist/in-store/edit/effective-storey.d.ts +13 -0
- package/dist/in-store/edit/effective-storey.d.ts.map +1 -0
- package/dist/in-store/edit/effective-storey.js +36 -0
- package/dist/in-store/edit/effective-storey.js.map +1 -0
- package/dist/in-store/edit/effective-storeys.d.ts +9 -0
- package/dist/in-store/edit/effective-storeys.d.ts.map +1 -0
- package/dist/in-store/edit/effective-storeys.js +16 -0
- package/dist/in-store/edit/effective-storeys.js.map +1 -0
- package/dist/in-store/edit/hosted-opening-refit.d.ts +29 -0
- package/dist/in-store/edit/hosted-opening-refit.d.ts.map +1 -0
- package/dist/in-store/edit/hosted-opening-refit.js +168 -0
- package/dist/in-store/edit/hosted-opening-refit.js.map +1 -0
- package/dist/in-store/edit/length-unit-scale.d.ts +24 -0
- package/dist/in-store/edit/length-unit-scale.d.ts.map +1 -0
- package/dist/in-store/edit/length-unit-scale.js +37 -0
- package/dist/in-store/edit/length-unit-scale.js.map +1 -0
- package/dist/in-store/edit/linear-element-edit.d.ts +131 -0
- package/dist/in-store/edit/linear-element-edit.d.ts.map +1 -0
- package/dist/in-store/edit/linear-element-edit.js +259 -0
- package/dist/in-store/edit/linear-element-edit.js.map +1 -0
- package/dist/in-store/edit/metadata-clone-effective.d.ts +5 -0
- package/dist/in-store/edit/metadata-clone-effective.d.ts.map +1 -0
- package/dist/in-store/edit/metadata-clone-effective.js +47 -0
- package/dist/in-store/edit/metadata-clone-effective.js.map +1 -0
- package/dist/in-store/edit/metadata-clone.d.ts +40 -0
- package/dist/in-store/edit/metadata-clone.d.ts.map +1 -0
- package/dist/in-store/edit/metadata-clone.js +107 -0
- package/dist/in-store/edit/metadata-clone.js.map +1 -0
- package/dist/in-store/edit/placement-core.d.ts +140 -0
- package/dist/in-store/edit/placement-core.d.ts.map +1 -0
- package/dist/in-store/edit/placement-core.js +317 -0
- package/dist/in-store/edit/placement-core.js.map +1 -0
- package/dist/in-store/edit/polygon-clip.d.ts +58 -0
- package/dist/in-store/edit/polygon-clip.d.ts.map +1 -0
- package/dist/in-store/edit/polygon-clip.js +153 -0
- package/dist/in-store/edit/polygon-clip.js.map +1 -0
- package/dist/in-store/edit/read-profile.d.ts +6 -0
- package/dist/in-store/edit/read-profile.d.ts.map +1 -0
- package/dist/in-store/edit/read-profile.js +95 -0
- package/dist/in-store/edit/read-profile.js.map +1 -0
- package/dist/in-store/edit/slab-edit-frame.d.ts +40 -0
- package/dist/in-store/edit/slab-edit-frame.d.ts.map +1 -0
- package/dist/in-store/edit/slab-edit-frame.js +146 -0
- package/dist/in-store/edit/slab-edit-frame.js.map +1 -0
- package/dist/in-store/edit/slab-edit.d.ts +112 -0
- package/dist/in-store/edit/slab-edit.d.ts.map +1 -0
- package/dist/in-store/edit/slab-edit.js +275 -0
- package/dist/in-store/edit/slab-edit.js.map +1 -0
- package/dist/in-store/edit/slab-opening-carry.d.ts +10 -0
- package/dist/in-store/edit/slab-opening-carry.d.ts.map +1 -0
- package/dist/in-store/edit/slab-opening-carry.js +65 -0
- package/dist/in-store/edit/slab-opening-carry.js.map +1 -0
- package/dist/in-store/edit/split-guid.d.ts +29 -0
- package/dist/in-store/edit/split-guid.d.ts.map +1 -0
- package/dist/in-store/edit/split-guid.js +64 -0
- package/dist/in-store/edit/split-guid.js.map +1 -0
- package/dist/in-store/edit/split-target.d.ts +90 -0
- package/dist/in-store/edit/split-target.d.ts.map +1 -0
- package/dist/in-store/edit/split-target.js +116 -0
- package/dist/in-store/edit/split-target.js.map +1 -0
- package/dist/in-store/edit/target.d.ts +8 -0
- package/dist/in-store/edit/target.d.ts.map +1 -0
- package/dist/in-store/edit/target.js +5 -0
- package/dist/in-store/edit/target.js.map +1 -0
- package/dist/in-store/edit/trim-extend-geometry.d.ts +99 -0
- package/dist/in-store/edit/trim-extend-geometry.d.ts.map +1 -0
- package/dist/in-store/edit/trim-extend-geometry.js +105 -0
- package/dist/in-store/edit/trim-extend-geometry.js.map +1 -0
- package/dist/in-store/edit/wall-axis-edit.d.ts +16 -0
- package/dist/in-store/edit/wall-axis-edit.d.ts.map +1 -0
- package/dist/in-store/edit/wall-axis-edit.js +40 -0
- package/dist/in-store/edit/wall-axis-edit.js.map +1 -0
- package/dist/in-store/edit/wall-edit.d.ts +157 -0
- package/dist/in-store/edit/wall-edit.d.ts.map +1 -0
- package/dist/in-store/edit/wall-edit.js +276 -0
- package/dist/in-store/edit/wall-edit.js.map +1 -0
- package/dist/in-store/edit/wall-hosted-cuts.d.ts +35 -0
- package/dist/in-store/edit/wall-hosted-cuts.d.ts.map +1 -0
- package/dist/in-store/edit/wall-hosted-cuts.js +27 -0
- package/dist/in-store/edit/wall-hosted-cuts.js.map +1 -0
- package/dist/in-store/edit/wall-opening-reassign.d.ts +18 -0
- package/dist/in-store/edit/wall-opening-reassign.d.ts.map +1 -0
- package/dist/in-store/edit/wall-opening-reassign.js +50 -0
- package/dist/in-store/edit/wall-opening-reassign.js.map +1 -0
- package/dist/in-store/element-align.d.ts +13 -0
- package/dist/in-store/element-align.d.ts.map +1 -0
- package/dist/in-store/element-align.js +90 -0
- package/dist/in-store/element-align.js.map +1 -0
- package/dist/in-store/element-replacement.d.ts +26 -0
- package/dist/in-store/element-replacement.d.ts.map +1 -0
- package/dist/in-store/element-replacement.js +68 -0
- package/dist/in-store/element-replacement.js.map +1 -0
- package/dist/in-store/element-size-edit.d.ts +40 -0
- package/dist/in-store/element-size-edit.d.ts.map +1 -0
- package/dist/in-store/element-size-edit.js +103 -0
- package/dist/in-store/element-size-edit.js.map +1 -0
- package/dist/in-store/element-split-axis.d.ts +6 -0
- package/dist/in-store/element-split-axis.d.ts.map +1 -0
- package/dist/in-store/element-split-axis.js +87 -0
- package/dist/in-store/element-split-axis.js.map +1 -0
- package/dist/in-store/element-split-joined.d.ts +13 -0
- package/dist/in-store/element-split-joined.d.ts.map +1 -0
- package/dist/in-store/element-split-joined.js +74 -0
- package/dist/in-store/element-split-joined.js.map +1 -0
- package/dist/in-store/element-split-placement.d.ts +19 -0
- package/dist/in-store/element-split-placement.d.ts.map +1 -0
- package/dist/in-store/element-split-placement.js +48 -0
- package/dist/in-store/element-split-placement.js.map +1 -0
- package/dist/in-store/element-split-slab.d.ts +19 -0
- package/dist/in-store/element-split-slab.d.ts.map +1 -0
- package/dist/in-store/element-split-slab.js +86 -0
- package/dist/in-store/element-split-slab.js.map +1 -0
- package/dist/in-store/element-split.d.ts +49 -0
- package/dist/in-store/element-split.d.ts.map +1 -0
- package/dist/in-store/element-split.js +52 -0
- package/dist/in-store/element-split.js.map +1 -0
- package/dist/in-store/element-transform-edit.d.ts +33 -0
- package/dist/in-store/element-transform-edit.d.ts.map +1 -0
- package/dist/in-store/element-transform-edit.js +97 -0
- package/dist/in-store/element-transform-edit.js.map +1 -0
- package/dist/in-store/element-transform-frames.d.ts +58 -0
- package/dist/in-store/element-transform-frames.d.ts.map +1 -0
- package/dist/in-store/element-transform-frames.js +110 -0
- package/dist/in-store/element-transform-frames.js.map +1 -0
- package/dist/in-store/element-transform-joins.d.ts +4 -0
- package/dist/in-store/element-transform-joins.d.ts.map +1 -0
- package/dist/in-store/element-transform-joins.js +62 -0
- package/dist/in-store/element-transform-joins.js.map +1 -0
- package/dist/in-store/element-transform-plan.d.ts +38 -0
- package/dist/in-store/element-transform-plan.d.ts.map +1 -0
- package/dist/in-store/element-transform-plan.js +115 -0
- package/dist/in-store/element-transform-plan.js.map +1 -0
- package/dist/in-store/element-trim-extend.d.ts +25 -0
- package/dist/in-store/element-trim-extend.d.ts.map +1 -0
- package/dist/in-store/element-trim-extend.js +97 -0
- package/dist/in-store/element-trim-extend.js.map +1 -0
- package/dist/in-store/extract-grids.d.ts +7 -17
- package/dist/in-store/extract-grids.d.ts.map +1 -1
- package/dist/in-store/extract-grids.js +11 -2
- package/dist/in-store/extract-grids.js.map +1 -1
- package/dist/in-store/grid-column.d.ts +23 -0
- package/dist/in-store/grid-column.d.ts.map +1 -0
- package/dist/in-store/grid-column.js +73 -0
- package/dist/in-store/grid-column.js.map +1 -0
- package/dist/in-store/grid-intersection-read.d.ts +10 -0
- package/dist/in-store/grid-intersection-read.d.ts.map +1 -0
- package/dist/in-store/grid-intersection-read.js +45 -0
- package/dist/in-store/grid-intersection-read.js.map +1 -0
- package/dist/in-store/grid.d.ts +7 -1
- package/dist/in-store/grid.d.ts.map +1 -1
- package/dist/in-store/grid.js +12 -2
- package/dist/in-store/grid.js.map +1 -1
- package/dist/in-store/group-evidence.d.ts +49 -0
- package/dist/in-store/group-evidence.d.ts.map +1 -0
- package/dist/in-store/group-evidence.js +111 -0
- package/dist/in-store/group-evidence.js.map +1 -0
- package/dist/in-store/group-graph.d.ts +51 -0
- package/dist/in-store/group-graph.d.ts.map +1 -0
- package/dist/in-store/group-graph.js +213 -0
- package/dist/in-store/group-graph.js.map +1 -0
- package/dist/in-store/group.d.ts +34 -0
- package/dist/in-store/group.d.ts.map +1 -0
- package/dist/in-store/group.js +181 -0
- package/dist/in-store/group.js.map +1 -0
- package/dist/in-store/host-geometry-frame.d.ts +5 -1
- package/dist/in-store/host-geometry-frame.d.ts.map +1 -1
- package/dist/in-store/host-geometry-frame.js +46 -2
- package/dist/in-store/host-geometry-frame.js.map +1 -1
- package/dist/in-store/index.d.ts +7 -0
- package/dist/in-store/index.d.ts.map +1 -1
- package/dist/in-store/index.js +7 -0
- package/dist/in-store/index.js.map +1 -1
- package/dist/in-store/linear-profile-frame.d.ts +10 -0
- package/dist/in-store/linear-profile-frame.d.ts.map +1 -0
- package/dist/in-store/linear-profile-frame.js +17 -0
- package/dist/in-store/linear-profile-frame.js.map +1 -0
- package/dist/in-store/material.d.ts.map +1 -1
- package/dist/in-store/material.js +17 -6
- package/dist/in-store/material.js.map +1 -1
- package/dist/in-store/member.d.ts.map +1 -1
- package/dist/in-store/member.js +3 -7
- package/dist/in-store/member.js.map +1 -1
- package/dist/in-store/ordinary-element.d.ts +47 -0
- package/dist/in-store/ordinary-element.d.ts.map +1 -0
- package/dist/in-store/ordinary-element.js +38 -0
- package/dist/in-store/ordinary-element.js.map +1 -0
- package/dist/in-store/placement-frame.d.ts +6 -1
- package/dist/in-store/placement-frame.d.ts.map +1 -1
- package/dist/in-store/placement-frame.js +5 -1
- package/dist/in-store/placement-frame.js.map +1 -1
- package/dist/in-store/resolve-anchor.d.ts +3 -2
- package/dist/in-store/resolve-anchor.d.ts.map +1 -1
- package/dist/in-store/resolve-anchor.js +7 -5
- package/dist/in-store/resolve-anchor.js.map +1 -1
- package/dist/in-store/resolve-relations.d.ts +3 -1
- package/dist/in-store/resolve-relations.d.ts.map +1 -1
- package/dist/in-store/resolve-relations.js +8 -3
- package/dist/in-store/resolve-relations.js.map +1 -1
- package/dist/in-store/room-candidates.d.ts +58 -0
- package/dist/in-store/room-candidates.d.ts.map +1 -0
- package/dist/in-store/room-candidates.js +135 -0
- package/dist/in-store/room-candidates.js.map +1 -0
- package/dist/in-store/room-creation-plan.d.ts +16 -0
- package/dist/in-store/room-creation-plan.d.ts.map +1 -0
- package/dist/in-store/room-creation-plan.js +28 -0
- package/dist/in-store/room-creation-plan.js.map +1 -0
- package/dist/in-store/room-floor-height.d.ts +24 -0
- package/dist/in-store/room-floor-height.d.ts.map +1 -0
- package/dist/in-store/room-floor-height.js +32 -0
- package/dist/in-store/room-floor-height.js.map +1 -0
- package/dist/in-store/room-footprint-native.d.ts +19 -0
- package/dist/in-store/room-footprint-native.d.ts.map +1 -0
- package/dist/in-store/room-footprint-native.js +117 -0
- package/dist/in-store/room-footprint-native.js.map +1 -0
- package/dist/in-store/room-layout-cache.d.ts +23 -0
- package/dist/in-store/room-layout-cache.d.ts.map +1 -0
- package/dist/in-store/room-layout-cache.js +84 -0
- package/dist/in-store/room-layout-cache.js.map +1 -0
- package/dist/in-store/room-layout-core.d.ts +68 -0
- package/dist/in-store/room-layout-core.d.ts.map +1 -0
- package/dist/in-store/room-layout-core.js +153 -0
- package/dist/in-store/room-layout-core.js.map +1 -0
- package/dist/in-store/room-population.d.ts +5 -0
- package/dist/in-store/room-population.d.ts.map +1 -0
- package/dist/in-store/room-population.js +28 -0
- package/dist/in-store/room-population.js.map +1 -0
- package/dist/in-store/room-space-meshes.d.ts +15 -0
- package/dist/in-store/room-space-meshes.d.ts.map +1 -0
- package/dist/in-store/room-space-meshes.js +38 -0
- package/dist/in-store/room-space-meshes.js.map +1 -0
- package/dist/in-store/room-store.d.ts +55 -0
- package/dist/in-store/room-store.d.ts.map +1 -0
- package/dist/in-store/room-store.js +173 -0
- package/dist/in-store/room-store.js.map +1 -0
- package/dist/in-store/room-storey-elevation.d.ts +5 -0
- package/dist/in-store/room-storey-elevation.d.ts.map +1 -0
- package/dist/in-store/room-storey-elevation.js +42 -0
- package/dist/in-store/room-storey-elevation.js.map +1 -0
- package/dist/in-store/room-storey-frame.d.ts +47 -0
- package/dist/in-store/room-storey-frame.d.ts.map +1 -0
- package/dist/in-store/room-storey-frame.js +48 -0
- package/dist/in-store/room-storey-frame.js.map +1 -0
- package/dist/in-store/room-wall-rects.d.ts +117 -0
- package/dist/in-store/room-wall-rects.d.ts.map +1 -0
- package/dist/in-store/room-wall-rects.js +157 -0
- package/dist/in-store/room-wall-rects.js.map +1 -0
- package/dist/in-store/schema-attributes.d.ts +3 -3
- package/dist/in-store/schema-attributes.d.ts.map +1 -1
- package/dist/in-store/schema-attributes.js +9 -7
- package/dist/in-store/schema-attributes.js.map +1 -1
- package/dist/in-store/slab.d.ts.map +1 -1
- package/dist/in-store/slab.js +1 -4
- package/dist/in-store/slab.js.map +1 -1
- package/dist/in-store/stair-removal.d.ts +17 -0
- package/dist/in-store/stair-removal.d.ts.map +1 -0
- package/dist/in-store/stair-removal.js +134 -0
- package/dist/in-store/stair-removal.js.map +1 -0
- package/dist/in-store/storey-plan-frame.d.ts +2 -1
- package/dist/in-store/storey-plan-frame.d.ts.map +1 -1
- package/dist/in-store/storey-plan-frame.js +20 -11
- package/dist/in-store/storey-plan-frame.js.map +1 -1
- package/dist/in-store/storey-reassignment-plan.d.ts +53 -0
- package/dist/in-store/storey-reassignment-plan.d.ts.map +1 -0
- package/dist/in-store/storey-reassignment-plan.js +237 -0
- package/dist/in-store/storey-reassignment-plan.js.map +1 -0
- package/dist/in-store/storey-reassignment.d.ts +8 -0
- package/dist/in-store/storey-reassignment.d.ts.map +1 -0
- package/dist/in-store/storey-reassignment.js +52 -0
- package/dist/in-store/storey-reassignment.js.map +1 -0
- package/dist/in-store/trim-extend-plan.d.ts +27 -0
- package/dist/in-store/trim-extend-plan.d.ts.map +1 -0
- package/dist/in-store/trim-extend-plan.js +49 -0
- package/dist/in-store/trim-extend-plan.js.map +1 -0
- package/dist/in-store/wall-join-edit.d.ts +0 -17
- package/dist/in-store/wall-join-edit.d.ts.map +1 -1
- package/dist/in-store/wall-join-edit.js +41 -7
- package/dist/in-store/wall-join-edit.js.map +1 -1
- package/dist/in-store/wall-section-edit.d.ts +16 -0
- package/dist/in-store/wall-section-edit.d.ts.map +1 -0
- package/dist/in-store/wall-section-edit.js +75 -0
- package/dist/in-store/wall-section-edit.js.map +1 -0
- package/dist/in-store/wall-size-edit.d.ts +29 -0
- package/dist/in-store/wall-size-edit.d.ts.map +1 -0
- package/dist/in-store/wall-size-edit.js +65 -0
- package/dist/in-store/wall-size-edit.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Core placement-chain reader + generic IfcProduct edits.
|
|
6
|
+
*
|
|
7
|
+
* Walks the standard product placement chain
|
|
8
|
+
*
|
|
9
|
+
* IfcProduct → ObjectPlacement → IfcLocalPlacement
|
|
10
|
+
* → RelativePlacement → IfcAxis2Placement3D
|
|
11
|
+
* → Location → IfcCartesianPoint → Coordinates [x, y, z]
|
|
12
|
+
*
|
|
13
|
+
* Reads honour the `StoreEditor` overlay (overlay-only entities,
|
|
14
|
+
* named/positional mutations and current retypes on top of source-buffer entities for placement owners).
|
|
15
|
+
* Writes go through `setPositionalAttribute` so they stack with
|
|
16
|
+
* other overlay edits and participate in the standard undo path.
|
|
17
|
+
*
|
|
18
|
+
* Wall-specific edits live in `wall-edit.ts`; this module stays
|
|
19
|
+
* generic so file size + cognitive scope stay manageable.
|
|
20
|
+
*/
|
|
21
|
+
import { EntityExtractor, resolveEffectiveEntityRecord } from '@ifc-lite/parser';
|
|
22
|
+
let configuredSourceReader = (store, id) => {
|
|
23
|
+
// @raw-entity-enumeration-ok source baseline; readAttributes applies positional overlay edits
|
|
24
|
+
const byId = store.entityIndex?.byId;
|
|
25
|
+
if (!store.source?.length || !byId)
|
|
26
|
+
return null;
|
|
27
|
+
const ref = byId.get(id);
|
|
28
|
+
return ref ? new EntityExtractor(store.source).extractEntity(ref)?.attributes ?? null : null;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Override the parser-backed source reader at app boot.
|
|
32
|
+
* Pass `null` to disable source reads (used by tests).
|
|
33
|
+
*/
|
|
34
|
+
export function setSourceAttrsReader(reader) {
|
|
35
|
+
configuredSourceReader = reader;
|
|
36
|
+
}
|
|
37
|
+
/** Shared source callback baseline; effective placement reads add no decoder. */
|
|
38
|
+
function baseAttributes(dataStore, editor, expressId) {
|
|
39
|
+
const overlay = editor.getNewEntity(expressId);
|
|
40
|
+
let attrs = null;
|
|
41
|
+
if (overlay) {
|
|
42
|
+
attrs = overlay.attributes.slice();
|
|
43
|
+
}
|
|
44
|
+
else if (configuredSourceReader) {
|
|
45
|
+
attrs = configuredSourceReader(dataStore, expressId);
|
|
46
|
+
if (!attrs)
|
|
47
|
+
return null;
|
|
48
|
+
attrs = attrs.slice();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// No source reader configured and no overlay entry — typical in
|
|
52
|
+
// unit tests that don't wire `setSourceAttrsReader`. Treat as
|
|
53
|
+
// "unknown entity" so callers fall back gracefully.
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return attrs;
|
|
57
|
+
}
|
|
58
|
+
/** #7315: only native placement owners use current named/retyped fields.
|
|
59
|
+
* The general body/profile reader retains its existing positional contract. */
|
|
60
|
+
export function readPlacementAttributes(dataStore, view, editor, expressId) {
|
|
61
|
+
if (view.isDeleted(expressId))
|
|
62
|
+
return null;
|
|
63
|
+
const attributes = baseAttributes(dataStore, editor, expressId);
|
|
64
|
+
if (!attributes)
|
|
65
|
+
return null;
|
|
66
|
+
const type = editor.getNewEntity(expressId)?.type ?? dataStore.getEntity(expressId)?.type ?? editor.getEntityType?.(expressId);
|
|
67
|
+
if (!type)
|
|
68
|
+
return null;
|
|
69
|
+
return resolveEffectiveEntityRecord({ type, attributes }, {
|
|
70
|
+
retype: view.getEntityTypeMutation(expressId)?.newType,
|
|
71
|
+
named: view.getAttributeMutationsForEntity(expressId).map(({ name, value }) => [name, value]),
|
|
72
|
+
positional: view.getPositionalMutationsForEntity(expressId) ?? [],
|
|
73
|
+
}, dataStore.schemaVersion).attributes;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Read the effective attribute list for an express id. Overlay-only
|
|
77
|
+
* entities come from the StoreEditor; source entities come from the
|
|
78
|
+
* original buffer. Positional-mutation overrides are layered on top so
|
|
79
|
+
* a previously-translated point reads back its mutated coords.
|
|
80
|
+
*/
|
|
81
|
+
export function readAttributes(dataStore, view,
|
|
82
|
+
/** Only its overlay lookup is read, so the view itself will do. */
|
|
83
|
+
editor, expressId) {
|
|
84
|
+
let attrs = baseAttributes(dataStore, editor, expressId);
|
|
85
|
+
if (!attrs)
|
|
86
|
+
return null;
|
|
87
|
+
// Apply positional mutations so a partially-edited entity reflects
|
|
88
|
+
// its current state (relevant when the user translates the same
|
|
89
|
+
// entity twice — the second read must see the first delta).
|
|
90
|
+
const mutated = view.getPositionalMutationsForEntity(expressId);
|
|
91
|
+
if (mutated) {
|
|
92
|
+
for (const [index, value] of mutated.entries()) {
|
|
93
|
+
attrs[index] = value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return attrs;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* References take two forms in our attribute graph:
|
|
100
|
+
* - number (the parser normalises `#123` → 123 when reading source)
|
|
101
|
+
* - string `#123` (overlay entities created via `editor.addEntity`
|
|
102
|
+
* carry the raw `#X` form straight through)
|
|
103
|
+
* Treat both as valid so the chain walker works for source-buffer
|
|
104
|
+
* AND overlay-only entities — it's the same conceptual reference.
|
|
105
|
+
*/
|
|
106
|
+
export function asExpressIdRef(value) {
|
|
107
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
108
|
+
return value;
|
|
109
|
+
if (typeof value === 'string' && value.startsWith('#')) {
|
|
110
|
+
const id = parseInt(value.slice(1), 10);
|
|
111
|
+
return Number.isFinite(id) ? id : null;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
export function asCoordinateTriple(value) {
|
|
116
|
+
if (!Array.isArray(value))
|
|
117
|
+
return null;
|
|
118
|
+
if (value.length < 2)
|
|
119
|
+
return null;
|
|
120
|
+
const x = typeof value[0] === 'number' ? value[0] : NaN;
|
|
121
|
+
const y = typeof value[1] === 'number' ? value[1] : NaN;
|
|
122
|
+
// Coordinates may be 2D ([x, y]) — treat the missing Z as 0.
|
|
123
|
+
const z = value.length >= 3 && typeof value[2] === 'number' ? value[2] : 0;
|
|
124
|
+
if (Number.isNaN(x) || Number.isNaN(y))
|
|
125
|
+
return null;
|
|
126
|
+
return [x, y, z];
|
|
127
|
+
}
|
|
128
|
+
export function asDirectionRatios(value) {
|
|
129
|
+
if (!Array.isArray(value))
|
|
130
|
+
return null;
|
|
131
|
+
if (value.length < 2)
|
|
132
|
+
return null;
|
|
133
|
+
const x = typeof value[0] === 'number' ? value[0] : NaN;
|
|
134
|
+
const y = typeof value[1] === 'number' ? value[1] : NaN;
|
|
135
|
+
const z = value.length >= 3 && typeof value[2] === 'number' ? value[2] : 0;
|
|
136
|
+
if (Number.isNaN(x) || Number.isNaN(y))
|
|
137
|
+
return null;
|
|
138
|
+
return [x, y, z];
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Resolve the full placement chain for an IfcProduct. Returns `null`
|
|
142
|
+
* if any link is missing or has the wrong shape — callers should treat
|
|
143
|
+
* this as "this entity's placement isn't directly translatable" and
|
|
144
|
+
* surface a clear message rather than crashing.
|
|
145
|
+
*
|
|
146
|
+
* Indices follow the IfcProduct attribute order:
|
|
147
|
+
* [0] GlobalId · [1] OwnerHistory · [2] Name · [3] Description
|
|
148
|
+
* [4] ObjectType · [5] ObjectPlacement · [6] Representation · ...
|
|
149
|
+
*
|
|
150
|
+
* For non-product entities (e.g. profiles, points themselves) attrs[5]
|
|
151
|
+
* either doesn't exist or isn't a placement reference, so we bail.
|
|
152
|
+
*/
|
|
153
|
+
export function resolvePlacementChain(dataStore, view, editor, expressId) {
|
|
154
|
+
const productAttrs = readPlacementAttributes(dataStore, view, editor, expressId);
|
|
155
|
+
if (!productAttrs)
|
|
156
|
+
return null;
|
|
157
|
+
const localPlacementId = asExpressIdRef(productAttrs[5]);
|
|
158
|
+
if (localPlacementId === null || editor.getEntityType(localPlacementId)?.toUpperCase() !== 'IFCLOCALPLACEMENT')
|
|
159
|
+
return null;
|
|
160
|
+
// This API exposes the same point to both numeric edits and the move gizmo.
|
|
161
|
+
// A child-local point below IfcGridPlacement is not a storey-local writable
|
|
162
|
+
// position: returning zero would offer a misleading edit origin (#6232).
|
|
163
|
+
// Inspect the complete parent chain so an intermediate local placement
|
|
164
|
+
// cannot hide the grid frame. File references are iterative and bounded.
|
|
165
|
+
const visited = new Set();
|
|
166
|
+
let ancestor = localPlacementId;
|
|
167
|
+
while (ancestor !== null) {
|
|
168
|
+
if (visited.size >= 10_000 || visited.has(ancestor))
|
|
169
|
+
return null;
|
|
170
|
+
visited.add(ancestor);
|
|
171
|
+
if (editor.getEntityType(ancestor)?.toUpperCase() !== 'IFCLOCALPLACEMENT')
|
|
172
|
+
return null;
|
|
173
|
+
const attrs = readPlacementAttributes(dataStore, view, editor, ancestor);
|
|
174
|
+
if (!attrs)
|
|
175
|
+
return null;
|
|
176
|
+
const parent = attrs[0];
|
|
177
|
+
ancestor = parent === null || parent === undefined ? null : asExpressIdRef(parent);
|
|
178
|
+
if (parent !== null && parent !== undefined && ancestor === null)
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const localPlacementAttrs = readPlacementAttributes(dataStore, view, editor, localPlacementId);
|
|
182
|
+
if (!localPlacementAttrs)
|
|
183
|
+
return null;
|
|
184
|
+
// IfcLocalPlacement.RelativePlacement is at index 1
|
|
185
|
+
// ([0] = PlacementRelTo (parent placement)).
|
|
186
|
+
const axisPlacementId = asExpressIdRef(localPlacementAttrs[1]);
|
|
187
|
+
if (axisPlacementId === null)
|
|
188
|
+
return null;
|
|
189
|
+
const axisAttrs = readPlacementAttributes(dataStore, view, editor, axisPlacementId);
|
|
190
|
+
if (!axisAttrs)
|
|
191
|
+
return null;
|
|
192
|
+
// IfcAxis2Placement3D.Location at index 0.
|
|
193
|
+
const cartesianPointId = asExpressIdRef(axisAttrs[0]);
|
|
194
|
+
if (cartesianPointId === null)
|
|
195
|
+
return null;
|
|
196
|
+
const pointAttrs = readPlacementAttributes(dataStore, view, editor, cartesianPointId);
|
|
197
|
+
if (!pointAttrs)
|
|
198
|
+
return null;
|
|
199
|
+
const coordinates = asCoordinateTriple(pointAttrs[0]);
|
|
200
|
+
if (!coordinates)
|
|
201
|
+
return null;
|
|
202
|
+
return { localPlacementId, axisPlacementId, cartesianPointId, coordinates };
|
|
203
|
+
}
|
|
204
|
+
/** Pure preview shared by atomic preflight and the placement writer. */
|
|
205
|
+
export function translatedCoordinates(coordinates, delta) {
|
|
206
|
+
const next = [coordinates[0] + delta[0], coordinates[1] + delta[1], coordinates[2] + delta[2]];
|
|
207
|
+
return delta.every(Number.isFinite) && next.every(Number.isFinite) ? next : null;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Translate an IfcProduct by `delta` (storey-local IFC Z-up). Reads
|
|
211
|
+
* the current coordinates from the chain, adds the delta, writes back
|
|
212
|
+
* via `setPositionalAttribute`. Caller is responsible for batching
|
|
213
|
+
* undo (the upstream `setPositionalAttribute` action already pushes a
|
|
214
|
+
* single mutation onto the model's undo stack).
|
|
215
|
+
*/
|
|
216
|
+
export function translateProduct(dataStore, view, editor, expressId, delta) {
|
|
217
|
+
const chain = resolvePlacementChain(dataStore, view, editor, expressId);
|
|
218
|
+
if (!chain) {
|
|
219
|
+
return {
|
|
220
|
+
ok: false,
|
|
221
|
+
reason: 'Entity placement is not a simple IfcLocalPlacement → IfcAxis2Placement3D → IfcCartesianPoint chain',
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
const next = translatedCoordinates(chain.coordinates, delta);
|
|
225
|
+
if (!next)
|
|
226
|
+
return { ok: false, reason: 'Placement translation overflow: derived coordinates must be finite' };
|
|
227
|
+
editor.setPositionalAttribute(chain.cartesianPointId, 0, next);
|
|
228
|
+
return { ok: true, oldCoordinates: chain.coordinates, newCoordinates: next };
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Set the entity's position to an absolute storey-local coordinate.
|
|
232
|
+
* Convenience over `translateProduct` when the caller has a target
|
|
233
|
+
* (e.g. a numeric form bound to current coordinates).
|
|
234
|
+
*/
|
|
235
|
+
export function setProductPosition(dataStore, view, editor, expressId, position) {
|
|
236
|
+
const chain = resolvePlacementChain(dataStore, view, editor, expressId);
|
|
237
|
+
if (!chain) {
|
|
238
|
+
return {
|
|
239
|
+
ok: false,
|
|
240
|
+
reason: 'Entity placement is not a simple IfcLocalPlacement → IfcAxis2Placement3D → IfcCartesianPoint chain',
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
if (!position.every(Number.isFinite))
|
|
244
|
+
return { ok: false, reason: 'Placement coordinates must be finite' };
|
|
245
|
+
editor.setPositionalAttribute(chain.cartesianPointId, 0, position);
|
|
246
|
+
return { ok: true, oldCoordinates: chain.coordinates, newCoordinates: position };
|
|
247
|
+
}
|
|
248
|
+
export function resolveRotationState(dataStore, view, editor, expressId) {
|
|
249
|
+
const chain = resolvePlacementChain(dataStore, view, editor, expressId);
|
|
250
|
+
if (!chain)
|
|
251
|
+
return null;
|
|
252
|
+
const axisAttrs = readPlacementAttributes(dataStore, view, editor, chain.axisPlacementId);
|
|
253
|
+
if (!axisAttrs)
|
|
254
|
+
return null;
|
|
255
|
+
// IfcAxis2Placement3D index 2 = RefDirection (an optional IfcDirection ref).
|
|
256
|
+
const refDirectionId = asExpressIdRef(axisAttrs[2]);
|
|
257
|
+
if (refDirectionId === null) {
|
|
258
|
+
return {
|
|
259
|
+
axisPlacementId: chain.axisPlacementId,
|
|
260
|
+
refDirectionId: null,
|
|
261
|
+
refDirection: [1, 0, 0],
|
|
262
|
+
yawZ: 0,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const dirAttrs = readPlacementAttributes(dataStore, view, editor, refDirectionId);
|
|
266
|
+
if (!dirAttrs)
|
|
267
|
+
return null;
|
|
268
|
+
// IfcDirection index 0 = DirectionRatios (list of doubles).
|
|
269
|
+
const ratios = asDirectionRatios(dirAttrs[0]);
|
|
270
|
+
if (!ratios)
|
|
271
|
+
return null;
|
|
272
|
+
// Yaw about Z derived from the in-plane direction. Numerically
|
|
273
|
+
// stable for any unit-length input; for non-unit inputs we still
|
|
274
|
+
// recover the angle from atan2.
|
|
275
|
+
const yawZ = Math.atan2(ratios[1], ratios[0]);
|
|
276
|
+
return { axisPlacementId: chain.axisPlacementId, refDirectionId, refDirection: ratios, yawZ };
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Rotate an IfcProduct about the storey-up Z axis by `deltaYaw`
|
|
280
|
+
* radians. Updates RefDirection on the IfcAxis2Placement3D in place
|
|
281
|
+
* when one already exists.
|
|
282
|
+
*
|
|
283
|
+
* Refuses to operate when the placement has no explicit RefDirection
|
|
284
|
+
* (the implicit `[1, 0, 0]` STEP default). Materialising a fresh
|
|
285
|
+
* IfcDirection there would require a multi-mutation atomic undo
|
|
286
|
+
* entry to avoid orphans on undo, which the store doesn't have yet.
|
|
287
|
+
* Every entity emitted by `@ifc-lite/create`'s in-store builders
|
|
288
|
+
* carries an explicit RefDirection, so the implicit branch only
|
|
289
|
+
* trips on hand-rolled source-buffer entities — surfacing a clear
|
|
290
|
+
* refusal beats silently leaking entities.
|
|
291
|
+
*/
|
|
292
|
+
export function rotateProductYaw(dataStore, view, editor, expressId, deltaYaw) {
|
|
293
|
+
const state = resolveRotationState(dataStore, view, editor, expressId);
|
|
294
|
+
if (!state) {
|
|
295
|
+
return {
|
|
296
|
+
ok: false,
|
|
297
|
+
reason: 'Entity placement is not a simple IfcLocalPlacement → IfcAxis2Placement3D chain',
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
if (state.refDirectionId === null) {
|
|
301
|
+
return {
|
|
302
|
+
ok: false,
|
|
303
|
+
reason: 'Entity has an implicit reference direction; rotation requires an explicit IfcDirection on its axis placement.',
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
const newYaw = state.yawZ + deltaYaw;
|
|
307
|
+
const newRatios = [
|
|
308
|
+
Math.cos(newYaw),
|
|
309
|
+
Math.sin(newYaw),
|
|
310
|
+
state.refDirection[2],
|
|
311
|
+
];
|
|
312
|
+
if (!Number.isFinite(newYaw) || !newRatios.every(Number.isFinite))
|
|
313
|
+
return { ok: false, reason: 'Placement rotation overflow: derived direction must be finite' };
|
|
314
|
+
editor.setPositionalAttribute(state.refDirectionId, 0, newRatios);
|
|
315
|
+
return { ok: true, oldYawZ: state.yawZ, newYawZ: newYaw, newRefDirection: newRatios };
|
|
316
|
+
}
|
|
317
|
+
//# sourceMappingURL=placement-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placement-core.js","sourceRoot":"","sources":["../../../src/in-store/edit/placement-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 2D polygon half-plane clipping. Used by slab / roof / plate /
|
|
3
|
+
* space split to divide a footprint polygon into two halves by a
|
|
4
|
+
* cut line.
|
|
5
|
+
*
|
|
6
|
+
* The cut line is defined by two points in the polygon's local
|
|
7
|
+
* plane. We derive the line's normal (rotated 90° CCW from the
|
|
8
|
+
* direction) and use it to assign each polygon vertex to one of
|
|
9
|
+
* the two half-planes. Sutherland-Hodgman-style edge walk
|
|
10
|
+
* produces the clipped polygon for each side; the union of the
|
|
11
|
+
* two output polygons reconstructs the input (minus any sliver
|
|
12
|
+
* vertices that landed exactly on the cut line, which both halves
|
|
13
|
+
* include as boundary).
|
|
14
|
+
*
|
|
15
|
+
* Returns:
|
|
16
|
+
*
|
|
17
|
+
* - `{ ok: true, left, right }` when the cut intersects the
|
|
18
|
+
* polygon and both halves have ≥ 3 vertices (a valid polygon).
|
|
19
|
+
* - `{ ok: false, reason }` when the cut misses the polygon, is
|
|
20
|
+
* tangent to a single vertex, or produces a degenerate sliver
|
|
21
|
+
* (< 3 vertices on either side).
|
|
22
|
+
*
|
|
23
|
+
* "Left" / "right" naming follows the cut-line direction: walking
|
|
24
|
+
* from A to B, "left" is the half-plane on the user's left
|
|
25
|
+
* (positive cross product of (B-A) with (vertex-A)).
|
|
26
|
+
*/
|
|
27
|
+
export type Point2D = [number, number];
|
|
28
|
+
export type PolygonClipResult = {
|
|
29
|
+
ok: true;
|
|
30
|
+
left: Point2D[];
|
|
31
|
+
right: Point2D[];
|
|
32
|
+
} | {
|
|
33
|
+
ok: false;
|
|
34
|
+
reason: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Split a polygon into two halves by a cut line.
|
|
38
|
+
*
|
|
39
|
+
* Inputs:
|
|
40
|
+
* - `polygon` — outer curve as an ordered list of 2D vertices
|
|
41
|
+
* (CW or CCW; the algorithm is orientation-independent).
|
|
42
|
+
* First vertex should NOT repeat at the end.
|
|
43
|
+
* - `a`, `b` — two points defining the cut line. The line
|
|
44
|
+
* extends infinitely in both directions through these points,
|
|
45
|
+
* so the user-clicked endpoints don't need to lie on the
|
|
46
|
+
* polygon edge.
|
|
47
|
+
*
|
|
48
|
+
* Returns `{ ok: true, left, right }` when both halves are valid
|
|
49
|
+
* polygons (≥ 3 vertices). Otherwise returns `{ ok: false, reason }`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function clipPolygonByLine(polygon: Point2D[], a: Point2D, b: Point2D): PolygonClipResult;
|
|
52
|
+
/**
|
|
53
|
+
* Test helper: is `p` strictly inside `polygon` (ray-cast). Used by
|
|
54
|
+
* the slab-split tool to figure out which half the user clicked on
|
|
55
|
+
* after committing the cut, so we can move selection to that half.
|
|
56
|
+
*/
|
|
57
|
+
export declare function pointInPolygon(polygon: Point2D[], p: Point2D): boolean;
|
|
58
|
+
//# sourceMappingURL=polygon-clip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon-clip.d.ts","sourceRoot":"","sources":["../../../src/in-store/edit/polygon-clip.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEvC,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,EAAE,CAAA;CAAE,GAC/C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA4FlC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,OAAO,EAAE,EAClB,CAAC,EAAE,OAAO,EACV,CAAC,EAAE,OAAO,GACT,iBAAiB,CA+BnB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CActE"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
const EPS = 1e-9;
|
|
5
|
+
/**
|
|
6
|
+
* Signed perpendicular distance of `p` to the directed line through
|
|
7
|
+
* `a → b`. Positive means `p` is to the LEFT of A→B in standard
|
|
8
|
+
* math coords (y-up) — i.e. the side reached by rotating the A→B
|
|
9
|
+
* direction 90° counter-clockwise.
|
|
10
|
+
*/
|
|
11
|
+
function signedDistance(a, b, p) {
|
|
12
|
+
// Standard 2D cross product (b - a) × (p - a).
|
|
13
|
+
return (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Linear interpolation between two polygon vertices at the cut line.
|
|
17
|
+
* `da`, `db` are signed distances of `a` and `b` from the line; the
|
|
18
|
+
* intersection sits where the signed distance crosses zero.
|
|
19
|
+
*/
|
|
20
|
+
function intersectEdge(a, b, da, db) {
|
|
21
|
+
const t = da / (da - db); // never 0/0 because callers ensure signs differ
|
|
22
|
+
return [a[0] + t * (b[0] - a[0]), a[1] + t * (b[1] - a[1])];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Clip a polygon to one side of the cut line. `keep` selects which
|
|
26
|
+
* side to retain: `'positive'` keeps vertices with signed distance
|
|
27
|
+
* > 0 (left of A→B); `'negative'` keeps vertices with signed
|
|
28
|
+
* distance < 0 (right). On-line vertices (|d| < EPS) belong to
|
|
29
|
+
* both halves and are emitted unchanged.
|
|
30
|
+
*
|
|
31
|
+
* Standard Sutherland-Hodgman: walk each edge of the input polygon,
|
|
32
|
+
* decide whether to emit the current vertex and/or an intersection
|
|
33
|
+
* with the cut line based on which side current and previous
|
|
34
|
+
* vertices are on.
|
|
35
|
+
*/
|
|
36
|
+
function clipPolygonHalfPlane(polygon, a, b, keep) {
|
|
37
|
+
if (polygon.length === 0)
|
|
38
|
+
return [];
|
|
39
|
+
const out = [];
|
|
40
|
+
const sign = keep === 'positive' ? 1 : -1;
|
|
41
|
+
const pushUnique = (p) => {
|
|
42
|
+
// Skip duplicate emits — the on-line edge case (prev outside,
|
|
43
|
+
// curr on the line) would otherwise emit the intersection AND
|
|
44
|
+
// curr, which are the same point. Cheap O(1) check against the
|
|
45
|
+
// most recent vertex; the polygon body itself is allowed to
|
|
46
|
+
// have repeated adjacent vertices in pathological input but we
|
|
47
|
+
// don't want to manufacture them.
|
|
48
|
+
if (out.length > 0) {
|
|
49
|
+
const last = out[out.length - 1];
|
|
50
|
+
if (Math.abs(last[0] - p[0]) < EPS && Math.abs(last[1] - p[1]) < EPS)
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
out.push(p);
|
|
54
|
+
};
|
|
55
|
+
let prev = polygon[polygon.length - 1];
|
|
56
|
+
let prevD = signedDistance(a, b, prev) * sign;
|
|
57
|
+
for (const curr of polygon) {
|
|
58
|
+
const currD = signedDistance(a, b, curr) * sign;
|
|
59
|
+
if (currD >= -EPS) {
|
|
60
|
+
// Current vertex is inside (or on the line).
|
|
61
|
+
if (prevD < -EPS) {
|
|
62
|
+
// Crossing into the half-plane — emit the intersection.
|
|
63
|
+
pushUnique(intersectEdge(prev, curr, prevD, currD));
|
|
64
|
+
}
|
|
65
|
+
pushUnique(curr);
|
|
66
|
+
}
|
|
67
|
+
else if (prevD >= -EPS) {
|
|
68
|
+
// Crossing out of the half-plane — emit the intersection.
|
|
69
|
+
pushUnique(intersectEdge(prev, curr, prevD, currD));
|
|
70
|
+
}
|
|
71
|
+
// Else both outside — skip.
|
|
72
|
+
prev = curr;
|
|
73
|
+
prevD = currD;
|
|
74
|
+
}
|
|
75
|
+
// The pushUnique guard runs against the previous push; the
|
|
76
|
+
// wrap-around (last vs first) can also produce a dup when the
|
|
77
|
+
// polygon closes on a near-coincident pair. Trim once.
|
|
78
|
+
if (out.length > 1) {
|
|
79
|
+
const first = out[0];
|
|
80
|
+
const last = out[out.length - 1];
|
|
81
|
+
if (Math.abs(last[0] - first[0]) < EPS && Math.abs(last[1] - first[1]) < EPS) {
|
|
82
|
+
out.pop();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Split a polygon into two halves by a cut line.
|
|
89
|
+
*
|
|
90
|
+
* Inputs:
|
|
91
|
+
* - `polygon` — outer curve as an ordered list of 2D vertices
|
|
92
|
+
* (CW or CCW; the algorithm is orientation-independent).
|
|
93
|
+
* First vertex should NOT repeat at the end.
|
|
94
|
+
* - `a`, `b` — two points defining the cut line. The line
|
|
95
|
+
* extends infinitely in both directions through these points,
|
|
96
|
+
* so the user-clicked endpoints don't need to lie on the
|
|
97
|
+
* polygon edge.
|
|
98
|
+
*
|
|
99
|
+
* Returns `{ ok: true, left, right }` when both halves are valid
|
|
100
|
+
* polygons (≥ 3 vertices). Otherwise returns `{ ok: false, reason }`.
|
|
101
|
+
*/
|
|
102
|
+
export function clipPolygonByLine(polygon, a, b) {
|
|
103
|
+
if (polygon.length < 3) {
|
|
104
|
+
return { ok: false, reason: 'Polygon must have at least 3 vertices' };
|
|
105
|
+
}
|
|
106
|
+
const dx = b[0] - a[0];
|
|
107
|
+
const dy = b[1] - a[1];
|
|
108
|
+
if (Math.hypot(dx, dy) < EPS) {
|
|
109
|
+
return { ok: false, reason: 'Cut endpoints are coincident' };
|
|
110
|
+
}
|
|
111
|
+
// Count how many vertices land strictly on each side. If all
|
|
112
|
+
// vertices are on one side, the cut line misses the polygon.
|
|
113
|
+
let pos = 0;
|
|
114
|
+
let neg = 0;
|
|
115
|
+
for (const p of polygon) {
|
|
116
|
+
const d = signedDistance(a, b, p);
|
|
117
|
+
if (d > EPS)
|
|
118
|
+
pos++;
|
|
119
|
+
else if (d < -EPS)
|
|
120
|
+
neg++;
|
|
121
|
+
}
|
|
122
|
+
if (pos === 0 || neg === 0) {
|
|
123
|
+
return { ok: false, reason: 'Cut line does not cross the polygon' };
|
|
124
|
+
}
|
|
125
|
+
const left = clipPolygonHalfPlane(polygon, a, b, 'positive');
|
|
126
|
+
const right = clipPolygonHalfPlane(polygon, a, b, 'negative');
|
|
127
|
+
if (left.length < 3 || right.length < 3) {
|
|
128
|
+
return { ok: false, reason: 'Cut produces a degenerate half (< 3 vertices)' };
|
|
129
|
+
}
|
|
130
|
+
return { ok: true, left, right };
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Test helper: is `p` strictly inside `polygon` (ray-cast). Used by
|
|
134
|
+
* the slab-split tool to figure out which half the user clicked on
|
|
135
|
+
* after committing the cut, so we can move selection to that half.
|
|
136
|
+
*/
|
|
137
|
+
export function pointInPolygon(polygon, p) {
|
|
138
|
+
if (polygon.length < 3)
|
|
139
|
+
return false;
|
|
140
|
+
let inside = false;
|
|
141
|
+
let j = polygon.length - 1;
|
|
142
|
+
for (let i = 0; i < polygon.length; i++) {
|
|
143
|
+
const a = polygon[i];
|
|
144
|
+
const b = polygon[j];
|
|
145
|
+
const intersects = (a[1] > p[1]) !== (b[1] > p[1]) &&
|
|
146
|
+
p[0] < ((b[0] - a[0]) * (p[1] - a[1])) / (b[1] - a[1] + EPS) + a[0];
|
|
147
|
+
if (intersects)
|
|
148
|
+
inside = !inside;
|
|
149
|
+
j = i;
|
|
150
|
+
}
|
|
151
|
+
return inside;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=polygon-clip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon-clip.js","sourceRoot":"","sources":["../../../src/in-store/edit/polygon-clip.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ProfileSection } from '../profile.js';
|
|
2
|
+
/** Whether `stepType` names one of the nine profile classes the picker writes. */
|
|
3
|
+
export declare function isSectionProfileClass(stepType: string | null | undefined): boolean;
|
|
4
|
+
/** Read a profile in metres without dropping geometry when it is rebuilt. */
|
|
5
|
+
export declare function sectionFromProfile(stepType: string, attributes: readonly unknown[], lengthUnitScale: number, schemaVersion?: string): ProfileSection | null;
|
|
6
|
+
//# sourceMappingURL=read-profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-profile.d.ts","sourceRoot":"","sources":["../../../src/in-store/edit/read-profile.ts"],"names":[],"mappings":"AAiBA,OAAO,EAA0B,KAAK,cAAc,EAA2B,MAAM,eAAe,CAAC;AAsBrG,kFAAkF;AAClF,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAElF;AAQD,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,SAAS,OAAO,EAAE,EAC9B,eAAe,EAAE,MAAM,EACvB,aAAa,SAAS,GACrB,cAAc,GAAG,IAAI,CAwCvB"}
|