Files
Aislo/B05_Profile/logic/B05_Profile_Footprint_Strokes.ts
T
eomsangdonandClaude Opus 5.5 281c71b55b refactor(logic): 348-1 순수 계산 TS 49 파일 <페이지>/logic/ 로 옮김 — 이름 앞머리 그대로 · 동작 고침 없음
- 옮김: B04 2 · B05 23 · B06 11 · A00_Common/design 13 (9,299 줄) · 이미 logic/ 에 있던 16 파일 그대로
- 안 옮김: 묶음 입구(package.json build:*) · 파이썬 · 순수지만 계산 아닌 8 (보기 결선 · 콜백 · API 타입 · 갈아끼움 알림판)
- import 266 줄(142 파일) · 시험 · 주석 · 짝 표시 문자열 경로 고침 · B05 · B06 CLAUDE.md 짝 줄 logic/
- 시험 도우미 새 경로: 가짜 require 열쇠 · B05()/B06() 부름 · 형제 import 자리 · tsc 묶어 돌리는 시험 · 정규식 · rglob
- design_view_cross 줄 한도 시험 685 → 688 (긴 import 경로 줄바꿈 3줄)
- 확인: typecheck 0 · 서버 묶음 넷(corridor · server-calc · b07-extent · b07-note) 다시 지어 코드 같음(//#region 경로 주석만 다름) · 관련 시험 270 파일 — 남은 실패 19 는 옮기기 전과 같음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
2026-10-16 13:44:50 +09:00

55 lines
2.3 KiB
TypeScript

/* =============================================================================
* B05_Profile_Footprint_Strokes.ts
* 평면 발자국(가게 키 `footprint` · 계약 `PlanFootprint`) → 그릴 선 갈래(PLAN 346-2).
*
* 도로 끝 좌 · 우 = `road` · 비탈 끝 = 점마다 깎기 여부(`slopeLeftCut` · `slopeRightCut` —
* footprint 단계가 붙임)로 `cut` · `fill` 조각 · 깎기 여부가 없으면 `slope` 한 줄.
* 조각이 바뀌는 점은 앞뒤 조각이 함께 가짐(선이 끊겨 보이지 않게 · `splitRuns` 와 같은 규칙).
* ========================================================================== */
import type { PlanFootprint, Vertex } from "../../A00_Common/design/logic/design_pipeline_types";
export type FootprintStrokeKind = "road" | "cut" | "fill" | "slope";
export interface FootprintStroke {
kind: FootprintStrokeKind;
points: Vertex[];
}
/** footprint 단계 출력 — 계약 칸 + 비탈 끝 점마다 깎기 여부(없을 수 있음). */
export type FootprintValue = PlanFootprint & {
slopeLeftCut?: ReadonlyArray<boolean>;
slopeRightCut?: ReadonlyArray<boolean>;
};
function slopeRuns(points: Vertex[], cut: ReadonlyArray<boolean> | undefined): FootprintStroke[] {
if (points.length < 2) return [];
if (!cut || cut.length !== points.length) return [{ kind: "slope", points }];
const runs: FootprintStroke[] = [];
let current: FootprintStroke | null = null;
points.forEach((point, index) => {
const kind = cut[index] ? "cut" : "fill";
if (current?.kind !== kind) {
current?.points.push(point);
current = { kind, points: [point] };
runs.push(current);
} else {
current.points.push(point);
}
});
return runs.filter((run) => run.points.length >= 2);
}
/** 그릴 선 — 도로 끝 둘 · 비탈 끝 조각들(2점 미만은 뺌). */
export function footprintStrokes(footprint: FootprintValue | null): FootprintStroke[] {
if (!footprint) return [];
const road = [footprint.roadLeft, footprint.roadRight]
.filter((points) => points?.length >= 2)
.map((points): FootprintStroke => ({ kind: "road", points }));
return [
...road,
...slopeRuns(footprint.slopeLeft ?? [], footprint.slopeLeftCut),
...slopeRuns(footprint.slopeRight ?? [], footprint.slopeRightCut),
];
}