fix(editor): 2D slab/zone/ceiling drafting honors the active snapping mode
The polygon-draft snap path used the legacy model: bypassSnap = shiftPressed and angleSnap = pointCount > 0 && !bypassSnap, so the 15deg angle lock engaged after the first vertex regardless of mode — hijacking grid/lines/off into angle-snap even though the HUD chip showed the right mode. Migrate all three placement paths (move preview, single-click vertex, double- click close) to the unified model: angleSnap = isAngleSnapActive(); grid flows through snapToHalf (step 0 in non-grid modes); wall-snap/alignment already gates on isMagneticSnapActive(). Behavior now matches the chip — grid quantizes, angles locks 15deg rays, lines snaps to walls/alignment, off is free. Drop the now-dead bypassSnap param from snapPolygonDraftPoint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a769b45756
commit
bc9e075b2d
@@ -2167,15 +2167,14 @@ function snapPolygonDraftPoint({
|
||||
point,
|
||||
start,
|
||||
angleSnap,
|
||||
bypassSnap,
|
||||
}: {
|
||||
point: WallPlanPoint
|
||||
start?: WallPlanPoint
|
||||
angleSnap: boolean
|
||||
bypassSnap?: boolean
|
||||
}): WallPlanPoint {
|
||||
if (bypassSnap) return point
|
||||
|
||||
// `snapToHalf`'s default step is 0 in any non-`grid` mode, so the grid branch
|
||||
// passes the raw point through for `lines` / `off` (where wall-snap /
|
||||
// alignment, run by the caller, takes over) — no explicit bypass needed.
|
||||
if (!(start && angleSnap)) {
|
||||
return [snapToHalf(point[0]), snapToHalf(point[1])]
|
||||
}
|
||||
@@ -8624,24 +8623,23 @@ export function FloorplanPanel({
|
||||
}
|
||||
|
||||
if (isCeilingBuildActive) {
|
||||
const bypassSnap = shiftPressed || event.shiftKey
|
||||
// Polygon vertex: grid (snapToHalf) or 15° angle snap from the
|
||||
// previous vertex. Wall magnetic snap may still win, while
|
||||
// generic alignment runs only when angle snap is OFF (first vertex,
|
||||
// or Shift held) so it does not pull a locked angle sideways.
|
||||
const angleSnap = ceilingDraftPoints.length > 0 && !bypassSnap
|
||||
// Polygon vertex snapping is governed by the active snapping mode (the
|
||||
// chip on the right): `grid` quantizes via `snapToHalf` (whose step is
|
||||
// 0 — i.e. off — in any non-grid mode), `angles` locks to 15° rays from
|
||||
// the previous vertex, `lines` pulls onto wall corners / alignment
|
||||
// guides, `off` is free. No Shift hold-to-bypass; Alt forces (skips
|
||||
// alignment).
|
||||
const angleSnap = ceilingDraftPoints.length > 0 && isAngleSnapActive()
|
||||
const fallbackPoint = snapPolygonDraftPoint({
|
||||
point: planPoint,
|
||||
start: ceilingDraftPoints[ceilingDraftPoints.length - 1],
|
||||
angleSnap,
|
||||
bypassSnap,
|
||||
})
|
||||
const snappedPoint = resolveCeilingPlanPointSnap({
|
||||
rawPoint: planPoint,
|
||||
fallbackPoint,
|
||||
levelId,
|
||||
altKey: event.altKey,
|
||||
shiftKey: bypassSnap,
|
||||
align: !angleSnap,
|
||||
}).point
|
||||
|
||||
@@ -8719,13 +8717,15 @@ export function FloorplanPanel({
|
||||
// the local polygon-draft state actually updates as the cursor
|
||||
// moves (the catch-all would otherwise swallow the move event).
|
||||
if (isPolygonBuildActive) {
|
||||
const bypassSnap = shiftPressed || event.shiftKey
|
||||
const angleSnap = activePolygonDraftPoints.length > 0 && !bypassSnap
|
||||
// Mode-driven (matches the chip): `grid` quantizes (`snapToHalf`'s step
|
||||
// is 0 in non-grid modes), `angles` locks 15° rays from the previous
|
||||
// vertex, `lines` snaps onto wall corners / alignment guides, `off` is
|
||||
// free. No Shift bypass; Alt forces (skips alignment).
|
||||
const angleSnap = activePolygonDraftPoints.length > 0 && isAngleSnapActive()
|
||||
const fallbackPoint = snapPolygonDraftPoint({
|
||||
point: planPoint,
|
||||
start: activePolygonDraftPoints[activePolygonDraftPoints.length - 1],
|
||||
angleSnap,
|
||||
bypassSnap,
|
||||
})
|
||||
let snappedPoint = fallbackPoint
|
||||
if (isSlabBuildActive) {
|
||||
@@ -8734,14 +8734,13 @@ export function FloorplanPanel({
|
||||
fallbackPoint,
|
||||
levelId,
|
||||
altKey: event.altKey,
|
||||
shiftKey: bypassSnap,
|
||||
align: !angleSnap,
|
||||
}).point
|
||||
} else if (angleSnap) {
|
||||
useAlignmentGuides.getState().clear()
|
||||
} else {
|
||||
snappedPoint = alignFloorplanDraftPoint(fallbackPoint, {
|
||||
bypass: event.altKey || bypassSnap,
|
||||
bypass: event.altKey || !isMagneticSnapActive(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8751,7 +8750,7 @@ export function FloorplanPanel({
|
||||
|
||||
setCursorPoint((previousPoint) => {
|
||||
const hasChanged = !(previousPoint && pointsEqual(previousPoint, snappedPoint))
|
||||
if (!bypassSnap && hasChanged && activePolygonDraftPoints.length > 0) {
|
||||
if (hasChanged && activePolygonDraftPoints.length > 0) {
|
||||
sfxEmitter.emit('sfx:grid-snap')
|
||||
}
|
||||
return snappedPoint
|
||||
@@ -9396,13 +9395,11 @@ export function FloorplanPanel({
|
||||
return
|
||||
}
|
||||
|
||||
const bypassSnap = shiftPressed || event.shiftKey
|
||||
const angleSnap = activePolygonDraftPoints.length > 0 && !bypassSnap
|
||||
const angleSnap = activePolygonDraftPoints.length > 0 && isAngleSnapActive()
|
||||
const fallbackPoint = snapPolygonDraftPoint({
|
||||
point: planPoint,
|
||||
start: activePolygonDraftPoints[activePolygonDraftPoints.length - 1],
|
||||
angleSnap,
|
||||
bypassSnap,
|
||||
})
|
||||
|
||||
if (isCeilingBuildActive) {
|
||||
@@ -9411,7 +9408,6 @@ export function FloorplanPanel({
|
||||
fallbackPoint,
|
||||
levelId,
|
||||
altKey: event.altKey,
|
||||
shiftKey: bypassSnap,
|
||||
align: !angleSnap,
|
||||
}).point
|
||||
emitFloorplanGridEvent('double-click', snappedPoint, event)
|
||||
@@ -9427,7 +9423,6 @@ export function FloorplanPanel({
|
||||
fallbackPoint,
|
||||
levelId,
|
||||
altKey: event.altKey,
|
||||
shiftKey: bypassSnap,
|
||||
align: !angleSnap,
|
||||
}).point
|
||||
// Slab is registry-driven: forward the double-click so the 3D tool
|
||||
@@ -9448,7 +9443,6 @@ export function FloorplanPanel({
|
||||
isRoofBuildActive,
|
||||
isZoneBuildActive,
|
||||
levelId,
|
||||
shiftPressed,
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@ type UseFloorplanBackgroundPlacementArgs = {
|
||||
point: WallPlanPoint
|
||||
start?: WallPlanPoint
|
||||
angleSnap: boolean
|
||||
bypassSnap?: boolean
|
||||
}) => WallPlanPoint
|
||||
toPoint2D: (point: WallPlanPoint) => { x: number; y: number }
|
||||
walls: WallNode[]
|
||||
@@ -161,24 +160,21 @@ export function useFloorplanBackgroundPlacement({
|
||||
}
|
||||
|
||||
if (isCeilingBuildActive) {
|
||||
const bypassSnap = shiftPressed || event.shiftKey
|
||||
// Align the committed vertex the same way the move-preview did, so
|
||||
// the placed point matches what the user saw. Wall magnetic snap may
|
||||
// still win; generic alignment is skipped when angle snap owns the
|
||||
// vertex (matches the move branch).
|
||||
const angleSnap = ceilingDraftPoints.length > 0 && !bypassSnap
|
||||
// Align the committed vertex the same way the move-preview did, so the
|
||||
// placed point matches what the user saw — mode-driven (the chip):
|
||||
// `grid` quantizes, `angles` locks 15° rays, `lines` snaps onto walls /
|
||||
// alignment, `off` is free. Alt forces (skips alignment).
|
||||
const angleSnap = ceilingDraftPoints.length > 0 && isAngleSnapActive()
|
||||
const fallbackPoint = snapPolygonDraftPoint({
|
||||
point: planPoint,
|
||||
start: ceilingDraftPoints[ceilingDraftPoints.length - 1],
|
||||
angleSnap,
|
||||
bypassSnap,
|
||||
})
|
||||
const snappedPoint = resolveCeilingPlanPointSnap({
|
||||
rawPoint: planPoint,
|
||||
fallbackPoint,
|
||||
levelId,
|
||||
altKey: event.altKey,
|
||||
shiftKey: bypassSnap,
|
||||
align: !angleSnap,
|
||||
}).point
|
||||
|
||||
@@ -272,13 +268,11 @@ export function useFloorplanBackgroundPlacement({
|
||||
// swallow the click and skip local draft state updates — leaving
|
||||
// the 2D draft polygon invisible while the 3D tool builds fine).
|
||||
if (isPolygonBuildActive) {
|
||||
const bypassSnap = shiftPressed || event.shiftKey
|
||||
const angleSnap = activePolygonDraftPoints.length > 0 && !bypassSnap
|
||||
const angleSnap = activePolygonDraftPoints.length > 0 && isAngleSnapActive()
|
||||
const fallbackPoint = snapPolygonDraftPoint({
|
||||
point: planPoint,
|
||||
start: activePolygonDraftPoints[activePolygonDraftPoints.length - 1],
|
||||
angleSnap,
|
||||
bypassSnap,
|
||||
})
|
||||
let snappedPoint = fallbackPoint
|
||||
if (isSlabBuildActive) {
|
||||
@@ -287,12 +281,11 @@ export function useFloorplanBackgroundPlacement({
|
||||
fallbackPoint,
|
||||
levelId,
|
||||
altKey: event.altKey,
|
||||
shiftKey: bypassSnap,
|
||||
align: !angleSnap,
|
||||
}).point
|
||||
} else if (!angleSnap) {
|
||||
snappedPoint = alignFloorplanDraftPoint(fallbackPoint, {
|
||||
bypass: event.altKey || bypassSnap,
|
||||
bypass: event.altKey || !isMagneticSnapActive(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user