diff --git a/packages/editor/src/components/tools/wall/wall-drafting.ts b/packages/editor/src/components/tools/wall/wall-drafting.ts index a69256af..c8b28a00 100644 --- a/packages/editor/src/components/tools/wall/wall-drafting.ts +++ b/packages/editor/src/components/tools/wall/wall-drafting.ts @@ -1,40 +1,32 @@ import { useScene, type WallNode, WallNode as WallSchema } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' import { sfxEmitter } from '../../../lib/sfx-bus' - 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 - +export const WALL_MIN_LENGTH = 0.5 function distanceSquared(a: WallPlanPoint, b: WallPlanPoint): number { const dx = a[0] - b[0] const dz = a[1] - b[1] return dx * dx + dz * dz } - function snapScalarToGrid(value: number, step = WALL_GRID_STEP): number { return Math.round(value / step) * step } - export function snapPointToGrid(point: WallPlanPoint, step = WALL_GRID_STEP): WallPlanPoint { return [snapScalarToGrid(point[0], step), snapScalarToGrid(point[1], step)] } - export function snapPointTo45Degrees(start: WallPlanPoint, cursor: WallPlanPoint): 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 distance = Math.sqrt(dx * dx + dz * dz) - return snapPointToGrid([ start[0] + Math.cos(snappedAngle) * distance, start[1] + Math.sin(snappedAngle) * distance, ]) } - function projectPointOntoWall(point: WallPlanPoint, wall: WallNode): WallPlanPoint | null { const [x1, z1] = wall.start const [x2, z2] = wall.end @@ -44,15 +36,12 @@ function projectPointOntoWall(point: WallPlanPoint, wall: WallNode): WallPlanPoi if (lengthSquared < 1e-9) { return null } - const t = ((point[0] - x1) * dx + (point[1] - z1) * dz) / lengthSquared if (t <= 0 || t >= 1) { return null } - return [x1 + dx * t, z1 + dz * t] } - export function findWallSnapTarget( point: WallPlanPoint, walls: WallNode[], @@ -62,12 +51,10 @@ export function findWallSnapTarget( const radiusSquared = (options?.radius ?? WALL_JOIN_SNAP_RADIUS) ** 2 let bestTarget: WallPlanPoint | null = null let bestDistanceSquared = Number.POSITIVE_INFINITY - for (const wall of walls) { if (ignoreWallIds.has(wall.id)) { continue } - const candidates: Array = [ wall.start, wall.end, @@ -77,7 +64,6 @@ export function findWallSnapTarget( if (!candidate) { continue } - const candidateDistanceSquared = distanceSquared(point, candidate) if ( candidateDistanceSquared > radiusSquared || @@ -85,15 +71,12 @@ export function findWallSnapTarget( ) { continue } - bestTarget = candidate bestDistanceSquared = candidateDistanceSquared } } - return bestTarget } - export function snapWallDraftPoint(args: { point: WallPlanPoint walls: WallNode[] @@ -103,38 +86,31 @@ export function snapWallDraftPoint(args: { }): WallPlanPoint { const { point, walls, start, angleSnap = false, ignoreWallIds } = args const basePoint = start && angleSnap ? snapPointTo45Degrees(start, point) : snapPointToGrid(point) - return ( findWallSnapTarget(basePoint, walls, { ignoreWallIds, }) ?? basePoint ) } - export function isWallLongEnough(start: WallPlanPoint, end: WallPlanPoint): boolean { return distanceSquared(start, end) >= WALL_MIN_LENGTH * WALL_MIN_LENGTH } - export function createWallOnCurrentLevel( start: WallPlanPoint, end: WallPlanPoint, ): WallNode | null { const currentLevelId = useViewer.getState().selection.levelId const { createNode, nodes } = useScene.getState() - if (!(currentLevelId && isWallLongEnough(start, end))) { return null } - const wallCount = Object.values(nodes).filter((node) => node.type === 'wall').length const wall = WallSchema.parse({ name: `Wall ${wallCount + 1}`, start, end, }) - createNode(wall, currentLevelId) sfxEmitter.emit('sfx:structure-build') - return wall } diff --git a/packages/editor/src/components/tools/wall/wall-tool.tsx b/packages/editor/src/components/tools/wall/wall-tool.tsx index 4a58c4ab..c5fa0f33 100644 --- a/packages/editor/src/components/tools/wall/wall-tool.tsx +++ b/packages/editor/src/components/tools/wall/wall-tool.tsx @@ -5,7 +5,7 @@ import { DoubleSide, type Group, type Mesh, Shape, ShapeGeometry, Vector3 } from import { EDITOR_LAYER } from '../../../lib/constants' import { sfxEmitter } from '../../../lib/sfx-bus' import { CursorSphere } from '../shared/cursor-sphere' -import { createWallOnCurrentLevel, snapWallDraftPoint, type WallPlanPoint } from './wall-drafting' +import { createWallOnCurrentLevel, snapWallDraftPoint, WALL_MIN_LENGTH, type WallPlanPoint } from './wall-drafting' const WALL_HEIGHT = 2.5 @@ -17,7 +17,7 @@ const updateWallPreview = (mesh: Mesh, start: Vector3, end: Vector3) => { const direction = new Vector3(end.x - start.x, 0, end.z - start.z) const length = direction.length() - if (length < 0.01) { + if (length < WALL_MIN_LENGTH) { mesh.visible = false return } @@ -142,7 +142,7 @@ export const WallTool: React.FC = () => { endingPoint.current.set(snappedEnd[0], event.position[1], snappedEnd[1]) const dx = endingPoint.current.x - startingPoint.current.x const dz = endingPoint.current.z - startingPoint.current.z - if (dx * dx + dz * dz < 0.01 * 0.01) return + if (dx * dx + dz * dz < WALL_MIN_LENGTH * WALL_MIN_LENGTH) return createWallOnCurrentLevel( [startingPoint.current.x, startingPoint.current.z], [endingPoint.current.x, endingPoint.current.z],