/** * 점 물음 보조(337 설계 1-4 · 2-5 ④ · 가-2) — 한 번 스냅 이름 · FROM · M2P(MTP) · `@`(마지막 점) · `#` · `*`(절대 좌표). * FROM · M2P 는 덧물음 두 개를 잇고 끝에 고른 점을 원래 물음에 넘김(도구 머신은 모름 → 투명). */ import { Point } from '@flatten-js/core'; import { lastPoint, normalizeKeyword } from '../commands/prompt'; import { ActorEvent } from '../tools/tool.types'; import { parsePointText } from './input-patterns'; import { absentSnapName, setSnapOverride, snapName } from './input-snap-override'; import { distanceCursor, notice, pushSubPrompt, sendPoint } from './prompt-input'; const point = (x: number, y: number) => new Point(x, y); /** FROM — 「기준점:」 → 「<간격띄우기>:」(`@dx,dy` · 거리 = 기준점에서 커서 쪽) */ function startFrom() { pushSubPrompt({ prompt: { text: '기준점' }, kind: 'point', onPoint: (base) => { pushSubPrompt({ prompt: { text: '<간격띄우기>' }, kind: 'point', base, onPoint: (target) => ({ point: target }), }); return 'done'; }, }); } /** M2P · MTP — 두 점의 가운데 */ function startMidBetween() { pushSubPrompt({ prompt: { text: '중간점의 첫 번째 점' }, kind: 'point', onPoint: (first) => { pushSubPrompt({ prompt: { text: '중간점의 두 번째 점' }, kind: 'point', base: first, onPoint: (second) => ({ point: point((first.x + second.x) / 2, (first.y + second.y) / 2) }), }); return 'done'; }, }); } /** 점 물음에서 친 글이 보조면 처리하고 true · 아니면 false(옵션 · 좌표 차례로) */ export function tryPointModifier(text: string): boolean { const typed = normalizeKeyword(text); const snap = snapName(typed); if (snap) { setSnapOverride(snap); return true; } const absent = absentSnapName(typed); if (absent) { notice(`「${absent}」 스냅은 이 CAD 에 없음.`); return true; } if (typed === 'FROM' || typed === 'FRO') { startFrom(); return true; } if (typed === 'M2P' || typed === 'MTP') { startMidBetween(); return true; } if (typed === '@') { const last = lastPoint(); if (!last) return false; sendPoint({ type: ActorEvent.ABSOLUTE_POINT_INPUT, value: point(last.x, last.y) }); return true; } if (typed.startsWith('#') || typed.startsWith('*')) { // 절대 좌표 강제 — `#x,y` · `*d