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