/** 명령 입력 해석 — 숫자 · 좌표 · 극좌표 · 각도 고정 꼴 */ import { Point } from '@flatten-js/core'; import { type AbsolutePointInputEvent, ActorEvent, type NumberInputEvent, type RelativePointInputEvent, } from '../tools/tool.types.ts'; /** 부호 있는 실수 한 개 — `-5` · `.5` · `1.5` */ const SIGNED = '(-?(?:[0-9]+(?:[.][0-9]+)?|[.][0-9]+))'; export const NUMBER_REGEXP = new RegExp(`^${SIGNED}$`); export const ABSOLUTE_POINT_REGEXP = new RegExp(`^${SIGNED}[ ]*,[ ]*${SIGNED}$`); export const RELATIVE_POINT_REGEXP = new RegExp(`^@${SIGNED}[ ]*,[ ]*${SIGNED}$`); /** 극좌표 — 거리<각도(도). `@`가 붙으면 직전 점 기준 */ export const ABSOLUTE_POLAR_REGEXP = new RegExp(`^${SIGNED}[ ]*<[ ]*${SIGNED}$`); export const RELATIVE_POLAR_REGEXP = new RegExp(`^@${SIGNED}[ ]*<[ ]*${SIGNED}$`); /** 각도 고정 — `<30` (다음 한 점만 그 방향) */ export const ANGLE_LOCK_REGEXP = new RegExp(`^<[ ]*${SIGNED}$`); /** 거리·각도(도)를 x·y 변위로 바꾼다 — 각도 = 동쪽 0° 반시계 + */ export function polarToPoint(distance: number, degrees: number): Point { const radians = (degrees * Math.PI) / 180; return new Point(distance * Math.cos(radians), distance * Math.sin(radians)); } export type PointTextEvent = NumberInputEvent | AbsolutePointInputEvent | RelativePointInputEvent; /** 친 글 → 점 · 거리 사건(숫자 · `x,y` · `@x,y` · `@d Point): PointTextEvent | null { const num = (value: string) => Number.parseFloat(value); let match = NUMBER_REGEXP.exec(text); if (match) { return { type: ActorEvent.NUMBER_INPUT, value: num(match[1]), worldMouseLocation: cursor() }; } match = ABSOLUTE_POINT_REGEXP.exec(text); if (match) { return { type: ActorEvent.ABSOLUTE_POINT_INPUT, value: new Point(num(match[1]), num(match[2])), }; } match = RELATIVE_POINT_REGEXP.exec(text); if (match) { return { type: ActorEvent.RELATIVE_POINT_INPUT, value: new Point(num(match[1]), num(match[2])), }; } match = RELATIVE_POLAR_REGEXP.exec(text); if (match) { return { type: ActorEvent.RELATIVE_POINT_INPUT, value: polarToPoint(num(match[1]), num(match[2])), }; } match = ABSOLUTE_POLAR_REGEXP.exec(text); if (match) { return { type: ActorEvent.ABSOLUTE_POINT_INPUT, value: polarToPoint(num(match[1]), num(match[2])), }; } return null; }