Respect active grid snap for wall dragging and angle
This commit is contained in:
@@ -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, {
|
||||||
|
|||||||
Reference in New Issue
Block a user