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
@@ -148,3 +148,52 @@ describe("331-1 각도 고정 → 길이", () => {
expect(getActiveToolActor()?.getSnapshot()?.context.values).toHaveLength(2);
});
});
/** 선 (x1,y1)-(x2,y2) 하나를 키보드로 그리고 고름 */
const drawAndSelect = (x1: number, y1: number, x2: number, y2: number) => {
type(controller, "l");
type(controller, `${x1},${y1}`);
type(controller, `${x2},${y2}`);
key(controller, "Escape");
key(controller, "Escape");
setSelectedEntityIds(getEntities().map((entity) => entity.id));
};
describe("331-2 이동 · 복사 · 회전 키보드 값", () => {
it("MOVE · 0,0 · @10,0 → 오른쪽 10", () => {
drawAndSelect(0, 0, 20, 0);
type(controller, "move");
type(controller, "0,0");
type(controller, "@10,0");
const drawn = lines();
expect(drawn).toHaveLength(1);
expectXy(drawn[0].start, 10, 0);
expectXy(drawn[0].end, 30, 0);
});
it("COPY · 0,0 · <0 · 5 → 원본 + 오른쪽 5", () => {
drawAndSelect(0, 0, 20, 0);
type(controller, "copy");
type(controller, "0,0");
type(controller, "<0");
type(controller, "5");
const starts = lines()
.map((segment) => segment.start.x)
.sort((a, b) => a - b);
expect(starts).toHaveLength(2);
expect(starts[0]).toBeCloseTo(0, 3);
expect(starts[1]).toBeCloseTo(5, 3);
});
it("ROTATE · 0,0 · 90 → 반시계 90°", () => {
drawAndSelect(10, 0, 20, 0);
type(controller, "rotate");
type(controller, "0,0");
type(controller, "90");
const drawn = lines();
expect(drawn).toHaveLength(1);
expectXy(drawn[0].start, 0, 10);
expectXy(drawn[0].end, 0, 20);
expect(toast.error).not.toHaveBeenCalled();
});
});