@pascal-app/nodes 1.0.1 → 1.0.3
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/block/definition.d.ts.map +1 -1
- package/dist/block/definition.js +4 -1
- package/dist/block/face-host.d.ts.map +1 -1
- package/dist/block/face-host.js +19 -2
- package/dist/block/hosted-edit.d.ts +13 -0
- package/dist/block/hosted-edit.d.ts.map +1 -0
- package/dist/block/hosted-edit.js +205 -0
- package/dist/block/last-operation.d.ts +1 -1
- package/dist/block/last-operation.d.ts.map +1 -1
- package/dist/block/last-operation.js +6 -4
- package/dist/block/modal-session.d.ts +2 -1
- package/dist/block/modal-session.d.ts.map +1 -1
- package/dist/block/modal-session.js +2 -2
- package/dist/block/selection.d.ts.map +1 -1
- package/dist/block/selection.js +82 -24
- package/dist/block/surface.d.ts +4 -0
- package/dist/block/surface.d.ts.map +1 -0
- package/dist/block/surface.js +54 -0
- package/dist/block/use-block-face-operation.d.ts +2 -2
- package/dist/block/use-block-face-operation.d.ts.map +1 -1
- package/dist/block/use-block-face-operation.js +25 -11
- package/dist/box-vent/definition.d.ts.map +1 -1
- package/dist/box-vent/definition.js +1 -0
- package/dist/building/renderer.d.ts.map +1 -1
- package/dist/building/renderer.js +1 -1
- package/dist/cabinet/definition.d.ts.map +1 -1
- package/dist/cabinet/definition.js +3 -1
- package/dist/cabinet/hosted-resize.d.ts +3 -6
- package/dist/cabinet/hosted-resize.d.ts.map +1 -1
- package/dist/cabinet/hosted-resize.js +9 -153
- package/dist/cabinet/placement-snap.d.ts.map +1 -1
- package/dist/cabinet/placement-snap.js +4 -2
- package/dist/cabinet/surfaces.d.ts +1 -0
- package/dist/cabinet/surfaces.d.ts.map +1 -1
- package/dist/cabinet/surfaces.js +13 -1
- package/dist/cabinet/tool.d.ts.map +1 -1
- package/dist/cabinet/tool.js +8 -4
- package/dist/ceiling/definition.d.ts.map +1 -1
- package/dist/ceiling/definition.js +5 -0
- package/dist/ceiling/renderer.d.ts.map +1 -1
- package/dist/ceiling/renderer.js +3 -2
- package/dist/chimney/definition.d.ts.map +1 -1
- package/dist/chimney/definition.js +1 -0
- package/dist/column/definition.d.ts.map +1 -1
- package/dist/column/definition.js +10 -3
- package/dist/column/floorplan-affordances.d.ts.map +1 -1
- package/dist/column/floorplan-affordances.js +6 -1
- package/dist/column/floorplan.d.ts.map +1 -1
- package/dist/column/floorplan.js +23 -11
- package/dist/column/hosted-resize.d.ts +116 -0
- package/dist/column/hosted-resize.d.ts.map +1 -0
- package/dist/column/hosted-resize.js +9 -0
- package/dist/column/panel.d.ts.map +1 -1
- package/dist/column/panel.js +6 -3
- package/dist/column/renderer.d.ts.map +1 -1
- package/dist/column/renderer.js +25 -103
- package/dist/column/shape.d.ts +22 -0
- package/dist/column/shape.d.ts.map +1 -0
- package/dist/column/shape.js +120 -0
- package/dist/column/surface.d.ts +4 -0
- package/dist/column/surface.d.ts.map +1 -0
- package/dist/column/surface.js +66 -0
- package/dist/cupola/definition.d.ts.map +1 -1
- package/dist/cupola/definition.js +1 -0
- package/dist/door/definition.d.ts.map +1 -1
- package/dist/door/definition.js +40 -1
- package/dist/door/door-math.d.ts +1 -1
- package/dist/door/door-math.d.ts.map +1 -1
- package/dist/door/door-math.js +7 -10
- package/dist/door/floorplan-affordances.d.ts.map +1 -1
- package/dist/door/floorplan-affordances.js +8 -12
- package/dist/door/move-tool.d.ts.map +1 -1
- package/dist/door/move-tool.js +3 -4
- package/dist/door/panel.d.ts.map +1 -1
- package/dist/door/panel.js +23 -52
- package/dist/door/tool.d.ts.map +1 -1
- package/dist/door/tool.js +20 -2
- package/dist/dormer/definition.d.ts.map +1 -1
- package/dist/dormer/definition.js +1 -0
- package/dist/downspout/definition.d.ts.map +1 -1
- package/dist/downspout/definition.js +1 -0
- package/dist/duct-segment/tool.d.ts.map +1 -1
- package/dist/duct-segment/tool.js +11 -0
- package/dist/duct-terminal/tool.d.ts.map +1 -1
- package/dist/duct-terminal/tool.js +77 -8
- package/dist/elevator/definition.d.ts.map +1 -1
- package/dist/elevator/definition.js +2 -0
- package/dist/elevator/parametrics.d.ts.map +1 -1
- package/dist/elevator/parametrics.js +98 -1
- package/dist/eyebrow-vent/definition.d.ts.map +1 -1
- package/dist/eyebrow-vent/definition.js +1 -0
- package/dist/fence/definition.d.ts.map +1 -1
- package/dist/fence/definition.js +1 -0
- package/dist/fence/tool.js +2 -2
- package/dist/guide/definition.d.ts.map +1 -1
- package/dist/guide/definition.js +1 -0
- package/dist/gutter/definition.d.ts.map +1 -1
- package/dist/gutter/definition.js +1 -0
- package/dist/hvac-equipment/tool.d.ts.map +1 -1
- package/dist/hvac-equipment/tool.js +8 -2
- package/dist/item/__fixtures__/main-floorplan.d.ts +26 -0
- package/dist/item/__fixtures__/main-floorplan.d.ts.map +1 -0
- package/dist/item/__fixtures__/main-floorplan.js +297 -0
- package/dist/item/definition.d.ts.map +1 -1
- package/dist/item/definition.js +3 -1
- package/dist/item/floorplan-move.d.ts.map +1 -1
- package/dist/item/floorplan-move.js +209 -130
- package/dist/item/floorplan.d.ts +22 -0
- package/dist/item/floorplan.d.ts.map +1 -1
- package/dist/item/floorplan.js +61 -2
- package/dist/item/move-tool.d.ts +1 -1
- package/dist/item/move-tool.d.ts.map +1 -1
- package/dist/item/move-tool.js +15 -7
- package/dist/item/renderer.d.ts.map +1 -1
- package/dist/item/renderer.js +8 -2
- package/dist/level/renderer.js +1 -1
- package/dist/lineset/tool.d.ts.map +1 -1
- package/dist/lineset/tool.js +1 -0
- package/dist/liquid-line/tool.d.ts.map +1 -1
- package/dist/liquid-line/tool.js +5 -1
- package/dist/measurement/definition.d.ts.map +1 -1
- package/dist/measurement/definition.js +1 -0
- package/dist/pipe-segment/tool.d.ts.map +1 -1
- package/dist/pipe-segment/tool.js +14 -3
- package/dist/pipe-trap/tool.d.ts.map +1 -1
- package/dist/pipe-trap/tool.js +7 -8
- package/dist/procedural-item/definition.d.ts.map +1 -1
- package/dist/procedural-item/definition.js +4 -1
- package/dist/ridge-vent/definition.d.ts.map +1 -1
- package/dist/ridge-vent/definition.js +1 -0
- package/dist/roof/definition.d.ts.map +1 -1
- package/dist/roof/definition.js +4 -1
- package/dist/roof/panel-model.d.ts +4 -0
- package/dist/roof/panel-model.d.ts.map +1 -0
- package/dist/roof/panel-model.js +151 -0
- package/dist/roof/panel.d.ts.map +1 -1
- package/dist/roof/panel.js +3 -4
- package/dist/roof/parametrics.d.ts.map +1 -1
- package/dist/roof/parametrics.js +16 -1
- package/dist/roof-segment/definition.d.ts.map +1 -1
- package/dist/roof-segment/definition.js +1 -0
- package/dist/roof-segment/parametrics.d.ts.map +1 -1
- package/dist/roof-segment/parametrics.js +176 -1
- package/dist/scan/definition.d.ts.map +1 -1
- package/dist/scan/definition.js +1 -0
- package/dist/shared/commit-opening-move.d.ts +4 -0
- package/dist/shared/commit-opening-move.d.ts.map +1 -0
- package/dist/shared/commit-opening-move.js +9 -0
- package/dist/shared/curtain-opening-limits.d.ts +14 -0
- package/dist/shared/curtain-opening-limits.d.ts.map +1 -0
- package/dist/shared/curtain-opening-limits.js +53 -0
- package/dist/shared/draft-axis-guides.d.ts +0 -6
- package/dist/shared/draft-axis-guides.d.ts.map +1 -1
- package/dist/shared/draft-axis-guides.js +1 -8
- package/dist/shared/hosted-resize.d.ts +12 -0
- package/dist/shared/hosted-resize.d.ts.map +1 -0
- package/dist/shared/hosted-resize.js +166 -0
- package/dist/shared/opening-grid-follow.d.ts +8 -0
- package/dist/shared/opening-grid-follow.d.ts.map +1 -0
- package/dist/shared/opening-grid-follow.js +12 -0
- package/dist/shared/opening-property-preview-host.d.ts +3 -0
- package/dist/shared/opening-property-preview-host.d.ts.map +1 -0
- package/dist/shared/opening-property-preview-host.js +21 -0
- package/dist/shared/opening-property-preview.d.ts +19 -0
- package/dist/shared/opening-property-preview.d.ts.map +1 -0
- package/dist/shared/opening-property-preview.js +99 -0
- package/dist/shared/resting-surface-plan.d.ts +2 -1
- package/dist/shared/resting-surface-plan.d.ts.map +1 -1
- package/dist/shared/resting-surface-plan.js +29 -4
- package/dist/shared/surface-counterparts.d.ts +12 -0
- package/dist/shared/surface-counterparts.d.ts.map +1 -0
- package/dist/shared/surface-counterparts.js +27 -0
- package/dist/shared/wall-attach-target.d.ts +1 -0
- package/dist/shared/wall-attach-target.d.ts.map +1 -1
- package/dist/shared/wall-attach-target.js +4 -1
- package/dist/shared/wall-event-from-grid.d.ts +5 -0
- package/dist/shared/wall-event-from-grid.d.ts.map +1 -0
- package/dist/shared/wall-event-from-grid.js +36 -0
- package/dist/shelf/definition.d.ts.map +1 -1
- package/dist/shelf/definition.js +3 -1
- package/dist/shelf/floorplan.d.ts.map +1 -1
- package/dist/shelf/floorplan.js +9 -2
- package/dist/site/renderer.d.ts.map +1 -1
- package/dist/site/renderer.js +9 -2
- package/dist/skylight/definition.d.ts.map +1 -1
- package/dist/skylight/definition.js +1 -0
- package/dist/slab/definition.d.ts.map +1 -1
- package/dist/slab/definition.js +4 -0
- package/dist/solar-panel/definition.d.ts.map +1 -1
- package/dist/solar-panel/definition.js +1 -0
- package/dist/spawn/definition.d.ts.map +1 -1
- package/dist/spawn/definition.js +1 -0
- package/dist/stair/definition.d.ts.map +1 -1
- package/dist/stair/definition.js +2 -0
- package/dist/stair/parametrics.d.ts.map +1 -1
- package/dist/stair/parametrics.js +164 -1
- package/dist/stair-segment/definition.d.ts.map +1 -1
- package/dist/stair-segment/definition.js +1 -0
- package/dist/stair-segment/parametrics.d.ts.map +1 -1
- package/dist/stair-segment/parametrics.js +81 -1
- package/dist/turbine-vent/definition.d.ts.map +1 -1
- package/dist/turbine-vent/definition.js +1 -0
- package/dist/wall/actions.d.ts +3 -0
- package/dist/wall/actions.d.ts.map +1 -0
- package/dist/wall/actions.js +56 -0
- package/dist/wall/curtain-opening-frame.d.ts +14 -0
- package/dist/wall/curtain-opening-frame.d.ts.map +1 -0
- package/dist/wall/curtain-opening-frame.js +111 -0
- package/dist/wall/curtain-panel-highlight.d.ts +3 -0
- package/dist/wall/curtain-panel-highlight.d.ts.map +1 -0
- package/dist/wall/curtain-panel-highlight.js +113 -0
- package/dist/wall/curtain-wall-adapter.d.ts +3 -0
- package/dist/wall/curtain-wall-adapter.d.ts.map +1 -0
- package/dist/wall/curtain-wall-adapter.js +55 -0
- package/dist/wall/curtain-wall-floorplan.d.ts +3 -0
- package/dist/wall/curtain-wall-floorplan.d.ts.map +1 -0
- package/dist/wall/curtain-wall-floorplan.js +91 -0
- package/dist/wall/curtain-wall-geometry.d.ts +4 -0
- package/dist/wall/curtain-wall-geometry.d.ts.map +1 -0
- package/dist/wall/curtain-wall-geometry.js +226 -0
- package/dist/wall/curtain-wall-layout.d.ts +16 -0
- package/dist/wall/curtain-wall-layout.d.ts.map +1 -0
- package/dist/wall/curtain-wall-layout.js +176 -0
- package/dist/wall/curtain-wall-materials.d.ts +5 -0
- package/dist/wall/curtain-wall-materials.d.ts.map +1 -0
- package/dist/wall/curtain-wall-materials.js +55 -0
- package/dist/wall/curtain-wall-panel.d.ts +14 -0
- package/dist/wall/curtain-wall-panel.d.ts.map +1 -0
- package/dist/wall/curtain-wall-panel.js +167 -0
- package/dist/wall/curtain-wall-piece-geometry.d.ts +5 -0
- package/dist/wall/curtain-wall-piece-geometry.d.ts.map +1 -0
- package/dist/wall/curtain-wall-piece-geometry.js +220 -0
- package/dist/wall/curtain-wall-shadow.d.ts +4 -0
- package/dist/wall/curtain-wall-shadow.d.ts.map +1 -0
- package/dist/wall/curtain-wall-shadow.js +15 -0
- package/dist/wall/definition.d.ts +0 -15
- package/dist/wall/definition.d.ts.map +1 -1
- package/dist/wall/definition.js +65 -4
- package/dist/wall/drawing-mode.d.ts +12 -0
- package/dist/wall/drawing-mode.d.ts.map +1 -0
- package/dist/wall/drawing-mode.js +38 -0
- package/dist/wall/floorplan-tool.d.ts +4 -0
- package/dist/wall/floorplan-tool.d.ts.map +1 -0
- package/dist/wall/floorplan-tool.js +107 -0
- package/dist/wall/floorplan.d.ts.map +1 -1
- package/dist/wall/floorplan.js +6 -2
- package/dist/wall/length-patch.d.ts +3 -0
- package/dist/wall/length-patch.d.ts.map +1 -0
- package/dist/wall/length-patch.js +14 -0
- package/dist/wall/move-tool.d.ts.map +1 -1
- package/dist/wall/move-tool.js +23 -1
- package/dist/wall/paint.d.ts.map +1 -1
- package/dist/wall/paint.js +39 -4
- package/dist/wall/panel-model.d.ts +4 -0
- package/dist/wall/panel-model.d.ts.map +1 -0
- package/dist/wall/panel-model.js +117 -0
- package/dist/wall/panel.d.ts.map +1 -1
- package/dist/wall/panel.js +20 -24
- package/dist/wall/property-preview.d.ts +7 -0
- package/dist/wall/property-preview.d.ts.map +1 -0
- package/dist/wall/property-preview.js +31 -0
- package/dist/wall/rectangle-command.d.ts +149 -0
- package/dist/wall/rectangle-command.d.ts.map +1 -0
- package/dist/wall/rectangle-command.js +22 -0
- package/dist/wall/rectangle-tool.d.ts +2 -0
- package/dist/wall/rectangle-tool.d.ts.map +1 -0
- package/dist/wall/rectangle-tool.js +147 -0
- package/dist/wall/renderer.d.ts.map +1 -1
- package/dist/wall/renderer.js +7 -4
- package/dist/wall/slots.d.ts +2 -2
- package/dist/wall/slots.d.ts.map +1 -1
- package/dist/wall/slots.js +10 -2
- package/dist/wall/split-floorplan-layer.d.ts +4 -0
- package/dist/wall/split-floorplan-layer.d.ts.map +1 -0
- package/dist/wall/split-floorplan-layer.js +71 -0
- package/dist/wall/split-pointer.d.ts +3 -0
- package/dist/wall/split-pointer.d.ts.map +1 -0
- package/dist/wall/split-pointer.js +95 -0
- package/dist/wall/split-preview.d.ts +55 -0
- package/dist/wall/split-preview.d.ts.map +1 -0
- package/dist/wall/split-preview.js +106 -0
- package/dist/wall/split-session.d.ts +16 -0
- package/dist/wall/split-session.d.ts.map +1 -0
- package/dist/wall/split-session.js +138 -0
- package/dist/wall/split-store.d.ts +16 -0
- package/dist/wall/split-store.d.ts.map +1 -0
- package/dist/wall/split-store.js +6 -0
- package/dist/wall/split-tool.d.ts +10 -0
- package/dist/wall/split-tool.d.ts.map +1 -0
- package/dist/wall/split-tool.js +95 -0
- package/dist/wall/system.d.ts.map +1 -1
- package/dist/wall/system.js +3 -1
- package/dist/wall/tool.d.ts.map +1 -1
- package/dist/wall/tool.js +14 -6
- package/dist/wall/wall-batch-system.d.ts.map +1 -1
- package/dist/wall/wall-batch-system.js +3 -0
- package/dist/window/definition.d.ts.map +1 -1
- package/dist/window/definition.js +48 -1
- package/dist/window/floorplan-affordances.d.ts.map +1 -1
- package/dist/window/floorplan-affordances.js +8 -10
- package/dist/window/move-tool.d.ts.map +1 -1
- package/dist/window/move-tool.js +4 -6
- package/dist/window/panel.d.ts.map +1 -1
- package/dist/window/panel.js +21 -59
- package/dist/window/tool.d.ts.map +1 -1
- package/dist/window/tool.js +34 -2
- package/dist/window/window-math.d.ts +1 -1
- package/dist/window/window-math.d.ts.map +1 -1
- package/dist/window/window-math.js +8 -11
- package/dist/zone/definition.d.ts.map +1 -1
- package/dist/zone/definition.js +1 -0
- package/dist/zone/quantities-panel.d.ts.map +1 -1
- package/dist/zone/quantities-panel.js +3 -19
- package/dist/zone/renderer.d.ts.map +1 -1
- package/dist/zone/renderer.js +1 -1
- package/package.json +8 -8
- package/dist/shared/opening-documentation-fields.d.ts +0 -16
- package/dist/shared/opening-documentation-fields.d.ts.map +0 -1
- package/dist/shared/opening-documentation-fields.js +0 -54
package/dist/wall/move-tool.js
CHANGED
|
@@ -121,6 +121,7 @@ export const MoveWallTool = ({ node }) => {
|
|
|
121
121
|
const levelId = node.parentId ?? null;
|
|
122
122
|
pauseSceneHistory(useScene);
|
|
123
123
|
let shouldRestoreOnCleanup = true;
|
|
124
|
+
let active = true;
|
|
124
125
|
// Wall ids that currently carry a live position override. Cleared on commit
|
|
125
126
|
// (after the final store write lands) and on cancel / external unmount.
|
|
126
127
|
const touchedWallIds = new Set();
|
|
@@ -284,6 +285,13 @@ export const MoveWallTool = ({ node }) => {
|
|
|
284
285
|
return linkedOriginalsRef.current.map((wall) => movedById.get(wall.id) ?? { id: wall.id, start: wall.start, end: wall.end });
|
|
285
286
|
};
|
|
286
287
|
const applyPreview = (nextStart, nextEnd) => {
|
|
288
|
+
const previous = previewRef.current ?? { start: originalStart, end: originalEnd };
|
|
289
|
+
if (nextStart[0] === previous.start[0] &&
|
|
290
|
+
nextStart[1] === previous.start[1] &&
|
|
291
|
+
nextEnd[0] === previous.end[0] &&
|
|
292
|
+
nextEnd[1] === previous.end[1])
|
|
293
|
+
return;
|
|
294
|
+
hasDraggedRef.current = true;
|
|
287
295
|
previewRef.current = { start: nextStart, end: nextEnd };
|
|
288
296
|
const centerX = (nextStart[0] + nextEnd[0]) / 2;
|
|
289
297
|
const centerZ = (nextStart[1] + nextEnd[1]) / 2;
|
|
@@ -324,15 +332,24 @@ export const MoveWallTool = ({ node }) => {
|
|
|
324
332
|
clearSurfaceOverrides();
|
|
325
333
|
};
|
|
326
334
|
const onGridMove = (event) => {
|
|
335
|
+
if (!active)
|
|
336
|
+
return;
|
|
327
337
|
const rawX = event.localPosition[0];
|
|
328
338
|
const rawZ = event.localPosition[2];
|
|
329
339
|
const snapStep = getSegmentGridStep();
|
|
330
340
|
// Anchor at the raw cursor so the displacement is measured in
|
|
331
341
|
// continuous space.
|
|
332
342
|
const anchor = dragAnchorRef.current ?? [rawX, rawZ];
|
|
343
|
+
const firstMove = dragAnchorRef.current === null;
|
|
333
344
|
dragAnchorRef.current = anchor;
|
|
345
|
+
// Seeding a controller grab is not movement; don't snap an off-grid wall
|
|
346
|
+
// to the lattice before the user has moved their hand.
|
|
347
|
+
if (firstMove)
|
|
348
|
+
return;
|
|
334
349
|
const rawDeltaX = rawX - anchor[0];
|
|
335
350
|
const rawDeltaZ = rawZ - anchor[1];
|
|
351
|
+
if (!hasDraggedRef.current && Math.hypot(rawDeltaX, rawDeltaZ) < 1e-6)
|
|
352
|
+
return;
|
|
336
353
|
// When the move is axis-locked (side-handle drag), snap the wall
|
|
337
354
|
// center's absolute perpendicular offset to a multiple of
|
|
338
355
|
// `snapStep`. For axis-aligned walls this puts the wall on grid
|
|
@@ -378,7 +395,6 @@ export const MoveWallTool = ({ node }) => {
|
|
|
378
395
|
previousGridPosRef.current = constrainedGridPos;
|
|
379
396
|
const nextCenter = [originalCenter[0] + deltaX, originalCenter[1] + deltaZ];
|
|
380
397
|
const nextWall = buildWallFromCenter(nextCenter);
|
|
381
|
-
hasDraggedRef.current = true;
|
|
382
398
|
applyPreview(nextWall.start, nextWall.end);
|
|
383
399
|
};
|
|
384
400
|
const commitPreview = () => {
|
|
@@ -459,6 +475,9 @@ export const MoveWallTool = ({ node }) => {
|
|
|
459
475
|
exitMoveMode();
|
|
460
476
|
};
|
|
461
477
|
const onPointerUp = () => {
|
|
478
|
+
if (!active)
|
|
479
|
+
return;
|
|
480
|
+
active = false;
|
|
462
481
|
// Press-release without drag: dismiss the tool without committing.
|
|
463
482
|
// This is the same UX as MoveWallEndpointTool / WallHeightArrowHandle
|
|
464
483
|
// — pointer-down on the affordance starts the move, drag updates the
|
|
@@ -496,6 +515,9 @@ export const MoveWallTool = ({ node }) => {
|
|
|
496
515
|
applyPreview(nextWall.start, nextWall.end);
|
|
497
516
|
};
|
|
498
517
|
const onCancel = () => {
|
|
518
|
+
if (!active)
|
|
519
|
+
return;
|
|
520
|
+
active = false;
|
|
499
521
|
shouldRestoreOnCleanup = false;
|
|
500
522
|
restoreOriginal();
|
|
501
523
|
useViewer.getState().setSelection({ selectedIds: [nodeId] });
|
package/dist/wall/paint.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paint.d.ts","sourceRoot":"","sources":["../../src/wall/paint.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"paint.d.ts","sourceRoot":"","sources":["../../src/wall/paint.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,eAAe,EAOpB,KAAK,QAAQ,EAGd,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAA2C,KAAK,GAAG,EAAa,MAAM,OAAO,CAAA;AAqDpF;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,IAAI,EAAE,QAAQ,CAAA;IACd,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE,CAAA;IAC/C,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;IACrD,aAAa,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;IAC5D,GAAG,CAAC,EAAE,GAAG,CAAA;CACV,GAAG,MAAM,GAAG,IAAI,CAwEhB;AAsCD;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,eA8DtB,CAAA"}
|
package/dist/wall/paint.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getEffectiveWallSurfaceMaterial, getWallBandSlotId, getWallFaceBandConfig, getWallFaceBandForHeight, getWallSurfaceSideFromBandSlot, parseMaterialRef, sceneRegistry, useScene, WALL_SURFACE_SLOT_DEFAULTS, } from '@pascal-app/core';
|
|
1
|
+
import { getCurtainWallConfig, getEffectiveWallSurfaceMaterial, getWallBandSlotId, getWallFaceBandConfig, getWallFaceBandForHeight, getWallSurfaceSideFromBandSlot, parseMaterialRef, sceneRegistry, useScene, WALL_SURFACE_SLOT_DEFAULTS, } from '@pascal-app/core';
|
|
2
2
|
import { setSurfaceRaycastLayers } from '@pascal-app/viewer';
|
|
3
3
|
import { Raycaster } from 'three';
|
|
4
4
|
import { buildSlotPreviewMaterial, createSlotPaintCapability, previewSlotByUserData, } from '../shared/slot-paint';
|
|
@@ -57,6 +57,14 @@ function resolveWallSlotByRay(node, ray) {
|
|
|
57
57
|
*/
|
|
58
58
|
export function resolveWallRole(args) {
|
|
59
59
|
const { node, hitObject, materialIndex, normal, localPosition, ray } = args;
|
|
60
|
+
if (node.wallType === 'curtain') {
|
|
61
|
+
const root = sceneRegistry.nodes.get(node.id);
|
|
62
|
+
if (!(root && ray))
|
|
63
|
+
return null;
|
|
64
|
+
wallSlotRaycaster.ray.copy(ray);
|
|
65
|
+
const hit = wallSlotRaycaster.intersectObject(root, false)[0];
|
|
66
|
+
return (['curtain-frame', 'curtain-glass', 'curtain-solid'][hit?.face?.materialIndex ?? -1] ?? null);
|
|
67
|
+
}
|
|
60
68
|
const directSlotId = hitObject?.userData?.slotId;
|
|
61
69
|
if (typeof directSlotId === 'string' && WALL_SLOT_IDS.has(directSlotId)) {
|
|
62
70
|
return directSlotId;
|
|
@@ -113,11 +121,12 @@ export function resolveWallRole(args) {
|
|
|
113
121
|
*/
|
|
114
122
|
function applyWallPreview(args) {
|
|
115
123
|
const { role, material, materialPreset } = args;
|
|
116
|
-
|
|
124
|
+
const curtainIndex = ['curtain-frame', 'curtain-glass', 'curtain-solid'].indexOf(role);
|
|
125
|
+
if (curtainIndex < 0 && !(role in WALL_ARRAY_SLOT_INDEX)) {
|
|
117
126
|
return previewSlotByUserData(args);
|
|
118
127
|
}
|
|
119
|
-
const index = WALL_ARRAY_SLOT_INDEX[role];
|
|
120
|
-
if (
|
|
128
|
+
const index = curtainIndex >= 0 ? curtainIndex : WALL_ARRAY_SLOT_INDEX[role];
|
|
129
|
+
if (index === undefined)
|
|
121
130
|
return previewSlotByUserData(args);
|
|
122
131
|
const mesh = sceneRegistry.nodes.get(args.node.id);
|
|
123
132
|
if (!(mesh && mesh.isMesh))
|
|
@@ -155,6 +164,32 @@ export const wallPaint = createSlotPaintCapability({
|
|
|
155
164
|
}),
|
|
156
165
|
applyPreview: applyWallPreview,
|
|
157
166
|
legacyEffective: (node, role) => {
|
|
167
|
+
if (node.type === 'wall' && node.wallType === 'curtain') {
|
|
168
|
+
const config = getCurtainWallConfig(node);
|
|
169
|
+
const color = role === 'curtain-frame'
|
|
170
|
+
? config.frameColor
|
|
171
|
+
: role === 'curtain-glass'
|
|
172
|
+
? config.glassColor
|
|
173
|
+
: role === 'curtain-solid'
|
|
174
|
+
? config.solidColor
|
|
175
|
+
: undefined;
|
|
176
|
+
if (!color)
|
|
177
|
+
return null;
|
|
178
|
+
return {
|
|
179
|
+
materialPreset: undefined,
|
|
180
|
+
material: {
|
|
181
|
+
preset: 'custom',
|
|
182
|
+
properties: {
|
|
183
|
+
color,
|
|
184
|
+
roughness: role === 'curtain-glass' ? config.glassRoughness : 0.4,
|
|
185
|
+
metalness: role === 'curtain-frame' ? 0.65 : 0,
|
|
186
|
+
opacity: role === 'curtain-glass' ? config.glassOpacity : 1,
|
|
187
|
+
transparent: role === 'curtain-glass',
|
|
188
|
+
side: 'front',
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
158
193
|
const side = getWallSurfaceSideFromBandSlot(role);
|
|
159
194
|
if (!side && role in WALL_SURFACE_SLOT_DEFAULTS) {
|
|
160
195
|
return {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type AnyNode, type AnyNodeId, type WallNode } from '@pascal-app/core';
|
|
2
|
+
import { type PanelRow } from '@pascal-app/editor';
|
|
3
|
+
export declare function wallSettings(node: WallNode, nodes: Record<AnyNodeId, AnyNode>, update: (patch: Partial<WallNode>) => void, reshape?: () => void): PanelRow[];
|
|
4
|
+
//# sourceMappingURL=panel-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel-model.d.ts","sourceRoot":"","sources":["../../src/wall/panel-model.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EAad,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAEL,KAAK,QAAQ,EAGd,MAAM,oBAAoB,CAAA;AAiB3B,wBAAgB,YAAY,CAC1B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,EAC1C,OAAO,GAAE,MAAM,IAId,GACA,QAAQ,EAAE,CAmNZ"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { buildWallFaceBandCountPatch, GROUND_SUPPORT_ID, getClampedWallCurveOffset, getMaxWallCurveOffset, getWallCurveLength, getWallFaceBandConfig, normalizeWallCurveOffset, terrainSupportLift, WALL_CHAIR_RAIL_DEFAULT, WALL_CROWN_DEFAULT, WALL_FACE_BAND_DEFAULT, WALL_SKIRTING_DEFAULT, } from '@pascal-app/core';
|
|
2
|
+
import { curveReshapeScope, triggerSFX, useInteractionScope, } from '@pascal-app/editor';
|
|
3
|
+
import { useViewer } from '@pascal-app/viewer';
|
|
4
|
+
import { resolveWallOpeningCeiling } from '../shared/wall-opening-ceiling';
|
|
5
|
+
import { hasWallCurveBlockingChildren } from './curve-eligibility';
|
|
6
|
+
import { buildWallLengthPatch } from './length-patch';
|
|
7
|
+
const profiles = {
|
|
8
|
+
skirting: ['flat', 'base-modern', 'base-colonial', 'base-shoe', 'base-ogee'],
|
|
9
|
+
crown: ['flat', 'crown-cove', 'crown-ogee', 'crown-craftsman', 'crown-layered'],
|
|
10
|
+
chairRail: ['flat', 'rail-rounded', 'rail-ogee', 'rail-picture', 'rail-stepped'],
|
|
11
|
+
};
|
|
12
|
+
const pretty = (value) => value
|
|
13
|
+
.replace(/^(base|crown|rail)-/, '')
|
|
14
|
+
.replace(/(^|[- ])\w/g, (s) => s.replace('-', ' ').toUpperCase());
|
|
15
|
+
export function wallSettings(node, nodes, update, reshape = () => {
|
|
16
|
+
triggerSFX('sfx:item-pick');
|
|
17
|
+
useInteractionScope.getState().begin(curveReshapeScope(node.id));
|
|
18
|
+
useViewer.getState().setSelection({ selectedIds: [] });
|
|
19
|
+
}) {
|
|
20
|
+
const rows = [];
|
|
21
|
+
const height = resolveWallOpeningCeiling(node, nodes);
|
|
22
|
+
const repairBase = () => ({
|
|
23
|
+
supportOffset: undefined,
|
|
24
|
+
...(node.supportSlabId === GROUND_SUPPORT_ID &&
|
|
25
|
+
!(node.parentId && terrainSupportLift(nodes, node.parentId, ...node.start) != null)
|
|
26
|
+
? { supportSlabId: undefined }
|
|
27
|
+
: {}),
|
|
28
|
+
});
|
|
29
|
+
const number = (section, id, label, value, min, max, step, onChange, unit = 'm') => rows.push({
|
|
30
|
+
section,
|
|
31
|
+
id,
|
|
32
|
+
kind: 'stepper',
|
|
33
|
+
label,
|
|
34
|
+
value,
|
|
35
|
+
min,
|
|
36
|
+
max,
|
|
37
|
+
step,
|
|
38
|
+
unit,
|
|
39
|
+
onChange: (next) => onChange(Math.max(min, Math.min(max, next))),
|
|
40
|
+
});
|
|
41
|
+
const choice = (section, id, label, value, onSelect) => rows.push({ section, id, kind: 'choice', label, value, onSelect });
|
|
42
|
+
const cycle = (section, id, label, value, values, onChange) => {
|
|
43
|
+
const change = (direction) => onChange(values[(Math.max(0, values.indexOf(value)) + direction + values.length) % values.length]);
|
|
44
|
+
rows.push({
|
|
45
|
+
section,
|
|
46
|
+
id,
|
|
47
|
+
kind: 'cycle',
|
|
48
|
+
label,
|
|
49
|
+
value: pretty(value),
|
|
50
|
+
next: () => change(1),
|
|
51
|
+
previous: () => change(-1),
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
const length = getWallCurveLength(node);
|
|
55
|
+
number('Dimensions', 'wall-length', 'Length', length, 0.1, 1000, 0.05, (next) => {
|
|
56
|
+
update(buildWallLengthPatch(node, next));
|
|
57
|
+
});
|
|
58
|
+
choice('Dimensions', 'wall-top', 'Top', node.height == null ? 'Follows level' : 'Custom height', () => update(node.height == null
|
|
59
|
+
? { height: Math.max(0.1, height) }
|
|
60
|
+
: { height: undefined, ...repairBase() }));
|
|
61
|
+
if (node.height == null)
|
|
62
|
+
choice('Dimensions', 'wall-height-auto', 'Current height', `${Number(height.toFixed(3))} m`);
|
|
63
|
+
else
|
|
64
|
+
number('Dimensions', 'height', 'Height', node.height, 0.1, 1000, 0.05, (height) => update({ height }));
|
|
65
|
+
choice('Dimensions', 'wall-bottom', 'Bottom', node.fillToTerrain ? 'Fill to terrain' : 'Auto', () => update(node.fillToTerrain
|
|
66
|
+
? { fillToTerrain: undefined, ...repairBase() }
|
|
67
|
+
: { fillToTerrain: true }));
|
|
68
|
+
number('Dimensions', 'thickness', 'Thickness', node.thickness ?? 0.1, 0.05, 1000, 0.01, (thickness) => update({ thickness }));
|
|
69
|
+
const blockedCurve = hasWallCurveBlockingChildren((node.children ?? []).flatMap((id) => nodes[id] ? [nodes[id]] : []));
|
|
70
|
+
if (!blockedCurve) {
|
|
71
|
+
const limit = Math.max(0.01, getMaxWallCurveOffset(node));
|
|
72
|
+
number('Dimensions', 'curveOffset', 'Curve', getClampedWallCurveOffset(node), -limit, limit, 0.05, (next) => update({ curveOffset: normalizeWallCurveOffset(node, next) }));
|
|
73
|
+
if (reshape)
|
|
74
|
+
rows.push({
|
|
75
|
+
section: 'Dimensions',
|
|
76
|
+
id: 'wall-reshape',
|
|
77
|
+
kind: 'action',
|
|
78
|
+
label: 'Reshape curve in scene',
|
|
79
|
+
onSelect: reshape,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const bands = getWallFaceBandConfig(node, height);
|
|
83
|
+
number('Wall bands', 'wall-band-count', 'Bands', bands.count, 1, 4, 1, (count) => update(buildWallFaceBandCountPatch(node, Math.round(count))), '');
|
|
84
|
+
const band = (key, label, max) => number('Wall bands', `wall-band-${key}`, label, bands[key], 0, Math.max(0, max), 0.01, (value) => update({
|
|
85
|
+
faceBands: {
|
|
86
|
+
...WALL_FACE_BAND_DEFAULT,
|
|
87
|
+
...node.faceBands,
|
|
88
|
+
enabled: bands.count > 1,
|
|
89
|
+
count: bands.count,
|
|
90
|
+
[key]: value,
|
|
91
|
+
},
|
|
92
|
+
}));
|
|
93
|
+
if (bands.count >= 2)
|
|
94
|
+
band('lowerHeight', 'Lower', height);
|
|
95
|
+
if (bands.count >= 3)
|
|
96
|
+
band('middleHeight', 'Middle', height - bands.lowerHeight);
|
|
97
|
+
if (bands.count >= 4)
|
|
98
|
+
band('upperHeight', 'Upper', height - bands.lowerHeight - bands.middleHeight);
|
|
99
|
+
for (const [key, title, defaults] of [
|
|
100
|
+
['skirting', 'Skirting', WALL_SKIRTING_DEFAULT],
|
|
101
|
+
['crown', 'Crown molding', WALL_CROWN_DEFAULT],
|
|
102
|
+
['chairRail', 'Chair rail', WALL_CHAIR_RAIL_DEFAULT],
|
|
103
|
+
]) {
|
|
104
|
+
const trim = { ...defaults, ...node[key] };
|
|
105
|
+
const patch = (value) => update({ [key]: { ...trim, ...value } });
|
|
106
|
+
choice(title, `${key}-enabled`, title, trim.enabled ? 'On' : 'Off', () => patch({ enabled: !trim.enabled }));
|
|
107
|
+
if (!trim.enabled)
|
|
108
|
+
continue;
|
|
109
|
+
cycle(title, `${key}-sides`, 'Sides', trim.sides, ['interior', 'exterior', 'both'], (sides) => patch({ sides: sides }));
|
|
110
|
+
cycle(title, `${key}-profile`, 'Profile', trim.profile, profiles[key], (profile) => patch({ profile: profile }));
|
|
111
|
+
number(title, `${key}-height`, 'Height', trim.height, 0.01, Math.max(0.05, height), 0.01, (height) => patch({ height }));
|
|
112
|
+
number(title, `${key}-proud`, 'Projection', trim.proud, 0.001, 0.2, 0.005, (proud) => patch({ proud }));
|
|
113
|
+
if (key === 'chairRail')
|
|
114
|
+
number(title, `${key}-offset`, 'Offset', trim.offsetY ?? 0, 0, Math.max(0.05, height - trim.height), 0.01, (offsetY) => patch({ offsetY }));
|
|
115
|
+
}
|
|
116
|
+
return rows;
|
|
117
|
+
}
|
package/dist/wall/panel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/wall/panel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/wall/panel.tsx"],"names":[],"mappings":"AA6FA,MAAM,CAAC,OAAO,UAAU,SAAS,uCAiWhC"}
|
package/dist/wall/panel.js
CHANGED
|
@@ -4,9 +4,12 @@ import { buildWallFaceBandCountPatch, GROUND_SUPPORT_ID, getClampedWallCurveOffs
|
|
|
4
4
|
import { ActionButton, ActionGroup, curveReshapeScope, formatLinearMeasurement, getLinearUnitLabel, linearControlValueToMeters, metersToLinearUnit, PanelSection, PanelWrapper, SegmentedControl, SliderControl, triggerSFX, useInteractionScope, } from '@pascal-app/editor';
|
|
5
5
|
import { useViewer } from '@pascal-app/viewer';
|
|
6
6
|
import { Spline } from 'lucide-react';
|
|
7
|
-
import { useCallback, useMemo, useRef } from 'react';
|
|
7
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
8
8
|
import { resolveWallOpeningCeiling } from '../shared/wall-opening-ceiling';
|
|
9
|
+
import { CurtainWallPanel } from './curtain-wall-panel';
|
|
9
10
|
import { hasWallCurveBlockingChildren } from './curve-eligibility';
|
|
11
|
+
import { buildWallLengthPatch } from './length-patch';
|
|
12
|
+
import { createWallPropertyPreview } from './property-preview';
|
|
10
13
|
/**
|
|
11
14
|
* Base half of the plane-bound repair: a stamped draft offset goes, and a
|
|
12
15
|
* ground host is dropped unless sculpted terrain actually supports it — a
|
|
@@ -90,28 +93,18 @@ export default function WallPanel() {
|
|
|
90
93
|
// "Maximum update depth exceeded" cascade. Same fix in fence-panel.tsx.
|
|
91
94
|
const nodeRef = useRef(node);
|
|
92
95
|
nodeRef.current = node;
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
const propertyPreview = useMemo(() => (selectedId ? createWallPropertyPreview(selectedId) : undefined), [selectedId]);
|
|
97
|
+
useEffect(() => () => propertyPreview?.cancel(), [propertyPreview]);
|
|
98
|
+
const handleUpdate = useCallback((updates) => propertyPreview?.commit(updates), [propertyPreview]);
|
|
99
|
+
const handlePreview = useCallback((updates) => propertyPreview?.preview(updates), [propertyPreview]);
|
|
100
|
+
const handleCommit = useCallback(() => propertyPreview?.commit(), [propertyPreview]);
|
|
101
|
+
const handleCancel = useCallback(() => propertyPreview?.cancel(), [propertyPreview]);
|
|
98
102
|
const handleUpdateLength = useCallback((newLength) => {
|
|
99
103
|
const n = nodeRef.current;
|
|
100
104
|
if (!n || newLength <= 0)
|
|
101
105
|
return;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const currentLength = Math.sqrt(dx * dx + dz * dz);
|
|
105
|
-
if (currentLength === 0)
|
|
106
|
-
return;
|
|
107
|
-
const dirX = dx / currentLength;
|
|
108
|
-
const dirZ = dz / currentLength;
|
|
109
|
-
const newEnd = [
|
|
110
|
-
n.start[0] + dirX * newLength,
|
|
111
|
-
n.start[1] + dirZ * newLength,
|
|
112
|
-
];
|
|
113
|
-
handleUpdate({ end: newEnd });
|
|
114
|
-
}, [handleUpdate]);
|
|
106
|
+
handlePreview(buildWallLengthPatch(n, newLength));
|
|
107
|
+
}, [handlePreview]);
|
|
115
108
|
const handleTopModeChange = useCallback((mode) => {
|
|
116
109
|
const n = nodeRef.current;
|
|
117
110
|
if (!n)
|
|
@@ -174,25 +167,28 @@ export default function WallPanel() {
|
|
|
174
167
|
const skirting = { ...WALL_SKIRTING_DEFAULT, ...(node.skirting ?? {}) };
|
|
175
168
|
const crown = { ...WALL_CROWN_DEFAULT, ...(node.crown ?? {}) };
|
|
176
169
|
const chairRail = { ...WALL_CHAIR_RAIL_DEFAULT, ...(node.chairRail ?? {}) };
|
|
177
|
-
return (_jsxs(PanelWrapper, { icon: "/icons/wall.webp", onClose: handleClose, title: node.name || 'Wall', width: 280, children: [
|
|
170
|
+
return (_jsxs(PanelWrapper, { icon: "/icons/wall.webp", onClose: handleClose, title: node.name || 'Wall', width: 280, children: [_jsx(PanelSection, { title: "Wall type", children: _jsx(SegmentedControl, { onChange: (wallType) => handleUpdate({ wallType }), options: [
|
|
171
|
+
{ label: 'Standard', value: 'standard' },
|
|
172
|
+
{ label: 'Curtain wall', value: 'curtain' },
|
|
173
|
+
], value: node.wallType ?? 'standard' }) }), _jsxs(PanelSection, { title: "Dimensions", children: [_jsx(SliderControl, { onCommit: handleCommit, onCancel: handleCancel, restoreOnCommit: false, previewWhileTyping: true, label: "Length", max: metersToLinearUnit(1000, unit), min: metersToLinearUnit(0.1, unit), onChange: (value) => handleUpdateLength(linearControlValueToMeters(value, unit, { maxMeters: 1000, minMeters: 0.1 })), precision: 2, step: unit === 'imperial' ? 0.1 : 0.01, unit: unitLabel, value: displayLength }), _jsx("div", { className: "px-1 font-medium text-[10px] text-muted-foreground/80 uppercase tracking-wider", children: "Top" }), _jsx(SegmentedControl, { onChange: handleTopModeChange, options: [
|
|
178
174
|
{ label: 'Follows level', value: 'storey' },
|
|
179
175
|
{ label: 'Custom height', value: 'custom' },
|
|
180
|
-
], value: isPlaneBound ? 'storey' : 'custom' }), isPlaneBound ? (_jsxs("div", { className: "px-1 text-[11px] text-muted-foreground", children: ["Currently ", formatLinearMeasurement(height, unit)] })) : (_jsx(SliderControl, { label: "Height", max: metersToLinearUnit(1000, unit), min: metersToLinearUnit(0.1, unit), onChange: (v) =>
|
|
176
|
+
], value: isPlaneBound ? 'storey' : 'custom' }), isPlaneBound ? (_jsxs("div", { className: "px-1 text-[11px] text-muted-foreground", children: ["Currently ", formatLinearMeasurement(height, unit)] })) : (_jsx(SliderControl, { onCommit: handleCommit, onCancel: handleCancel, restoreOnCommit: false, previewWhileTyping: true, label: "Height", max: metersToLinearUnit(1000, unit), min: metersToLinearUnit(0.1, unit), onChange: (v) => handlePreview({
|
|
181
177
|
height: linearControlValueToMeters(v, unit, { maxMeters: 1000, minMeters: 0.1 }),
|
|
182
178
|
}), precision: 2, step: 0.1, unit: unitLabel, value: Math.round(displayHeight * 100) / 100 })), _jsx("div", { className: "px-1 font-medium text-[10px] text-muted-foreground/80 uppercase tracking-wider", children: "Bottom" }), _jsx(SegmentedControl, { onChange: handleInfillChange, options: [
|
|
183
179
|
{ label: 'Auto', value: 'auto' },
|
|
184
180
|
{ label: 'Fill to terrain', value: 'terrain' },
|
|
185
|
-
], value: followsTerrain ? 'terrain' : 'auto' }), followsTerrain && (_jsx("div", { className: "px-1 text-[11px] text-muted-foreground", children: "Extends downward to meet the terrain. Height and top stay unchanged." })), _jsx(SliderControl, { label:
|
|
181
|
+
], value: followsTerrain ? 'terrain' : 'auto' }), followsTerrain && (_jsx("div", { className: "px-1 text-[11px] text-muted-foreground", children: "Extends downward to meet the terrain. Height and top stay unchanged." })), _jsx(SliderControl, { onCommit: handleCommit, onCancel: handleCancel, restoreOnCommit: false, previewWhileTyping: true, label: node.wallType === 'curtain' ? 'Frame depth' : 'Thickness', max: metersToLinearUnit(1000, unit), min: metersToLinearUnit(0.05, unit), onChange: (v) => handlePreview({
|
|
186
182
|
thickness: linearControlValueToMeters(v, unit, {
|
|
187
183
|
maxMeters: 1000,
|
|
188
184
|
minMeters: 0.05,
|
|
189
185
|
}),
|
|
190
|
-
}), precision: 3, step: 0.01, unit: unitLabel, value: Math.round(displayThickness * 1000) / 1000 }), !hasWallChildrenBlockingCurve && (_jsx(SliderControl, { label: "Curve", max: Math.max(metersToLinearUnit(0.01, unit), displayMaxCurveOffset), min: -Math.max(metersToLinearUnit(0.01, unit), displayMaxCurveOffset), onChange: (v) =>
|
|
186
|
+
}), precision: 3, step: 0.01, unit: unitLabel, value: Math.round(displayThickness * 1000) / 1000 }), !hasWallChildrenBlockingCurve && (_jsx(SliderControl, { onCommit: handleCommit, onCancel: handleCancel, restoreOnCommit: false, previewWhileTyping: true, label: "Curve", max: Math.max(metersToLinearUnit(0.01, unit), displayMaxCurveOffset), min: -Math.max(metersToLinearUnit(0.01, unit), displayMaxCurveOffset), onChange: (v) => handlePreview({
|
|
191
187
|
curveOffset: normalizeWallCurveOffset(node, linearControlValueToMeters(v, unit, {
|
|
192
188
|
maxMeters: curveOffsetLimit,
|
|
193
189
|
minMeters: -curveOffsetLimit,
|
|
194
190
|
})),
|
|
195
|
-
}), precision: 2, step: 0.1, unit: unitLabel, value: Math.round(displayCurveOffset * 100) / 100 }))] }), _jsx(WallFaceBandSection, { node: node, onUpdate: handleUpdate, unit: unit, unitLabel: unitLabel, wallHeightMeters: wallHeightMeters }), _jsx(WallTrimSection, { node: node, onUpdate: handleUpdate, title: "Skirting", trimKey: "skirting", trimValue: skirting, unit: unit, unitLabel: unitLabel, wallHeightMeters: wallHeightMeters }), _jsx(WallTrimSection, { node: node, onUpdate: handleUpdate, title: "Crown molding", trimKey: "crown", trimValue: crown, unit: unit, unitLabel: unitLabel, wallHeightMeters: wallHeightMeters }), _jsx(WallTrimSection, { node: node, onUpdate: handleUpdate, title: "Chair rail", trimKey: "chairRail", trimValue: chairRail, unit: unit, unitLabel: unitLabel, wallHeightMeters: wallHeightMeters }), !hasWallChildrenBlockingCurve && (_jsx(PanelSection, { title: "Actions", children: _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Spline, { className: "h-3.5 w-3.5" }), label: "Curve", onClick: handleCurve }) }) }))] }));
|
|
191
|
+
}), precision: 2, step: 0.1, unit: unitLabel, value: Math.round(displayCurveOffset * 100) / 100 }))] }), node.wallType === 'curtain' ? (_jsx(CurtainWallPanel, { height: height, node: node, onUpdate: handleUpdate, onPreview: handlePreview, onCommit: handleCommit, onCancel: handleCancel, unit: unit }, node.id)) : (_jsxs(_Fragment, { children: [_jsx(WallFaceBandSection, { node: node, onUpdate: handleUpdate, unit: unit, unitLabel: unitLabel, wallHeightMeters: wallHeightMeters }), _jsx(WallTrimSection, { node: node, onUpdate: handleUpdate, title: "Skirting", trimKey: "skirting", trimValue: skirting, unit: unit, unitLabel: unitLabel, wallHeightMeters: wallHeightMeters }), _jsx(WallTrimSection, { node: node, onUpdate: handleUpdate, title: "Crown molding", trimKey: "crown", trimValue: crown, unit: unit, unitLabel: unitLabel, wallHeightMeters: wallHeightMeters }), _jsx(WallTrimSection, { node: node, onUpdate: handleUpdate, title: "Chair rail", trimKey: "chairRail", trimValue: chairRail, unit: unit, unitLabel: unitLabel, wallHeightMeters: wallHeightMeters })] })), !hasWallChildrenBlockingCurve && (_jsx(PanelSection, { title: "Actions", children: _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Spline, { className: "h-3.5 w-3.5" }), label: "Curve", onClick: handleCurve }) }) }))] }));
|
|
196
192
|
}
|
|
197
193
|
function WallFaceBandSection({ node, onUpdate, unit, unitLabel, wallHeightMeters, }) {
|
|
198
194
|
const bandConfig = getWallFaceBandConfig(node, wallHeightMeters);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type AnyNodeId, type WallNode } from '@pascal-app/core';
|
|
2
|
+
export declare function createWallPropertyPreview(id: AnyNodeId): {
|
|
3
|
+
preview(patch: Partial<WallNode>): void;
|
|
4
|
+
commit(patch?: Partial<WallNode>): void;
|
|
5
|
+
cancel: () => void;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=property-preview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-preview.d.ts","sourceRoot":"","sources":["../../src/wall/property-preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAkC,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAEhG,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,SAAS;mBASpC,OAAO,CAAC,QAAQ,CAAC;mBAKjB,OAAO,CAAC,QAAQ,CAAC;;EAiBnC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useLiveNodeOverrides, useScene } from '@pascal-app/core';
|
|
2
|
+
export function createWallPropertyPreview(id) {
|
|
3
|
+
let pending;
|
|
4
|
+
const clear = () => {
|
|
5
|
+
if (!pending)
|
|
6
|
+
return;
|
|
7
|
+
useLiveNodeOverrides.getState().clearFields(id, Object.keys(pending));
|
|
8
|
+
pending = undefined;
|
|
9
|
+
useScene.getState().markDirty(id);
|
|
10
|
+
};
|
|
11
|
+
return {
|
|
12
|
+
preview(patch) {
|
|
13
|
+
pending = { ...pending, ...patch };
|
|
14
|
+
useLiveNodeOverrides.getState().set(id, patch);
|
|
15
|
+
useScene.getState().markDirty(id);
|
|
16
|
+
},
|
|
17
|
+
commit(patch) {
|
|
18
|
+
const live = useLiveNodeOverrides.getState().get(id);
|
|
19
|
+
const current = pending && live
|
|
20
|
+
? Object.fromEntries(Object.keys(pending)
|
|
21
|
+
.filter((key) => key in live)
|
|
22
|
+
.map((key) => [key, live[key]]))
|
|
23
|
+
: undefined;
|
|
24
|
+
const updates = { ...current, ...patch };
|
|
25
|
+
if (Object.keys(updates).length && useScene.getState().nodes[id]?.type === 'wall')
|
|
26
|
+
useScene.getState().updateNode(id, updates);
|
|
27
|
+
clear();
|
|
28
|
+
},
|
|
29
|
+
cancel: clear,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { type AnyNodeId, type WallConstructionOptions, type WallNode, type WallPlanPoint } from '@pascal-app/core';
|
|
2
|
+
export declare function createWallRectangle(levelId: AnyNodeId, start: WallPlanPoint, end: WallPlanPoint, defaults?: Partial<WallNode>, options?: WallConstructionOptions): {
|
|
3
|
+
object: "node";
|
|
4
|
+
parentId: string | null;
|
|
5
|
+
visible: boolean;
|
|
6
|
+
metadata: Record<string, unknown>;
|
|
7
|
+
id: `wall_${string}`;
|
|
8
|
+
type: "wall";
|
|
9
|
+
children: (`item_${string}` | `procedural-item_${string}` | `leanto_${string}` | `door_${string}` | `window_${string}`)[];
|
|
10
|
+
start: [number, number];
|
|
11
|
+
end: [number, number];
|
|
12
|
+
frontSide: "unknown" | "interior" | "exterior";
|
|
13
|
+
backSide: "unknown" | "interior" | "exterior";
|
|
14
|
+
name?: string | undefined;
|
|
15
|
+
camera?: {
|
|
16
|
+
position: [number, number, number];
|
|
17
|
+
target: [number, number, number];
|
|
18
|
+
mode: "perspective" | "orthographic";
|
|
19
|
+
fov?: number | undefined;
|
|
20
|
+
zoom?: number | undefined;
|
|
21
|
+
} | undefined;
|
|
22
|
+
wallType?: "standard" | "curtain" | undefined;
|
|
23
|
+
curtainWall?: {
|
|
24
|
+
construction: "stick" | "unitized";
|
|
25
|
+
framing: "capped" | "vertical-caps" | "horizontal-caps" | "structural-glazing";
|
|
26
|
+
columns: {
|
|
27
|
+
layout: "count" | "maximum-spacing" | "fixed-spacing";
|
|
28
|
+
count: number;
|
|
29
|
+
spacing: number;
|
|
30
|
+
alignment: "center" | "start" | "end";
|
|
31
|
+
};
|
|
32
|
+
rows: {
|
|
33
|
+
layout: "count" | "maximum-spacing" | "fixed-spacing";
|
|
34
|
+
count: number;
|
|
35
|
+
spacing: number;
|
|
36
|
+
alignment: "center" | "start" | "end";
|
|
37
|
+
};
|
|
38
|
+
mullionWidth: number;
|
|
39
|
+
transomWidth: number;
|
|
40
|
+
perimeterWidth: number;
|
|
41
|
+
jointWidth: number;
|
|
42
|
+
glassThickness: number;
|
|
43
|
+
panelType: "glass" | "solid" | "empty";
|
|
44
|
+
spandrel: "top" | "none" | "bottom";
|
|
45
|
+
frameColor: string;
|
|
46
|
+
glassColor: string;
|
|
47
|
+
solidColor: string;
|
|
48
|
+
glassOpacity: number;
|
|
49
|
+
glassRoughness: number;
|
|
50
|
+
panels: {
|
|
51
|
+
column: number;
|
|
52
|
+
row: number;
|
|
53
|
+
type: "glass" | "solid" | "empty";
|
|
54
|
+
}[];
|
|
55
|
+
} | undefined;
|
|
56
|
+
material?: {
|
|
57
|
+
id?: string | undefined;
|
|
58
|
+
preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
|
|
59
|
+
properties?: {
|
|
60
|
+
color: string;
|
|
61
|
+
roughness: number;
|
|
62
|
+
metalness: number;
|
|
63
|
+
opacity: number;
|
|
64
|
+
transparent: boolean;
|
|
65
|
+
side: "front" | "back" | "double";
|
|
66
|
+
} | undefined;
|
|
67
|
+
texture?: {
|
|
68
|
+
url: string;
|
|
69
|
+
repeat?: [number, number] | undefined;
|
|
70
|
+
scale?: number | undefined;
|
|
71
|
+
} | undefined;
|
|
72
|
+
} | undefined;
|
|
73
|
+
materialPreset?: string | undefined;
|
|
74
|
+
interiorMaterial?: {
|
|
75
|
+
id?: string | undefined;
|
|
76
|
+
preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
|
|
77
|
+
properties?: {
|
|
78
|
+
color: string;
|
|
79
|
+
roughness: number;
|
|
80
|
+
metalness: number;
|
|
81
|
+
opacity: number;
|
|
82
|
+
transparent: boolean;
|
|
83
|
+
side: "front" | "back" | "double";
|
|
84
|
+
} | undefined;
|
|
85
|
+
texture?: {
|
|
86
|
+
url: string;
|
|
87
|
+
repeat?: [number, number] | undefined;
|
|
88
|
+
scale?: number | undefined;
|
|
89
|
+
} | undefined;
|
|
90
|
+
} | undefined;
|
|
91
|
+
interiorMaterialPreset?: string | undefined;
|
|
92
|
+
exteriorMaterial?: {
|
|
93
|
+
id?: string | undefined;
|
|
94
|
+
preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
|
|
95
|
+
properties?: {
|
|
96
|
+
color: string;
|
|
97
|
+
roughness: number;
|
|
98
|
+
metalness: number;
|
|
99
|
+
opacity: number;
|
|
100
|
+
transparent: boolean;
|
|
101
|
+
side: "front" | "back" | "double";
|
|
102
|
+
} | undefined;
|
|
103
|
+
texture?: {
|
|
104
|
+
url: string;
|
|
105
|
+
repeat?: [number, number] | undefined;
|
|
106
|
+
scale?: number | undefined;
|
|
107
|
+
} | undefined;
|
|
108
|
+
} | undefined;
|
|
109
|
+
exteriorMaterialPreset?: string | undefined;
|
|
110
|
+
slots?: Record<string, string> | undefined;
|
|
111
|
+
thickness?: number | undefined;
|
|
112
|
+
height?: number | undefined;
|
|
113
|
+
curveOffset?: number | undefined;
|
|
114
|
+
supportSlabId?: string | undefined;
|
|
115
|
+
supportOffset?: number | undefined;
|
|
116
|
+
fillToTerrain?: boolean | undefined;
|
|
117
|
+
faceBands?: {
|
|
118
|
+
enabled: boolean;
|
|
119
|
+
count: number;
|
|
120
|
+
lowerHeight: number;
|
|
121
|
+
middleHeight: number;
|
|
122
|
+
upperHeight: number;
|
|
123
|
+
} | undefined;
|
|
124
|
+
skirting?: {
|
|
125
|
+
enabled: boolean;
|
|
126
|
+
sides: "interior" | "exterior" | "both";
|
|
127
|
+
height: number;
|
|
128
|
+
proud: number;
|
|
129
|
+
profile: "flat" | "bevel" | "triangle" | "cove" | "bullnose" | "base-modern" | "base-colonial" | "base-shoe" | "base-ogee" | "crown-cove" | "crown-ogee" | "crown-craftsman" | "crown-layered" | "rail-rounded" | "rail-ogee" | "rail-picture" | "rail-stepped";
|
|
130
|
+
offsetY?: number | undefined;
|
|
131
|
+
} | undefined;
|
|
132
|
+
crown?: {
|
|
133
|
+
enabled: boolean;
|
|
134
|
+
sides: "interior" | "exterior" | "both";
|
|
135
|
+
height: number;
|
|
136
|
+
proud: number;
|
|
137
|
+
profile: "flat" | "bevel" | "triangle" | "cove" | "bullnose" | "base-modern" | "base-colonial" | "base-shoe" | "base-ogee" | "crown-cove" | "crown-ogee" | "crown-craftsman" | "crown-layered" | "rail-rounded" | "rail-ogee" | "rail-picture" | "rail-stepped";
|
|
138
|
+
offsetY?: number | undefined;
|
|
139
|
+
} | undefined;
|
|
140
|
+
chairRail?: {
|
|
141
|
+
enabled: boolean;
|
|
142
|
+
sides: "interior" | "exterior" | "both";
|
|
143
|
+
height: number;
|
|
144
|
+
proud: number;
|
|
145
|
+
profile: "flat" | "bevel" | "triangle" | "cove" | "bullnose" | "base-modern" | "base-colonial" | "base-shoe" | "base-ogee" | "crown-cove" | "crown-ogee" | "crown-craftsman" | "crown-layered" | "rail-rounded" | "rail-ogee" | "rail-picture" | "rail-stepped";
|
|
146
|
+
offsetY?: number | undefined;
|
|
147
|
+
} | undefined;
|
|
148
|
+
}[];
|
|
149
|
+
//# sourceMappingURL=rectangle-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rectangle-command.d.ts","sourceRoot":"","sources":["../../src/wall/rectangle-command.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAKd,KAAK,uBAAuB,EAC5B,KAAK,QAAQ,EACb,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAA;AAEzB,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,EAClB,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,aAAa,EAClB,QAAQ,GAAE,OAAO,CAAC,QAAQ,CAAM,EAChC,OAAO,CAAC,EAAE,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmBlC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { planWallRectangle, resolveWallConstruction, runAsSingleSceneHistoryStep, useScene, } from '@pascal-app/core';
|
|
2
|
+
export function createWallRectangle(levelId, start, end, defaults = {}, options) {
|
|
3
|
+
const scene = useScene.getState();
|
|
4
|
+
if (scene.readOnly)
|
|
5
|
+
throw Error('This scene is read-only.');
|
|
6
|
+
const plan = planWallRectangle(scene.nodes, { levelId, start, end, wallDefaults: defaults });
|
|
7
|
+
if (!plan.changes.create.length && !plan.changes.update.length && !plan.changes.delete.length)
|
|
8
|
+
return [];
|
|
9
|
+
const construction = resolveWallConstruction(scene.nodes, levelId, plan.walls, options);
|
|
10
|
+
const walls = new Map(construction.walls.map((w) => [w.id, w]));
|
|
11
|
+
const changes = {
|
|
12
|
+
...plan.changes,
|
|
13
|
+
create: plan.changes.create.map((op) => ({
|
|
14
|
+
...op,
|
|
15
|
+
node: walls.get(op.node.id) ?? op.node,
|
|
16
|
+
})),
|
|
17
|
+
};
|
|
18
|
+
if (construction.sourceSupportUpdate)
|
|
19
|
+
changes.update.push(construction.sourceSupportUpdate);
|
|
20
|
+
runAsSingleSceneHistoryStep(useScene, () => scene.applyNodeChanges(changes));
|
|
21
|
+
return construction.walls;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rectangle-tool.d.ts","sourceRoot":"","sources":["../../src/wall/rectangle-tool.tsx"],"names":[],"mappings":"AAmCA,MAAM,CAAC,OAAO,UAAU,iBAAiB,gCAkMxC"}
|