feat(CAD): 331-2 이동 · 복사 · 회전 키보드 값

- 이동 · 복사 — 기준점 `x,y` · 둘째 점 거리 · `x,y` · `@x,y` · 각도 고정 · 미리보기도 같은 점 계산(getPointFromEvent)
- 회전 — 기준점 `x,y` · 각도 숫자 바로(반시계 +)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
This commit is contained in:
2026-10-15 12:36:19 +09:00
co-authored by Claude Opus 5.5
parent 8e96880880
commit 32ddaa8064
4 changed files with 154 additions and 26 deletions
@@ -11,7 +11,8 @@ import {
setShouldDrawHelpers,
} from '../state';
import { Tool } from '../tools';
import type { DrawEvent, MouseClickEvent, StateEvent, ToolContext } from './tool.types';
import type { DrawEvent, PointInputEvent, StateEvent, ToolContext } from './tool.types';
import { getPointFromEvent } from '../helpers/get-point-from-event';
import { assign, createMachine, sendTo } from 'xstate';
import { selectToolStateMachine } from './select-tool';
import type { Entity } from '../entities/Entity';
@@ -148,6 +149,10 @@ export const moveToolStateMachine = createMachine(
actions: [MoveAction.RECORD_START_POINT, MoveAction.COPY_SELECTION_BEFORE_MOVE],
target: MoveState.WAITING_FOR_END_MOVE_POINT,
},
ABSOLUTE_POINT_INPUT: {
actions: [MoveAction.RECORD_START_POINT, MoveAction.COPY_SELECTION_BEFORE_MOVE],
target: MoveState.WAITING_FOR_END_MOVE_POINT,
},
ESC: {
actions: MoveAction.DESELECT_ENTITIES,
target: MoveState.INIT,
@@ -167,6 +172,18 @@ export const moveToolStateMachine = createMachine(
actions: [MoveAction.MOVE_SELECTION, MoveAction.DESELECT_ENTITIES],
target: MoveState.WAITING_FOR_SELECTION,
},
NUMBER_INPUT: {
actions: [MoveAction.MOVE_SELECTION, MoveAction.DESELECT_ENTITIES],
target: MoveState.WAITING_FOR_SELECTION,
},
ABSOLUTE_POINT_INPUT: {
actions: [MoveAction.MOVE_SELECTION, MoveAction.DESELECT_ENTITIES],
target: MoveState.WAITING_FOR_SELECTION,
},
RELATIVE_POINT_INPUT: {
actions: [MoveAction.MOVE_SELECTION, MoveAction.DESELECT_ENTITIES],
target: MoveState.WAITING_FOR_SELECTION,
},
ESC: {
actions: MoveAction.RESTORE_ORIGINAL_ENTITIES,
target: MoveState.INIT,
@@ -192,10 +209,9 @@ export const moveToolStateMachine = createMachine(
setShouldDrawHelpers(true);
},
[MoveAction.RECORD_START_POINT]: assign(({ event }) => {
setAngleGuideOriginPoint((event as MouseClickEvent).worldMouseLocation);
return {
startPoint: (event as MouseClickEvent).worldMouseLocation,
};
const startPoint = getPointFromEvent(null, event as PointInputEvent);
setAngleGuideOriginPoint(startPoint);
return { startPoint };
}),
[MoveAction.COPY_SELECTION_BEFORE_MOVE]: assign(({ context }) => {
const selectedEntities = getSelectedEntities();
@@ -211,7 +227,9 @@ export const moveToolStateMachine = createMachine(
return {
startPoint: context.startPoint,
// Make a copy of the selected entities before moving them, so we can restore them when the user cancels the move action
originalSelectedEntities: compact(selectedEntities.map((entity) => cloneKeepingLook(entity, true))),
originalSelectedEntities: compact(
selectedEntities.map((entity) => cloneKeepingLook(entity, true))
),
movedEntities: selectedEntities,
};
}),
@@ -220,11 +238,13 @@ export const moveToolStateMachine = createMachine(
throw new Error('[MOVE] Calling draw temp move line without a start point');
}
const endPointTemp = (event as DrawEvent).drawController.getWorldMouseLocation();
const endPointTemp = getPointFromEvent(context.startPoint, event as DrawEvent);
// Move the entities to the new location
// Draw all selected entities according to translation vector, so the user gets visual feedback of where the entities will be moved;
const movedEntities = context.originalSelectedEntities.map((entity) => cloneKeepingLook(entity, true));
const movedEntities = context.originalSelectedEntities.map((entity) =>
cloneKeepingLook(entity, true)
);
moveEntities(
movedEntities,
endPointTemp.x - context.startPoint.x,
@@ -248,7 +268,8 @@ export const moveToolStateMachine = createMachine(
}
// Move the entities one final time
const currentEndPoint = (event as MouseClickEvent).worldMouseLocation;
// 클릭 · 거리 · 절대 · 상대 좌표(키보드)
const currentEndPoint = getPointFromEvent(context.startPoint, event as PointInputEvent);
moveEntities(
context.originalSelectedEntities,
currentEndPoint.x - context.startPoint.x,