@pascal-app/nodes 1.0.0-beta.3 → 1.0.0-beta.5
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/cabinet/flame-index.d.ts +3 -0
- package/dist/cabinet/flame-index.d.ts.map +1 -0
- package/dist/cabinet/flame-index.js +13 -0
- package/dist/cabinet/system.d.ts +2 -0
- package/dist/cabinet/system.d.ts.map +1 -1
- package/dist/cabinet/system.js +28 -8
- package/dist/cabinet/tool.d.ts.map +1 -1
- package/dist/cabinet/tool.js +2 -1
- package/dist/ceiling/panel.d.ts.map +1 -1
- package/dist/ceiling/panel.js +8 -2
- package/dist/ceiling/parametrics.js +1 -1
- package/dist/column/panel.js +1 -1
- package/dist/column/parametrics.js +1 -1
- package/dist/dormer/placement-guides.d.ts.map +1 -1
- package/dist/dormer/placement-guides.js +5 -4
- package/dist/elevator/definition.d.ts.map +1 -1
- package/dist/elevator/definition.js +2 -0
- package/dist/fence/curve-tool.d.ts.map +1 -1
- package/dist/fence/curve-tool.js +14 -9
- package/dist/fence/move-control-point-tool.d.ts.map +1 -1
- package/dist/fence/move-control-point-tool.js +13 -8
- package/dist/fence/move-tangent-tool.d.ts.map +1 -1
- package/dist/fence/move-tangent-tool.js +13 -8
- package/dist/fence/tool.d.ts.map +1 -1
- package/dist/fence/tool.js +8 -11
- package/dist/measurement/renderer.d.ts.map +1 -1
- package/dist/measurement/renderer.js +6 -5
- package/dist/measurement/surface-query.js +5 -5
- package/dist/measurement/tool.d.ts.map +1 -1
- package/dist/measurement/tool.js +7 -5
- package/dist/ridge-vent/renderer.d.ts.map +1 -1
- package/dist/ridge-vent/renderer.js +2 -2
- package/dist/shared/mep-ghost.d.ts.map +1 -1
- package/dist/shared/mep-ghost.js +19 -1
- package/dist/slab/panel.d.ts.map +1 -1
- package/dist/slab/panel.js +1 -1
- package/dist/wall/curve-tool.d.ts +3 -4
- package/dist/wall/curve-tool.d.ts.map +1 -1
- package/dist/wall/curve-tool.js +17 -13
- package/dist/wall/panel.d.ts.map +1 -1
- package/dist/wall/panel.js +56 -14
- package/dist/wall/parametrics.js +1 -1
- package/dist/wall/system.d.ts +3 -0
- package/dist/wall/system.d.ts.map +1 -1
- package/dist/wall/system.js +5 -1
- package/dist/wall/tool.d.ts.map +1 -1
- package/dist/wall/tool.js +24 -27
- package/dist/wall/wall-batch-system.d.ts +23 -0
- package/dist/wall/wall-batch-system.d.ts.map +1 -0
- package/dist/wall/wall-batch-system.js +389 -0
- package/dist/wall/wall-batch.d.ts +66 -0
- package/dist/wall/wall-batch.d.ts.map +1 -0
- package/dist/wall/wall-batch.js +169 -0
- package/dist/zone/quantities-panel.d.ts.map +1 -1
- package/dist/zone/quantities-panel.js +4 -3
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/measurement/tool.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/measurement/tool.tsx"],"names":[],"mappings":"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"}
|
package/dist/measurement/tool.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { collectAlignmentAnchors, emitter, measurementAngle, measurementArea, measurementCentroid, measurementDistance, measurementFeatureLength, measurementPerimeter, measurementPrismVolume, sceneRegistry, useScene, } from '@pascal-app/core';
|
|
4
4
|
import { buildMeasurementAngleArcPoints, commitMeasurementDraft, EDITOR_LAYER, finishMeasurementDraft, formatAngleRadians, formatAreaLabel, formatLinearMeasurement, formatVolumeLabel, getLinearUnitLabel, handleMeasurementDraftEscape, isAlignmentGuideActive, isGridSnapActive, linearUnitToMeters, MEASUREMENT_ACTIVE_COLOR, markToolCancelConsumed, measurementPolygonLabelAnchor, measurementPolygonMidpoints, metersToLinearUnit, useEditor, useInteractionScope, useMeasurementDraft, } from '@pascal-app/editor';
|
|
5
|
-
import {
|
|
5
|
+
import { setSurfaceRaycastLayers, useViewer } from '@pascal-app/viewer';
|
|
6
6
|
import { Html } from '@react-three/drei';
|
|
7
7
|
import { useFrame, useThree } from '@react-three/fiber';
|
|
8
8
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
@@ -247,7 +247,7 @@ export function collectMeasurementAxisSurfaceIntersections(scene, levelObject, a
|
|
|
247
247
|
const origin = levelObject.localToWorld(new Vector3(...anchor));
|
|
248
248
|
const levelRotation = levelObject.getWorldQuaternion(new Quaternion());
|
|
249
249
|
const raycaster = new Raycaster();
|
|
250
|
-
raycaster.layers
|
|
250
|
+
setSurfaceRaycastLayers(raycaster.layers);
|
|
251
251
|
raycaster.near = 0;
|
|
252
252
|
raycaster.far = maxDistance;
|
|
253
253
|
const intersections = [];
|
|
@@ -766,6 +766,7 @@ const MeasurementDraftPreview = ({ buildingId, levelId, surfaceQuery }) => {
|
|
|
766
766
|
const extrusionHeight = useMeasurementDraft((state) => state.extrusionHeight);
|
|
767
767
|
const error = useMeasurementDraft((state) => state.error);
|
|
768
768
|
const unit = useViewer((state) => state.unit);
|
|
769
|
+
const metricNotation = useViewer((state) => state.metricNotation);
|
|
769
770
|
const axisIntersectionCache = useRef(null);
|
|
770
771
|
const draftPointMaterial = useMemo(() => new MeshBasicNodeMaterial({
|
|
771
772
|
color: DRAFT_COLOR,
|
|
@@ -897,7 +898,7 @@ const MeasurementDraftPreview = ({ buildingId, levelId, surfaceQuery }) => {
|
|
|
897
898
|
const end = livePoints[livePoints.length - 1];
|
|
898
899
|
label = {
|
|
899
900
|
position: localToPreviewFrame(levelObject, buildingObject, midpoint(start, end)),
|
|
900
|
-
text: formatLinearMeasurement(measurementDistance(start, end), unit),
|
|
901
|
+
text: formatLinearMeasurement(measurementDistance(start, end), unit, metricNotation),
|
|
901
902
|
};
|
|
902
903
|
}
|
|
903
904
|
else if (kind === 'angle' && livePoints.length >= 3) {
|
|
@@ -915,7 +916,7 @@ const MeasurementDraftPreview = ({ buildingId, levelId, surfaceQuery }) => {
|
|
|
915
916
|
position: localToPreviewFrame(levelObject, buildingObject, center),
|
|
916
917
|
text: kind === 'area'
|
|
917
918
|
? `A ${formatAreaLabel(measurementArea(livePoints), unit)}`
|
|
918
|
-
: `P ${formatLinearMeasurement(measurementPerimeter(livePoints), unit)}`,
|
|
919
|
+
: `P ${formatLinearMeasurement(measurementPerimeter(livePoints), unit, metricNotation)}`,
|
|
919
920
|
};
|
|
920
921
|
}
|
|
921
922
|
}
|
|
@@ -971,6 +972,7 @@ const MeasurementDraftPreview = ({ buildingId, levelId, surfaceQuery }) => {
|
|
|
971
972
|
hoverOwner,
|
|
972
973
|
kind,
|
|
973
974
|
levelId,
|
|
975
|
+
metricNotation,
|
|
974
976
|
points,
|
|
975
977
|
stage,
|
|
976
978
|
surfaceQuery,
|
|
@@ -1005,7 +1007,7 @@ export const MeasurementTool = () => {
|
|
|
1005
1007
|
const cancelVertexGesture = useRef(() => { });
|
|
1006
1008
|
const surfaceQuery = useMemo(() => createMeasurementSurfaceQuerySession(scene), [scene]);
|
|
1007
1009
|
useEffect(() => {
|
|
1008
|
-
raycaster.current.layers
|
|
1010
|
+
setSurfaceRaycastLayers(raycaster.current.layers);
|
|
1009
1011
|
}, []);
|
|
1010
1012
|
useEffect(() => () => surfaceQuery.dispose(), [surfaceQuery]);
|
|
1011
1013
|
useEffect(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/ridge-vent/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/ridge-vent/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,aAAa,EAMnB,MAAM,kBAAkB,CAAA;AAuDzB;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,iBAAiB,GAAI,qBAAqB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,uCAiMtE,CAAA;AAED,eAAe,iBAAiB,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { getEffectiveRoofSurfaceMaterial, getEffectiveSegmentSurfaceMaterial, useLiveNodeOverrides, useRegistry, useScene, } from '@pascal-app/core';
|
|
3
|
+
import { getEffectiveRoofSurfaceMaterial, getEffectiveSegmentSurfaceMaterial, normalizeRoofSegmentTrim, useLiveNodeOverrides, useRegistry, useScene, } from '@pascal-app/core';
|
|
4
4
|
import { createMaterial, createMaterialFromPresetRef, createSurfaceRoleMaterial, getRoofMaterialArray, useNodeEvents, useViewer, } from '@pascal-app/viewer';
|
|
5
5
|
import { useEffect, useMemo, useRef } from 'react';
|
|
6
6
|
import * as THREE from 'three';
|
|
@@ -11,7 +11,7 @@ import { buildRidgeVentGeometry } from './geometry';
|
|
|
11
11
|
function ridgeVentSegmentGeometryKey(segment) {
|
|
12
12
|
if (!segment)
|
|
13
13
|
return 'none';
|
|
14
|
-
const trim = segment
|
|
14
|
+
const trim = normalizeRoofSegmentTrim(segment);
|
|
15
15
|
return [
|
|
16
16
|
segment.roofType,
|
|
17
17
|
segment.width,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mep-ghost.d.ts","sourceRoot":"","sources":["../../src/shared/mep-ghost.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,EAChB,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"mep-ghost.d.ts","sourceRoot":"","sources":["../../src/shared/mep-ghost.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,eAAe,EACf,eAAe,EAChB,MAAM,kBAAkB,CAAA;AAWzB,gFAAgF;AAChF,eAAO,MAAM,WAAW,YAAY,CAAA;AACpC,eAAO,MAAM,aAAa,OAAO,CAAA;AAEjC;;;oCAGoC;AACpC,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAA;AAmCvD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IAAE,OAAO,EAAE,eAAe,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,+BAU7F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,+BAQ3F;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,IAAI,GACL,EAAE;IACD,OAAO,EAAE,eAAe,CAAA;IACxB,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB,+BAUA;AAED,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,+BAQ3F"}
|
package/dist/shared/mep-ghost.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { EDITOR_LAYER } from '@pascal-app/editor';
|
|
4
|
-
import {
|
|
4
|
+
import { disposeObject3DResources } from '@pascal-app/viewer';
|
|
5
|
+
import { useEffect, useMemo } from 'react';
|
|
5
6
|
import { Mesh, MeshBasicMaterial } from 'three';
|
|
6
7
|
import { buildDuctFittingGeometry } from '../duct-fitting/geometry';
|
|
7
8
|
import { buildDuctSegmentGeometry } from '../duct-segment/geometry';
|
|
@@ -21,8 +22,17 @@ function ghostColor(tint) {
|
|
|
21
22
|
/** Repaint every mesh in `group` as a translucent, depth-test-free preview. */
|
|
22
23
|
function ghostify(group, tint) {
|
|
23
24
|
const color = ghostColor(tint);
|
|
25
|
+
const replacedMaterials = new Set();
|
|
24
26
|
group.traverse((child) => {
|
|
25
27
|
if (child instanceof Mesh) {
|
|
28
|
+
const previous = child.material;
|
|
29
|
+
if (Array.isArray(previous)) {
|
|
30
|
+
for (const material of previous)
|
|
31
|
+
replacedMaterials.add(material);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
replacedMaterials.add(previous);
|
|
35
|
+
}
|
|
26
36
|
child.layers.set(EDITOR_LAYER);
|
|
27
37
|
child.material = new MeshBasicMaterial({
|
|
28
38
|
color,
|
|
@@ -33,6 +43,10 @@ function ghostify(group, tint) {
|
|
|
33
43
|
child.renderOrder = 999;
|
|
34
44
|
}
|
|
35
45
|
});
|
|
46
|
+
for (const material of replacedMaterials) {
|
|
47
|
+
if (!material.userData.__pascalCachedMaterial)
|
|
48
|
+
material.dispose();
|
|
49
|
+
}
|
|
36
50
|
}
|
|
37
51
|
/**
|
|
38
52
|
* Translucent ghost of a duct fitting, built from the same geometry the
|
|
@@ -48,6 +62,7 @@ export function FittingGhost({ fitting, tint }) {
|
|
|
48
62
|
ghostify(group, tint);
|
|
49
63
|
return group;
|
|
50
64
|
}, [fitting, tint]);
|
|
65
|
+
useEffect(() => () => disposeObject3DResources(ghost), [ghost]);
|
|
51
66
|
return _jsx("primitive", { object: ghost });
|
|
52
67
|
}
|
|
53
68
|
/**
|
|
@@ -61,6 +76,7 @@ export function DuctSegmentGhost({ duct, tint }) {
|
|
|
61
76
|
ghostify(group, tint);
|
|
62
77
|
return group;
|
|
63
78
|
}, [duct, tint]);
|
|
79
|
+
useEffect(() => () => disposeObject3DResources(ghost), [ghost]);
|
|
64
80
|
return _jsx("primitive", { object: ghost });
|
|
65
81
|
}
|
|
66
82
|
export function PipeFittingGhost({ fitting, tint, }) {
|
|
@@ -71,6 +87,7 @@ export function PipeFittingGhost({ fitting, tint, }) {
|
|
|
71
87
|
ghostify(group, tint);
|
|
72
88
|
return group;
|
|
73
89
|
}, [fitting, tint]);
|
|
90
|
+
useEffect(() => () => disposeObject3DResources(ghost), [ghost]);
|
|
74
91
|
return _jsx("primitive", { object: ghost });
|
|
75
92
|
}
|
|
76
93
|
export function PipeSegmentGhost({ pipe, tint }) {
|
|
@@ -79,5 +96,6 @@ export function PipeSegmentGhost({ pipe, tint }) {
|
|
|
79
96
|
ghostify(group, tint);
|
|
80
97
|
return group;
|
|
81
98
|
}, [pipe, tint]);
|
|
99
|
+
useEffect(() => () => disposeObject3DResources(ghost), [ghost]);
|
|
82
100
|
return _jsx("primitive", { object: ghost });
|
|
83
101
|
}
|
package/dist/slab/panel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/slab/panel.tsx"],"names":[],"mappings":"AA+BA;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,
|
|
1
|
+
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/slab/panel.tsx"],"names":[],"mappings":"AA+BA;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,uCAgaxB;AAED,eAAe,SAAS,CAAA"}
|
package/dist/slab/panel.js
CHANGED
|
@@ -203,7 +203,7 @@ export function SlabPanel() {
|
|
|
203
203
|
{ label: 'Standard (5cm)', elevation: 0.05 },
|
|
204
204
|
{ label: 'Thick (15cm)', elevation: 0.15 },
|
|
205
205
|
];
|
|
206
|
-
return (_jsxs(PanelWrapper, { icon: "/icons/floor.webp", onClose: handleClose, title: node.name || 'Slab', width: 320, children: [_jsxs(PanelSection, { title: "Elevation", children: [_jsx(SliderControl, { label: node.recessed ? 'Floor' : 'Surface', max:
|
|
206
|
+
return (_jsxs(PanelWrapper, { icon: "/icons/floor.webp", onClose: handleClose, title: node.name || 'Slab', width: 320, children: [_jsxs(PanelSection, { title: "Elevation", children: [_jsx(SliderControl, { label: node.recessed ? 'Floor' : 'Surface', max: 20, min: -3, onChange: handleElevationChange, precision: 3, step: 0.01, unit: "m", value: Math.round(node.elevation * 1000) / 1000 }), _jsx(SliderControl, { label: node.recessed ? 'Rim' : 'Base', max: 20, min: -3, onChange: handleAnchorChange, precision: 3, step: 0.01, unit: "m", value: Math.round(getSlabAnchorElevation(node) * 1000) / 1000 }), node.recessed ? (_jsx(SliderControl, { label: "Depth", max: 2, min: MIN_SLAB_THICKNESS, onChange: handleRecessDepthChange, precision: 2, step: 0.01, unit: "m", value: Math.round(getSlabRecessDepth(node) * 100) / 100 })) : (_jsx(SliderControl, { label: "Thickness", max: 0.5, min: MIN_SLAB_THICKNESS, onChange: handleThicknessChange, precision: 2, step: 0.01, unit: "m", value: Math.round((node.thickness ?? 0.05) * 100) / 100 })), !node.recessed && (_jsxs(_Fragment, { children: [_jsx("div", { className: "px-1 font-medium text-[10px] text-muted-foreground/80 uppercase tracking-wider", children: "Foundation" }), _jsx(SegmentedControl, { onChange: handleTerrainModeChange, options: [
|
|
207
207
|
{ label: 'Fixed', value: 'fixed' },
|
|
208
208
|
{ label: 'Follows terrain', value: 'terrain' },
|
|
209
209
|
], value: node.fillToTerrain ? 'terrain' : 'fixed' }), node.fillToTerrain && (_jsx("div", { className: "px-1 text-[11px] text-muted-foreground", children: "Extends the perimeter down to terrain. The flat surface, base, and thickness stay unchanged." }))] })), _jsx("div", { className: "mt-2 grid grid-cols-2 gap-1.5 px-1 pb-1", children: elevationPresets.map((preset) => (_jsx(ActionButton, { label: preset.label, onClick: () => handleElevationPreset(preset.elevation) }, preset.label))) })] }), _jsx(PanelSection, { title: "Info", children: _jsxs("div", { className: "flex items-center justify-between px-2 py-1 text-muted-foreground text-sm", children: [_jsx("span", { children: "Area" }), _jsxs("span", { className: "font-mono text-white", children: [area.toFixed(2), " m\u00B2"] })] }) }), _jsxs(PanelSection, { title: "Holes", children: [node.holes && node.holes.length > 0 ? (_jsx("div", { className: "flex flex-col gap-1 pb-2", children: node.holes.map((hole, index) => {
|
|
@@ -2,10 +2,9 @@ import { type WallNode } from '@pascal-app/core';
|
|
|
2
2
|
/**
|
|
3
3
|
* Phase 5 Stage D — wall curve tool (kind-owned).
|
|
4
4
|
*
|
|
5
|
-
* 1:1 port of the legacy `CurveWallTool`. Same snap pipeline
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* than the depth-counted `pauseSceneHistory` helpers — matches legacy.
|
|
5
|
+
* 1:1 port of the legacy `CurveWallTool`. Same snap pipeline and
|
|
6
|
+
* activation grace. History uses an idempotent lease because cancel and
|
|
7
|
+
* effect cleanup can both release the active interaction.
|
|
9
8
|
*/
|
|
10
9
|
export declare const CurveWallTool: React.FC<{
|
|
11
10
|
node: WallNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"curve-tool.d.ts","sourceRoot":"","sources":["../../src/wall/curve-tool.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"curve-tool.d.ts","sourceRoot":"","sources":["../../src/wall/curve-tool.tsx"],"names":[],"mappings":"AAEA,OAAO,EAWL,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAazB;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAgJtD,CAAA;AAED,eAAe,aAAa,CAAA"}
|
package/dist/wall/curve-tool.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { emitter, getClampedWallCurveOffset, getMaxWallCurveOffset, getWallChordFrame, getWallMidpointHandlePoint, normalizeWallCurveOffset, useScene, } from '@pascal-app/core';
|
|
3
|
+
import { acquireSceneHistoryPause, emitter, getClampedWallCurveOffset, getMaxWallCurveOffset, getWallChordFrame, getWallMidpointHandlePoint, normalizeWallCurveOffset, useScene, } from '@pascal-app/core';
|
|
4
4
|
import { CursorSphere, getSegmentGridStep, markToolCancelConsumed, snapBuildingLocalToWorldGrid, snapScalarToGrid, triggerSFX, useInteractionScope, } from '@pascal-app/editor';
|
|
5
5
|
import { useViewer } from '@pascal-app/viewer';
|
|
6
6
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
7
7
|
/**
|
|
8
8
|
* Phase 5 Stage D — wall curve tool (kind-owned).
|
|
9
9
|
*
|
|
10
|
-
* 1:1 port of the legacy `CurveWallTool`. Same snap pipeline
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* than the depth-counted `pauseSceneHistory` helpers — matches legacy.
|
|
10
|
+
* 1:1 port of the legacy `CurveWallTool`. Same snap pipeline and
|
|
11
|
+
* activation grace. History uses an idempotent lease because cancel and
|
|
12
|
+
* effect cleanup can both release the active interaction.
|
|
14
13
|
*/
|
|
15
14
|
export const CurveWallTool = ({ node }) => {
|
|
16
15
|
const activatedAtRef = useRef(Date.now());
|
|
@@ -33,8 +32,8 @@ export const CurveWallTool = ({ node }) => {
|
|
|
33
32
|
const originalCurveOffset = originalCurveOffsetRef.current;
|
|
34
33
|
const chord = getWallChordFrame(node);
|
|
35
34
|
const maxCurveOffset = getMaxWallCurveOffset(node);
|
|
36
|
-
useScene
|
|
37
|
-
let
|
|
35
|
+
let releaseHistory = acquireSceneHistoryPause(useScene);
|
|
36
|
+
let wasFinalized = false;
|
|
38
37
|
const applyPreview = (curveOffset) => {
|
|
39
38
|
if (previewOffsetRef.current === curveOffset) {
|
|
40
39
|
return;
|
|
@@ -77,21 +76,23 @@ export const CurveWallTool = ({ node }) => {
|
|
|
77
76
|
applyPreview(nextCurveOffset);
|
|
78
77
|
};
|
|
79
78
|
const onGridClick = (event) => {
|
|
79
|
+
if (wasFinalized)
|
|
80
|
+
return;
|
|
80
81
|
if (Date.now() - activatedAtRef.current < 150) {
|
|
81
82
|
event.nativeEvent?.stopPropagation?.();
|
|
82
83
|
return;
|
|
83
84
|
}
|
|
84
85
|
const curveOffset = previewOffsetRef.current;
|
|
85
|
-
|
|
86
|
+
wasFinalized = true;
|
|
86
87
|
if (curveOffset !== originalCurveOffset) {
|
|
87
88
|
// Restore original baseline while paused so the next resume+update
|
|
88
89
|
// registers as a single tracked change (undo reverts to original).
|
|
89
90
|
useScene.getState().updateNode(nodeId, { curveOffset: originalCurveOffset });
|
|
90
91
|
useScene.getState().markDirty(nodeId);
|
|
91
|
-
|
|
92
|
+
releaseHistory();
|
|
92
93
|
useScene.getState().updateNode(nodeId, { curveOffset });
|
|
93
94
|
useScene.getState().markDirty(nodeId);
|
|
94
|
-
useScene
|
|
95
|
+
releaseHistory = acquireSceneHistoryPause(useScene);
|
|
95
96
|
}
|
|
96
97
|
triggerSFX('sfx:item-place');
|
|
97
98
|
useViewer.getState().setSelection({ selectedIds: [nodeId] });
|
|
@@ -99,9 +100,12 @@ export const CurveWallTool = ({ node }) => {
|
|
|
99
100
|
event.nativeEvent?.stopPropagation?.();
|
|
100
101
|
};
|
|
101
102
|
const onCancel = () => {
|
|
103
|
+
if (wasFinalized)
|
|
104
|
+
return;
|
|
102
105
|
restoreOriginal();
|
|
106
|
+
wasFinalized = true;
|
|
103
107
|
useViewer.getState().setSelection({ selectedIds: [nodeId] });
|
|
104
|
-
|
|
108
|
+
releaseHistory();
|
|
105
109
|
markToolCancelConsumed();
|
|
106
110
|
exitCurveMode();
|
|
107
111
|
};
|
|
@@ -109,10 +113,10 @@ export const CurveWallTool = ({ node }) => {
|
|
|
109
113
|
emitter.on('grid:click', onGridClick);
|
|
110
114
|
emitter.on('tool:cancel', onCancel);
|
|
111
115
|
return () => {
|
|
112
|
-
if (!
|
|
116
|
+
if (!wasFinalized) {
|
|
113
117
|
restoreOriginal();
|
|
114
118
|
}
|
|
115
|
-
|
|
119
|
+
releaseHistory();
|
|
116
120
|
emitter.off('grid:move', onGridMove);
|
|
117
121
|
emitter.off('grid:click', onGridClick);
|
|
118
122
|
emitter.off('tool:cancel', onCancel);
|
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":"AAyFA,MAAM,CAAC,OAAO,UAAU,SAAS,uCAkUhC"}
|
package/dist/wall/panel.js
CHANGED
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { buildWallFaceBandCountPatch, getClampedWallCurveOffset, getMaxWallCurveOffset, getWallCurveLength, getWallFaceBandConfig, normalizeWallCurveOffset, useLiveNodeOverrides, useScene, WALL_CHAIR_RAIL_DEFAULT, WALL_CROWN_DEFAULT, WALL_FACE_BAND_DEFAULT, WALL_SKIRTING_DEFAULT, } from '@pascal-app/core';
|
|
4
|
-
import { ActionButton, ActionGroup, curveReshapeScope, getLinearUnitLabel, linearControlValueToMeters, metersToLinearUnit, PanelSection, PanelWrapper, SegmentedControl, SliderControl, triggerSFX, useInteractionScope, } from '@pascal-app/editor';
|
|
3
|
+
import { buildWallFaceBandCountPatch, GROUND_SUPPORT_ID, getClampedWallCurveOffset, getMaxWallCurveOffset, getWallCurveLength, getWallFaceBandConfig, normalizeWallCurveOffset, terrainSupportLift, useLiveNodeOverrides, useScene, WALL_CHAIR_RAIL_DEFAULT, WALL_CROWN_DEFAULT, WALL_FACE_BAND_DEFAULT, WALL_SKIRTING_DEFAULT, } from '@pascal-app/core';
|
|
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
7
|
import { useCallback, useMemo, useRef } from 'react';
|
|
8
8
|
import { resolveWallOpeningCeiling } from '../shared/wall-opening-ceiling';
|
|
9
|
+
/**
|
|
10
|
+
* Base half of the plane-bound repair: a stamped draft offset goes, and a
|
|
11
|
+
* ground host is dropped unless sculpted terrain actually supports it — a
|
|
12
|
+
* terrain-less ground host (regression-era data) pins the base at the level
|
|
13
|
+
* floor and buries the wall in any later slab.
|
|
14
|
+
*/
|
|
15
|
+
function wallBaseRepairPatch(n) {
|
|
16
|
+
const nodes = useScene.getState().nodes;
|
|
17
|
+
const terrainSupported = n.parentId != null && terrainSupportLift(nodes, n.parentId, n.start[0], n.start[1]) != null;
|
|
18
|
+
return {
|
|
19
|
+
supportOffset: undefined,
|
|
20
|
+
...(n.supportSlabId === GROUND_SUPPORT_ID && !terrainSupported
|
|
21
|
+
? { supportSlabId: undefined }
|
|
22
|
+
: {}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
9
25
|
const WALL_TRIM_PROFILE_OPTIONS = {
|
|
10
26
|
skirting: [
|
|
11
27
|
{ label: 'Flat', value: 'flat' },
|
|
@@ -103,15 +119,37 @@ export default function WallPanel() {
|
|
|
103
119
|
];
|
|
104
120
|
handleUpdate({ end: newEnd });
|
|
105
121
|
}, [handleUpdate]);
|
|
106
|
-
const
|
|
122
|
+
const handleTopModeChange = useCallback((mode) => {
|
|
107
123
|
const n = nodeRef.current;
|
|
108
124
|
if (!n)
|
|
109
125
|
return;
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
height
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
const isCustom = n.height != null;
|
|
127
|
+
if (mode === 'custom' && !isCustom) {
|
|
128
|
+
// Seed from the current effective height so the geometry doesn't
|
|
129
|
+
// jump at the moment of detaching from the storey plane.
|
|
130
|
+
const seeded = resolveWallOpeningCeiling(n, useScene.getState().nodes);
|
|
131
|
+
handleUpdate({ height: Math.max(0.1, seeded) });
|
|
132
|
+
}
|
|
133
|
+
else if (mode === 'storey' && isCustom) {
|
|
134
|
+
// Absent `height` = plane-bound; the store strips undefined keys.
|
|
135
|
+
handleUpdate({ height: undefined, ...wallBaseRepairPatch(n) });
|
|
136
|
+
}
|
|
137
|
+
}, [handleUpdate]);
|
|
138
|
+
// Terrain infill only extends the bottom; it must never materialize an
|
|
139
|
+
// explicit height, or toggling it would silently detach the wall top from
|
|
140
|
+
// the storey plane. "Auto" is a re-election, so it carries the same base
|
|
141
|
+
// repair as the follows-level toggle — and the control fires on a click of
|
|
142
|
+
// the already-selected segment, so regression-era walls that DISPLAY Auto
|
|
143
|
+
// while secretly ground-pinned heal from a click on Auto itself.
|
|
144
|
+
const handleInfillChange = useCallback((mode) => {
|
|
145
|
+
const n = nodeRef.current;
|
|
146
|
+
if (!n)
|
|
147
|
+
return;
|
|
148
|
+
if (mode === 'terrain') {
|
|
149
|
+
handleUpdate({ fillToTerrain: true });
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
handleUpdate({ fillToTerrain: undefined, ...wallBaseRepairPatch(n) });
|
|
115
153
|
}, [handleUpdate]);
|
|
116
154
|
const handleClose = useCallback(() => {
|
|
117
155
|
setSelection({ selectedIds: [] });
|
|
@@ -127,6 +165,7 @@ export default function WallPanel() {
|
|
|
127
165
|
return null;
|
|
128
166
|
const length = getWallCurveLength(node);
|
|
129
167
|
const followsTerrain = node.fillToTerrain === true;
|
|
168
|
+
const isPlaneBound = node.height == null;
|
|
130
169
|
const height = node.height ?? resolvedHeightMeters ?? 2.5;
|
|
131
170
|
const thickness = node.thickness ?? 0.1;
|
|
132
171
|
const curveOffset = getClampedWallCurveOffset(node);
|
|
@@ -142,12 +181,15 @@ export default function WallPanel() {
|
|
|
142
181
|
const skirting = { ...WALL_SKIRTING_DEFAULT, ...(node.skirting ?? {}) };
|
|
143
182
|
const crown = { ...WALL_CROWN_DEFAULT, ...(node.crown ?? {}) };
|
|
144
183
|
const chairRail = { ...WALL_CHAIR_RAIL_DEFAULT, ...(node.chairRail ?? {}) };
|
|
145
|
-
return (_jsxs(PanelWrapper, { icon: "/icons/wall.webp", onClose: handleClose, title: node.name || 'Wall', width: 280, children: [_jsxs(PanelSection, { title: "Dimensions", children: [_jsx(SliderControl, { label: "Length", max: metersToLinearUnit(20, unit), min: metersToLinearUnit(0.1, unit), onChange: (value) => handleUpdateLength(linearControlValueToMeters(value, unit, { maxMeters: 20, minMeters: 0.1 })), precision: 2, step: unit === 'imperial' ? 0.1 : 0.01, unit: unitLabel, value: displayLength }), _jsx(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
{
|
|
150
|
-
|
|
184
|
+
return (_jsxs(PanelWrapper, { icon: "/icons/wall.webp", onClose: handleClose, title: node.name || 'Wall', width: 280, children: [_jsxs(PanelSection, { title: "Dimensions", children: [_jsx(SliderControl, { label: "Length", max: metersToLinearUnit(20, unit), min: metersToLinearUnit(0.1, unit), onChange: (value) => handleUpdateLength(linearControlValueToMeters(value, unit, { maxMeters: 20, 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: [
|
|
185
|
+
{ label: 'Follows level', value: 'storey' },
|
|
186
|
+
{ label: 'Custom height', value: 'custom' },
|
|
187
|
+
], 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(20, unit), min: metersToLinearUnit(0.1, unit), onChange: (v) => handleUpdate({
|
|
188
|
+
height: linearControlValueToMeters(v, unit, { maxMeters: 20, minMeters: 0.1 }),
|
|
189
|
+
}), 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: [
|
|
190
|
+
{ label: 'Auto', value: 'auto' },
|
|
191
|
+
{ label: 'Fill to terrain', value: 'terrain' },
|
|
192
|
+
], 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: "Thickness", max: metersToLinearUnit(1, unit), min: metersToLinearUnit(0.05, unit), onChange: (v) => handleUpdate({
|
|
151
193
|
thickness: linearControlValueToMeters(v, unit, {
|
|
152
194
|
maxMeters: 1,
|
|
153
195
|
minMeters: 0.05,
|
package/dist/wall/parametrics.js
CHANGED
|
@@ -18,7 +18,7 @@ export const wallParametrics = {
|
|
|
18
18
|
{ key: 'thickness', kind: 'number', unit: 'm', min: 0.05, max: 0.6, step: 0.01 },
|
|
19
19
|
// `height` may be absent (plane-bound top); the custom panel owns the
|
|
20
20
|
// Follows storey / Custom height mode switch, so this is metadata only.
|
|
21
|
-
{ key: 'height', kind: 'number', unit: 'm', min: 1.5, max:
|
|
21
|
+
{ key: 'height', kind: 'number', unit: 'm', min: 1.5, max: 20, step: 0.05 },
|
|
22
22
|
{ key: 'curveOffset', kind: 'number', unit: 'm', min: -3, max: 3, step: 0.05 },
|
|
23
23
|
],
|
|
24
24
|
},
|
package/dist/wall/system.d.ts
CHANGED
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
* bulk of the wall runtime (~820 lines in viewer).
|
|
9
9
|
* - **`WallCutout`** — cutaway-mode hide/show logic based on camera
|
|
10
10
|
* direction and `frontSide` / `backSide` interior/exterior tags.
|
|
11
|
+
* - **`WallBatchSystem`** — once a level stops changing, sews its opaque
|
|
12
|
+
* walls into one mesh per material set so a floor costs a handful of
|
|
13
|
+
* draw calls instead of one per wall face run.
|
|
11
14
|
*/
|
|
12
15
|
declare const WallSystems: () => import("react").JSX.Element;
|
|
13
16
|
export default WallSystems;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/wall/system.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/wall/system.tsx"],"names":[],"mappings":"AA0CA;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,WAAW,mCAShB,CAAA;AAED,eAAe,WAAW,CAAA"}
|
package/dist/wall/system.js
CHANGED
|
@@ -5,6 +5,7 @@ import { WallCutout, WallSystem } from '@pascal-app/viewer';
|
|
|
5
5
|
import { useFrame } from '@react-three/fiber';
|
|
6
6
|
import { buildWallTreatmentLevelData, useWallTreatmentLevelData } from './treatment-level-data';
|
|
7
7
|
import { wallTreatmentProudOffsets } from './treatments';
|
|
8
|
+
import { WallBatchSystem } from './wall-batch-system';
|
|
8
9
|
function effectiveWall(wall) {
|
|
9
10
|
const override = useLiveNodeOverrides.getState().get(wall.id);
|
|
10
11
|
return override ? { ...wall, ...override } : wall;
|
|
@@ -46,8 +47,11 @@ const WallTreatmentMiterSystem = () => {
|
|
|
46
47
|
* bulk of the wall runtime (~820 lines in viewer).
|
|
47
48
|
* - **`WallCutout`** — cutaway-mode hide/show logic based on camera
|
|
48
49
|
* direction and `frontSide` / `backSide` interior/exterior tags.
|
|
50
|
+
* - **`WallBatchSystem`** — once a level stops changing, sews its opaque
|
|
51
|
+
* walls into one mesh per material set so a floor costs a handful of
|
|
52
|
+
* draw calls instead of one per wall face run.
|
|
49
53
|
*/
|
|
50
54
|
const WallSystems = () => {
|
|
51
|
-
return (_jsxs(_Fragment, { children: [_jsx(WallTreatmentMiterSystem, {}), _jsx(WallSystem, {}), _jsx(WallCutout, {})] }));
|
|
55
|
+
return (_jsxs(_Fragment, { children: [_jsx(WallTreatmentMiterSystem, {}), _jsx(WallSystem, {}), _jsx(WallCutout, {}), _jsx(WallBatchSystem, {})] }));
|
|
52
56
|
};
|
|
53
57
|
export default WallSystems;
|
package/dist/wall/tool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/wall/tool.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/wall/tool.tsx"],"names":[],"mappings":"AA6bA,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAkf5B,CAAA;AAED,eAAe,QAAQ,CAAA"}
|
package/dist/wall/tool.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { calculateLevelMiters, collectAlignmentAnchors, DEFAULT_LEVEL_HEIGHT, emitter, getWallMiterBoundaryPoints, resolveAlignment, resolveBuildingForLevel, sceneRegistry, useScene, wallClosesRoom, } from '@pascal-app/core';
|
|
2
|
+
import { calculateLevelMiters, collectAlignmentAnchors, DEFAULT_LEVEL_HEIGHT, emitter, GROUND_SUPPORT_ID, getWallMiterBoundaryPoints, resolveAlignment, resolveBuildingForLevel, sceneRegistry, useScene, wallClosesRoom, } from '@pascal-app/core';
|
|
3
3
|
import { CursorSphere, chainEndJoinsExistingWall, clearPlacementSurface, createWallOnCurrentLevel, EDITOR_LAYER, formatAngleRadians, formatLinearMeasurement, getAngleArcToSegmentReference, getAngleToSegmentReference, getSegmentAngleReferenceAtPoint, isAlignmentGuideActive, isAngleSnapActive, isMagneticSnapActive, markToolCancelConsumed, publishHorizontalConstructionPlane, publishPlacementSurface, resampleTerrainConstructionPlane, resolveEventConstructionPlane, resolvePointerSupportSurface, snapWallDraftPointDetailed, triggerSFX, useAlignmentGuides, useEditor, useFloorplanDraftPreview, useSegmentDraftChain, useWallSnapIndicator, WALL_CONNECT_SNAP_RADIUS, WALL_JOIN_SNAP_RADIUS, } from '@pascal-app/editor';
|
|
4
4
|
import { getSceneTheme, useViewer } from '@pascal-app/viewer';
|
|
5
5
|
import { useThree } from '@react-three/fiber';
|
|
6
6
|
import { useEffect, useRef, useState } from 'react';
|
|
7
|
-
import {
|
|
7
|
+
import { DoubleSide, Vector3 } from 'three';
|
|
8
8
|
import { DraftAngleArc, DraftAxisGuides, DraftMeasurementLabel, getNearestAxisAngleLabel, } from '../shared/draft-axis-guides';
|
|
9
9
|
/**
|
|
10
10
|
* Phase 5 Stage D — wall placement tool (kind-owned).
|
|
@@ -217,14 +217,14 @@ function getDraftAngleLabels(start, end, walls, baseY, previewHeight) {
|
|
|
217
217
|
}
|
|
218
218
|
return labels;
|
|
219
219
|
}
|
|
220
|
-
function getDraftMeasurementState(start, end, walls, unit, baseY, previewHeight) {
|
|
220
|
+
function getDraftMeasurementState(start, end, walls, unit, metricNotation, baseY, previewHeight) {
|
|
221
221
|
const dx = end[0] - start[0];
|
|
222
222
|
const dz = end[1] - start[1];
|
|
223
223
|
const length = Math.hypot(dx, dz);
|
|
224
224
|
if (length < 0.01)
|
|
225
225
|
return null;
|
|
226
226
|
return {
|
|
227
|
-
lengthLabel: formatLinearMeasurement(length, unit),
|
|
227
|
+
lengthLabel: formatLinearMeasurement(length, unit, metricNotation),
|
|
228
228
|
lengthPosition: [
|
|
229
229
|
(start[0] + end[0]) / 2,
|
|
230
230
|
baseY + previewHeight + DRAFT_LABEL_Y_OFFSET,
|
|
@@ -242,14 +242,10 @@ function updateWallPreview(mesh, start, end, previewHeight, previewThickness) {
|
|
|
242
242
|
}
|
|
243
243
|
mesh.visible = true;
|
|
244
244
|
direction.normalize();
|
|
245
|
-
const geometry = new BoxGeometry(length, previewHeight, previewThickness);
|
|
246
245
|
const angle = Math.atan2(direction.z, direction.x);
|
|
247
246
|
mesh.position.set((start.x + end.x) / 2, start.y + previewHeight / 2, (start.z + end.z) / 2);
|
|
248
247
|
mesh.rotation.y = -angle;
|
|
249
|
-
|
|
250
|
-
mesh.geometry.dispose();
|
|
251
|
-
}
|
|
252
|
-
mesh.geometry = geometry;
|
|
248
|
+
mesh.scale.set(length, previewHeight, previewThickness);
|
|
253
249
|
}
|
|
254
250
|
function getLevelWalls(levelId, nodes) {
|
|
255
251
|
if (!levelId)
|
|
@@ -295,6 +291,7 @@ function getBelowLevelWalls() {
|
|
|
295
291
|
}
|
|
296
292
|
export const WallTool = () => {
|
|
297
293
|
const unit = useViewer((state) => state.unit);
|
|
294
|
+
const metricNotation = useViewer((state) => state.metricNotation);
|
|
298
295
|
const isDark = useViewer((state) => getSceneTheme(state.sceneTheme).appearance === 'dark');
|
|
299
296
|
const activeLevelId = useViewer((state) => state.selection.levelId);
|
|
300
297
|
const activeLevelHeight = useScene((state) => {
|
|
@@ -512,7 +509,7 @@ export const WallTool = () => {
|
|
|
512
509
|
}
|
|
513
510
|
previousWallEnd = currentWallEnd;
|
|
514
511
|
updateWallPreview(wallPreviewRef.current, startingPoint.current, endingPoint.current, previewHeightRef.current, previewThicknessRef.current);
|
|
515
|
-
setDraftMeasurement(getDraftMeasurementState([startingPoint.current.x, startingPoint.current.z], snappedLocal, walls, unit, startingPoint.current.y, previewHeightRef.current));
|
|
512
|
+
setDraftMeasurement(getDraftMeasurementState([startingPoint.current.x, startingPoint.current.z], snappedLocal, walls, unit, metricNotation, startingPoint.current.y, previewHeightRef.current));
|
|
516
513
|
}
|
|
517
514
|
else {
|
|
518
515
|
const hoverPlane = resampleTerrainConstructionPlane(resolveEventConstructionPlane(event, pointed), gridPosition);
|
|
@@ -564,13 +561,9 @@ export const WallTool = () => {
|
|
|
564
561
|
angleLabel: null,
|
|
565
562
|
});
|
|
566
563
|
triggerSFX('sfx:structure-build-start');
|
|
567
|
-
// Visibility is owned by `updateWallPreview
|
|
568
|
-
//
|
|
569
|
-
//
|
|
570
|
-
// mesh's empty `<shapeGeometry/>` placeholder, which WebGPU
|
|
571
|
-
// flags as "Vertex buffer slot 0 ... was not set" on the
|
|
572
|
-
// first frame after click. Leaving it false until the next
|
|
573
|
-
// `onGridMove` writes a real BoxGeometry skips that frame.
|
|
564
|
+
// Visibility is owned by `updateWallPreview`. Leave the
|
|
565
|
+
// unit box hidden until the first pointer move scales and
|
|
566
|
+
// positions it for the active segment.
|
|
574
567
|
setDraftMeasurement(null);
|
|
575
568
|
}
|
|
576
569
|
else if (buildingState.current === 1) {
|
|
@@ -586,11 +579,17 @@ export const WallTool = () => {
|
|
|
586
579
|
const dz = snappedEnd[1] - startingPoint.current.z;
|
|
587
580
|
if (dx * dx + dz * dz < 0.01 * 0.01)
|
|
588
581
|
return;
|
|
582
|
+
// A ground(terrain)-hosted chain keeps its frozen construction plane;
|
|
583
|
+
// any other chain re-resolves the aimed surface per commit so a later
|
|
584
|
+
// segment can still elect the slab it visibly crosses instead of
|
|
585
|
+
// being capped at the first click's elevation.
|
|
586
|
+
const draftPlane = constructionPlane.current;
|
|
587
|
+
const commitPointed = draftPlane?.supportSlabId === GROUND_SUPPORT_ID ? null : pointedSurfaceFor(event);
|
|
589
588
|
// Both start and end are building-local ✓
|
|
590
589
|
const createdWall = createWallOnCurrentLevel([startingPoint.current.x, startingPoint.current.z], snappedEnd, {
|
|
591
|
-
supportCap:
|
|
592
|
-
preferredSupportSlabId:
|
|
593
|
-
constructionElevation:
|
|
590
|
+
supportCap: commitPointed ? commitPointed.elevation : (draftPlane?.elevation ?? null),
|
|
591
|
+
preferredSupportSlabId: draftPlane?.supportSlabId ?? null,
|
|
592
|
+
constructionElevation: draftPlane?.elevation ?? null,
|
|
594
593
|
constructionHeight: previewHeightRef.current,
|
|
595
594
|
});
|
|
596
595
|
if (!createdWall)
|
|
@@ -642,11 +641,9 @@ export const WallTool = () => {
|
|
|
642
641
|
y: draftY,
|
|
643
642
|
angleLabel: null,
|
|
644
643
|
});
|
|
645
|
-
// Hide the preview until the next `onGridMove`
|
|
646
|
-
//
|
|
647
|
-
//
|
|
648
|
-
// freshly-committed real wall, producing a brief
|
|
649
|
-
// double-paint at the new wall's position.
|
|
644
|
+
// Hide the preview until the next `onGridMove` scales and
|
|
645
|
+
// repositions it. Otherwise the prior segment stays visible
|
|
646
|
+
// for a frame on top of the freshly committed wall.
|
|
650
647
|
if (wallPreviewRef.current) {
|
|
651
648
|
wallPreviewRef.current.visible = false;
|
|
652
649
|
}
|
|
@@ -674,7 +671,7 @@ export const WallTool = () => {
|
|
|
674
671
|
draftPreview.setWallDraftStart(null);
|
|
675
672
|
draftPreview.setWallDraftEnd(null);
|
|
676
673
|
};
|
|
677
|
-
}, [unit]);
|
|
678
|
-
return (_jsxs("group", { children: [_jsx(DraftAxisGuides, { guide: axisGuide, labelColor: measurementColor, labelShadowColor: measurementShadowColor }), _jsx(CursorSphere, { height: previewHeight, ref: cursorRef }), _jsxs("mesh", { layers: EDITOR_LAYER, ref: wallPreviewRef, renderOrder: 1, visible: false, children: [_jsx("
|
|
674
|
+
}, [unit, metricNotation]);
|
|
675
|
+
return (_jsxs("group", { children: [_jsx(DraftAxisGuides, { guide: axisGuide, labelColor: measurementColor, labelShadowColor: measurementShadowColor }), _jsx(CursorSphere, { height: previewHeight, ref: cursorRef }), _jsxs("mesh", { layers: EDITOR_LAYER, ref: wallPreviewRef, renderOrder: 1, visible: false, children: [_jsx("boxGeometry", {}), _jsx("meshBasicMaterial", { color: "#818cf8", depthTest: false, depthWrite: false, opacity: 0.5, side: DoubleSide, transparent: true })] }), draftMeasurement && (_jsxs(_Fragment, { children: [_jsx(DraftMeasurementLabel, { color: measurementColor, label: draftMeasurement.lengthLabel, position: draftMeasurement.lengthPosition, shadowColor: measurementShadowColor }), draftMeasurement.angleLabels.map((angleLabel) => (_jsxs("group", { children: [_jsx(DraftAngleArc, { arc: angleLabel.arc, color: measurementColor }), _jsx(DraftMeasurementLabel, { color: measurementColor, label: angleLabel.label, position: angleLabel.position, shadowColor: measurementShadowColor })] }, angleLabel.id)))] }))] }));
|
|
679
676
|
};
|
|
680
677
|
export default WallTool;
|