Respect active grid snap for wall dragging and angle

This commit is contained in:
sudhir
2026-04-17 10:56:34 +05:30
parent 4edf45f7c9
commit 096f4c161a
3 changed files with 35 additions and 17 deletions
@@ -18,10 +18,7 @@ import { markToolCancelConsumed } from '../../../hooks/use-keyboard'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import { CursorSphere } from '../shared/cursor-sphere'
function snap(value: number) {
return Math.round(value * 2) / 2
}
import { getWallGridStep, snapScalarToGrid } from './wall-drafting'
export const CurveWallTool: React.FC<{ node: WallNode }> = ({ node }) => {
const activatedAtRef = useRef<number>(Date.now())
@@ -76,15 +73,22 @@ export const CurveWallTool: React.FC<{ node: WallNode }> = ({ node }) => {
}
const onGridMove = (event: GridEvent) => {
const localX = shiftPressedRef.current ? event.localPosition[0] : snap(event.localPosition[0])
const localZ = shiftPressedRef.current ? event.localPosition[2] : snap(event.localPosition[2])
const snapStep = getWallGridStep()
const localX = shiftPressedRef.current
? event.localPosition[0]
: snapScalarToGrid(event.localPosition[0], snapStep)
const localZ = shiftPressedRef.current
? event.localPosition[2]
: snapScalarToGrid(event.localPosition[2], snapStep)
const offsetFromMidpoint =
-(
(localX - chord.midpoint.x) * chord.normal.x +
(localZ - chord.midpoint.y) * chord.normal.y
)
const snappedOffset = shiftPressedRef.current ? offsetFromMidpoint : snap(offsetFromMidpoint)
const snappedOffset = shiftPressedRef.current
? offsetFromMidpoint
: snapScalarToGrid(offsetFromMidpoint, snapStep)
const nextCurveOffset = normalizeWallCurveOffset(node, Math.max(-maxCurveOffset, Math.min(maxCurveOffset, snappedOffset)))
if (
@@ -7,10 +7,7 @@ import { markToolCancelConsumed } from '../../../hooks/use-keyboard'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import { CursorSphere } from '../shared/cursor-sphere'
function snap(value: number) {
return Math.round(value * 2) / 2
}
import { getWallGridStep, snapScalarToGrid } from './wall-drafting'
function rotateVector([x, z]: [number, number], angle: number): [number, number] {
const cos = Math.cos(angle)
@@ -183,8 +180,9 @@ export const MoveWallTool: React.FC<{ node: WallNode }> = ({ node }) => {
const onGridMove = (event: GridEvent) => {
const rawX = event.localPosition[0]
const rawZ = event.localPosition[2]
const localX = shiftPressedRef.current ? rawX : snap(rawX)
const localZ = shiftPressedRef.current ? rawZ : snap(rawZ)
const snapStep = getWallGridStep()
const localX = shiftPressedRef.current ? rawX : snapScalarToGrid(rawX, snapStep)
const localZ = shiftPressedRef.current ? rawZ : snapScalarToGrid(rawZ, snapStep)
if (
previousGridPosRef.current &&
@@ -18,6 +18,14 @@ export type WallPlanPoint = [number, number]
export const WALL_GRID_STEP = 0.5
export const WALL_JOIN_SNAP_RADIUS = 0.35
export const WALL_MIN_LENGTH = 0.01
const DEFAULT_WALL_ANGLE_SNAP_STEP = Math.PI / 4
const WALL_ANGLE_SNAP_BY_GRID_STEP: Record<number, number> = {
0.5: Math.PI / 4,
0.25: Math.PI / 8,
0.1: Math.PI / 12,
0.05: Math.PI / 36,
}
type WallSplitIntersection = {
wallId: WallNode['id']
@@ -30,11 +38,11 @@ function distanceSquared(a: WallPlanPoint, b: WallPlanPoint): number {
return dx * dx + dz * dz
}
function getWallGridStep(): number {
export function getWallGridStep(): number {
return useEditor.getState().gridSnapStep
}
function snapScalarToGrid(value: number, step = WALL_GRID_STEP): number {
export function snapScalarToGrid(value: number, step = WALL_GRID_STEP): number {
return Math.round(value / step) * step
}
@@ -46,11 +54,12 @@ export function snapPointTo45Degrees(
start: WallPlanPoint,
cursor: WallPlanPoint,
step = WALL_GRID_STEP,
angleStep = DEFAULT_WALL_ANGLE_SNAP_STEP,
): WallPlanPoint {
const dx = cursor[0] - start[0]
const dz = cursor[1] - start[1]
const angle = Math.atan2(dz, dx)
const snappedAngle = Math.round(angle / (Math.PI / 4)) * (Math.PI / 4)
const snappedAngle = Math.round(angle / angleStep) * angleStep
const distance = Math.sqrt(dx * dx + dz * dz)
return snapPointToGrid([
@@ -59,6 +68,10 @@ export function snapPointTo45Degrees(
], step)
}
export function getWallAngleSnapStep(step = getWallGridStep()): number {
return WALL_ANGLE_SNAP_BY_GRID_STEP[step] ?? DEFAULT_WALL_ANGLE_SNAP_STEP
}
function projectPointOntoWall(point: WallPlanPoint, wall: WallNode): WallPlanPoint | null {
const [x1, z1] = wall.start
const [x2, z2] = wall.end
@@ -358,8 +371,11 @@ export function snapWallDraftPoint(args: {
}): WallPlanPoint {
const { point, walls, start, angleSnap = false, ignoreWallIds } = args
const step = getWallGridStep()
const angleStep = getWallAngleSnapStep(step)
const basePoint =
start && angleSnap ? snapPointTo45Degrees(start, point, step) : snapPointToGrid(point, step)
start && angleSnap
? snapPointTo45Degrees(start, point, step, angleStep)
: snapPointToGrid(point, step)
return (
findWallSnapTarget(basePoint, walls, {