@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/column/panel.js
CHANGED
|
@@ -5,6 +5,7 @@ import { ActionButton, ActionGroup, cn, PanelSection, PanelWrapper, SliderContro
|
|
|
5
5
|
import { useViewer } from '@pascal-app/viewer';
|
|
6
6
|
import { Move, Trash2 } from 'lucide-react';
|
|
7
7
|
import { useCallback } from 'react';
|
|
8
|
+
import { planColumnEdit } from './hosted-resize';
|
|
8
9
|
const SELECT_CLASS = 'h-10 w-full rounded-lg border border-border/50 bg-[#2C2C2E] px-3 text-sm text-foreground outline-none transition-colors hover:bg-[#3e3e3e] focus:ring-1 focus:ring-border';
|
|
9
10
|
const MANAGED_LEAN_TO_LAYOUT_FIELDS = new Set([
|
|
10
11
|
'position',
|
|
@@ -246,7 +247,7 @@ export default function ColumnPanel() {
|
|
|
246
247
|
const selectedId = useViewer((s) => s.selection.selectedIds[0]);
|
|
247
248
|
const selectedCount = useViewer((s) => s.selection.selectedIds.length);
|
|
248
249
|
const setSelection = useViewer((s) => s.setSelection);
|
|
249
|
-
const
|
|
250
|
+
const updateNodes = useScene((s) => s.updateNodes);
|
|
250
251
|
const deleteNode = useScene((s) => s.deleteNode);
|
|
251
252
|
const setMovingNode = useEditor((s) => s.setMovingNode);
|
|
252
253
|
const node = useScene((s) => selectedId ? s.nodes[selectedId] : undefined);
|
|
@@ -256,8 +257,10 @@ export default function ColumnPanel() {
|
|
|
256
257
|
const nextUpdates = node && isManagedLeanToPost(node) ? filterManagedLeanToLayoutUpdates(updates) : updates;
|
|
257
258
|
if (Object.keys(nextUpdates).length === 0)
|
|
258
259
|
return;
|
|
259
|
-
|
|
260
|
-
|
|
260
|
+
const updatesToApply = planColumnEdit(selectedId, nextUpdates);
|
|
261
|
+
if (updatesToApply)
|
|
262
|
+
updateNodes(updatesToApply.map(([id, data]) => ({ id, data })));
|
|
263
|
+
}, [node, selectedId, updateNodes]);
|
|
261
264
|
const handleClose = useCallback(() => {
|
|
262
265
|
setSelection({ selectedIds: [] });
|
|
263
266
|
}, [setSelection]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/column/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/column/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,UAAU,EAOhB,MAAM,kBAAkB,CAAA;AA6nEzB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,GAAI,UAAU;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,gCA6C3D,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,mBAAmB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,gCAgErE,CAAA;AAED,eAAe,cAAc,CAAA"}
|
package/dist/column/renderer.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useLiveNodeOverrides, useLiveTransforms, useRegistry, useScene, } from '@pascal-app/core';
|
|
4
|
-
import { baseMaterial, createColumnBoxGeometry, createColumnCylinderGeometry, createColumnSphereGeometry, createColumnTorusGeometry, createMaterial, createMaterialFromPresetRef, createSurfaceRoleMaterial, resolveMaterialRef, resolveSlotDefaultMaterial, useNodeEvents, useViewer, } from '@pascal-app/viewer';
|
|
3
|
+
import { collectDescendants, createSceneApi, useLiveNodeOverrides, useLiveTransforms, useRegistry, useScene, } from '@pascal-app/core';
|
|
4
|
+
import { baseMaterial, createColumnBoxGeometry, createColumnCylinderGeometry, createColumnSphereGeometry, createColumnTorusGeometry, createMaterial, createMaterialFromPresetRef, createSurfaceRoleMaterial, NodeRenderer, resolveMaterialRef, resolveSlotDefaultMaterial, useNodeEvents, useViewer, } from '@pascal-app/viewer';
|
|
5
5
|
import { createContext, useContext, useEffect, useMemo, useRef } from 'react';
|
|
6
6
|
import { BufferGeometry, Float32BufferAttribute } from 'three';
|
|
7
|
+
import { columnCapitalBlocks, columnShaftLayout, getSegments, getShaftScaleAt, getShaftSegmentCount, getShaftTwistRadians, } from './shape';
|
|
7
8
|
import { COLUMN_BASE_DEFAULT, COLUMN_CAPITAL_DEFAULT, COLUMN_FRAME_DEFAULT, COLUMN_SHAFT_DEFAULT, } from './slots';
|
|
8
9
|
const DEFAULT_COLUMN_MATERIAL = baseMaterial();
|
|
9
10
|
const DEFAULT_COLUMN_SLOT_MATERIALS = createSingleColumnMaterialMap(DEFAULT_COLUMN_MATERIAL);
|
|
@@ -99,51 +100,6 @@ function createColumnSlotMaterials({ colorPreset, material, materialPreset, node
|
|
|
99
100
|
}),
|
|
100
101
|
};
|
|
101
102
|
}
|
|
102
|
-
function getSegments(node) {
|
|
103
|
-
if (node.crossSection === 'octagonal')
|
|
104
|
-
return 8;
|
|
105
|
-
if (node.crossSection === 'sixteen-sided')
|
|
106
|
-
return 16;
|
|
107
|
-
return 32;
|
|
108
|
-
}
|
|
109
|
-
function getShaftProfile(node) {
|
|
110
|
-
return node.shaftProfile ?? (node.shaftTaper > 0 ? 'tapered' : 'straight');
|
|
111
|
-
}
|
|
112
|
-
function getShaftSegmentCount(node) {
|
|
113
|
-
const shaftProfile = getShaftProfile(node);
|
|
114
|
-
const shaftTaper = node.shaftTaper ?? 0;
|
|
115
|
-
const hasTwist = Math.abs(node.shaftTwistStep ?? 0) > 0.001;
|
|
116
|
-
return Math.max(hasTwist ? 4 : 1, shaftProfile === 'straight' && shaftTaper <= 0 && !hasTwist
|
|
117
|
-
? 1
|
|
118
|
-
: (node.shaftSegmentCount ?? (hasTwist ? 12 : 24)));
|
|
119
|
-
}
|
|
120
|
-
function getShaftTwistRadians(node, index) {
|
|
121
|
-
return ((node.shaftTwistStep ?? 0) * Math.PI * index) / 180;
|
|
122
|
-
}
|
|
123
|
-
function getShaftScaleAt(node, t) {
|
|
124
|
-
const shaftProfile = getShaftProfile(node);
|
|
125
|
-
const shaftTaper = Math.min(node.shaftTaper ?? 0, 0.85);
|
|
126
|
-
const startScale = node.shaftStartScale ?? 0.72;
|
|
127
|
-
const endScale = node.shaftEndScale ?? startScale;
|
|
128
|
-
const shaftBulge = node.shaftBulge ??
|
|
129
|
-
(shaftProfile === 'bulged'
|
|
130
|
-
? 0.16
|
|
131
|
-
: shaftProfile === 'baluster'
|
|
132
|
-
? 0.2
|
|
133
|
-
: shaftProfile === 'hourglass'
|
|
134
|
-
? 0.18
|
|
135
|
-
: 0);
|
|
136
|
-
const taperedScale = 1 - shaftTaper * t;
|
|
137
|
-
const linearScale = (startScale + (endScale - startScale) * t) * taperedScale;
|
|
138
|
-
const bulgeCurve = Math.sin(Math.PI * t);
|
|
139
|
-
const hourglassCurve = Math.abs(t - 0.5) * 2;
|
|
140
|
-
const profileScale = shaftProfile === 'bulged' || shaftProfile === 'baluster'
|
|
141
|
-
? linearScale + shaftBulge * bulgeCurve
|
|
142
|
-
: shaftProfile === 'hourglass'
|
|
143
|
-
? linearScale - shaftBulge * (1 - hourglassCurve)
|
|
144
|
-
: linearScale;
|
|
145
|
-
return Math.max(0.1, profileScale);
|
|
146
|
-
}
|
|
147
103
|
function clamp(value, min, max) {
|
|
148
104
|
return Math.min(max, Math.max(min, value));
|
|
149
105
|
}
|
|
@@ -868,58 +824,15 @@ function LeafCarvings({ node, capitalY, capitalHeight, }) {
|
|
|
868
824
|
})) }));
|
|
869
825
|
}
|
|
870
826
|
function Capital({ node, y, height }) {
|
|
871
|
-
|
|
827
|
+
const blocks = columnCapitalBlocks(node, y, height);
|
|
828
|
+
if (!blocks.length)
|
|
872
829
|
return null;
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
if (capitalStyle === 'south-indian-bracket' || capitalStyle === 'wood-bracket') {
|
|
877
|
-
const tierCount = Math.max(1, node.bracketTierCount ?? 3);
|
|
878
|
-
const tierHeight = height / tierCount;
|
|
879
|
-
const bracketDepth = node.bracketDepth ?? 0.35;
|
|
880
|
-
return (_jsxs("group", { children: [Array.from({ length: tierCount }, (_, index) => {
|
|
881
|
-
const t = index / Math.max(1, tierCount - 1);
|
|
882
|
-
const scale = (node.capitalWidthScale ?? 1.6) + t * 0.32;
|
|
883
|
-
return (_jsx(SquareBlock, { depth: node.depth * scale + bracketDepth * t, height: tierHeight, width: node.width * scale + bracketDepth * t, y: y + index * tierHeight }, index));
|
|
884
|
-
}), Array.from({ length: node.pendantCount ?? 0 }, (_, index) => {
|
|
885
|
-
const count = Math.max(1, node.pendantCount ?? 0);
|
|
886
|
-
const angle = (index / count) * Math.PI * 2;
|
|
830
|
+
return (_jsxs("group", { children: [blocks.map((block, index) => block.kind === 'box' ? (_jsx(SquareBlock, { y: block.y, height: block.height, width: block.width, depth: block.depth }, index)) : block.kind === 'oval' ? (_jsx(OvalBlock, { y: block.y, height: block.height, width: block.width, depth: block.depth }, index)) : block.kind === 'round' ? (_jsx(RoundBlock, { y: block.y, height: block.height, radius: block.radius, segments: getSegments(node) }, index)) : (_jsx(ColumnBlock, { node: node, y: block.y, height: block.height, scale: block.scale }, index))), (node.capitalStyle === 'south-indian-bracket' || node.capitalStyle === 'wood-bracket') &&
|
|
831
|
+
Array.from({ length: node.pendantCount ?? 0 }, (_, index) => {
|
|
832
|
+
const angle = (index / Math.max(1, node.pendantCount ?? 0)) * Math.PI * 2;
|
|
887
833
|
const distance = Math.max(node.width, node.depth) * 0.56;
|
|
888
834
|
return (_jsx(MappedCone, { height: height * 0.28, position: [Math.cos(angle) * distance, y - height * 0.1, Math.sin(angle) * distance], radiusX: 0.035, rotation: [0, 0, 0], segments: 6 }, index));
|
|
889
|
-
})] }));
|
|
890
|
-
}
|
|
891
|
-
if (capitalStyle === 'rounded' || capitalStyle === 'doric') {
|
|
892
|
-
const topWidth = node.width * (node.capitalWidthScale ?? 1.34);
|
|
893
|
-
const topDepth = node.depth * (node.capitalDepthScale ?? node.capitalWidthScale ?? 1.34);
|
|
894
|
-
return (_jsxs("group", { children: [_jsx(OvalBlock, { depth: topDepth * 0.72, height: height * 0.24, segments: 32, width: topWidth * 0.72, y: y }), _jsx(OvalBlock, { depth: topDepth * 0.92, height: height * 0.32, segments: 32, width: topWidth * 0.92, y: y + height * 0.24 }), _jsx(SquareBlock, { depth: topDepth, height: height * 0.44, width: topWidth, y: y + height * 0.56 })] }));
|
|
895
|
-
}
|
|
896
|
-
if (capitalStyle === 'stepped') {
|
|
897
|
-
const widthScale = node.capitalWidthScale ?? 1.46;
|
|
898
|
-
const depthScale = node.capitalDepthScale ?? widthScale;
|
|
899
|
-
const tierCount = Math.max(3, node.capitalTierCount ?? 3);
|
|
900
|
-
const tierHeight = height / tierCount;
|
|
901
|
-
const stepSpread = node.capitalStepSpread ?? 0.42;
|
|
902
|
-
return (_jsx("group", { children: Array.from({ length: tierCount }, (_, index) => {
|
|
903
|
-
const t = index / Math.max(1, tierCount - 1);
|
|
904
|
-
const widthScaleAt = Math.max(0.5, widthScale - (1 - t) * stepSpread);
|
|
905
|
-
const depthScaleAt = Math.max(0.5, depthScale - (1 - t) * stepSpread);
|
|
906
|
-
return (_jsx(SquareBlock, { depth: node.depth * depthScaleAt, height: tierHeight * 1.01, width: node.width * widthScaleAt, y: y + index * tierHeight }, index));
|
|
907
|
-
}) }));
|
|
908
|
-
}
|
|
909
|
-
if (capitalStyle === 'volute' ||
|
|
910
|
-
capitalStyle === 'ionic-volute' ||
|
|
911
|
-
capitalStyle === 'leaf-carved' ||
|
|
912
|
-
capitalStyle === 'corinthian-leaf') {
|
|
913
|
-
const topWidth = node.width * (node.capitalWidthScale ?? 1.46);
|
|
914
|
-
const topDepth = node.depth * (node.capitalDepthScale ?? node.capitalWidthScale ?? 1.46);
|
|
915
|
-
return (_jsxs("group", { children: [_jsx(ColumnBlock, { height: height * 0.24, node: node, scale: 0.9, y: y }), _jsx(ColumnBlock, { height: height * 0.2, node: node, scale: 1.08, y: y + height * 0.24 }), _jsx(SquareBlock, { depth: topDepth, height: height * 0.28, width: topWidth, y: y + height * 0.44 }), _jsx(Volutes, { capitalHeight: height, capitalY: y, node: node }), _jsx(LeafCarvings, { capitalHeight: height, capitalY: y, node: node })] }));
|
|
916
|
-
}
|
|
917
|
-
const widthScale = node.capitalWidthScale ?? (capitalStyle === 'simple-slab' ? 1.28 : 1.18);
|
|
918
|
-
const depthScale = node.capitalDepthScale ?? widthScale;
|
|
919
|
-
if (node.crossSection === 'square' || node.crossSection === 'rectangular') {
|
|
920
|
-
return (_jsx(SquareBlock, { depth: node.depth * depthScale, height: height, width: node.width * widthScale, y: y }));
|
|
921
|
-
}
|
|
922
|
-
return (_jsx(RoundBlock, { height: height, radius: Math.max(node.radius * widthScale, node.width * widthScale * 0.5), segments: getSegments(node), y: y }));
|
|
835
|
+
}), _jsx(Volutes, { capitalHeight: height, capitalY: y, node: node }), _jsx(LeafCarvings, { capitalHeight: height, capitalY: y, node: node })] }));
|
|
923
836
|
}
|
|
924
837
|
/**
|
|
925
838
|
* The column's geometry tree — either a fabricated support frame or the
|
|
@@ -931,12 +844,7 @@ function Capital({ node, y, height }) {
|
|
|
931
844
|
* wrapping this in its own providers.
|
|
932
845
|
*/
|
|
933
846
|
function ColumnBody({ node }) {
|
|
934
|
-
const shaftLayout =
|
|
935
|
-
const baseHeight = node.baseStyle === 'none' ? 0 : Math.min(node.baseHeight, node.height * 0.4);
|
|
936
|
-
const capitalHeight = node.capitalStyle === 'none' ? 0 : Math.min(node.capitalHeight, node.height * 0.4);
|
|
937
|
-
const shaftHeight = Math.max(0.1, node.height - baseHeight - capitalHeight);
|
|
938
|
-
return { baseHeight, capitalHeight, shaftY: baseHeight, shaftHeight };
|
|
939
|
-
}, [node.baseHeight, node.baseStyle, node.capitalHeight, node.capitalStyle, node.height]);
|
|
847
|
+
const shaftLayout = columnShaftLayout(node);
|
|
940
848
|
if (node.supportStyle !== 'vertical') {
|
|
941
849
|
const support = node.supportStyle === 'a-frame' ? (_jsx(AFrameSupport, { node: node })) : node.supportStyle === 'y-frame' ? (_jsx(YFrameSupport, { node: node })) : node.supportStyle === 'v-frame' ? (_jsx(VFrameSupport, { node: node })) : node.supportStyle === 'x-brace' ? (_jsx(XBraceSupport, { node: node })) : node.supportStyle === 'k-brace' ? (_jsx(KBraceSupport, { node: node })) : node.supportStyle === 'single-strut' ? (_jsx(SingleStrutSupport, { node: node })) : node.supportStyle === 'tripod' ? (_jsx(TripodSupport, { node: node })) : node.supportStyle === 'trestle' ? (_jsx(TrestleSupport, { node: node })) : node.supportStyle === 'portal-frame' ? (_jsx(PortalFrameSupport, { node: node })) : (_jsx(BoxFrameSupport, { node: node }));
|
|
942
850
|
return _jsx(ColumnSlot, { slotId: "frame", children: support });
|
|
@@ -1011,6 +919,20 @@ export const ColumnRenderer = ({ node: rawNode }) => {
|
|
|
1011
919
|
colorPreset,
|
|
1012
920
|
}), [shading, textures, colorPreset, node, sceneMaterials]);
|
|
1013
921
|
useRegistry(node.id, node.type, ref);
|
|
1014
|
-
|
|
922
|
+
// This renderer bypasses GeometrySystem, which normally invalidates hosted descendants.
|
|
923
|
+
useEffect(() => {
|
|
924
|
+
const dirtySubtree = () => {
|
|
925
|
+
const scene = createSceneApi(useScene);
|
|
926
|
+
for (const id of collectDescendants(node.id, { scene })) {
|
|
927
|
+
scene.markDirty(id);
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
dirtySubtree();
|
|
931
|
+
return useLiveTransforms.subscribe((state, previous) => {
|
|
932
|
+
if (state.transforms.get(node.id) !== previous.transforms.get(node.id))
|
|
933
|
+
dirtySubtree();
|
|
934
|
+
});
|
|
935
|
+
}, [node]);
|
|
936
|
+
return (_jsx(ColumnMaterialContext.Provider, { value: materials, children: _jsx(ColumnEdgeSoftnessContext.Provider, { value: node.edgeSoftness ?? 0.025, children: _jsxs("group", { position: liveTransform?.position ?? node.position, ref: ref, rotation: [0, liveTransform?.rotation ?? node.rotation, 0], visible: node.visible, ...handlers, children: [_jsx(ColumnBody, { node: node }), node.children.map((id) => (_jsx(NodeRenderer, { nodeId: id }, id)))] }) }) }));
|
|
1015
937
|
};
|
|
1016
938
|
export default ColumnRenderer;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ColumnNode } from '@pascal-app/core';
|
|
2
|
+
export declare function getSegments(node: ColumnNode): 8 | 16 | 32;
|
|
3
|
+
export declare function getShaftSegmentCount(node: ColumnNode): number;
|
|
4
|
+
export declare function getShaftTwistRadians(node: ColumnNode, index: number): number;
|
|
5
|
+
export declare function getShaftScaleAt(node: ColumnNode, t: number): number;
|
|
6
|
+
export declare function columnShaftLayout(node: ColumnNode): {
|
|
7
|
+
baseHeight: number;
|
|
8
|
+
capitalHeight: number;
|
|
9
|
+
shaftY: number;
|
|
10
|
+
shaftHeight: number;
|
|
11
|
+
};
|
|
12
|
+
export type CapitalBlock = {
|
|
13
|
+
kind: 'box' | 'round' | 'oval' | 'column';
|
|
14
|
+
y: number;
|
|
15
|
+
height: number;
|
|
16
|
+
width?: number;
|
|
17
|
+
depth?: number;
|
|
18
|
+
radius?: number;
|
|
19
|
+
scale?: number;
|
|
20
|
+
};
|
|
21
|
+
export declare function columnCapitalBlocks(node: ColumnNode, y: number, height: number): CapitalBlock[];
|
|
22
|
+
//# sourceMappingURL=shape.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shape.d.ts","sourceRoot":"","sources":["../../src/column/shape.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,eAI3C;AAMD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,UAUpD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,UAEnE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,UA0B1D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU;;;;;EAMjD;AACD,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;IACzC,CAAC,EAAE,MAAM,CAAA;IACT,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AACD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAyE/F"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export function getSegments(node) {
|
|
2
|
+
if (node.crossSection === 'octagonal')
|
|
3
|
+
return 8;
|
|
4
|
+
if (node.crossSection === 'sixteen-sided')
|
|
5
|
+
return 16;
|
|
6
|
+
return 32;
|
|
7
|
+
}
|
|
8
|
+
function getShaftProfile(node) {
|
|
9
|
+
return node.shaftProfile ?? (node.shaftTaper > 0 ? 'tapered' : 'straight');
|
|
10
|
+
}
|
|
11
|
+
export function getShaftSegmentCount(node) {
|
|
12
|
+
const shaftProfile = getShaftProfile(node);
|
|
13
|
+
const shaftTaper = node.shaftTaper ?? 0;
|
|
14
|
+
const hasTwist = Math.abs(node.shaftTwistStep ?? 0) > 0.001;
|
|
15
|
+
return Math.max(hasTwist ? 4 : 1, shaftProfile === 'straight' && shaftTaper <= 0 && !hasTwist
|
|
16
|
+
? 1
|
|
17
|
+
: (node.shaftSegmentCount ?? (hasTwist ? 12 : 24)));
|
|
18
|
+
}
|
|
19
|
+
export function getShaftTwistRadians(node, index) {
|
|
20
|
+
return ((node.shaftTwistStep ?? 0) * Math.PI * index) / 180;
|
|
21
|
+
}
|
|
22
|
+
export function getShaftScaleAt(node, t) {
|
|
23
|
+
const shaftProfile = getShaftProfile(node);
|
|
24
|
+
const shaftTaper = Math.min(node.shaftTaper ?? 0, 0.85);
|
|
25
|
+
const startScale = node.shaftStartScale ?? 0.72;
|
|
26
|
+
const endScale = node.shaftEndScale ?? startScale;
|
|
27
|
+
const shaftBulge = node.shaftBulge ??
|
|
28
|
+
(shaftProfile === 'bulged'
|
|
29
|
+
? 0.16
|
|
30
|
+
: shaftProfile === 'baluster'
|
|
31
|
+
? 0.2
|
|
32
|
+
: shaftProfile === 'hourglass'
|
|
33
|
+
? 0.18
|
|
34
|
+
: 0);
|
|
35
|
+
const taperedScale = 1 - shaftTaper * t;
|
|
36
|
+
const linearScale = (startScale + (endScale - startScale) * t) * taperedScale;
|
|
37
|
+
const bulgeCurve = Math.sin(Math.PI * t);
|
|
38
|
+
const hourglassCurve = Math.abs(t - 0.5) * 2;
|
|
39
|
+
const profileScale = shaftProfile === 'bulged' || shaftProfile === 'baluster'
|
|
40
|
+
? linearScale + shaftBulge * bulgeCurve
|
|
41
|
+
: shaftProfile === 'hourglass'
|
|
42
|
+
? linearScale - shaftBulge * (1 - hourglassCurve)
|
|
43
|
+
: linearScale;
|
|
44
|
+
return Math.max(0.1, profileScale);
|
|
45
|
+
}
|
|
46
|
+
export function columnShaftLayout(node) {
|
|
47
|
+
const baseHeight = node.baseStyle === 'none' ? 0 : Math.min(node.baseHeight, node.height * 0.4);
|
|
48
|
+
const capitalHeight = node.capitalStyle === 'none' ? 0 : Math.min(node.capitalHeight, node.height * 0.4);
|
|
49
|
+
const shaftHeight = Math.max(0.1, node.height - baseHeight - capitalHeight);
|
|
50
|
+
return { baseHeight, capitalHeight, shaftY: baseHeight, shaftHeight };
|
|
51
|
+
}
|
|
52
|
+
export function columnCapitalBlocks(node, y, height) {
|
|
53
|
+
const style = node.capitalStyle ?? 'simple';
|
|
54
|
+
if (height <= 0 || style === 'none')
|
|
55
|
+
return [];
|
|
56
|
+
if (style === 'south-indian-bracket' || style === 'wood-bracket') {
|
|
57
|
+
const count = Math.max(1, node.bracketTierCount ?? 3);
|
|
58
|
+
return Array.from({ length: count }, (_, index) => {
|
|
59
|
+
const t = index / Math.max(1, count - 1), scale = (node.capitalWidthScale ?? 1.6) + t * 0.32;
|
|
60
|
+
return {
|
|
61
|
+
kind: 'box',
|
|
62
|
+
y: y + (index * height) / count,
|
|
63
|
+
height: height / count,
|
|
64
|
+
width: node.width * scale + (node.bracketDepth ?? 0.35) * t,
|
|
65
|
+
depth: node.depth * scale + (node.bracketDepth ?? 0.35) * t,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (style === 'rounded' || style === 'doric') {
|
|
70
|
+
const width = node.width * (node.capitalWidthScale ?? 1.34), depth = node.depth * (node.capitalDepthScale ?? node.capitalWidthScale ?? 1.34);
|
|
71
|
+
return [
|
|
72
|
+
{ kind: 'oval', y, height: height * 0.24, width: width * 0.72, depth: depth * 0.72 },
|
|
73
|
+
{
|
|
74
|
+
kind: 'oval',
|
|
75
|
+
y: y + height * 0.24,
|
|
76
|
+
height: height * 0.32,
|
|
77
|
+
width: width * 0.92,
|
|
78
|
+
depth: depth * 0.92,
|
|
79
|
+
},
|
|
80
|
+
{ kind: 'box', y: y + height * 0.56, height: height * 0.44, width, depth },
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
if (style === 'stepped') {
|
|
84
|
+
const widthScale = node.capitalWidthScale ?? 1.46, depthScale = node.capitalDepthScale ?? widthScale, count = Math.max(3, node.capitalTierCount ?? 3);
|
|
85
|
+
return Array.from({ length: count }, (_, index) => {
|
|
86
|
+
const t = index / Math.max(1, count - 1), spread = (1 - t) * (node.capitalStepSpread ?? 0.42);
|
|
87
|
+
return {
|
|
88
|
+
kind: 'box',
|
|
89
|
+
y: y + (index * height) / count,
|
|
90
|
+
height: (height / count) * 1.01,
|
|
91
|
+
width: node.width * Math.max(0.5, widthScale - spread),
|
|
92
|
+
depth: node.depth * Math.max(0.5, depthScale - spread),
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (['volute', 'ionic-volute', 'leaf-carved', 'corinthian-leaf'].includes(style)) {
|
|
97
|
+
return [
|
|
98
|
+
{ kind: 'column', y, height: height * 0.24, scale: 0.9 },
|
|
99
|
+
{ kind: 'column', y: y + height * 0.24, height: height * 0.2, scale: 1.08 },
|
|
100
|
+
{
|
|
101
|
+
kind: 'box',
|
|
102
|
+
y: y + height * 0.44,
|
|
103
|
+
height: height * 0.28,
|
|
104
|
+
width: node.width * (node.capitalWidthScale ?? 1.46),
|
|
105
|
+
depth: node.depth * (node.capitalDepthScale ?? node.capitalWidthScale ?? 1.46),
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
const widthScale = node.capitalWidthScale ?? (style === 'simple-slab' ? 1.28 : 1.18), depthScale = node.capitalDepthScale ?? widthScale;
|
|
110
|
+
return node.crossSection === 'square' || node.crossSection === 'rectangular'
|
|
111
|
+
? [{ kind: 'box', y, height, width: node.width * widthScale, depth: node.depth * depthScale }]
|
|
112
|
+
: [
|
|
113
|
+
{
|
|
114
|
+
kind: 'round',
|
|
115
|
+
y,
|
|
116
|
+
height,
|
|
117
|
+
radius: Math.max(node.radius * widthScale, node.width * widthScale * 0.5),
|
|
118
|
+
},
|
|
119
|
+
];
|
|
120
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ColumnNode, type DeclaredHostSurface, type SurfaceProvider } from '@pascal-app/core';
|
|
2
|
+
export declare function columnTopSurfaces(node: ColumnNode): DeclaredHostSurface[];
|
|
3
|
+
export declare const columnSurfaceProvider: SurfaceProvider;
|
|
4
|
+
//# sourceMappingURL=surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/column/surface.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,mBAAmB,EAExB,KAAK,eAAe,EAErB,MAAM,kBAAkB,CAAA;AAoBzB,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,mBAAmB,EAAE,CAgDzE;AAED,eAAO,MAAM,qBAAqB,EAAE,eAUnC,CAAA"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { hitDerivedSurfaceProvider, } from '@pascal-app/core';
|
|
2
|
+
import { columnCapitalBlocks, columnShaftLayout, getSegments, getShaftScaleAt, getShaftSegmentCount, getShaftTwistRadians, } from './shape';
|
|
3
|
+
function roundRegion(radius, segments, yaw = 0) {
|
|
4
|
+
return {
|
|
5
|
+
kind: 'polygon',
|
|
6
|
+
points: Array.from({ length: segments }, (_, i) => {
|
|
7
|
+
const angle = (i * Math.PI * 2) / segments + yaw;
|
|
8
|
+
return [Math.sin(angle) * radius, Math.cos(angle) * radius];
|
|
9
|
+
}),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function columnTopSurfaces(node) {
|
|
13
|
+
if (node.supportStyle !== 'vertical' || node.style === 'cluster')
|
|
14
|
+
return [];
|
|
15
|
+
const layout = columnShaftLayout(node);
|
|
16
|
+
const cap = columnCapitalBlocks(node, layout.shaftY + layout.shaftHeight, layout.capitalHeight).at(-1);
|
|
17
|
+
let y;
|
|
18
|
+
let region;
|
|
19
|
+
if (cap) {
|
|
20
|
+
y = cap.y + cap.height;
|
|
21
|
+
if (cap.kind === 'round')
|
|
22
|
+
region = roundRegion(cap.radius, getSegments(node));
|
|
23
|
+
else {
|
|
24
|
+
const bevel = Math.min(Math.max(0, node.edgeSoftness ?? 0.025), Math.min(cap.width, cap.depth, cap.height) * 0.35);
|
|
25
|
+
region = { kind: 'rect', size: [cap.width / 2 - bevel, cap.depth / 2 - bevel] };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const segments = getShaftSegmentCount(node);
|
|
30
|
+
const scale = getShaftScaleAt(node, (segments - 0.5) / segments);
|
|
31
|
+
const yaw = getShaftTwistRadians(node, segments - 1);
|
|
32
|
+
y = layout.shaftY + layout.shaftHeight + (layout.shaftHeight / segments) * 0.015;
|
|
33
|
+
if (node.crossSection === 'square' || node.crossSection === 'rectangular') {
|
|
34
|
+
const corner = Math.min(Math.max(0, node.shaftCornerRadius ?? 0.035), Math.min(node.width, node.depth) * 0.45) * scale;
|
|
35
|
+
const x = (node.width * scale) / 2 - corner;
|
|
36
|
+
const z = (node.depth * scale) / 2 - corner;
|
|
37
|
+
region = {
|
|
38
|
+
kind: 'polygon',
|
|
39
|
+
points: [
|
|
40
|
+
[-x, -z],
|
|
41
|
+
[x, -z],
|
|
42
|
+
[x, z],
|
|
43
|
+
[-x, z],
|
|
44
|
+
].map(([px, pz]) => [
|
|
45
|
+
px * Math.cos(yaw) + pz * Math.sin(yaw),
|
|
46
|
+
-px * Math.sin(yaw) + pz * Math.cos(yaw),
|
|
47
|
+
]),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
else
|
|
51
|
+
region = roundRegion(node.radius * scale, getSegments(node), yaw);
|
|
52
|
+
}
|
|
53
|
+
return [{ id: 'top', position: [0, y, 0], normal: [0, 1, 0], region }];
|
|
54
|
+
}
|
|
55
|
+
export const columnSurfaceProvider = {
|
|
56
|
+
...hitDerivedSurfaceProvider,
|
|
57
|
+
surfaces: (host) => columnTopSurfaces(host),
|
|
58
|
+
resolveHit(host, hit, ctx) {
|
|
59
|
+
const derived = hitDerivedSurfaceProvider.resolveHit(host, hit, ctx);
|
|
60
|
+
if (!derived)
|
|
61
|
+
return null;
|
|
62
|
+
const top = columnTopSurfaces(host)[0];
|
|
63
|
+
// Lower ornaments remain hit-derived; only the principal top has a durable resize identity.
|
|
64
|
+
return top && Math.abs(hit.point[1] - top.position[1]) < 1e-4 ? top : derived;
|
|
65
|
+
},
|
|
66
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/cupola/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AA6FrC;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,OAAO,UAAU,
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/cupola/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AA6FrC;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,OAAO,UAAU,CAiE9D,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/door/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAIV,cAAc,EAGf,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/door/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAIV,cAAc,EAGf,MAAM,kBAAkB,CAAA;AAqBzB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAkKnC;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,OAAO,QAAQ,CAsH1D,CAAA"}
|
package/dist/door/definition.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { curtainOpeningResizeMax } from '../shared/curtain-opening-limits';
|
|
1
2
|
import { buildDoorFloorplanSchedule, computeDoorFloorplanLevelData, } from '../shared/opening-documentation';
|
|
2
3
|
import { publishOpeningResizeGuides } from '../shared/opening-guides-runtime';
|
|
4
|
+
import { createOpeningPropertyPreview } from '../shared/opening-property-preview';
|
|
5
|
+
import { openingPropertyPreviewHost } from '../shared/opening-property-preview-host';
|
|
3
6
|
import { readRoofFaceHeightMax, readRoofFaceWidthMax } from '../shared/roof-opening-host';
|
|
4
7
|
import { buildRoofWallOpeningCut } from '../shared/roof-wall-opening-cut';
|
|
5
8
|
import { readHostWallCeiling } from '../shared/wall-opening-ceiling';
|
|
@@ -46,7 +49,7 @@ function doorWidthHandle(side) {
|
|
|
46
49
|
const roofMax = readRoofFaceWidthMax(n, scene, sign);
|
|
47
50
|
if (roofMax !== null)
|
|
48
51
|
return Math.max(MIN_DOOR_WIDTH, roofMax);
|
|
49
|
-
return readWallLength(n, scene);
|
|
52
|
+
return curtainOpeningResizeMax(n, scene.nodes(), 'x', sign) ?? readWallLength(n, scene);
|
|
50
53
|
},
|
|
51
54
|
currentValue: (n) => n.width,
|
|
52
55
|
onDrag: (node) => publishOpeningResizeGuides(node, false),
|
|
@@ -88,6 +91,9 @@ function doorHeightHandle() {
|
|
|
88
91
|
const roofMax = readRoofFaceHeightMax(n, scene, 1);
|
|
89
92
|
if (roofMax !== null)
|
|
90
93
|
return Math.max(MIN_DOOR_HEIGHT, roofMax);
|
|
94
|
+
const curtainMax = curtainOpeningResizeMax(n, scene.nodes(), 'y', 1);
|
|
95
|
+
if (curtainMax !== undefined)
|
|
96
|
+
return curtainMax;
|
|
91
97
|
const bottom = n.position[1] - n.height / 2;
|
|
92
98
|
return Math.max(MIN_DOOR_HEIGHT, readHostWallCeiling(n.wallId, scene) - bottom);
|
|
93
99
|
},
|
|
@@ -126,11 +132,43 @@ function doorMoveHandle() {
|
|
|
126
132
|
},
|
|
127
133
|
};
|
|
128
134
|
}
|
|
135
|
+
function doorRadiusHandle(index) {
|
|
136
|
+
const sign = index === 0 ? -1 : 1;
|
|
137
|
+
return {
|
|
138
|
+
kind: 'corner-radius',
|
|
139
|
+
corner: [sign, 1],
|
|
140
|
+
width: (node) => node.width,
|
|
141
|
+
height: (node) => node.height,
|
|
142
|
+
currentValue: (node) => node.openingRadiusMode === 'individual'
|
|
143
|
+
? (node.openingTopRadii[index] ?? 0)
|
|
144
|
+
: node.cornerRadius,
|
|
145
|
+
max: (node) => Math.min(node.width / 2, node.height),
|
|
146
|
+
apply: (node, radius, _scene, modifiers) => {
|
|
147
|
+
if (!modifiers.shiftKey) {
|
|
148
|
+
return { openingShape: 'rounded', openingRadiusMode: 'all', cornerRadius: radius };
|
|
149
|
+
}
|
|
150
|
+
const radii = node.openingRadiusMode === 'individual'
|
|
151
|
+
? [...node.openingTopRadii]
|
|
152
|
+
: [node.cornerRadius, node.cornerRadius];
|
|
153
|
+
radii[index] = radius;
|
|
154
|
+
return {
|
|
155
|
+
openingShape: 'rounded',
|
|
156
|
+
openingRadiusMode: 'individual',
|
|
157
|
+
openingTopRadii: radii,
|
|
158
|
+
};
|
|
159
|
+
},
|
|
160
|
+
createPreview: (node) => createOpeningPropertyPreview(node.id, openingPropertyPreviewHost),
|
|
161
|
+
visible: (node) => node.openingShape !== 'arch',
|
|
162
|
+
portal: 'grandparent',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
129
165
|
const doorHandles = [
|
|
130
166
|
doorMoveHandle(),
|
|
131
167
|
doorWidthHandle('left'),
|
|
132
168
|
doorWidthHandle('right'),
|
|
133
169
|
doorHeightHandle(),
|
|
170
|
+
doorRadiusHandle(0),
|
|
171
|
+
doorRadiusHandle(1),
|
|
134
172
|
];
|
|
135
173
|
/**
|
|
136
174
|
* Door — Phase 5 batch kind. Hosted on walls, cuts holes in them,
|
|
@@ -200,6 +238,7 @@ export const doorDefinition = {
|
|
|
200
238
|
},
|
|
201
239
|
parametrics: doorParametrics,
|
|
202
240
|
handles: doorHandles,
|
|
241
|
+
rendersChildren: false,
|
|
203
242
|
renderer: {
|
|
204
243
|
kind: 'parametric',
|
|
205
244
|
module: () => import('./renderer'),
|
package/dist/door/door-math.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"door-math.d.ts","sourceRoot":"","sources":["../../src/door/door-math.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"door-math.d.ts","sourceRoot":"","sources":["../../src/door/door-math.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAEzB;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,MAAM,CAGR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,YAAY,SAAI,EAChB,aAAa,SAAI,GAChB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAI1B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAOxC;AAKD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAA"}
|
package/dist/door/door-math.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getCurtainWallConfig, getWallCurveFrameAt, getWallCurveLength, } from '@pascal-app/core';
|
|
1
2
|
/**
|
|
2
3
|
* Keep the door handle at the same relative height when the door is resized:
|
|
3
4
|
* scale it by the height ratio, then clamp to the panel's slider bounds
|
|
@@ -13,22 +14,18 @@ export function scaleHandleHeight(handleHeight, oldHeight, newHeight) {
|
|
|
13
14
|
* Converts wall-local (X along wall, Y = height above wall base) to world XYZ.
|
|
14
15
|
*/
|
|
15
16
|
export function wallLocalToWorld(wallNode, localX, localY, levelYOffset = 0, slabElevation = 0) {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
slabElevation + localY + levelYOffset,
|
|
20
|
-
wallNode.start[1] + localX * Math.sin(wallAngle),
|
|
21
|
-
];
|
|
17
|
+
const wallLength = getWallCurveLength(wallNode);
|
|
18
|
+
const frame = getWallCurveFrameAt(wallNode, wallLength > 1e-6 ? localX / wallLength : 0);
|
|
19
|
+
return [frame.point.x, slabElevation + localY + levelYOffset, frame.point.y];
|
|
22
20
|
}
|
|
23
21
|
/**
|
|
24
22
|
* Clamps door center X so it stays fully within wall bounds.
|
|
25
23
|
* Y is always height/2 — doors sit at floor level.
|
|
26
24
|
*/
|
|
27
25
|
export function clampToWall(wallNode, localX, width, height) {
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const clampedX = Math.max(width / 2, Math.min(wallLength - width / 2, localX));
|
|
26
|
+
const wallLength = getWallCurveLength(wallNode);
|
|
27
|
+
const margin = wallNode.wallType === 'curtain' ? getCurtainWallConfig(wallNode).perimeterWidth : 0;
|
|
28
|
+
const clampedX = Math.max(margin + width / 2, Math.min(wallLength - margin - width / 2, localX));
|
|
32
29
|
const clampedY = height / 2; // Doors always sit at floor level
|
|
33
30
|
return { clampedX, clampedY };
|
|
34
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/door/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/door/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,mBAAmB,EAMzB,MAAM,kBAAkB,CAAA;AAQzB;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,EAAE,mBAAmB,CAAC,QAAQ,CAkF7D,CAAA"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
1
|
+
import { getWallCurveLength, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
2
|
+
import { curtainOpeningLimits } from '../shared/curtain-opening-limits';
|
|
3
|
+
import { projectPlanPointToWallLocalX } from '../shared/wall-attach-target';
|
|
2
4
|
const MIN_DOOR_WIDTH = 0.3;
|
|
3
5
|
/**
|
|
4
6
|
* 2D drag affordance for the door's width side-arrows. Sister to the 3D
|
|
@@ -29,21 +31,15 @@ export const doorWidthAffordance = {
|
|
|
29
31
|
// toward wall.end), -1 for 'start' (drag outward toward wall.start).
|
|
30
32
|
const growDir = side === 'end' ? 1 : -1;
|
|
31
33
|
const anchorX = side === 'end' ? initialDoorX - initialWidth / 2 : initialDoorX + initialWidth / 2;
|
|
32
|
-
|
|
33
|
-
// wall-local X delta.
|
|
34
|
-
const wallStart = wall ? wall.start : [0, 0];
|
|
35
|
-
const wallEnd = wall ? wall.end : [1, 0];
|
|
36
|
-
const dx = wallEnd[0] - wallStart[0];
|
|
37
|
-
const dz = wallEnd[1] - wallStart[1];
|
|
38
|
-
const wallLength = Math.hypot(dx, dz) || 1;
|
|
39
|
-
const dirX = dx / wallLength;
|
|
40
|
-
const dirZ = dz / wallLength;
|
|
34
|
+
const wallLength = wall ? getWallCurveLength(wall) : 1;
|
|
41
35
|
// Max width keeps the dragged edge inside the wall span. With the
|
|
42
36
|
// anchor fixed, the moving edge is `anchorX ± width`, so the largest
|
|
43
37
|
// legal width is the headroom on the grow side.
|
|
44
|
-
const
|
|
38
|
+
const limits = curtainOpeningLimits(node, nodes);
|
|
39
|
+
const margin = limits?.margin ?? 0;
|
|
40
|
+
const maxWidth = growDir > 0 ? (limits?.length ?? wallLength) - margin - anchorX : anchorX - margin;
|
|
45
41
|
const projectToWallLocalX = (planPoint) => {
|
|
46
|
-
return (planPoint
|
|
42
|
+
return wall ? projectPlanPointToWallLocalX(wall, planPoint) : planPoint[0];
|
|
47
43
|
};
|
|
48
44
|
// Initial pointer in wall-local X — anchored to where the user
|
|
49
45
|
// actually pressed, so any subtle offset between the arrow's visual
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"move-tool.d.ts","sourceRoot":"","sources":["../../src/door/move-tool.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAYT,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"move-tool.d.ts","sourceRoot":"","sources":["../../src/door/move-tool.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAYT,MAAM,kBAAkB,CAAA;AAmDzB,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAwhC9C,CAAA;AAED,eAAe,YAAY,CAAA"}
|