@pascal-app/editor 1.0.7 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -7
- package/src/components/editor/custom-camera-controls.tsx +90 -34
- package/src/components/editor/duplicate-node.ts +2 -1
- package/src/components/editor/first-person-controls.tsx +5 -7
- package/src/components/editor/fit-scene-framing.test.ts +318 -0
- package/src/components/editor/fit-scene-framing.ts +142 -0
- package/src/components/editor/floating-action-menu.tsx +4 -2
- package/src/components/editor/floor-openings-overlay.tsx +1 -1
- package/src/components/editor/floor-region-controls.tsx +2 -2
- package/src/components/editor/floorplan-panel.tsx +173 -8
- package/src/components/editor/floorplan-wall-typing-keys.test.tsx +152 -0
- package/src/components/editor/floorplan-wall-typing-keys.ts +79 -0
- package/src/components/editor/footprint-height-handle.tsx +1 -1
- package/src/components/editor/group-transform-shared.ts +3 -1
- package/src/components/editor/index.tsx +20 -0
- package/src/components/editor/measurement-pill.tsx +1 -1
- package/src/components/editor/node-arrow-handles.tsx +1 -1
- package/src/components/editor/open-wall-ends-3d-layer.tsx +1 -2
- package/src/components/editor/open-wall-ends-hint.tsx +1 -1
- package/src/components/editor/quick-measurement-card.tsx +1 -1
- package/src/components/editor/room-controls.tsx +3 -2
- package/src/components/editor/room-handles-2d.tsx +2 -1
- package/src/components/editor/room-handles.tsx +3 -3
- package/src/components/editor/room-labels.tsx +4 -2
- package/src/components/editor/site-edge-labels.tsx +6 -2
- package/src/components/editor/wall-measurement-label.tsx +30 -14
- package/src/components/editor/wall-move-side-handles.tsx +10 -6
- package/src/components/editor/wall-region-handles.tsx +2 -2
- package/src/components/editor/wall-snap-beacon-layer.tsx +53 -32
- package/src/components/editor-2d/floorplan-group-move.tsx +1 -1
- package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +12 -12
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +1 -2
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +2 -1
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +22 -4
- package/src/components/editor-2d/renderers/floorplan-draft-measurement.tsx +7 -1
- package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +13 -1
- package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.test.tsx +35 -0
- package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.tsx +65 -0
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +22 -0
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +14 -2
- package/src/components/systems/roof/roof-edit-system.test.tsx +15 -1
- package/src/components/systems/roof/roof-edit-system.tsx +30 -19
- package/src/components/tools/distribution/distribution-run-tool.test.tsx +371 -3
- package/src/components/tools/distribution/distribution-run-tool.tsx +150 -32
- package/src/components/tools/item/move-tool.tsx +1 -6
- package/src/components/tools/item/use-placement-coordinator.tsx +1 -1
- package/src/components/tools/paint-region/wall-paint-region-tool.tsx +1 -1
- package/src/components/tools/registry/move-registry-node-tool.test.ts +42 -1
- package/src/components/tools/registry/move-registry-node-tool.tsx +38 -14
- package/src/components/tools/shared/placement-box.tsx +1 -5
- package/src/components/tools/shared/placement-coordinate-input.tsx +94 -0
- package/src/components/tools/shared/segment-angle.ts +0 -4
- package/src/components/tools/tool-manager.tsx +1 -24
- package/src/components/tools/wall/wall-typed-entry.test.ts +99 -0
- package/src/components/tools/wall/wall-typed-entry.ts +70 -0
- package/src/components/ui/controls/slider-control.tsx +18 -6
- package/src/components/ui/controls/tool-options-panel.tsx +74 -44
- package/src/components/ui/helpers/helper-manager.test.tsx +53 -0
- package/src/components/ui/helpers/helper-manager.tsx +54 -0
- package/src/components/ui/panels/floor-foundation-panel.tsx +1 -1
- package/src/components/ui/panels/floor-opening-panel.tsx +1 -1
- package/src/components/ui/panels/mobile-selection-bar.tsx +28 -24
- package/src/components/ui/panels/multi-height-mode.tsx +3 -3
- package/src/components/ui/panels/multi-selection-panel.tsx +1 -1
- package/src/components/ui/panels/panel-manager.tsx +4 -2
- package/src/components/ui/panels/panel-wrapper.tsx +41 -18
- package/src/components/ui/panels/room-construction-rows.tsx +1 -1
- package/src/components/ui/panels/room-openings-field.tsx +1 -1
- package/src/components/ui/panels/room-panel.tsx +1 -1
- package/src/components/ui/right-stack.test.ts +13 -6
- package/src/components/ui/right-stack.tsx +21 -10
- package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +1 -8
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +1 -1
- package/src/components/ui/wall-type/wall-type-editor-dialog.tsx +1 -1
- package/src/components/viewer/viewer-rooms.tsx +1 -1
- package/src/i18n/locales/en/messages.po +856 -124
- package/src/i18n/locales/en/messages.ts +1 -1
- package/src/i18n/locales/en-XA/messages.ts +1 -1
- package/src/i18n/locales/es/messages.po +2087 -257
- package/src/i18n/locales/fr/messages.po +2087 -257
- package/src/i18n/locales/ja/messages.po +2087 -257
- package/src/i18n/locales/zh-CN/messages.po +2087 -257
- package/src/index.tsx +74 -47
- package/src/lib/contextual-help.ts +6 -0
- package/src/lib/elevation-guides.ts +21 -6
- package/src/lib/elevator-support.ts +1 -72
- package/src/lib/floor-footprints.test.ts +1 -1
- package/src/lib/floor-footprints.ts +1 -9
- package/src/lib/floor-foundation-support.test.ts +8 -3
- package/src/lib/floor-opening-draft.ts +1 -1
- package/src/lib/floor-region-session.ts +1 -1
- package/src/lib/floorplan/open-wall-ends.ts +2 -1
- package/src/lib/gesture-lifecycle.ts +3 -1
- package/src/lib/interaction/scope.ts +1 -0
- package/src/lib/layer-thickness.ts +1 -1
- package/src/lib/level-selection.test.ts +18 -2
- package/src/lib/level-selection.ts +31 -8
- package/src/lib/linear-display.ts +1 -1
- package/src/lib/live-gesture-round-trip.test.ts +1 -1
- package/src/lib/measurement-label.test.ts +1 -1
- package/src/lib/measurements.test.ts +8 -7
- package/src/lib/measurements.ts +1 -218
- package/src/lib/node-action-movement.test.tsx +115 -0
- package/src/lib/node-action-movement.ts +2 -0
- package/src/lib/placement-metadata.ts +4 -0
- package/src/lib/point-ask/describe-target.ts +6 -8
- package/src/lib/point-ask/region.ts +1 -1
- package/src/lib/print-shell-compiler.ts +12 -1
- package/src/lib/print-wall-solids.test.ts +11 -0
- package/src/lib/print-wall-solids.ts +9 -0
- package/src/lib/room-assembly-overlay.ts +1 -1
- package/src/lib/room-built-on.test.ts +2 -5
- package/src/lib/room-built-on.ts +1 -15
- package/src/lib/room-construction-commands.ts +3 -2
- package/src/lib/room-controls-phase6.test.ts +1 -1
- package/src/lib/room-handle-drag.ts +6 -25
- package/src/lib/room-push-dimensions.test.ts +1 -1
- package/src/lib/scene-bounds.test.ts +144 -0
- package/src/lib/scene-bounds.ts +79 -15
- package/src/lib/scene-clipboard.ts +2 -1
- package/src/lib/snapping-mode.test.ts +23 -1
- package/src/lib/viewer-selection.ts +1 -1
- package/src/lib/wall-region-list.ts +3 -1
- package/src/lib/window-interaction.test.ts +4 -2
- package/src/store/use-editor.tsx +5 -0
- package/src/store/use-placement-typing.test.ts +165 -0
- package/src/store/use-placement-typing.ts +186 -0
- package/src/components/tools/elevator/elevator-defaults.ts +0 -8
- package/src/components/tools/elevator/elevator-tool.tsx +0 -372
- package/src/components/tools/elevator/move-elevator-tool.tsx +0 -262
- package/src/lib/door-interaction.ts +0 -102
- package/src/lib/measurement-label.ts +0 -68
- package/src/lib/window-interaction.ts +0 -142
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type AnyNodeId,
|
|
3
|
-
type DoorInteractiveState,
|
|
4
|
-
isOperationDoorType,
|
|
5
|
-
useInteractive,
|
|
6
|
-
useScene,
|
|
7
|
-
} from '@pascal-app/core'
|
|
8
|
-
|
|
9
|
-
export const DOOR_SWING_OPEN_ANGLE = Math.PI / 2
|
|
10
|
-
export const DOOR_TOGGLE_ANIMATION_MS = 520
|
|
11
|
-
|
|
12
|
-
export { isOperationDoorType }
|
|
13
|
-
|
|
14
|
-
type DoorOpenAnimationOptions = {
|
|
15
|
-
persist?: boolean
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function getDisplayedDoorValue(
|
|
19
|
-
doorId: AnyNodeId,
|
|
20
|
-
field: keyof DoorInteractiveState,
|
|
21
|
-
nodeValue: number | undefined,
|
|
22
|
-
) {
|
|
23
|
-
const interactive = useInteractive.getState()
|
|
24
|
-
const runtimeValue = interactive.doors[doorId]?.[field]
|
|
25
|
-
if (runtimeValue !== undefined) return runtimeValue
|
|
26
|
-
|
|
27
|
-
const queuedValue = interactive.doorAnimations[doorId]?.from
|
|
28
|
-
if (queuedValue !== undefined) return queuedValue
|
|
29
|
-
|
|
30
|
-
return nodeValue ?? 0
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function startDoorOpenAnimation(
|
|
34
|
-
doorId: AnyNodeId,
|
|
35
|
-
field: keyof DoorInteractiveState,
|
|
36
|
-
from: number,
|
|
37
|
-
to: number,
|
|
38
|
-
options?: DoorOpenAnimationOptions,
|
|
39
|
-
) {
|
|
40
|
-
useInteractive.getState().startDoorAnimation(doorId, {
|
|
41
|
-
field,
|
|
42
|
-
from,
|
|
43
|
-
to,
|
|
44
|
-
startedAt: null,
|
|
45
|
-
durationMs: DOOR_TOGGLE_ANIMATION_MS,
|
|
46
|
-
persist: options?.persist ?? true,
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function toggleDoorOpenState(doorId: AnyNodeId, options?: DoorOpenAnimationOptions) {
|
|
51
|
-
const node = useScene.getState().nodes[doorId]
|
|
52
|
-
if (node?.type !== 'door' || node.openingKind === 'opening') return
|
|
53
|
-
|
|
54
|
-
if (isOperationDoorType(node.doorType)) {
|
|
55
|
-
const currentOpenAmount = getDisplayedDoorValue(doorId, 'operationState', node.operationState)
|
|
56
|
-
startDoorOpenAnimation(
|
|
57
|
-
doorId,
|
|
58
|
-
'operationState',
|
|
59
|
-
currentOpenAmount,
|
|
60
|
-
currentOpenAmount >= 0.5 ? 0 : 1,
|
|
61
|
-
options,
|
|
62
|
-
)
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const currentSwingAngle = getDisplayedDoorValue(doorId, 'swingAngle', node.swingAngle)
|
|
67
|
-
startDoorOpenAnimation(
|
|
68
|
-
doorId,
|
|
69
|
-
'swingAngle',
|
|
70
|
-
currentSwingAngle,
|
|
71
|
-
currentSwingAngle >= DOOR_SWING_OPEN_ANGLE / 2 ? 0 : DOOR_SWING_OPEN_ANGLE,
|
|
72
|
-
options,
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function closeDoorOpenState(doorId: AnyNodeId, options?: DoorOpenAnimationOptions) {
|
|
77
|
-
const node = useScene.getState().nodes[doorId]
|
|
78
|
-
if (node?.type !== 'door' || node.openingKind === 'opening') return
|
|
79
|
-
|
|
80
|
-
if (isOperationDoorType(node.doorType)) {
|
|
81
|
-
const currentOpenAmount = getDisplayedDoorValue(doorId, 'operationState', node.operationState)
|
|
82
|
-
startDoorOpenAnimation(doorId, 'operationState', currentOpenAmount, 0, options)
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const currentSwingAngle = getDisplayedDoorValue(doorId, 'swingAngle', node.swingAngle)
|
|
87
|
-
startDoorOpenAnimation(doorId, 'swingAngle', currentSwingAngle, 0, options)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function openDoorOpenState(doorId: AnyNodeId, options?: DoorOpenAnimationOptions) {
|
|
91
|
-
const node = useScene.getState().nodes[doorId]
|
|
92
|
-
if (node?.type !== 'door' || node.openingKind === 'opening') return
|
|
93
|
-
|
|
94
|
-
if (isOperationDoorType(node.doorType)) {
|
|
95
|
-
const currentOpenAmount = getDisplayedDoorValue(doorId, 'operationState', node.operationState)
|
|
96
|
-
startDoorOpenAnimation(doorId, 'operationState', currentOpenAmount, 1, options)
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const currentSwingAngle = getDisplayedDoorValue(doorId, 'swingAngle', node.swingAngle)
|
|
101
|
-
startDoorOpenAnimation(doorId, 'swingAngle', currentSwingAngle, DOOR_SWING_OPEN_ANGLE, options)
|
|
102
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { type MeasurementPoint, measurementCentroid, measurementNormal } from '@pascal-app/core'
|
|
2
|
-
import { ShapeUtils, Vector2, Vector3 } from 'three'
|
|
3
|
-
|
|
4
|
-
type MeasurementPolygonProjection = {
|
|
5
|
-
contour: Vector2[]
|
|
6
|
-
triangles: number[][]
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function projectMeasurementPolygon(
|
|
10
|
-
points: readonly MeasurementPoint[],
|
|
11
|
-
): MeasurementPolygonProjection | null {
|
|
12
|
-
const normalValue = measurementNormal(points)
|
|
13
|
-
const originValue = points[0]
|
|
14
|
-
if (!(normalValue && originValue)) return null
|
|
15
|
-
|
|
16
|
-
const normal = new Vector3(...normalValue)
|
|
17
|
-
const reference = Math.abs(normal.y) < 0.9 ? new Vector3(0, 1, 0) : new Vector3(1, 0, 0)
|
|
18
|
-
const tangent = new Vector3().crossVectors(reference, normal).normalize()
|
|
19
|
-
const bitangent = new Vector3().crossVectors(normal, tangent).normalize()
|
|
20
|
-
const origin = new Vector3(...originValue)
|
|
21
|
-
const contour = points.map((point) => {
|
|
22
|
-
const relative = new Vector3(...point).sub(origin)
|
|
23
|
-
return new Vector2(relative.dot(tangent), relative.dot(bitangent))
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
return { contour, triangles: ShapeUtils.triangulateShape(contour, []) }
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function triangulateMeasurementPolygon(points: readonly MeasurementPoint[]): number[][] {
|
|
30
|
-
return projectMeasurementPolygon(points)?.triangles ?? []
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function measurementPolygonLabelAnchor(
|
|
34
|
-
points: readonly MeasurementPoint[],
|
|
35
|
-
): MeasurementPoint | null {
|
|
36
|
-
const projection = projectMeasurementPolygon(points)
|
|
37
|
-
if (!projection || projection.triangles.length === 0) return measurementCentroid(points)
|
|
38
|
-
|
|
39
|
-
let largestTriangle: number[] | null = null
|
|
40
|
-
let largestArea = Number.NEGATIVE_INFINITY
|
|
41
|
-
for (const triangle of projection.triangles) {
|
|
42
|
-
const [firstIndex, secondIndex, thirdIndex] = triangle
|
|
43
|
-
const first = firstIndex === undefined ? null : projection.contour[firstIndex]
|
|
44
|
-
const second = secondIndex === undefined ? null : projection.contour[secondIndex]
|
|
45
|
-
const third = thirdIndex === undefined ? null : projection.contour[thirdIndex]
|
|
46
|
-
if (!(first && second && third)) continue
|
|
47
|
-
const area = Math.abs(
|
|
48
|
-
(second.x - first.x) * (third.y - first.y) - (second.y - first.y) * (third.x - first.x),
|
|
49
|
-
)
|
|
50
|
-
if (area > largestArea) {
|
|
51
|
-
largestArea = area
|
|
52
|
-
largestTriangle = triangle
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (!largestTriangle) return measurementCentroid(points)
|
|
57
|
-
const [firstIndex, secondIndex, thirdIndex] = largestTriangle
|
|
58
|
-
const first = firstIndex === undefined ? null : points[firstIndex]
|
|
59
|
-
const second = secondIndex === undefined ? null : points[secondIndex]
|
|
60
|
-
const third = thirdIndex === undefined ? null : points[thirdIndex]
|
|
61
|
-
if (!(first && second && third)) return measurementCentroid(points)
|
|
62
|
-
|
|
63
|
-
return [
|
|
64
|
-
(first[0] + second[0] + third[0]) / 3,
|
|
65
|
-
(first[1] + second[1] + third[1]) / 3,
|
|
66
|
-
(first[2] + second[2] + third[2]) / 3,
|
|
67
|
-
]
|
|
68
|
-
}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type AnyNodeId,
|
|
3
|
-
type InteractiveState,
|
|
4
|
-
useInteractive,
|
|
5
|
-
useScene,
|
|
6
|
-
type WindowInteractiveState,
|
|
7
|
-
} from '@pascal-app/core'
|
|
8
|
-
|
|
9
|
-
export const WINDOW_TOGGLE_ANIMATION_MS = 520
|
|
10
|
-
|
|
11
|
-
export type WindowOpenAnimationOptions = {
|
|
12
|
-
persist?: boolean
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function isOperableWindowType(windowType: string | undefined) {
|
|
16
|
-
return (
|
|
17
|
-
windowType === 'sliding' ||
|
|
18
|
-
windowType === 'casement' ||
|
|
19
|
-
windowType === 'awning' ||
|
|
20
|
-
windowType === 'hopper' ||
|
|
21
|
-
windowType === 'tilt-turn' ||
|
|
22
|
-
windowType === 'single-hung' ||
|
|
23
|
-
windowType === 'double-hung' ||
|
|
24
|
-
windowType === 'louvered'
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function getDisplayedWindowValue(
|
|
29
|
-
windowId: AnyNodeId,
|
|
30
|
-
nodeValue: number | undefined,
|
|
31
|
-
field: keyof WindowInteractiveState = 'operationState',
|
|
32
|
-
interactive: InteractiveState = useInteractive.getState(),
|
|
33
|
-
) {
|
|
34
|
-
const runtimeValue = interactive.windows[windowId]?.[field]
|
|
35
|
-
if (runtimeValue !== undefined) return runtimeValue
|
|
36
|
-
|
|
37
|
-
const queuedValue = interactive.windowAnimations[windowId]?.[field]?.from
|
|
38
|
-
if (queuedValue !== undefined) return queuedValue
|
|
39
|
-
|
|
40
|
-
return nodeValue ?? 0
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function startWindowOpenAnimation(
|
|
44
|
-
windowId: AnyNodeId,
|
|
45
|
-
field: keyof WindowInteractiveState,
|
|
46
|
-
from: number,
|
|
47
|
-
to: number,
|
|
48
|
-
options?: WindowOpenAnimationOptions,
|
|
49
|
-
) {
|
|
50
|
-
useInteractive.getState().startWindowAnimation(windowId, {
|
|
51
|
-
field,
|
|
52
|
-
from,
|
|
53
|
-
to,
|
|
54
|
-
startedAt: null,
|
|
55
|
-
durationMs: WINDOW_TOGGLE_ANIMATION_MS,
|
|
56
|
-
persist: options?.persist ?? true,
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function toggleWindowOpenState(windowId: AnyNodeId, options?: WindowOpenAnimationOptions) {
|
|
61
|
-
const node = useScene.getState().nodes[windowId]
|
|
62
|
-
if (
|
|
63
|
-
node?.type !== 'window' ||
|
|
64
|
-
node.openingKind === 'opening' ||
|
|
65
|
-
!isOperableWindowType(node.windowType)
|
|
66
|
-
) {
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const currentOpenAmount = getDisplayedWindowValue(windowId, node.operationState)
|
|
71
|
-
startWindowOpenAnimation(
|
|
72
|
-
windowId,
|
|
73
|
-
'operationState',
|
|
74
|
-
currentOpenAmount,
|
|
75
|
-
currentOpenAmount >= 0.5 ? 0 : 1,
|
|
76
|
-
options,
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function closeWindowOpenState(windowId: AnyNodeId, options?: WindowOpenAnimationOptions) {
|
|
81
|
-
const node = useScene.getState().nodes[windowId]
|
|
82
|
-
if (
|
|
83
|
-
node?.type !== 'window' ||
|
|
84
|
-
node.openingKind === 'opening' ||
|
|
85
|
-
!isOperableWindowType(node.windowType)
|
|
86
|
-
) {
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const currentOpenAmount = getDisplayedWindowValue(windowId, node.operationState)
|
|
91
|
-
startWindowOpenAnimation(windowId, 'operationState', currentOpenAmount, 0, options)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function openWindowOpenState(windowId: AnyNodeId, options?: WindowOpenAnimationOptions) {
|
|
95
|
-
const node = useScene.getState().nodes[windowId]
|
|
96
|
-
if (
|
|
97
|
-
node?.type !== 'window' ||
|
|
98
|
-
node.openingKind === 'opening' ||
|
|
99
|
-
!isOperableWindowType(node.windowType)
|
|
100
|
-
) {
|
|
101
|
-
return
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const currentOpenAmount = getDisplayedWindowValue(windowId, node.operationState)
|
|
105
|
-
startWindowOpenAnimation(windowId, 'operationState', currentOpenAmount, 1, options)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export type WindowShutterField = 'shutterOpen' | 'rollerShutterOpen'
|
|
109
|
-
|
|
110
|
-
export function getDisplayedWindowShutterValue(
|
|
111
|
-
windowId: AnyNodeId,
|
|
112
|
-
field: WindowShutterField,
|
|
113
|
-
nodeValue: number | undefined,
|
|
114
|
-
state: InteractiveState = useInteractive.getState(),
|
|
115
|
-
): number {
|
|
116
|
-
return getDisplayedWindowValue(windowId, nodeValue ?? 1, field, state)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Preview both shutter styles together, independently of the sash. */
|
|
120
|
-
export function setWindowShuttersOpenState(
|
|
121
|
-
windowId: AnyNodeId,
|
|
122
|
-
on: boolean,
|
|
123
|
-
options?: WindowOpenAnimationOptions,
|
|
124
|
-
): void {
|
|
125
|
-
const node = useScene.getState().nodes[windowId]
|
|
126
|
-
if (node?.type !== 'window' || node.source) return
|
|
127
|
-
const fields: WindowShutterField[] = []
|
|
128
|
-
if (node.shutters && node.shutters !== 'none') fields.push('shutterOpen')
|
|
129
|
-
if (node.rollerShutter === 'box' || node.rollerShutter === 'concealed')
|
|
130
|
-
fields.push('rollerShutterOpen')
|
|
131
|
-
if (!fields.length) return
|
|
132
|
-
useInteractive.getState().setMechanismPart(windowId, 'shutters', on)
|
|
133
|
-
for (const field of fields) {
|
|
134
|
-
startWindowOpenAnimation(
|
|
135
|
-
windowId,
|
|
136
|
-
field,
|
|
137
|
-
getDisplayedWindowShutterValue(windowId, field, node[field]),
|
|
138
|
-
on ? 1 : 0,
|
|
139
|
-
options,
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
}
|