diff --git a/packages/editor/src/components/tools/wall/curve-wall-tool.tsx b/packages/editor/src/components/tools/wall/curve-wall-tool.tsx index 374911bb..6703acec 100644 --- a/packages/editor/src/components/tools/wall/curve-wall-tool.tsx +++ b/packages/editor/src/components/tools/wall/curve-wall-tool.tsx @@ -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(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 ( diff --git a/packages/editor/src/components/tools/wall/move-wall-tool.tsx b/packages/editor/src/components/tools/wall/move-wall-tool.tsx index 8d466f6e..28e9cbee 100644 --- a/packages/editor/src/components/tools/wall/move-wall-tool.tsx +++ b/packages/editor/src/components/tools/wall/move-wall-tool.tsx @@ -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 && diff --git a/packages/editor/src/components/tools/wall/wall-drafting.ts b/packages/editor/src/components/tools/wall/wall-drafting.ts index ab017197..b6e18c1a 100755 --- a/packages/editor/src/components/tools/wall/wall-drafting.ts +++ b/packages/editor/src/components/tools/wall/wall-drafting.ts @@ -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 = { + 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, {