@pascal-app/core 1.0.7 → 1.1.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/dist/agent-operations/__fixtures__/cases.d.ts +3 -2
- package/dist/agent-operations/__fixtures__/cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/native-materials.d.ts +4 -0
- package/dist/agent-operations/__fixtures__/native-materials.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/place-items-cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/place-items-cases.js +28 -0
- package/dist/agent-operations/__fixtures__/roof-bearing-cases.d.ts +9567 -9563
- package/dist/agent-operations/__fixtures__/roof-bearing-cases.d.ts.map +1 -1
- package/dist/agent-operations/__fixtures__/verify-scene-cases.d.ts +77 -77
- package/dist/agent-operations/asset-catalog.d.ts +21 -11
- package/dist/agent-operations/asset-catalog.d.ts.map +1 -1
- package/dist/agent-operations/asset-catalog.js +28 -10
- package/dist/agent-operations/asset-views.d.ts +8 -3
- package/dist/agent-operations/asset-views.d.ts.map +1 -1
- package/dist/agent-operations/asset-views.js +19 -3
- package/dist/agent-operations/author-scene.d.ts.map +1 -1
- package/dist/agent-operations/author-scene.js +2 -3
- package/dist/agent-operations/batch.d.ts +7 -1
- package/dist/agent-operations/batch.d.ts.map +1 -1
- package/dist/agent-operations/batch.js +17 -2
- package/dist/agent-operations/catalog-asset.d.ts +15 -0
- package/dist/agent-operations/catalog-asset.d.ts.map +1 -0
- package/dist/agent-operations/catalog-asset.js +4 -0
- package/dist/agent-operations/circulation-spaces.d.ts +1724 -1723
- package/dist/agent-operations/circulation-spaces.d.ts.map +1 -1
- package/dist/agent-operations/design-brief.d.ts.map +1 -1
- package/dist/agent-operations/design-brief.js +2 -0
- package/dist/agent-operations/furnish-room.d.ts.map +1 -1
- package/dist/agent-operations/furnish-room.js +2 -1
- package/dist/agent-operations/index.d.ts +3 -0
- package/dist/agent-operations/index.d.ts.map +1 -1
- package/dist/agent-operations/index.js +4 -1
- package/dist/agent-operations/level-reads.d.ts.map +1 -1
- package/dist/agent-operations/level-reads.js +5 -2
- package/dist/agent-operations/move-plan.d.ts.map +1 -1
- package/dist/agent-operations/move-plan.js +11 -9
- package/dist/agent-operations/place-in-room.d.ts.map +1 -1
- package/dist/agent-operations/place-in-room.js +2 -1
- package/dist/agent-operations/place-items.d.ts.map +1 -1
- package/dist/agent-operations/place-items.js +2 -1
- package/dist/agent-operations/scene-queries.d.ts +2944 -2943
- package/dist/agent-operations/scene-queries.d.ts.map +1 -1
- package/dist/agent-operations/scene-view.d.ts.map +1 -1
- package/dist/agent-operations/scene-view.js +38 -13
- package/dist/agent-operations/search-assets.d.ts.map +1 -1
- package/dist/agent-operations/search-assets.js +6 -0
- package/dist/agent-operations/types.d.ts +3 -2
- package/dist/agent-operations/types.d.ts.map +1 -1
- package/dist/agent-operations/usage-checks.js +18 -3
- package/dist/agent-operations/verify-scene.d.ts.map +1 -1
- package/dist/agent-operations/verify-scene.js +4 -2
- package/dist/agent-operations/wall-object-observations.d.ts.map +1 -1
- package/dist/agent-operations/wall-object-observations.js +1 -1
- package/dist/agent-tools/assets.js +1 -1
- package/dist/agent-tools/wall-openings.js +2 -2
- package/dist/building/__fixtures__/wall-opening-cases.d.ts +13 -12
- package/dist/building/__fixtures__/wall-opening-cases.d.ts.map +1 -1
- package/dist/building/level-duplication.d.ts +1281 -1279
- package/dist/building/level-duplication.d.ts.map +1 -1
- package/dist/building/level-duplication.js +3 -1
- package/dist/building/merge-windows.d.ts.map +1 -1
- package/dist/building/merge-windows.js +4 -3
- package/dist/building/wall-openings.d.ts +95 -81
- package/dist/building/wall-openings.d.ts.map +1 -1
- package/dist/building/wall-openings.js +74 -25
- package/dist/commands/structure/shared.d.ts +3203 -3202
- package/dist/commands/structure/shared.d.ts.map +1 -1
- package/dist/commands/structure/zone-wall-merge.d.ts +2028 -2025
- package/dist/commands/structure/zone-wall-merge.d.ts.map +1 -1
- package/dist/contracts/reference-inventory.d.ts.map +1 -1
- package/dist/contracts/reference-inventory.js +0 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +6 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.js +30 -9
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +2101 -2100
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-sync.js +8 -4
- package/dist/index.d.ts +13 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -4
- package/dist/lib/__fixtures__/mezzanine.d.ts +6428 -6424
- package/dist/lib/__fixtures__/mezzanine.d.ts.map +1 -1
- package/dist/lib/absorb-wall-separators.d.ts +2267 -2266
- package/dist/lib/absorb-wall-separators.d.ts.map +1 -1
- package/dist/lib/asset-storage.d.ts.map +1 -1
- package/dist/lib/asset-storage.js +3 -0
- package/dist/lib/build-mode.d.ts +11 -0
- package/dist/lib/build-mode.d.ts.map +1 -0
- package/dist/lib/build-mode.js +24 -0
- package/dist/lib/corner-pair.d.ts +2 -0
- package/dist/lib/corner-pair.d.ts.map +1 -1
- package/dist/lib/door-interaction.d.ts +14 -0
- package/dist/lib/door-interaction.d.ts.map +1 -0
- package/dist/lib/door-interaction.js +62 -0
- package/dist/lib/elevator-support.d.ts +15 -0
- package/dist/lib/elevator-support.d.ts.map +1 -0
- package/dist/lib/elevator-support.js +40 -0
- package/dist/lib/floor-foundation-datum.d.ts.map +1 -1
- package/dist/lib/floor-foundation-datum.js +5 -1
- package/dist/lib/floor-intent-changes.d.ts.map +1 -1
- package/dist/lib/floor-intent-changes.js +6 -4
- package/dist/lib/floorplan/context.d.ts +95 -0
- package/dist/lib/floorplan/context.d.ts.map +1 -0
- package/dist/lib/floorplan/context.js +155 -0
- package/dist/lib/floorplan/index.d.ts +6 -0
- package/dist/lib/floorplan/index.d.ts.map +1 -0
- package/dist/lib/floorplan/index.js +5 -0
- package/dist/lib/floorplan/marks.d.ts +71 -0
- package/dist/lib/floorplan/marks.d.ts.map +1 -0
- package/dist/lib/floorplan/marks.js +157 -0
- package/dist/lib/floorplan/plan-math.d.ts +18 -0
- package/dist/lib/floorplan/plan-math.d.ts.map +1 -0
- package/dist/lib/floorplan/plan-math.js +82 -0
- package/dist/lib/floorplan/svg-paths.d.ts +17 -0
- package/dist/lib/floorplan/svg-paths.d.ts.map +1 -0
- package/dist/lib/floorplan/svg-paths.js +92 -0
- package/dist/lib/floorplan/wall-affordances.d.ts +31 -0
- package/dist/lib/floorplan/wall-affordances.d.ts.map +1 -0
- package/dist/lib/floorplan/wall-affordances.js +24 -0
- package/dist/lib/hierarchy.d.ts +19 -0
- package/dist/lib/hierarchy.d.ts.map +1 -0
- package/dist/lib/hierarchy.js +53 -0
- package/dist/lib/opening-floor-datum.d.ts +1 -1
- package/dist/lib/opening-floor-datum.d.ts.map +1 -1
- package/dist/lib/opening-floor-datum.js +2 -2
- package/dist/lib/own-floor-intent.d.ts.map +1 -1
- package/dist/lib/own-floor-intent.js +2 -2
- package/dist/lib/polygon-boolean.d.ts.map +1 -1
- package/dist/lib/polygon-boolean.js +2 -1
- package/dist/lib/room-floor-elevation.d.ts +12 -0
- package/dist/lib/room-floor-elevation.d.ts.map +1 -0
- package/dist/lib/room-floor-elevation.js +41 -0
- package/dist/lib/room-floor-feasibility.d.ts.map +1 -1
- package/dist/lib/room-floor-feasibility.js +1 -1
- package/dist/lib/space-detection.d.ts.map +1 -1
- package/dist/lib/space-detection.js +1 -0
- package/dist/lib/wall-face-script.d.ts.map +1 -1
- package/dist/lib/wall-face-script.js +3 -3
- package/dist/lib/window-interaction.d.ts +16 -0
- package/dist/lib/window-interaction.d.ts.map +1 -0
- package/dist/lib/window-interaction.js +82 -0
- package/dist/lib/zone-quantities.js +1 -1
- package/dist/node-slots/column.d.ts +5 -0
- package/dist/node-slots/column.d.ts.map +1 -1
- package/dist/node-slots/column.js +10 -0
- package/dist/registry/__fixtures__/roof-planes.d.ts +69 -0
- package/dist/registry/__fixtures__/roof-planes.d.ts.map +1 -0
- package/dist/registry/__fixtures__/roof-planes.js +59 -0
- package/dist/registry/index.d.ts +3 -2
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +2 -1
- package/dist/registry/registry.d.ts +5 -0
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/registry.js +10 -0
- package/dist/registry/roofs.d.ts +34 -0
- package/dist/registry/roofs.d.ts.map +1 -0
- package/dist/registry/roofs.js +61 -0
- package/dist/registry/types.d.ts +54 -0
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry/validate-relations.d.ts +5 -1
- package/dist/registry/validate-relations.d.ts.map +1 -1
- package/dist/registry/validate-relations.js +6 -2
- package/dist/schema/asset-url.d.ts +8 -0
- package/dist/schema/asset-url.d.ts.map +1 -1
- package/dist/schema/asset-url.js +17 -0
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +1 -1
- package/dist/schema/nodes/roof-segment-resize.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment-resize.js +2 -2
- package/dist/schema/nodes/roof-segment.d.ts +2 -0
- package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment.js +40 -2
- package/dist/schema/nodes/roof.d.ts +1 -1
- package/dist/schema/nodes/roof.d.ts.map +1 -1
- package/dist/schema/nodes/roof.js +13 -8
- package/dist/schema/nodes/wall.d.ts +1 -0
- package/dist/schema/nodes/wall.d.ts.map +1 -1
- package/dist/schema/nodes/wall.js +6 -0
- package/dist/schema/types.d.ts +2 -1
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/movement.d.ts +7 -0
- package/dist/services/movement.d.ts.map +1 -1
- package/dist/services/movement.js +13 -0
- package/dist/services/port-connectivity.d.ts +15 -6
- package/dist/services/port-connectivity.d.ts.map +1 -1
- package/dist/services/port-connectivity.js +83 -17
- package/dist/services/roof-bearing.js +2 -1
- package/dist/services/roof-level.d.ts.map +1 -1
- package/dist/services/roof-level.js +12 -2
- package/dist/services/roof-move.d.ts +4 -2
- package/dist/services/roof-move.d.ts.map +1 -1
- package/dist/services/roof-move.js +21 -9
- package/dist/services/storey.d.ts +6 -1
- package/dist/services/storey.d.ts.map +1 -1
- package/dist/services/storey.js +11 -2
- package/dist/spatial/usage-field/findings.d.ts +7 -1
- package/dist/spatial/usage-field/findings.d.ts.map +1 -1
- package/dist/spatial/usage-field/findings.js +42 -10
- package/dist/spatial/usage-field/path.d.ts.map +1 -1
- package/dist/spatial/usage-field/path.js +28 -18
- package/dist/spatial/usage-field/swings.d.ts +1 -0
- package/dist/spatial/usage-field/swings.d.ts.map +1 -1
- package/dist/spatial/usage-field/walls.d.ts +2 -0
- package/dist/spatial/usage-field/walls.d.ts.map +1 -1
- package/dist/spatial/usage-field/walls.js +18 -4
- package/dist/store/actions/node-actions.d.ts +2 -1
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +23 -5
- package/dist/store/derived-node-guard.d.ts.map +1 -1
- package/dist/store/derived-node-guard.js +2 -1
- package/dist/store/scene-annotations.d.ts +4634 -4632
- package/dist/store/scene-annotations.d.ts.map +1 -1
- package/dist/systems/document-reconcile.d.ts.map +1 -1
- package/dist/systems/document-reconcile.js +1 -2
- package/dist/systems/elevator/elevator-geometry.d.ts +25 -0
- package/dist/systems/elevator/elevator-geometry.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-geometry.js +40 -8
- package/dist/systems/elevator/elevator-opening-sync.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-opening-sync.js +4 -35
- package/dist/systems/elevator/elevator-runtime.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-runtime.js +95 -18
- package/dist/systems/elevator/elevator-service.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-service.js +24 -4
- package/dist/systems/roof/roof-elevation.d.ts +11 -6
- package/dist/systems/roof/roof-elevation.d.ts.map +1 -1
- package/dist/systems/roof/roof-elevation.js +26 -12
- package/dist/systems/slab/__fixtures__/floor-step.d.ts +5 -1
- package/dist/systems/slab/__fixtures__/floor-step.d.ts.map +1 -1
- package/dist/systems/slab/__fixtures__/raised-room.d.ts +2218 -2214
- package/dist/systems/slab/__fixtures__/raised-room.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-preview.d.ts +3203 -3202
- package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
- package/dist/systems/wall/wall-curve.d.ts +10 -0
- package/dist/systems/wall/wall-curve.d.ts.map +1 -1
- package/dist/systems/wall/wall-curve.js +38 -0
- package/dist/systems/wall/wall-frame.d.ts.map +1 -1
- package/dist/systems/wall/wall-frame.js +8 -0
- package/dist/systems/wall/wall-merge.d.ts +9 -1
- package/dist/systems/wall/wall-merge.d.ts.map +1 -1
- package/dist/systems/wall/wall-merge.js +38 -6
- package/dist/systems/wall/wall-top.d.ts +10 -3
- package/dist/systems/wall/wall-top.d.ts.map +1 -1
- package/dist/systems/wall/wall-top.js +24 -8
- package/dist/systems/wall/wall-topology.d.ts.map +1 -1
- package/dist/systems/wall/wall-topology.js +19 -1
- package/dist/utils/ensure-scene-openings.d.ts +5595 -5593
- package/dist/utils/ensure-scene-openings.d.ts.map +1 -1
- package/dist/utils/floor-plate-migration.d.ts +2267 -2266
- package/dist/utils/floor-plate-migration.d.ts.map +1 -1
- package/dist/utils/measurement-format.d.ts +27 -0
- package/dist/utils/measurement-format.d.ts.map +1 -0
- package/dist/utils/measurement-format.js +143 -0
- package/dist/utils/owned-floor-opening-migration.d.ts +653 -652
- package/dist/utils/owned-floor-opening-migration.d.ts.map +1 -1
- package/dist/utils/reconcile-structure-on-load.d.ts +1724 -1723
- package/dist/utils/reconcile-structure-on-load.d.ts.map +1 -1
- package/dist/utils/scene-bounds.d.ts +32 -0
- package/dist/utils/scene-bounds.d.ts.map +1 -0
- package/dist/utils/scene-bounds.js +201 -0
- package/dist/validation/validate-build-json.d.ts.map +1 -1
- package/dist/validation/validate-build-json.js +3 -1
- package/package.json +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { AnyNode, AnyNodeId, DoorNode, WindowNode } from '../../schema/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic door / window marks per level — WS3.
|
|
4
|
+
*
|
|
5
|
+
* `packages/core/src/schema/nodes/door.ts:75-79` promises "the deterministic
|
|
6
|
+
* level fallback (101, 102, ...)"; this is the implementation.
|
|
7
|
+
*
|
|
8
|
+
* Numbering
|
|
9
|
+
* ---------
|
|
10
|
+
* base = (level.level + 1) * 100 — level 0 → 100, level 1 → 200
|
|
11
|
+
* doors = `D${base + n}` → D101, D102 …
|
|
12
|
+
* windows= `W${base + n}` → W101, W102 …
|
|
13
|
+
*
|
|
14
|
+
* Order
|
|
15
|
+
* -----
|
|
16
|
+
* Openings are visited **clockwise** around the level, starting from the
|
|
17
|
+
* north-west-most exterior wall, exterior walls first and interior walls
|
|
18
|
+
* after. Clockwise is the ascending-angle sweep of the wall midpoint about
|
|
19
|
+
* the level centroid, anchored on the north-west diagonal (plan axes are
|
|
20
|
+
* x east, z south — z grows down the screen — so a screen-clockwise sweep
|
|
21
|
+
* is increasing atan2(z, x)). Openings on the same wall are ordered along
|
|
22
|
+
* the wall direction.
|
|
23
|
+
*
|
|
24
|
+
* Stability
|
|
25
|
+
* ---------
|
|
26
|
+
* An explicit `mark` on the node always wins and is never reassigned.
|
|
27
|
+
* `resolveMarks` also reports, in `assignments`, the marks it invented for
|
|
28
|
+
* nodes that had none — the caller is expected to PERSIST those back onto
|
|
29
|
+
* `node.mark` the first time they are resolved in an edit session
|
|
30
|
+
* (`persistResolvedMarks`). That is what makes numbering stable under
|
|
31
|
+
* insertion: once written, an existing opening keeps its number forever and
|
|
32
|
+
* a newly inserted opening only ever takes the next free number. Without
|
|
33
|
+
* the write-back, inserting a door in the middle of a wall would silently
|
|
34
|
+
* renumber every door after it.
|
|
35
|
+
*/
|
|
36
|
+
export type OpeningMarkKind = 'door' | 'window';
|
|
37
|
+
export type MarkResolution = {
|
|
38
|
+
/** Every door and window on the level → its mark. */
|
|
39
|
+
marks: ReadonlyMap<string, string>;
|
|
40
|
+
/** Only the marks that were invented (node.mark was empty). */
|
|
41
|
+
assignments: ReadonlyMap<string, string>;
|
|
42
|
+
/** Duplicate explicit marks and other reportable defects. */
|
|
43
|
+
issues: readonly string[];
|
|
44
|
+
};
|
|
45
|
+
export type MarkSceneInput = {
|
|
46
|
+
nodes: Readonly<Record<string, AnyNode>>;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Resolve marks for every door and window under `levelId`.
|
|
50
|
+
*
|
|
51
|
+
* `scene` may be a `{ nodes }` snapshot or the raw node map.
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveMarks(scene: MarkSceneInput | Readonly<Record<string, AnyNode>>, levelId: AnyNodeId): Map<string, string>;
|
|
54
|
+
export declare function resolveMarkDetail(scene: MarkSceneInput | Readonly<Record<string, AnyNode>>, levelId: AnyNodeId): MarkResolution;
|
|
55
|
+
/**
|
|
56
|
+
* Write invented marks back onto the nodes so numbering never drifts.
|
|
57
|
+
*
|
|
58
|
+
* Call once per level per edit session (the caller decides when — this
|
|
59
|
+
* module stays pure). `update` is typically `sceneApi.update`.
|
|
60
|
+
*/
|
|
61
|
+
export declare function persistResolvedMarks(resolution: MarkResolution, update: (id: AnyNodeId, data: Record<string, unknown>) => void): number;
|
|
62
|
+
type Opening = (DoorNode | WindowNode) & {
|
|
63
|
+
type: 'door' | 'window';
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Every door and window under the level, clockwise from the NW-most
|
|
67
|
+
* exterior wall, exterior walls first.
|
|
68
|
+
*/
|
|
69
|
+
export declare function orderedOpenings(nodes: Readonly<Record<string, AnyNode>>, levelId: AnyNodeId): Opening[];
|
|
70
|
+
export {};
|
|
71
|
+
//# sourceMappingURL=marks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marks.d.ts","sourceRoot":"","sources":["../../../src/lib/floorplan/marks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAuB,UAAU,EAAE,MAAM,cAAc,CAAA;AAEjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,CAAA;AAE/C,MAAM,MAAM,cAAc,GAAG;IAC3B,qDAAqD;IACrD,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,+DAA+D;IAC/D,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxC,6DAA6D;IAC7D,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CACzC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzD,OAAO,EAAE,SAAS,GACjB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAErB;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzD,OAAO,EAAE,SAAS,GACjB,cAAc,CAkDhB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,cAAc,EAC1B,MAAM,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAC7D,MAAM,CAOR;AAID,KAAK,OAAO,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,CAAA;AAEpE;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,OAAO,EAAE,SAAS,GACjB,OAAO,EAAE,CAuCX"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve marks for every door and window under `levelId`.
|
|
3
|
+
*
|
|
4
|
+
* `scene` may be a `{ nodes }` snapshot or the raw node map.
|
|
5
|
+
*/
|
|
6
|
+
export function resolveMarks(scene, levelId) {
|
|
7
|
+
return new Map(resolveMarkDetail(scene, levelId).marks);
|
|
8
|
+
}
|
|
9
|
+
export function resolveMarkDetail(scene, levelId) {
|
|
10
|
+
const nodes = normalizeNodes(scene);
|
|
11
|
+
const level = nodes[levelId];
|
|
12
|
+
const ordinal = level && level.type === 'level' ? (level.level ?? 0) : 0;
|
|
13
|
+
const base = (Math.max(0, ordinal) + 1) * 100;
|
|
14
|
+
const openings = orderedOpenings(nodes, levelId);
|
|
15
|
+
const marks = new Map();
|
|
16
|
+
const assignments = new Map();
|
|
17
|
+
const issues = [];
|
|
18
|
+
for (const kind of ['door', 'window']) {
|
|
19
|
+
const prefix = kind === 'door' ? 'D' : 'W';
|
|
20
|
+
const list = openings.filter((opening) => opening.type === kind);
|
|
21
|
+
const used = new Set();
|
|
22
|
+
const explicitOwners = new Map();
|
|
23
|
+
for (const opening of list) {
|
|
24
|
+
const explicit = opening.mark?.trim();
|
|
25
|
+
if (!explicit)
|
|
26
|
+
continue;
|
|
27
|
+
marks.set(opening.id, explicit);
|
|
28
|
+
const normalized = explicit.toLocaleUpperCase();
|
|
29
|
+
used.add(normalized);
|
|
30
|
+
const owners = explicitOwners.get(normalized);
|
|
31
|
+
if (owners)
|
|
32
|
+
owners.push(opening.id);
|
|
33
|
+
else
|
|
34
|
+
explicitOwners.set(normalized, [opening.id]);
|
|
35
|
+
}
|
|
36
|
+
let sequence = 1;
|
|
37
|
+
for (const opening of list) {
|
|
38
|
+
if (marks.has(opening.id))
|
|
39
|
+
continue;
|
|
40
|
+
let candidate = `${prefix}${base + sequence}`;
|
|
41
|
+
while (used.has(candidate.toLocaleUpperCase())) {
|
|
42
|
+
sequence++;
|
|
43
|
+
candidate = `${prefix}${base + sequence}`;
|
|
44
|
+
}
|
|
45
|
+
marks.set(opening.id, candidate);
|
|
46
|
+
assignments.set(opening.id, candidate);
|
|
47
|
+
used.add(candidate.toLocaleUpperCase());
|
|
48
|
+
sequence++;
|
|
49
|
+
}
|
|
50
|
+
for (const [mark, owners] of explicitOwners) {
|
|
51
|
+
if (owners.length > 1) {
|
|
52
|
+
issues.push(`Duplicate ${kind} mark ${mark} (${owners.length} instances)`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { marks, assignments, issues };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Write invented marks back onto the nodes so numbering never drifts.
|
|
60
|
+
*
|
|
61
|
+
* Call once per level per edit session (the caller decides when — this
|
|
62
|
+
* module stays pure). `update` is typically `sceneApi.update`.
|
|
63
|
+
*/
|
|
64
|
+
export function persistResolvedMarks(resolution, update) {
|
|
65
|
+
let written = 0;
|
|
66
|
+
for (const [id, mark] of resolution.assignments) {
|
|
67
|
+
update(id, { mark });
|
|
68
|
+
written++;
|
|
69
|
+
}
|
|
70
|
+
return written;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Every door and window under the level, clockwise from the NW-most
|
|
74
|
+
* exterior wall, exterior walls first.
|
|
75
|
+
*/
|
|
76
|
+
export function orderedOpenings(nodes, levelId) {
|
|
77
|
+
const walls = [];
|
|
78
|
+
const orphanOpenings = [];
|
|
79
|
+
const visit = (id) => {
|
|
80
|
+
const node = nodes[id];
|
|
81
|
+
if (!node)
|
|
82
|
+
return;
|
|
83
|
+
if (node.visible === false)
|
|
84
|
+
return;
|
|
85
|
+
if (node.type === 'wall')
|
|
86
|
+
walls.push(node);
|
|
87
|
+
else if (node.type === 'door' || node.type === 'window') {
|
|
88
|
+
const opening = node;
|
|
89
|
+
if (!opening.wallId || !nodes[opening.wallId])
|
|
90
|
+
orphanOpenings.push(opening);
|
|
91
|
+
}
|
|
92
|
+
for (const childId of node.children ?? [])
|
|
93
|
+
visit(childId);
|
|
94
|
+
};
|
|
95
|
+
visit(levelId);
|
|
96
|
+
const centroid = wallCentroid(walls);
|
|
97
|
+
const ordered = [...walls].sort((left, right) => {
|
|
98
|
+
const leftExterior = isExteriorWall(left) ? 0 : 1;
|
|
99
|
+
const rightExterior = isExteriorWall(right) ? 0 : 1;
|
|
100
|
+
if (leftExterior !== rightExterior)
|
|
101
|
+
return leftExterior - rightExterior;
|
|
102
|
+
return clockwiseKey(left, centroid) - clockwiseKey(right, centroid);
|
|
103
|
+
});
|
|
104
|
+
const result = [];
|
|
105
|
+
for (const wall of ordered) {
|
|
106
|
+
const wallOpenings = [];
|
|
107
|
+
for (const childId of wall.children ?? []) {
|
|
108
|
+
const child = nodes[childId];
|
|
109
|
+
if (child && child.visible !== false && (child.type === 'door' || child.type === 'window')) {
|
|
110
|
+
wallOpenings.push(child);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
wallOpenings.sort((left, right) => left.position[0] - right.position[0]);
|
|
114
|
+
result.push(...wallOpenings);
|
|
115
|
+
}
|
|
116
|
+
result.push(...orphanOpenings);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
function wallCentroid(walls) {
|
|
120
|
+
if (walls.length === 0)
|
|
121
|
+
return [0, 0];
|
|
122
|
+
let x = 0;
|
|
123
|
+
let z = 0;
|
|
124
|
+
for (const wall of walls) {
|
|
125
|
+
x += (wall.start[0] + wall.end[0]) / 2;
|
|
126
|
+
z += (wall.start[1] + wall.end[1]) / 2;
|
|
127
|
+
}
|
|
128
|
+
return [x / walls.length, z / walls.length];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Sweep key: 0 at the north-west direction, increasing clockwise on screen.
|
|
132
|
+
*
|
|
133
|
+
* Plan axes are x east, z south — z grows DOWN the screen — so a clockwise
|
|
134
|
+
* screen sweep (up → right → down → left) is the INCREASING atan2(z, x)
|
|
135
|
+
* direction. The north-west diagonal sits at atan2(-1, -1) = -3π/4, so
|
|
136
|
+
* anchoring there and wrapping into [0, 2π) yields north, east, south, west.
|
|
137
|
+
*/
|
|
138
|
+
const NORTH_WEST_ANGLE = (-3 * Math.PI) / 4;
|
|
139
|
+
function clockwiseKey(wall, centroid) {
|
|
140
|
+
const midX = (wall.start[0] + wall.end[0]) / 2 - centroid[0];
|
|
141
|
+
const midZ = (wall.start[1] + wall.end[1]) / 2 - centroid[1];
|
|
142
|
+
let sweep = Math.atan2(midZ, midX) - NORTH_WEST_ANGLE;
|
|
143
|
+
while (sweep < 0)
|
|
144
|
+
sweep += Math.PI * 2;
|
|
145
|
+
while (sweep >= Math.PI * 2)
|
|
146
|
+
sweep -= Math.PI * 2;
|
|
147
|
+
return sweep;
|
|
148
|
+
}
|
|
149
|
+
function isExteriorWall(wall) {
|
|
150
|
+
return wall.frontSide === 'exterior' || wall.backSide === 'exterior';
|
|
151
|
+
}
|
|
152
|
+
function normalizeNodes(scene) {
|
|
153
|
+
const candidate = scene;
|
|
154
|
+
return candidate && typeof candidate === 'object' && 'nodes' in candidate
|
|
155
|
+
? candidate.nodes
|
|
156
|
+
: scene;
|
|
157
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type WallJustification } from '../../systems/wall/wall-frame.js';
|
|
2
|
+
import type { Point2D } from '../../systems/wall/wall-mitering.js';
|
|
3
|
+
export declare const FLOORPLAN_VIEW_ROTATION_DEG = 0;
|
|
4
|
+
export declare function clampPlanValue(value: number, min: number, max: number): number;
|
|
5
|
+
export declare function rotatePlanVector(x: number, y: number, rotation: number): [number, number];
|
|
6
|
+
export declare function worldToFloorplanLocalPoint(worldX: number, worldZ: number, buildingPosition: readonly [number, number, number], buildingRotationY: number): Point2D;
|
|
7
|
+
export declare function floorplanLocalToWorldPoint(point: Point2D | [number, number], buildingPosition: readonly [number, number, number], buildingRotationY: number): {
|
|
8
|
+
x: number;
|
|
9
|
+
z: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function interpolatePlanPoint(start: Point2D, end: Point2D, t: number): Point2D;
|
|
12
|
+
export declare function getPlanPointDistance(start: Point2D, end: Point2D): number;
|
|
13
|
+
export declare function movePlanPointTowards(start: Point2D, end: Point2D, distance: number): Point2D;
|
|
14
|
+
export declare function getThickPlanLinePolygon(line: {
|
|
15
|
+
start: Point2D;
|
|
16
|
+
end: Point2D;
|
|
17
|
+
}, thickness: number, justification?: WallJustification): Point2D[];
|
|
18
|
+
//# sourceMappingURL=plan-math.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-math.d.ts","sourceRoot":"","sources":["../../../src/lib/floorplan/plan-math.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AAC1F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAA;AAY/D,eAAO,MAAM,2BAA2B,IAAI,CAAA;AAE5C,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,UAErE;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAIzF;AAQD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACnD,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAUT;AAGD,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,gBAAgB,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACnD,iBAAiB,EAAE,MAAM,GACxB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAU1B;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAKrF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAEzE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAO5F;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,EACtC,SAAS,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,iBAAiB,GAChC,OAAO,EAAE,CAqBX"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { getWallFaceOffsets } from '../../systems/wall/wall-frame.js';
|
|
2
|
+
// Baseline rotation (deg) that orients the plan-local scene "north up" on
|
|
3
|
+
// screen. The on-screen floor-plan scene `<g>` is rotated by
|
|
4
|
+
// `FLOORPLAN_VIEW_ROTATION_DEG + userRotation - buildingRotation`; PDF export
|
|
5
|
+
// uses the same user rotation so its orientation matches the live plan.
|
|
6
|
+
//
|
|
7
|
+
// North is world −Z: with a 0 baseline a rotation-0 reference image (top =
|
|
8
|
+
// −Z) reads upright in the north-aligned view, and "align north" maps to a
|
|
9
|
+
// 3D camera azimuth of 0. The old 90° baseline made north world −X, so
|
|
10
|
+
// north-up floorplan scans displayed sideways whenever the compass claimed
|
|
11
|
+
// the view was aligned.
|
|
12
|
+
export const FLOORPLAN_VIEW_ROTATION_DEG = 0;
|
|
13
|
+
export function clampPlanValue(value, min, max) {
|
|
14
|
+
return Math.min(Math.max(value, min), max);
|
|
15
|
+
}
|
|
16
|
+
export function rotatePlanVector(x, y, rotation) {
|
|
17
|
+
const cos = Math.cos(rotation);
|
|
18
|
+
const sin = Math.sin(rotation);
|
|
19
|
+
return [x * cos + y * sin, -x * sin + y * cos];
|
|
20
|
+
}
|
|
21
|
+
// Converts a world X/Z point into the floor-plan-local (building-local)
|
|
22
|
+
// frame used by the SVG scene `<g>` and every stored node position. The
|
|
23
|
+
// inverse of `floorplanLocalToWorldPoint`. Shared so the floor-plan panel
|
|
24
|
+
// and the 2D move overlay resolve the same frame — feeding a world-space
|
|
25
|
+
// `original` into a local-space cursor solver lands the drop off by the
|
|
26
|
+
// building's world X/Z (worse for an off-origin building).
|
|
27
|
+
export function worldToFloorplanLocalPoint(worldX, worldZ, buildingPosition, buildingRotationY) {
|
|
28
|
+
const dx = worldX - buildingPosition[0];
|
|
29
|
+
const dz = worldZ - buildingPosition[2];
|
|
30
|
+
const cos = Math.cos(buildingRotationY);
|
|
31
|
+
const sin = Math.sin(buildingRotationY);
|
|
32
|
+
return {
|
|
33
|
+
x: dx * cos - dz * sin,
|
|
34
|
+
y: dx * sin + dz * cos,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// Inverse of `worldToFloorplanLocalPoint`: floor-plan-local X/Y → world X/Z.
|
|
38
|
+
export function floorplanLocalToWorldPoint(point, buildingPosition, buildingRotationY) {
|
|
39
|
+
const localX = Array.isArray(point) ? point[0] : point.x;
|
|
40
|
+
const localY = Array.isArray(point) ? point[1] : point.y;
|
|
41
|
+
const cos = Math.cos(buildingRotationY);
|
|
42
|
+
const sin = Math.sin(buildingRotationY);
|
|
43
|
+
return {
|
|
44
|
+
x: buildingPosition[0] + localX * cos + localY * sin,
|
|
45
|
+
z: buildingPosition[2] - localX * sin + localY * cos,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function interpolatePlanPoint(start, end, t) {
|
|
49
|
+
return {
|
|
50
|
+
x: start.x + (end.x - start.x) * t,
|
|
51
|
+
y: start.y + (end.y - start.y) * t,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function getPlanPointDistance(start, end) {
|
|
55
|
+
return Math.hypot(end.x - start.x, end.y - start.y);
|
|
56
|
+
}
|
|
57
|
+
export function movePlanPointTowards(start, end, distance) {
|
|
58
|
+
const totalDistance = getPlanPointDistance(start, end);
|
|
59
|
+
if (totalDistance <= Number.EPSILON || distance <= 0) {
|
|
60
|
+
return start;
|
|
61
|
+
}
|
|
62
|
+
return interpolatePlanPoint(start, end, Math.min(1, distance / totalDistance));
|
|
63
|
+
}
|
|
64
|
+
export function getThickPlanLinePolygon(line, thickness, justification) {
|
|
65
|
+
const dx = line.end.x - line.start.x;
|
|
66
|
+
const dy = line.end.y - line.start.y;
|
|
67
|
+
const length = Math.hypot(dx, dy);
|
|
68
|
+
if (length <= Number.EPSILON || thickness <= 0) {
|
|
69
|
+
return [line.start, line.end, line.end, line.start];
|
|
70
|
+
}
|
|
71
|
+
const { a, b } = getWallFaceOffsets({ thickness, justification });
|
|
72
|
+
const normalX = (-dy / length) * a;
|
|
73
|
+
const normalY = (dx / length) * a;
|
|
74
|
+
const backX = (-dy / length) * -b;
|
|
75
|
+
const backY = (dx / length) * -b;
|
|
76
|
+
return [
|
|
77
|
+
{ x: line.start.x + normalX, y: line.start.y + normalY },
|
|
78
|
+
{ x: line.end.x + normalX, y: line.end.y + normalY },
|
|
79
|
+
{ x: line.end.x - backX, y: line.end.y - backY },
|
|
80
|
+
{ x: line.start.x - backX, y: line.start.y - backY },
|
|
81
|
+
];
|
|
82
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Point2D } from '../../systems/wall/wall-mitering.js';
|
|
2
|
+
export declare function formatPolygonPath(points: Point2D[], holes?: Point2D[][]): string;
|
|
3
|
+
export declare function buildSvgPolylinePath(points: Point2D[]): string | null;
|
|
4
|
+
export declare function getArcPlanPoint(center: Point2D, radius: number, angle: number): Point2D;
|
|
5
|
+
export declare function buildSvgArcPath(center: Point2D, radius: number, startAngle: number, endAngle: number): string;
|
|
6
|
+
export declare function buildSvgAnnularSectorPath(center: Point2D, innerRadius: number, outerRadius: number, startAngle: number, endAngle: number): string;
|
|
7
|
+
export declare function formatSvgPolygonPoints(points: Point2D[]): string;
|
|
8
|
+
/**
|
|
9
|
+
* Three points defining an arrow head — tip + two trailing barbs.
|
|
10
|
+
* Returned as plain `Point2D` objects so consumers can either feed them
|
|
11
|
+
* straight into `formatSvgPolygonPoints` (for SVG `points=""`) or push
|
|
12
|
+
* them onto a `FloorplanGeometry.polygon.points` array. Mixing both
|
|
13
|
+
* downstream paths through a string-returning helper was awkward — see
|
|
14
|
+
* `nodes/src/stair/floorplan.ts` which needs the points as objects.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildSvgArrowHeadPoints(point: Point2D, angle: number, size: number): Point2D[];
|
|
17
|
+
//# sourceMappingURL=svg-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg-paths.d.ts","sourceRoot":"","sources":["../../../src/lib/floorplan/svg-paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAA;AAiB/D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,GAAE,OAAO,EAAE,EAAO,UAoB3E;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,iBAWrD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAKvF;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,UAIjB;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,UAWjB;AAWD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,UAEvD;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAW9F"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
function toSvgX(value) {
|
|
2
|
+
return value;
|
|
3
|
+
}
|
|
4
|
+
function toSvgY(value) {
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
function toSvgPoint(point) {
|
|
8
|
+
return {
|
|
9
|
+
x: toSvgX(point.x),
|
|
10
|
+
y: toSvgY(point.y),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function formatPolygonPath(points, holes = []) {
|
|
14
|
+
const formatSubpath = (subpathPoints) => {
|
|
15
|
+
const [firstPoint, ...restPoints] = subpathPoints;
|
|
16
|
+
if (!firstPoint) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const firstSvgPoint = toSvgPoint(firstPoint);
|
|
20
|
+
return [
|
|
21
|
+
`M ${firstSvgPoint.x} ${firstSvgPoint.y}`,
|
|
22
|
+
...restPoints.map((point) => {
|
|
23
|
+
const svgPoint = toSvgPoint(point);
|
|
24
|
+
return `L ${svgPoint.x} ${svgPoint.y}`;
|
|
25
|
+
}),
|
|
26
|
+
'Z',
|
|
27
|
+
].join(' ');
|
|
28
|
+
};
|
|
29
|
+
return [points, ...holes].map(formatSubpath).filter(Boolean).join(' ');
|
|
30
|
+
}
|
|
31
|
+
export function buildSvgPolylinePath(points) {
|
|
32
|
+
if (points.length < 2) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return points
|
|
36
|
+
.map((point, index) => {
|
|
37
|
+
const svgPoint = toSvgPoint(point);
|
|
38
|
+
return `${index === 0 ? 'M' : 'L'} ${svgPoint.x} ${svgPoint.y}`;
|
|
39
|
+
})
|
|
40
|
+
.join(' ');
|
|
41
|
+
}
|
|
42
|
+
export function getArcPlanPoint(center, radius, angle) {
|
|
43
|
+
return {
|
|
44
|
+
x: center.x + Math.cos(angle) * radius,
|
|
45
|
+
y: center.y + Math.sin(angle) * radius,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function buildSvgArcPath(center, radius, startAngle, endAngle) {
|
|
49
|
+
const start = getArcPlanPoint(center, radius, startAngle);
|
|
50
|
+
return `M ${toSvgX(start.x)} ${toSvgY(start.y)} ${svgArcCommands(center, radius, startAngle, endAngle)}`;
|
|
51
|
+
}
|
|
52
|
+
export function buildSvgAnnularSectorPath(center, innerRadius, outerRadius, startAngle, endAngle) {
|
|
53
|
+
const outerStart = getArcPlanPoint(center, outerRadius, startAngle);
|
|
54
|
+
const innerEnd = getArcPlanPoint(center, innerRadius, endAngle);
|
|
55
|
+
return [
|
|
56
|
+
`M ${toSvgX(outerStart.x)} ${toSvgY(outerStart.y)}`,
|
|
57
|
+
svgArcCommands(center, outerRadius, startAngle, endAngle),
|
|
58
|
+
`L ${toSvgX(innerEnd.x)} ${toSvgY(innerEnd.y)}`,
|
|
59
|
+
svgArcCommands(center, innerRadius, endAngle, startAngle),
|
|
60
|
+
'Z',
|
|
61
|
+
].join(' ');
|
|
62
|
+
}
|
|
63
|
+
function svgArcCommands(center, radius, startAngle, endAngle) {
|
|
64
|
+
const delta = endAngle - startAngle;
|
|
65
|
+
const count = Math.max(1, Math.ceil(Math.abs(delta) / Math.PI));
|
|
66
|
+
return Array.from({ length: count }, (_, index) => {
|
|
67
|
+
const end = getArcPlanPoint(center, radius, startAngle + (delta * (index + 1)) / count);
|
|
68
|
+
return `A ${radius} ${radius} 0 0 ${delta >= 0 ? 1 : 0} ${toSvgX(end.x)} ${toSvgY(end.y)}`;
|
|
69
|
+
}).join(' ');
|
|
70
|
+
}
|
|
71
|
+
export function formatSvgPolygonPoints(points) {
|
|
72
|
+
return points.map((point) => `${toSvgX(point.x)},${toSvgY(point.y)}`).join(' ');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Three points defining an arrow head — tip + two trailing barbs.
|
|
76
|
+
* Returned as plain `Point2D` objects so consumers can either feed them
|
|
77
|
+
* straight into `formatSvgPolygonPoints` (for SVG `points=""`) or push
|
|
78
|
+
* them onto a `FloorplanGeometry.polygon.points` array. Mixing both
|
|
79
|
+
* downstream paths through a string-returning helper was awkward — see
|
|
80
|
+
* `nodes/src/stair/floorplan.ts` which needs the points as objects.
|
|
81
|
+
*/
|
|
82
|
+
export function buildSvgArrowHeadPoints(point, angle, size) {
|
|
83
|
+
const left = {
|
|
84
|
+
x: point.x - size * Math.cos(angle - Math.PI / 6),
|
|
85
|
+
y: point.y - size * Math.sin(angle - Math.PI / 6),
|
|
86
|
+
};
|
|
87
|
+
const right = {
|
|
88
|
+
x: point.x - size * Math.cos(angle + Math.PI / 6),
|
|
89
|
+
y: point.y - size * Math.sin(angle + Math.PI / 6),
|
|
90
|
+
};
|
|
91
|
+
return [point, left, right];
|
|
92
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { WallNode } from '../../schema/index.js';
|
|
2
|
+
import type { WallPlanPoint } from '../../systems/wall/wall-move.js';
|
|
3
|
+
/** The floor plan's affordance id for a wall end's pull grip (a `move-arrow`, variant `pull`). */
|
|
4
|
+
export declare const WALL_PULL_AFFORDANCE = "wall-pull";
|
|
5
|
+
/** What a pull grip carries: the wall, and which of its ends it pulls from. */
|
|
6
|
+
export type WallPullGripPayload = {
|
|
7
|
+
wallId: string;
|
|
8
|
+
endpoint: 'start' | 'end';
|
|
9
|
+
};
|
|
10
|
+
/** The grip's tooltip, in both views. */
|
|
11
|
+
export declare const WALL_PULL_GRIP_TITLE = "Drag to draw the next wall";
|
|
12
|
+
/**
|
|
13
|
+
* The pulled end of `wall` and the direction out of it: along the wall for a
|
|
14
|
+
* straight one, along its tangent for a curved one.
|
|
15
|
+
*/
|
|
16
|
+
export declare function wallPullSeed(wall: Pick<WallNode, 'start' | 'end' | 'curveOffset'>, endpoint: 'start' | 'end'): {
|
|
17
|
+
start: WallPlanPoint;
|
|
18
|
+
reference: WallPlanPoint;
|
|
19
|
+
} | null;
|
|
20
|
+
/**
|
|
21
|
+
* The affordance a floor-plan `move-arrow` carries to be a wall push arrow;
|
|
22
|
+
* its payload is a `WallPushArrowPayload`. The editor's floor plan runs its
|
|
23
|
+
* wall push for it instead of a registry affordance session.
|
|
24
|
+
*/
|
|
25
|
+
export declare const WALL_PUSH_AFFORDANCE = "wall-push";
|
|
26
|
+
/** A wall's or an invisible wall's side arrow: `wallId` is either. */
|
|
27
|
+
export type WallPushArrowPayload = {
|
|
28
|
+
wallId: string;
|
|
29
|
+
side: 'a' | 'b';
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=wall-affordances.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wall-affordances.d.ts","sourceRoot":"","sources":["../../../src/lib/floorplan/wall-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAE5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAEjE,kGAAkG;AAClG,eAAO,MAAM,oBAAoB,cAAc,CAAA;AAE/C,+EAA+E;AAC/E,MAAM,MAAM,mBAAmB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAA;CAAE,CAAA;AAE/E,yCAAyC;AACzC,eAAO,MAAM,oBAAoB,+BAA+B,CAAA;AAEhE;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,GAAG,aAAa,CAAC,EACrD,QAAQ,EAAE,OAAO,GAAG,KAAK,GACxB;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,SAAS,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAQ3D;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,cAAc,CAAA;AAE/C,sEAAsE;AACtE,MAAM,MAAM,oBAAoB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAAA;CAAE,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getWallCurveFrameAt } from '../../systems/wall/wall-curve.js';
|
|
2
|
+
/** The floor plan's affordance id for a wall end's pull grip (a `move-arrow`, variant `pull`). */
|
|
3
|
+
export const WALL_PULL_AFFORDANCE = 'wall-pull';
|
|
4
|
+
/** The grip's tooltip, in both views. */
|
|
5
|
+
export const WALL_PULL_GRIP_TITLE = 'Drag to draw the next wall';
|
|
6
|
+
/**
|
|
7
|
+
* The pulled end of `wall` and the direction out of it: along the wall for a
|
|
8
|
+
* straight one, along its tangent for a curved one.
|
|
9
|
+
*/
|
|
10
|
+
export function wallPullSeed(wall, endpoint) {
|
|
11
|
+
const start = endpoint === 'start' ? [wall.start[0], wall.start[1]] : [wall.end[0], wall.end[1]];
|
|
12
|
+
const tangent = getWallCurveFrameAt(wall, endpoint === 'start' ? 0 : 1).tangent;
|
|
13
|
+
const sign = endpoint === 'start' ? -1 : 1;
|
|
14
|
+
const length = Math.hypot(tangent.x, tangent.y);
|
|
15
|
+
if (!(length > 1e-9))
|
|
16
|
+
return null;
|
|
17
|
+
return { start, reference: [(tangent.x / length) * sign, (tangent.y / length) * sign] };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The affordance a floor-plan `move-arrow` carries to be a wall push arrow;
|
|
21
|
+
* its payload is a `WallPushArrowPayload`. The editor's floor plan runs its
|
|
22
|
+
* wall push for it instead of a registry affordance session.
|
|
23
|
+
*/
|
|
24
|
+
export const WALL_PUSH_AFFORDANCE = 'wall-push';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AnyNode, AnyNodeId } from '../schema/types.js';
|
|
2
|
+
type NodeMap = Readonly<Record<string, Pick<AnyNode, 'parentId'>>>;
|
|
3
|
+
type NodeLookup = (id: AnyNodeId) => Pick<AnyNode, 'parentId'> | undefined;
|
|
4
|
+
/**
|
|
5
|
+
* Whether assigning `newParentId` to `nodeId` would put `nodeId` on a cycle of
|
|
6
|
+
* parent links. A cycle the chain already holds without `nodeId` is not one it
|
|
7
|
+
* creates: counting it would refuse every edit beneath an old cyclic scene.
|
|
8
|
+
*/
|
|
9
|
+
export declare function wouldCreateHierarchyCycle(nodeId: AnyNodeId, newParentId: AnyNodeId | null, nodes: NodeMap | NodeLookup): boolean;
|
|
10
|
+
/** Return each distinct cycle encoded by `parentId` links. */
|
|
11
|
+
export declare function findHierarchyCycles(nodes: NodeMap): AnyNodeId[][];
|
|
12
|
+
/** The `parentId` error each node on a cycle raises, as every scene check lists it. */
|
|
13
|
+
export declare function hierarchyCycleErrors(nodes: NodeMap): {
|
|
14
|
+
nodeId: AnyNodeId;
|
|
15
|
+
path: 'parentId';
|
|
16
|
+
message: string;
|
|
17
|
+
}[];
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=hierarchy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hierarchy.d.ts","sourceRoot":"","sources":["../../src/lib/hierarchy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEzD,KAAK,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAA;AAClE,KAAK,UAAU,GAAG,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,SAAS,CAAA;AAE1E;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,SAAS,GAAG,IAAI,EAC7B,KAAK,EAAE,OAAO,GAAG,UAAU,GAC1B,OAAO,CAaT;AAED,8DAA8D;AAC9D,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,EAAE,EAAE,CAwBjE;AAED,uFAAuF;AACvF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,GACb;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAK5D"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether assigning `newParentId` to `nodeId` would put `nodeId` on a cycle of
|
|
3
|
+
* parent links. A cycle the chain already holds without `nodeId` is not one it
|
|
4
|
+
* creates: counting it would refuse every edit beneath an old cyclic scene.
|
|
5
|
+
*/
|
|
6
|
+
export function wouldCreateHierarchyCycle(nodeId, newParentId, nodes) {
|
|
7
|
+
if (!newParentId)
|
|
8
|
+
return false;
|
|
9
|
+
const nodeAt = typeof nodes === 'function' ? nodes : (id) => nodes[id];
|
|
10
|
+
const seen = new Set();
|
|
11
|
+
let currentId = newParentId;
|
|
12
|
+
while (currentId) {
|
|
13
|
+
if (currentId === nodeId)
|
|
14
|
+
return true;
|
|
15
|
+
if (seen.has(currentId))
|
|
16
|
+
return false;
|
|
17
|
+
seen.add(currentId);
|
|
18
|
+
currentId = nodeAt(currentId)?.parentId ?? null;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
/** Return each distinct cycle encoded by `parentId` links. */
|
|
23
|
+
export function findHierarchyCycles(nodes) {
|
|
24
|
+
const visited = new Set();
|
|
25
|
+
const cycles = [];
|
|
26
|
+
for (const startId of Object.keys(nodes)) {
|
|
27
|
+
if (visited.has(startId))
|
|
28
|
+
continue;
|
|
29
|
+
const chain = [];
|
|
30
|
+
const positions = new Map();
|
|
31
|
+
let currentId = startId;
|
|
32
|
+
while (currentId && nodes[currentId] && !visited.has(currentId)) {
|
|
33
|
+
const position = positions.get(currentId);
|
|
34
|
+
if (position !== undefined) {
|
|
35
|
+
cycles.push(chain.slice(position));
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
positions.set(currentId, chain.length);
|
|
39
|
+
chain.push(currentId);
|
|
40
|
+
currentId = nodes[currentId]?.parentId ?? null;
|
|
41
|
+
}
|
|
42
|
+
for (const id of chain)
|
|
43
|
+
visited.add(id);
|
|
44
|
+
}
|
|
45
|
+
return cycles;
|
|
46
|
+
}
|
|
47
|
+
/** The `parentId` error each node on a cycle raises, as every scene check lists it. */
|
|
48
|
+
export function hierarchyCycleErrors(nodes) {
|
|
49
|
+
return findHierarchyCycles(nodes).flatMap((cycle) => {
|
|
50
|
+
const message = `hierarchy cycle detected: ${[...cycle, cycle[0]].join(' -> ')}`;
|
|
51
|
+
return cycle.map((nodeId) => ({ nodeId, path: 'parentId', message }));
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -5,7 +5,7 @@ export declare function supportSegmentAt(segment: WallSlabSupportSegment, t: num
|
|
|
5
5
|
export declare function openingDatumFromSupport(wall: WallNode, opening: Pick<DoorNode | WindowNode, 'position' | 'width' | 'height'> & Partial<Pick<DoorNode, 'rotation' | 'sidelightLeft' | 'sidelightRight' | 'transomHeight' | 'doorType'>>, support: WallSlabSupport): number;
|
|
6
6
|
/** Unclamped floor intent, used by authoring feasibility and legacy migration. */
|
|
7
7
|
export declare function getOpeningFloorTarget(wall: WallNode, opening: Pick<DoorNode | WindowNode, 'position' | 'width' | 'height'> & Partial<Pick<DoorNode, 'rotation' | 'sidelightLeft' | 'sidelightRight' | 'transomHeight' | 'doorType'>>, nodes: Readonly<Record<string, AnyNode>>): number;
|
|
8
|
-
export declare function openingFitsAtDatum(wall: WallNode, opening: Pick<DoorNode | WindowNode, 'position' | 'height'> & Partial<Pick<DoorNode, 'transomHeight' | 'doorType'>>, datum: number, nodes: Readonly<Record<string, AnyNode>>, support?: WallSlabSupport): boolean;
|
|
8
|
+
export declare function openingFitsAtDatum(wall: WallNode, opening: Pick<DoorNode | WindowNode, 'position' | 'width' | 'height'> & Partial<Pick<DoorNode, 'transomHeight' | 'doorType'>>, datum: number, nodes: Readonly<Record<string, AnyNode>>, support?: WallSlabSupport): boolean;
|
|
9
9
|
/**
|
|
10
10
|
* The lowest the wall reaches under the opening's span, level-local, on its centreline or either
|
|
11
11
|
* face: where a face goes down beside a floor sunk under the one the wall stands on (a garage
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opening-floor-datum.d.ts","sourceRoot":"","sources":["../../src/lib/opening-floor-datum.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAY,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAElF,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC5B,MAAM,8BAA8B,CAAA;AAuBrC,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,eAAe,CAoCjB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,sBAAsB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAMnF;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,QAAQ,EACd,OAAO,EAAE,IAAI,CAAC,QAAQ,GAAG,UAAU,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC,GACnE,OAAO,CACL,IAAI,CAAC,QAAQ,EAAE,UAAU,GAAG,eAAe,GAAG,gBAAgB,GAAG,eAAe,GAAG,UAAU,CAAC,CAC/F,EACH,OAAO,EAAE,eAAe,GACvB,MAAM,CAaR;AAED,kFAAkF;AAClF,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,QAAQ,EACd,OAAO,EAAE,IAAI,CAAC,QAAQ,GAAG,UAAU,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC,GACnE,OAAO,CACL,IAAI,CAAC,QAAQ,EAAE,UAAU,GAAG,eAAe,GAAG,gBAAgB,GAAG,eAAe,GAAG,UAAU,CAAC,CAC/F,EACH,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,MAAM,CAER;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,EACd,OAAO,EAAE,IAAI,CAAC,QAAQ,GAAG,UAAU,EAAE,UAAU,GAAG,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"opening-floor-datum.d.ts","sourceRoot":"","sources":["../../src/lib/opening-floor-datum.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getWallTopOver } from '../services/storey.js';
|
|
2
2
|
import { computeWallSlabSupport, } from '../systems/slab/slab-support.js';
|
|
3
3
|
import { getWallCurveFrameAt, getWallCurveLength } from '../systems/wall/wall-curve.js';
|
|
4
4
|
import { calculateLevelMiters, getWallPlanFootprint } from '../systems/wall/wall-footprint.js';
|
|
@@ -64,7 +64,7 @@ export function getOpeningFloorTarget(wall, opening, nodes) {
|
|
|
64
64
|
return openingDatumFromSupport(wall, opening, wallSupportForNodes(wall, nodes));
|
|
65
65
|
}
|
|
66
66
|
export function openingFitsAtDatum(wall, opening, datum, nodes, support = wallSupportForNodes(wall, nodes)) {
|
|
67
|
-
const top =
|
|
67
|
+
const top = getWallTopOver(wall, wall.parentId, nodes, support.elevation, opening.position[0] - opening.width / 2, opening.position[0] + opening.width / 2);
|
|
68
68
|
return (datum +
|
|
69
69
|
opening.position[1] -
|
|
70
70
|
opening.height / 2 +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"own-floor-intent.d.ts","sourceRoot":"","sources":["../../src/lib/own-floor-intent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAsB,MAAM,WAAW,CAAA;AAavE,KAAK,MAAM,GAAG;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAA;AAEvD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,OAAO,EAAE,SAAS,MAAM,EAAE;aAKT,MAAM,EAAE;;;;;;
|
|
1
|
+
{"version":3,"file":"own-floor-intent.d.ts","sourceRoot":"","sources":["../../src/lib/own-floor-intent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAsB,MAAM,WAAW,CAAA;AAavE,KAAK,MAAM,GAAG;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAA;AAEvD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,OAAO,EAAE,SAAS,MAAM,EAAE;aAKT,MAAM,EAAE;;;;;;EAqO1B"}
|