@pascal-app/core 0.8.0 → 0.9.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/events/bus.d.ts +39 -13
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/hooks/scene-registry/scene-registry.d.ts +6 -22
- package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
- package/dist/hooks/scene-registry/scene-registry.js +33 -26
- package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +14 -0
- package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -0
- package/dist/hooks/spatial-grid/floor-placed-elevation.js +51 -0
- package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts +2 -0
- package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts.map +1 -0
- package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +273 -0
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +13 -2
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.js +95 -9
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +28 -1
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-sync.js +91 -18
- package/dist/index.d.ts +22 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -2
- package/dist/lib/polygon-relations.d.ts +10 -0
- package/dist/lib/polygon-relations.d.ts.map +1 -0
- package/dist/lib/polygon-relations.js +73 -0
- package/dist/lib/space-detection-pause.test.d.ts +2 -0
- package/dist/lib/space-detection-pause.test.d.ts.map +1 -0
- package/dist/lib/space-detection-pause.test.js +42 -0
- package/dist/lib/space-detection.d.ts +30 -1
- package/dist/lib/space-detection.d.ts.map +1 -1
- package/dist/lib/space-detection.js +215 -36
- package/dist/lib/space-detection.test.d.ts +2 -0
- package/dist/lib/space-detection.test.d.ts.map +1 -0
- package/dist/lib/space-detection.test.js +77 -0
- package/dist/material-library.d.ts +1 -1
- package/dist/material-library.d.ts.map +1 -1
- package/dist/material-library.js +1940 -143
- package/dist/registry/__bench__/relations-resolver.bench.d.ts +15 -0
- package/dist/registry/__bench__/relations-resolver.bench.d.ts.map +1 -0
- package/dist/registry/__bench__/relations-resolver.bench.js +170 -0
- package/dist/registry/handles.d.ts +321 -0
- package/dist/registry/handles.d.ts.map +1 -0
- package/dist/registry/handles.js +24 -0
- package/dist/registry/index.d.ts +7 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +4 -0
- package/dist/registry/registry.d.ts +93 -0
- package/dist/registry/registry.d.ts.map +1 -0
- package/dist/registry/registry.js +201 -0
- package/dist/registry/registry.test.d.ts +2 -0
- package/dist/registry/registry.test.d.ts.map +1 -0
- package/dist/registry/registry.test.js +183 -0
- package/dist/registry/relations-resolver.d.ts +42 -0
- package/dist/registry/relations-resolver.d.ts.map +1 -0
- package/dist/registry/relations-resolver.js +77 -0
- package/dist/registry/relations-resolver.test.d.ts +2 -0
- package/dist/registry/relations-resolver.test.d.ts.map +1 -0
- package/dist/registry/relations-resolver.test.js +183 -0
- package/dist/registry/scene-api.d.ts +44 -0
- package/dist/registry/scene-api.d.ts.map +1 -0
- package/dist/registry/scene-api.js +111 -0
- package/dist/registry/scene-api.test.d.ts +2 -0
- package/dist/registry/scene-api.test.d.ts.map +1 -0
- package/dist/registry/scene-api.test.js +183 -0
- package/dist/registry/subtree.d.ts +67 -0
- package/dist/registry/subtree.d.ts.map +1 -0
- package/dist/registry/subtree.js +119 -0
- package/dist/registry/subtree.test.d.ts +2 -0
- package/dist/registry/subtree.test.d.ts.map +1 -0
- package/dist/registry/subtree.test.js +133 -0
- package/dist/registry/types.d.ts +1420 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +1 -0
- package/dist/schema/index.d.ts +17 -2
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +17 -3
- package/dist/schema/material.d.ts +10 -0
- package/dist/schema/material.d.ts.map +1 -1
- package/dist/schema/material.js +10 -0
- package/dist/schema/nodes/box-vent.d.ts +74 -0
- package/dist/schema/nodes/box-vent.d.ts.map +1 -0
- package/dist/schema/nodes/box-vent.js +63 -0
- package/dist/schema/nodes/building.d.ts +1 -1
- package/dist/schema/nodes/building.d.ts.map +1 -1
- package/dist/schema/nodes/building.js +3 -2
- package/dist/schema/nodes/ceiling.d.ts +2 -0
- package/dist/schema/nodes/ceiling.d.ts.map +1 -1
- package/dist/schema/nodes/ceiling.js +1 -1
- package/dist/schema/nodes/chimney.d.ts +158 -0
- package/dist/schema/nodes/chimney.d.ts.map +1 -0
- package/dist/schema/nodes/chimney.js +67 -0
- package/dist/schema/nodes/column.d.ts +597 -5
- package/dist/schema/nodes/column.d.ts.map +1 -1
- package/dist/schema/nodes/column.js +586 -6
- package/dist/schema/nodes/cupola.d.ts +66 -0
- package/dist/schema/nodes/cupola.d.ts.map +1 -0
- package/dist/schema/nodes/cupola.js +28 -0
- package/dist/schema/nodes/dormer.d.ts +228 -0
- package/dist/schema/nodes/dormer.d.ts.map +1 -0
- package/dist/schema/nodes/dormer.js +119 -0
- package/dist/schema/nodes/downspout.d.ts +75 -0
- package/dist/schema/nodes/downspout.d.ts.map +1 -0
- package/dist/schema/nodes/downspout.js +63 -0
- package/dist/schema/nodes/elevator.d.ts +105 -0
- package/dist/schema/nodes/elevator.d.ts.map +1 -0
- package/dist/schema/nodes/elevator.js +54 -0
- package/dist/schema/nodes/eyebrow-vent.d.ts +68 -0
- package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -0
- package/dist/schema/nodes/eyebrow-vent.js +40 -0
- package/dist/schema/nodes/fence.d.ts +1 -0
- package/dist/schema/nodes/fence.d.ts.map +1 -1
- package/dist/schema/nodes/fence.js +2 -0
- package/dist/schema/nodes/gutter.d.ts +84 -0
- package/dist/schema/nodes/gutter.d.ts.map +1 -0
- package/dist/schema/nodes/gutter.js +76 -0
- package/dist/schema/nodes/item.d.ts +4 -0
- package/dist/schema/nodes/item.d.ts.map +1 -1
- package/dist/schema/nodes/item.js +9 -0
- package/dist/schema/nodes/level.d.ts +1 -1
- package/dist/schema/nodes/level.d.ts.map +1 -1
- package/dist/schema/nodes/level.js +2 -0
- package/dist/schema/nodes/ridge-vent.d.ts +67 -0
- package/dist/schema/nodes/ridge-vent.d.ts.map +1 -0
- package/dist/schema/nodes/ridge-vent.js +30 -0
- package/dist/schema/nodes/roof-segment.d.ts +195 -1
- package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment.js +254 -3
- package/dist/schema/nodes/roof.d.ts.map +1 -1
- package/dist/schema/nodes/roof.js +4 -16
- package/dist/schema/nodes/shelf.d.ts +105 -0
- package/dist/schema/nodes/shelf.d.ts.map +1 -0
- package/dist/schema/nodes/shelf.js +84 -0
- package/dist/schema/nodes/site.d.ts +1 -122
- package/dist/schema/nodes/site.d.ts.map +1 -1
- package/dist/schema/nodes/site.js +2 -6
- package/dist/schema/nodes/skylight.d.ts +279 -0
- package/dist/schema/nodes/skylight.d.ts.map +1 -0
- package/dist/schema/nodes/skylight.js +152 -0
- package/dist/schema/nodes/slab.d.ts +2 -0
- package/dist/schema/nodes/slab.d.ts.map +1 -1
- package/dist/schema/nodes/slab.js +1 -1
- package/dist/schema/nodes/solar-panel.d.ts +117 -0
- package/dist/schema/nodes/solar-panel.d.ts.map +1 -0
- package/dist/schema/nodes/solar-panel.js +47 -0
- package/dist/schema/nodes/surface-hole-metadata.d.ts +2 -0
- package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -1
- package/dist/schema/nodes/surface-hole-metadata.js +3 -1
- package/dist/schema/nodes/turbine-vent.d.ts +68 -0
- package/dist/schema/nodes/turbine-vent.d.ts.map +1 -0
- package/dist/schema/nodes/turbine-vent.js +41 -0
- package/dist/schema/types.d.ts +1325 -125
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +26 -0
- package/dist/services/alignment-anchors.d.ts +100 -0
- package/dist/services/alignment-anchors.d.ts.map +1 -0
- package/dist/services/alignment-anchors.js +283 -0
- package/dist/services/alignment-anchors.test.d.ts +2 -0
- package/dist/services/alignment-anchors.test.d.ts.map +1 -0
- package/dist/services/alignment-anchors.test.js +383 -0
- package/dist/services/alignment.d.ts +126 -0
- package/dist/services/alignment.d.ts.map +1 -0
- package/dist/services/alignment.js +169 -0
- package/dist/services/alignment.test.d.ts +2 -0
- package/dist/services/alignment.test.d.ts.map +1 -0
- package/dist/services/alignment.test.js +92 -0
- package/dist/services/drag-session.d.ts +47 -0
- package/dist/services/drag-session.d.ts.map +1 -0
- package/dist/services/drag-session.js +100 -0
- package/dist/services/drag-session.test.d.ts +2 -0
- package/dist/services/drag-session.test.d.ts.map +1 -0
- package/dist/services/drag-session.test.js +219 -0
- package/dist/services/hosting.d.ts +80 -0
- package/dist/services/hosting.d.ts.map +1 -0
- package/dist/services/hosting.js +122 -0
- package/dist/services/hosting.test.d.ts +2 -0
- package/dist/services/hosting.test.d.ts.map +1 -0
- package/dist/services/hosting.test.js +199 -0
- package/dist/services/index.d.ts +7 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +6 -0
- package/dist/services/movement.d.ts +48 -0
- package/dist/services/movement.d.ts.map +1 -0
- package/dist/services/movement.js +65 -0
- package/dist/services/movement.test.d.ts +2 -0
- package/dist/services/movement.test.d.ts.map +1 -0
- package/dist/services/movement.test.js +133 -0
- package/dist/services/single-undo-dance.test.d.ts +2 -0
- package/dist/services/single-undo-dance.test.d.ts.map +1 -0
- package/dist/services/single-undo-dance.test.js +210 -0
- package/dist/services/snap.d.ts +72 -0
- package/dist/services/snap.d.ts.map +1 -0
- package/dist/services/snap.js +120 -0
- package/dist/services/snap.test.d.ts +2 -0
- package/dist/services/snap.test.d.ts.map +1 -0
- package/dist/services/snap.test.js +95 -0
- package/dist/solar-panel-presets.d.ts +17 -0
- package/dist/solar-panel-presets.d.ts.map +1 -0
- package/dist/solar-panel-presets.js +43 -0
- package/dist/store/actions/node-actions.d.ts +14 -2
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +492 -15
- package/dist/store/actions/node-mutation-sanitize.test.d.ts +2 -0
- package/dist/store/actions/node-mutation-sanitize.test.d.ts.map +1 -0
- package/dist/store/actions/node-mutation-sanitize.test.js +147 -0
- package/dist/store/actions/reparent.test.d.ts +2 -0
- package/dist/store/actions/reparent.test.d.ts.map +1 -0
- package/dist/store/actions/reparent.test.js +212 -0
- package/dist/store/use-interactive.d.ts +39 -0
- package/dist/store/use-interactive.d.ts.map +1 -1
- package/dist/store/use-interactive.js +75 -0
- package/dist/store/use-live-node-overrides.d.ts +22 -0
- package/dist/store/use-live-node-overrides.d.ts.map +1 -0
- package/dist/store/use-live-node-overrides.js +59 -0
- package/dist/store/use-scene-elevator-migration.test.d.ts +2 -0
- package/dist/store/use-scene-elevator-migration.test.d.ts.map +1 -0
- package/dist/store/use-scene-elevator-migration.test.js +109 -0
- package/dist/store/use-scene.d.ts +11 -0
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +196 -6
- package/dist/systems/elevator/elevator-dispatch.d.ts +12 -0
- package/dist/systems/elevator/elevator-dispatch.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-dispatch.js +57 -0
- package/dist/systems/elevator/elevator-geometry.d.ts +15 -0
- package/dist/systems/elevator/elevator-geometry.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-geometry.js +50 -0
- package/dist/systems/elevator/elevator-opening-sync.d.ts +6 -0
- package/dist/systems/elevator/elevator-opening-sync.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-opening-sync.js +218 -0
- package/dist/systems/elevator/elevator-opening-sync.test.d.ts +2 -0
- package/dist/systems/elevator/elevator-opening-sync.test.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-opening-sync.test.js +146 -0
- package/dist/systems/elevator/elevator-opening-system.d.ts +2 -0
- package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-opening-system.js +48 -0
- package/dist/systems/elevator/elevator-runtime-system.d.ts +2 -0
- package/dist/systems/elevator/elevator-runtime-system.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-runtime-system.js +8 -0
- package/dist/systems/elevator/elevator-runtime.d.ts +18 -0
- package/dist/systems/elevator/elevator-runtime.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-runtime.js +225 -0
- package/dist/systems/elevator/elevator-runtime.test.d.ts +2 -0
- package/dist/systems/elevator/elevator-runtime.test.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-runtime.test.js +64 -0
- package/dist/systems/elevator/elevator-service.d.ts +19 -0
- package/dist/systems/elevator/elevator-service.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-service.js +111 -0
- package/dist/systems/stair/stair-footprint.d.ts +44 -0
- package/dist/systems/stair/stair-footprint.d.ts.map +1 -0
- package/dist/systems/stair/stair-footprint.js +168 -0
- package/dist/systems/stair/stair-opening-preview.d.ts +1777 -0
- package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -0
- package/dist/systems/stair/stair-opening-preview.js +93 -0
- package/dist/systems/stair/stair-opening-preview.test.d.ts +2 -0
- package/dist/systems/stair/stair-opening-preview.test.d.ts.map +1 -0
- package/dist/systems/stair/stair-opening-preview.test.js +80 -0
- package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-sync.js +172 -147
- package/dist/systems/stair/stair-opening-sync.test.js +385 -2
- package/dist/systems/stair/stair-opening-system.d.ts +2 -0
- package/dist/systems/stair/stair-opening-system.d.ts.map +1 -0
- package/dist/systems/stair/stair-opening-system.js +104 -0
- package/dist/systems/wall/wall-move.d.ts +48 -0
- package/dist/systems/wall/wall-move.d.ts.map +1 -0
- package/dist/systems/wall/wall-move.js +193 -0
- package/dist/utils/clone-scene-graph.d.ts +6 -4
- package/dist/utils/clone-scene-graph.d.ts.map +1 -1
- package/dist/utils/clone-scene-graph.js +6 -4
- package/dist/utils/clone-scene-graph.test.d.ts +2 -0
- package/dist/utils/clone-scene-graph.test.d.ts.map +1 -0
- package/dist/utils/clone-scene-graph.test.js +59 -0
- package/dist/validation/validate-build-json.d.ts +43 -0
- package/dist/validation/validate-build-json.d.ts.map +1 -0
- package/dist/validation/validate-build-json.js +227 -0
- package/package.json +9 -2
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test } from 'bun:test';
|
|
2
|
+
import useScene from './use-scene';
|
|
3
|
+
describe('scene elevator migrations', () => {
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
useScene.setState({
|
|
6
|
+
nodes: {},
|
|
7
|
+
rootNodeIds: [],
|
|
8
|
+
dirtyNodes: new Set(),
|
|
9
|
+
collections: {},
|
|
10
|
+
});
|
|
11
|
+
useScene.temporal.getState().clear();
|
|
12
|
+
});
|
|
13
|
+
test('normalizes legacy level-parented elevators into building-scoped nodes', () => {
|
|
14
|
+
useScene.getState().setScene({
|
|
15
|
+
site_test: {
|
|
16
|
+
object: 'node',
|
|
17
|
+
id: 'site_test',
|
|
18
|
+
type: 'site',
|
|
19
|
+
parentId: null,
|
|
20
|
+
visible: true,
|
|
21
|
+
metadata: {},
|
|
22
|
+
children: ['building_test'],
|
|
23
|
+
},
|
|
24
|
+
building_test: {
|
|
25
|
+
object: 'node',
|
|
26
|
+
id: 'building_test',
|
|
27
|
+
type: 'building',
|
|
28
|
+
parentId: 'site_test',
|
|
29
|
+
visible: true,
|
|
30
|
+
metadata: {},
|
|
31
|
+
children: ['level_test'],
|
|
32
|
+
},
|
|
33
|
+
level_test: {
|
|
34
|
+
object: 'node',
|
|
35
|
+
id: 'level_test',
|
|
36
|
+
type: 'level',
|
|
37
|
+
parentId: 'building_test',
|
|
38
|
+
visible: true,
|
|
39
|
+
metadata: {},
|
|
40
|
+
children: ['elevator_test'],
|
|
41
|
+
level: 0,
|
|
42
|
+
},
|
|
43
|
+
elevator_test: {
|
|
44
|
+
object: 'node',
|
|
45
|
+
id: 'elevator_test',
|
|
46
|
+
type: 'elevator',
|
|
47
|
+
parentId: 'level_test',
|
|
48
|
+
visible: true,
|
|
49
|
+
metadata: {},
|
|
50
|
+
},
|
|
51
|
+
}, ['site_test']);
|
|
52
|
+
const nodes = useScene.getState().nodes;
|
|
53
|
+
const elevator = nodes.elevator_test;
|
|
54
|
+
const level = nodes.level_test;
|
|
55
|
+
const building = nodes.building_test;
|
|
56
|
+
expect(elevator.parentId).toBe('building_test');
|
|
57
|
+
expect(elevator.position).toEqual([0, 0, 0]);
|
|
58
|
+
expect(elevator.rotation).toBe(0);
|
|
59
|
+
expect(level.children).not.toContain('elevator_test');
|
|
60
|
+
expect(building.children).toContain('elevator_test');
|
|
61
|
+
});
|
|
62
|
+
test('migrates level-parented elevators when the level parentId is missing', () => {
|
|
63
|
+
useScene.getState().setScene({
|
|
64
|
+
site_test: {
|
|
65
|
+
object: 'node',
|
|
66
|
+
id: 'site_test',
|
|
67
|
+
type: 'site',
|
|
68
|
+
parentId: null,
|
|
69
|
+
visible: true,
|
|
70
|
+
metadata: {},
|
|
71
|
+
children: ['building_test'],
|
|
72
|
+
},
|
|
73
|
+
building_test: {
|
|
74
|
+
object: 'node',
|
|
75
|
+
id: 'building_test',
|
|
76
|
+
type: 'building',
|
|
77
|
+
parentId: 'site_test',
|
|
78
|
+
visible: true,
|
|
79
|
+
metadata: {},
|
|
80
|
+
children: ['level_test'],
|
|
81
|
+
},
|
|
82
|
+
level_test: {
|
|
83
|
+
object: 'node',
|
|
84
|
+
id: 'level_test',
|
|
85
|
+
type: 'level',
|
|
86
|
+
parentId: null,
|
|
87
|
+
visible: true,
|
|
88
|
+
metadata: {},
|
|
89
|
+
children: ['elevator_test'],
|
|
90
|
+
level: 0,
|
|
91
|
+
},
|
|
92
|
+
elevator_test: {
|
|
93
|
+
object: 'node',
|
|
94
|
+
id: 'elevator_test',
|
|
95
|
+
type: 'elevator',
|
|
96
|
+
parentId: 'level_test',
|
|
97
|
+
visible: true,
|
|
98
|
+
metadata: {},
|
|
99
|
+
},
|
|
100
|
+
}, ['site_test']);
|
|
101
|
+
const nodes = useScene.getState().nodes;
|
|
102
|
+
const elevator = nodes.elevator_test;
|
|
103
|
+
const level = nodes.level_test;
|
|
104
|
+
const building = nodes.building_test;
|
|
105
|
+
expect(elevator.parentId).toBe('building_test');
|
|
106
|
+
expect(level.children).not.toContain('elevator_test');
|
|
107
|
+
expect(building.children).toContain('elevator_test');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -20,6 +20,17 @@ export type SceneState = {
|
|
|
20
20
|
node: AnyNode;
|
|
21
21
|
parentId?: AnyNodeId;
|
|
22
22
|
}[]) => void;
|
|
23
|
+
applyNodeChanges: (changes: {
|
|
24
|
+
create?: {
|
|
25
|
+
node: AnyNode;
|
|
26
|
+
parentId?: AnyNodeId;
|
|
27
|
+
}[];
|
|
28
|
+
update?: {
|
|
29
|
+
id: AnyNodeId;
|
|
30
|
+
data: Partial<AnyNode>;
|
|
31
|
+
}[];
|
|
32
|
+
delete?: AnyNodeId[];
|
|
33
|
+
}) => void;
|
|
23
34
|
updateNode: (id: AnyNodeId, data: Partial<AnyNode>) => void;
|
|
24
35
|
updateNodes: (updates: {
|
|
25
36
|
id: AnyNodeId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-scene.d.ts","sourceRoot":"","sources":["../../src/store/use-scene.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE1C,OAAO,EAAU,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAA;AAEnE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"use-scene.d.ts","sourceRoot":"","sources":["../../src/store/use-scene.ts"],"names":[],"mappings":"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"}
|
package/dist/store/use-scene.js
CHANGED
|
@@ -3,7 +3,11 @@ import { temporal } from 'zundo';
|
|
|
3
3
|
import { create } from 'zustand';
|
|
4
4
|
import { BuildingNode } from '../schema';
|
|
5
5
|
import { generateCollectionId } from '../schema/collections';
|
|
6
|
+
import { DoorNode as DoorNodeSchema } from '../schema/nodes/door';
|
|
7
|
+
import { ElevatorNode as ElevatorNodeSchema } from '../schema/nodes/elevator';
|
|
6
8
|
import { LevelNode } from '../schema/nodes/level';
|
|
9
|
+
import { getPitchFromActiveRoofHeight, } from '../schema/nodes/roof-segment';
|
|
10
|
+
import { ShelfNode as ShelfNodeSchema } from '../schema/nodes/shelf';
|
|
7
11
|
import { SiteNode } from '../schema/nodes/site';
|
|
8
12
|
import { StairNode as StairNodeSchema } from '../schema/nodes/stair';
|
|
9
13
|
import { StairSegmentNode as StairSegmentNodeSchema } from '../schema/nodes/stair-segment';
|
|
@@ -12,6 +16,10 @@ import { resetSceneHistoryPauseDepth } from './history-control';
|
|
|
12
16
|
function getFiniteNumber(value, fallback) {
|
|
13
17
|
return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
|
14
18
|
}
|
|
19
|
+
function getFiniteNumberInRange(value, fallback, min, max) {
|
|
20
|
+
const finite = getFiniteNumber(value, fallback);
|
|
21
|
+
return Math.min(Math.max(finite, min), max);
|
|
22
|
+
}
|
|
15
23
|
function getBoolean(value, fallback) {
|
|
16
24
|
return typeof value === 'boolean' ? value : fallback;
|
|
17
25
|
}
|
|
@@ -19,7 +27,7 @@ function getEnumValue(value, allowed, fallback) {
|
|
|
19
27
|
return typeof value === 'string' && allowed.includes(value) ? value : fallback;
|
|
20
28
|
}
|
|
21
29
|
function getNullableString(value) {
|
|
22
|
-
return typeof value === 'string' ? value : null;
|
|
30
|
+
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
23
31
|
}
|
|
24
32
|
function getStringArray(value) {
|
|
25
33
|
return Array.isArray(value)
|
|
@@ -81,6 +89,99 @@ function normalizeStairSegmentNode(node) {
|
|
|
81
89
|
const parsed = StairSegmentNodeSchema.safeParse(sanitized);
|
|
82
90
|
return parsed.success ? parsed.data : null;
|
|
83
91
|
}
|
|
92
|
+
function normalizeDoorNode(node) {
|
|
93
|
+
const parsed = DoorNodeSchema.safeParse(node);
|
|
94
|
+
return parsed.success ? { ...node, ...parsed.data } : null;
|
|
95
|
+
}
|
|
96
|
+
function normalizeShelfNode(node) {
|
|
97
|
+
const sanitized = {
|
|
98
|
+
...node,
|
|
99
|
+
children: getStringArray(node.children),
|
|
100
|
+
position: getVector3(node.position, [0, 0, 0]),
|
|
101
|
+
rotation: getVector3(node.rotation, [0, 0, 0]),
|
|
102
|
+
width: getFiniteNumberInRange(node.width, 1.2, 0.3, 3.0),
|
|
103
|
+
depth: getFiniteNumberInRange(node.depth, 0.3, 0.1, 1.0),
|
|
104
|
+
thickness: getFiniteNumberInRange(node.thickness, 0.04, 0.01, 0.1),
|
|
105
|
+
height: getFiniteNumberInRange(node.height, 0.9, 0.05, 2.5),
|
|
106
|
+
rows: Math.round(getFiniteNumberInRange(node.rows, 1, 1, 8)),
|
|
107
|
+
columns: Math.round(getFiniteNumberInRange(node.columns, 1, 1, 6)),
|
|
108
|
+
style: getEnumValue(node.style, ['wall-shelf', 'bookshelf', 'open-rack', 'cubby'], 'wall-shelf'),
|
|
109
|
+
withBack: getBoolean(node.withBack, false),
|
|
110
|
+
withSides: getBoolean(node.withSides, true),
|
|
111
|
+
withBottom: getBoolean(node.withBottom, false),
|
|
112
|
+
bracketStyle: getEnumValue(node.bracketStyle, ['minimal', 'industrial', 'hidden'], 'minimal'),
|
|
113
|
+
};
|
|
114
|
+
const parsed = ShelfNodeSchema.safeParse(sanitized);
|
|
115
|
+
return parsed.success ? parsed.data : null;
|
|
116
|
+
}
|
|
117
|
+
function normalizeElevatorNode(node) {
|
|
118
|
+
const sanitized = {
|
|
119
|
+
...node,
|
|
120
|
+
position: getVector3(node.position, [0, 0, 0]),
|
|
121
|
+
rotation: getFiniteNumber(node.rotation, 0),
|
|
122
|
+
width: getFiniteNumber(node.width, 1.84),
|
|
123
|
+
depth: getFiniteNumber(node.depth, 1.84),
|
|
124
|
+
shaftWidth: node.shaftWidth === undefined ? undefined : getFiniteNumber(node.shaftWidth, 1.84),
|
|
125
|
+
shaftDepth: node.shaftDepth === undefined ? undefined : getFiniteNumber(node.shaftDepth, 1.84),
|
|
126
|
+
shaftWallThickness: getFiniteNumber(node.shaftWallThickness, 0.09),
|
|
127
|
+
cabHeight: getFiniteNumber(node.cabHeight, 2.35),
|
|
128
|
+
doorWidth: getFiniteNumber(node.doorWidth, 0.95),
|
|
129
|
+
doorHeight: getFiniteNumber(node.doorHeight, 2.1),
|
|
130
|
+
fromLevelId: getNullableString(node.fromLevelId),
|
|
131
|
+
toLevelId: getNullableString(node.toLevelId),
|
|
132
|
+
servedLevelIds: node.servedLevelIds === undefined ? undefined : getStringArray(node.servedLevelIds),
|
|
133
|
+
disabledLevelIds: getStringArray(node.disabledLevelIds),
|
|
134
|
+
serviceOnlyLevelIds: getStringArray(node.serviceOnlyLevelIds),
|
|
135
|
+
defaultLevelId: getNullableString(node.defaultLevelId),
|
|
136
|
+
speed: getFiniteNumber(node.speed, 2.2),
|
|
137
|
+
doorDurationMs: getFiniteNumber(node.doorDurationMs, 900),
|
|
138
|
+
dwellMs: getFiniteNumber(node.dwellMs, 1400),
|
|
139
|
+
};
|
|
140
|
+
const parsed = ElevatorNodeSchema.safeParse(sanitized);
|
|
141
|
+
return parsed.success ? parsed.data : null;
|
|
142
|
+
}
|
|
143
|
+
function findBuildingIdForLevel(levelId, nodes) {
|
|
144
|
+
const level = nodes[levelId];
|
|
145
|
+
const directBuildingId = typeof level?.parentId === 'string' ? level.parentId : null;
|
|
146
|
+
if (directBuildingId && nodes[directBuildingId]?.type === 'building') {
|
|
147
|
+
return directBuildingId;
|
|
148
|
+
}
|
|
149
|
+
for (const [candidateId, candidate] of Object.entries(nodes)) {
|
|
150
|
+
if (candidate?.type !== 'building')
|
|
151
|
+
continue;
|
|
152
|
+
if (getStringArray(candidate.children).includes(levelId)) {
|
|
153
|
+
return candidateId;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
function migrateElevatorParent(id, node, nodes) {
|
|
159
|
+
const parentId = typeof node.parentId === 'string' ? node.parentId : null;
|
|
160
|
+
if (!parentId)
|
|
161
|
+
return node;
|
|
162
|
+
const parent = parentId ? nodes[parentId] : null;
|
|
163
|
+
if (parent?.type !== 'level')
|
|
164
|
+
return node;
|
|
165
|
+
const buildingId = findBuildingIdForLevel(parentId, nodes);
|
|
166
|
+
if (!buildingId)
|
|
167
|
+
return node;
|
|
168
|
+
const building = buildingId ? nodes[buildingId] : null;
|
|
169
|
+
if (building?.type !== 'building')
|
|
170
|
+
return node;
|
|
171
|
+
nodes[parentId] = {
|
|
172
|
+
...parent,
|
|
173
|
+
children: getStringArray(parent.children).filter((childId) => childId !== id),
|
|
174
|
+
};
|
|
175
|
+
const buildingChildren = getStringArray(building.children);
|
|
176
|
+
nodes[buildingId] = {
|
|
177
|
+
...building,
|
|
178
|
+
children: buildingChildren.includes(id) ? buildingChildren : [...buildingChildren, id],
|
|
179
|
+
};
|
|
180
|
+
return {
|
|
181
|
+
...node,
|
|
182
|
+
parentId: buildingId,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
84
185
|
function migrateWallSurfaceMaterials(node) {
|
|
85
186
|
const hasInterior = node.interiorMaterial !== undefined || typeof node.interiorMaterialPreset === 'string';
|
|
86
187
|
const hasExterior = node.exteriorMaterial !== undefined || typeof node.exteriorMaterialPreset === 'string';
|
|
@@ -244,6 +345,9 @@ function migrateNodes(nodes) {
|
|
|
244
345
|
const oldRoof = node;
|
|
245
346
|
const suffix = id.includes('_') ? id.split('_')[1] : Math.random().toString(36).slice(2);
|
|
246
347
|
const segmentId = `rseg_${suffix}`;
|
|
348
|
+
const segWidth = oldRoof.length ?? 8;
|
|
349
|
+
const segDepth = (oldRoof.leftWidth ?? 2.2) + (oldRoof.rightWidth ?? 2.2);
|
|
350
|
+
const legacyRoofHeight = oldRoof.height ?? 2.5;
|
|
247
351
|
const segment = {
|
|
248
352
|
object: 'node',
|
|
249
353
|
id: segmentId,
|
|
@@ -254,10 +358,18 @@ function migrateNodes(nodes) {
|
|
|
254
358
|
position: [0, 0, 0],
|
|
255
359
|
rotation: 0,
|
|
256
360
|
roofType: 'gable',
|
|
257
|
-
width:
|
|
258
|
-
depth:
|
|
259
|
-
|
|
260
|
-
|
|
361
|
+
width: segWidth,
|
|
362
|
+
depth: segDepth,
|
|
363
|
+
// Schema default (0.5), NOT 0: a zero-height wall builds a flat,
|
|
364
|
+
// degenerate CSG brush → "Coplanar clip not handled" + NaN geometry, so
|
|
365
|
+
// the migrated legacy roof never renders. New roofs use 0.5 too.
|
|
366
|
+
wallHeight: 0.5,
|
|
367
|
+
pitch: getPitchFromActiveRoofHeight({
|
|
368
|
+
roofType: 'gable',
|
|
369
|
+
width: segWidth,
|
|
370
|
+
depth: segDepth,
|
|
371
|
+
roofHeight: legacyRoofHeight,
|
|
372
|
+
}),
|
|
261
373
|
wallThickness: 0.1,
|
|
262
374
|
deckThickness: 0.1,
|
|
263
375
|
overhang: 0.3,
|
|
@@ -269,6 +381,35 @@ function migrateNodes(nodes) {
|
|
|
269
381
|
children: [segmentId],
|
|
270
382
|
};
|
|
271
383
|
}
|
|
384
|
+
// 2b. roof-segment: guarantee a valid positive pitch (degrees).
|
|
385
|
+
// Saved scenes wrote `roofHeight` in metres; the schema now stores `pitch`
|
|
386
|
+
// in degrees. Convert the legacy field when present, and — crucially — fall
|
|
387
|
+
// back to the schema default for any segment that carries no usable pitch or
|
|
388
|
+
// roofHeight (older/partial saves). Without this, the slope-frame guard
|
|
389
|
+
// resolves a missing pitch to a FLAT frame, so the roof renders as a slab.
|
|
390
|
+
// The migration result is cast, not zod-parsed, so the schema default never
|
|
391
|
+
// applies on its own — this branch is the only place it lands.
|
|
392
|
+
if (node.type === 'roof-segment') {
|
|
393
|
+
const currentPitch = node.pitch;
|
|
394
|
+
const hasValidPitch = typeof currentPitch === 'number' && currentPitch > 0;
|
|
395
|
+
if (!hasValidPitch) {
|
|
396
|
+
const { roofHeight, ...rest } = node;
|
|
397
|
+
const width = typeof node.width === 'number' ? node.width : 8;
|
|
398
|
+
const depth = typeof node.depth === 'number' ? node.depth : 6;
|
|
399
|
+
const roofType = (typeof node.roofType === 'string' ? node.roofType : 'gable');
|
|
400
|
+
const derived = typeof roofHeight === 'number' && roofHeight > 0
|
|
401
|
+
? getPitchFromActiveRoofHeight({ roofType, width, depth, roofHeight })
|
|
402
|
+
: 0;
|
|
403
|
+
// 40° matches the RoofSegmentNode schema default.
|
|
404
|
+
patchedNodes[id] = { ...rest, pitch: derived > 0 ? derived : 40 };
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (node.type === 'door') {
|
|
408
|
+
const normalized = normalizeDoorNode(node);
|
|
409
|
+
if (normalized) {
|
|
410
|
+
patchedNodes[id] = normalized;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
272
413
|
if (node.type === 'stair') {
|
|
273
414
|
const normalized = normalizeStairNode(migrateStairSurfaceMaterials(node));
|
|
274
415
|
if (normalized) {
|
|
@@ -284,9 +425,57 @@ function migrateNodes(nodes) {
|
|
|
284
425
|
if (node.type === 'wall') {
|
|
285
426
|
patchedNodes[id] = migrateWallSurfaceMaterials(patchedNodes[id]);
|
|
286
427
|
}
|
|
428
|
+
if (node.type === 'shelf') {
|
|
429
|
+
const normalized = normalizeShelfNode(node);
|
|
430
|
+
if (normalized) {
|
|
431
|
+
patchedNodes[id] = normalized;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (node.type === 'elevator') {
|
|
435
|
+
const parentMigrated = migrateElevatorParent(id, node, patchedNodes);
|
|
436
|
+
const normalized = normalizeElevatorNode(parentMigrated);
|
|
437
|
+
if (normalized) {
|
|
438
|
+
patchedNodes[id] = normalized;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
// Roof-segment hosting was added in this migration cycle (the same
|
|
442
|
+
// pattern as shelf above). Older segments saved before the schema
|
|
443
|
+
// gained `children` need the field initialised so
|
|
444
|
+
// `createNode(chimney, segmentId)` finds an array to append to —
|
|
445
|
+
// without this every "Add Element" click on the roof panel results
|
|
446
|
+
// in an orphaned accessory (parented in scene state but never
|
|
447
|
+
// appended to `seg.children`, so the renderer's recursive
|
|
448
|
+
// `<NodeRenderer>` mount never sees it).
|
|
449
|
+
if (node.type === 'roof-segment' && !Array.isArray(node.children)) {
|
|
450
|
+
patchedNodes[id] = { ...node, children: [] };
|
|
451
|
+
}
|
|
287
452
|
if (node.type === 'roof') {
|
|
288
453
|
patchedNodes[id] = migrateRoofSurfaceMaterials(patchedNodes[id]);
|
|
289
454
|
}
|
|
455
|
+
// Legacy: site.children used to hold nested BuildingNode / ItemNode
|
|
456
|
+
// objects (see the SiteNode schema before the children-as-ids fix).
|
|
457
|
+
// Flatten any leftover nested children into ids, and absorb the
|
|
458
|
+
// embedded nodes into the flat map so the rest of the loader can
|
|
459
|
+
// treat the site like every other parent.
|
|
460
|
+
if (node.type === 'site' && Array.isArray(node.children)) {
|
|
461
|
+
let needsFlatten = false;
|
|
462
|
+
const flattened = [];
|
|
463
|
+
for (const child of node.children) {
|
|
464
|
+
if (typeof child === 'string') {
|
|
465
|
+
flattened.push(child);
|
|
466
|
+
}
|
|
467
|
+
else if (child && typeof child === 'object' && typeof child.id === 'string') {
|
|
468
|
+
needsFlatten = true;
|
|
469
|
+
flattened.push(child.id);
|
|
470
|
+
if (!patchedNodes[child.id]) {
|
|
471
|
+
patchedNodes[child.id] = { ...child, parentId: id };
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
if (needsFlatten) {
|
|
476
|
+
patchedNodes[id] = { ...node, children: flattened };
|
|
477
|
+
}
|
|
478
|
+
}
|
|
290
479
|
}
|
|
291
480
|
return patchedNodes;
|
|
292
481
|
}
|
|
@@ -417,7 +606,7 @@ const useScene = create()(temporal((set, get) => ({
|
|
|
417
606
|
children: [level0.id],
|
|
418
607
|
});
|
|
419
608
|
const site = SiteNode.parse({
|
|
420
|
-
children: [building],
|
|
609
|
+
children: [building.id],
|
|
421
610
|
});
|
|
422
611
|
// Define all nodes flat
|
|
423
612
|
const nodes = {
|
|
@@ -437,6 +626,7 @@ const useScene = create()(temporal((set, get) => ({
|
|
|
437
626
|
},
|
|
438
627
|
createNodes: (ops) => nodeActions.createNodesAction(set, get, ops),
|
|
439
628
|
createNode: (node, parentId) => nodeActions.createNodesAction(set, get, [{ node, parentId }]),
|
|
629
|
+
applyNodeChanges: (changes) => nodeActions.applyNodeChangesAction(set, get, changes),
|
|
440
630
|
updateNodes: (updates) => nodeActions.updateNodesAction(set, get, updates),
|
|
441
631
|
updateNode: (id, data) => nodeActions.updateNodesAction(set, get, [{ id, data }]),
|
|
442
632
|
// --- DELETE ---
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AnyNode, AnyNodeId } from '../../schema';
|
|
2
|
+
import type { ElevatorInteractiveState } from '../../store/use-interactive';
|
|
3
|
+
type ElevatorRuntimeMap = Record<AnyNodeId, ElevatorInteractiveState>;
|
|
4
|
+
type ResolveElevatorDispatchTargetArgs = {
|
|
5
|
+
elevators: ElevatorRuntimeMap;
|
|
6
|
+
levelId: AnyNodeId;
|
|
7
|
+
nodes: Record<string, AnyNode>;
|
|
8
|
+
requestedElevatorId: AnyNodeId;
|
|
9
|
+
};
|
|
10
|
+
export declare function resolveElevatorDispatchTarget({ elevators, levelId, nodes, requestedElevatorId, }: ResolveElevatorDispatchTargetArgs): AnyNodeId;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=elevator-dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elevator-dispatch.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAgB,MAAM,cAAc,CAAA;AACpE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AAG3E,KAAK,kBAAkB,GAAG,MAAM,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAA;AAErE,KAAK,iCAAiC,GAAG;IACvC,SAAS,EAAE,kBAAkB,CAAA;IAC7B,OAAO,EAAE,SAAS,CAAA;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,mBAAmB,EAAE,SAAS,CAAA;CAC/B,CAAA;AAsCD,wBAAgB,6BAA6B,CAAC,EAC5C,SAAS,EACT,OAAO,EACP,KAAK,EACL,mBAAmB,GACpB,EAAE,iCAAiC,GAAG,SAAS,CAmC/C"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { resolveElevatorServiceLevels } from './elevator-service';
|
|
2
|
+
function getRuntimeLevelId(runtime, elevator) {
|
|
3
|
+
return runtime?.currentLevelId ?? elevator.defaultLevelId ?? elevator.fromLevelId ?? null;
|
|
4
|
+
}
|
|
5
|
+
function scoreDispatchCandidate({ elevator, elevators, levelId, nodes, }) {
|
|
6
|
+
if ((elevator.disabledLevelIds ?? []).includes(levelId))
|
|
7
|
+
return null;
|
|
8
|
+
if ((elevator.serviceOnlyLevelIds ?? []).includes(levelId))
|
|
9
|
+
return null;
|
|
10
|
+
const serviceLevels = resolveElevatorServiceLevels(elevator, nodes);
|
|
11
|
+
const targetIndex = serviceLevels.findIndex((level) => level.id === levelId);
|
|
12
|
+
if (targetIndex < 0)
|
|
13
|
+
return null;
|
|
14
|
+
const runtime = elevators[elevator.id];
|
|
15
|
+
const runtimeLevelId = getRuntimeLevelId(runtime, elevator);
|
|
16
|
+
const currentIndex = runtimeLevelId
|
|
17
|
+
? serviceLevels.findIndex((level) => level.id === runtimeLevelId)
|
|
18
|
+
: -1;
|
|
19
|
+
const resolvedCurrentIndex = currentIndex >= 0 ? currentIndex : 0;
|
|
20
|
+
const distance = Math.abs(targetIndex - resolvedCurrentIndex);
|
|
21
|
+
const queuePenalty = (runtime?.queue.length ?? 0) * 2 + (runtime?.targetLevelId ? 1 : 0);
|
|
22
|
+
const motionPenalty = runtime?.phase === 'moving' || runtime?.phase === 'closing' ? 0.5 : 0;
|
|
23
|
+
const openPenalty = runtime?.phase === 'open' || runtime?.phase === 'opening' ? 0.2 : 0;
|
|
24
|
+
return distance + queuePenalty + motionPenalty + openPenalty;
|
|
25
|
+
}
|
|
26
|
+
export function resolveElevatorDispatchTarget({ elevators, levelId, nodes, requestedElevatorId, }) {
|
|
27
|
+
const requestedElevator = nodes[requestedElevatorId];
|
|
28
|
+
if (!(requestedElevator?.type === 'elevator' && requestedElevator.parentId)) {
|
|
29
|
+
return requestedElevatorId;
|
|
30
|
+
}
|
|
31
|
+
const building = nodes[requestedElevator.parentId];
|
|
32
|
+
if (building?.type !== 'building') {
|
|
33
|
+
return requestedElevatorId;
|
|
34
|
+
}
|
|
35
|
+
let bestElevatorId = null;
|
|
36
|
+
let bestScore = Number.POSITIVE_INFINITY;
|
|
37
|
+
for (const childId of building.children) {
|
|
38
|
+
const candidate = nodes[childId];
|
|
39
|
+
if (!(candidate?.type === 'elevator' && candidate.visible !== false))
|
|
40
|
+
continue;
|
|
41
|
+
const score = scoreDispatchCandidate({
|
|
42
|
+
elevator: candidate,
|
|
43
|
+
elevators,
|
|
44
|
+
levelId,
|
|
45
|
+
nodes,
|
|
46
|
+
});
|
|
47
|
+
if (score === null)
|
|
48
|
+
continue;
|
|
49
|
+
const tieBreaker = candidate.id === requestedElevatorId ? -0.01 : 0;
|
|
50
|
+
const finalScore = score + tieBreaker;
|
|
51
|
+
if (finalScore < bestScore) {
|
|
52
|
+
bestScore = finalScore;
|
|
53
|
+
bestElevatorId = candidate.id;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return bestElevatorId ?? requestedElevatorId;
|
|
57
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ElevatorDoorPanelStyle, ElevatorDoorStyle, ElevatorNode, ElevatorShaftStyle } from '../../schema';
|
|
2
|
+
export type ElevatorDoorSide = 'left' | 'right';
|
|
3
|
+
export declare function getResolvedElevatorDoorStyle(doorStyle: ElevatorNode['doorStyle'] | undefined): ElevatorDoorStyle;
|
|
4
|
+
export declare function getResolvedElevatorDoorPanelStyle(doorPanelStyle: ElevatorNode['doorPanelStyle'] | undefined): ElevatorDoorPanelStyle;
|
|
5
|
+
export declare function getResolvedElevatorShaftStyle(shaftStyle: ElevatorNode['shaftStyle'] | undefined): ElevatorShaftStyle;
|
|
6
|
+
export declare function getElevatorDoorLeafSides(doorStyle: ElevatorNode['doorStyle'] | undefined): ElevatorDoorSide[];
|
|
7
|
+
export declare function getElevatorDoorLeafX(side: ElevatorDoorSide, openingWidth: number, doorOpen: number, doorStyle: ElevatorNode['doorStyle'] | undefined): number;
|
|
8
|
+
export declare function getElevatorDoorLeafWidth(openingWidth: number, doorStyle: ElevatorNode['doorStyle'] | undefined): number;
|
|
9
|
+
export declare function getElevatorCabWidth(node: ElevatorNode): number;
|
|
10
|
+
export declare function getElevatorCabDepth(node: ElevatorNode): number;
|
|
11
|
+
export declare function getElevatorShaftWallThickness(node: ElevatorNode): number;
|
|
12
|
+
export declare function getElevatorShaftWidth(node: ElevatorNode, cabWidth?: number): number;
|
|
13
|
+
export declare function getElevatorShaftDepth(node: ElevatorNode, cabDepth?: number): number;
|
|
14
|
+
export declare function getElevatorCabCenterZ(node: ElevatorNode): number;
|
|
15
|
+
//# sourceMappingURL=elevator-geometry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elevator-geometry.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-geometry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EACnB,MAAM,cAAc,CAAA;AAErB,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,CAAA;AAI/C,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,GAC/C,iBAAiB,CAEnB;AAED,wBAAgB,iCAAiC,CAC/C,cAAc,EAAE,YAAY,CAAC,gBAAgB,CAAC,GAAG,SAAS,GACzD,sBAAsB,CAExB;AAED,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,GAAG,SAAS,GACjD,kBAAkB,CAEpB;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,GAC/C,gBAAgB,EAAE,CAKpB;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,gBAAgB,EACtB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,UAUjD;AAED,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,UAKjD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,UAErD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,UAErD;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,YAAY,UAE/D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,SAA4B,UAE7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,SAA4B,UAE7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,UAEvD"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const DEFAULT_ELEVATOR_SHAFT_WALL_THICKNESS = 0.09;
|
|
2
|
+
export function getResolvedElevatorDoorStyle(doorStyle) {
|
|
3
|
+
return doorStyle ?? 'center-opening';
|
|
4
|
+
}
|
|
5
|
+
export function getResolvedElevatorDoorPanelStyle(doorPanelStyle) {
|
|
6
|
+
return doorPanelStyle ?? 'glass-frame';
|
|
7
|
+
}
|
|
8
|
+
export function getResolvedElevatorShaftStyle(shaftStyle) {
|
|
9
|
+
return shaftStyle ?? 'solid';
|
|
10
|
+
}
|
|
11
|
+
export function getElevatorDoorLeafSides(doorStyle) {
|
|
12
|
+
const resolvedDoorStyle = getResolvedElevatorDoorStyle(doorStyle);
|
|
13
|
+
if (resolvedDoorStyle === 'single-left')
|
|
14
|
+
return ['left'];
|
|
15
|
+
if (resolvedDoorStyle === 'single-right')
|
|
16
|
+
return ['right'];
|
|
17
|
+
return ['left', 'right'];
|
|
18
|
+
}
|
|
19
|
+
export function getElevatorDoorLeafX(side, openingWidth, doorOpen, doorStyle) {
|
|
20
|
+
const resolvedDoorStyle = getResolvedElevatorDoorStyle(doorStyle);
|
|
21
|
+
if (resolvedDoorStyle === 'center-opening') {
|
|
22
|
+
const direction = side === 'left' ? -1 : 1;
|
|
23
|
+
return direction * (openingWidth / 4 + doorOpen * openingWidth * 0.34);
|
|
24
|
+
}
|
|
25
|
+
const direction = resolvedDoorStyle === 'single-left' ? -1 : 1;
|
|
26
|
+
return direction * doorOpen * openingWidth * 0.68;
|
|
27
|
+
}
|
|
28
|
+
export function getElevatorDoorLeafWidth(openingWidth, doorStyle) {
|
|
29
|
+
return getResolvedElevatorDoorStyle(doorStyle) === 'center-opening'
|
|
30
|
+
? Math.max(openingWidth / 2 - 0.018, 0.12)
|
|
31
|
+
: Math.max(openingWidth - 0.018, 0.18);
|
|
32
|
+
}
|
|
33
|
+
export function getElevatorCabWidth(node) {
|
|
34
|
+
return Math.max(node.width, 0.8);
|
|
35
|
+
}
|
|
36
|
+
export function getElevatorCabDepth(node) {
|
|
37
|
+
return Math.max(node.depth, 0.8);
|
|
38
|
+
}
|
|
39
|
+
export function getElevatorShaftWallThickness(node) {
|
|
40
|
+
return Math.max(node.shaftWallThickness ?? DEFAULT_ELEVATOR_SHAFT_WALL_THICKNESS, 0.04);
|
|
41
|
+
}
|
|
42
|
+
export function getElevatorShaftWidth(node, cabWidth = getElevatorCabWidth(node)) {
|
|
43
|
+
return Math.max(node.shaftWidth ?? cabWidth, cabWidth, 0.8);
|
|
44
|
+
}
|
|
45
|
+
export function getElevatorShaftDepth(node, cabDepth = getElevatorCabDepth(node)) {
|
|
46
|
+
return Math.max(node.shaftDepth ?? cabDepth, cabDepth, 0.8);
|
|
47
|
+
}
|
|
48
|
+
export function getElevatorCabCenterZ(node) {
|
|
49
|
+
return -getElevatorShaftDepth(node) / 2 + getElevatorCabDepth(node) / 2;
|
|
50
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AnyNode, AnyNodeId, CeilingNode, SlabNode } from '../../schema';
|
|
2
|
+
export declare function syncAutoElevatorOpenings(nodes: Record<string, AnyNode>): {
|
|
3
|
+
id: AnyNodeId;
|
|
4
|
+
data: Partial<SlabNode | CeilingNode>;
|
|
5
|
+
}[];
|
|
6
|
+
//# sourceMappingURL=elevator-opening-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elevator-opening-sync.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-opening-sync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,WAAW,EAEX,QAAQ,EAET,MAAM,cAAc,CAAA;AA8JrB,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;QAQ1C,SAAS;UAAQ,OAAO,CAAC,QAAQ,GAAG,WAAW,CAAC;IAmG5E"}
|