Files
Aislo/B05_Profile/logic/B05_Profile_UI_Profile_Data.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

76 lines
2.9 KiB
TypeScript

/* =============================================================================
* 종단면 패널 자료 어댑터 (B05)
*
* 저장된 종단면 자료(`longitudinal_sections.data`)를 화면이 쓰는 모양으로 바꾸는 순수 함수들.
* 상태를 갖지 않으며 DOM도 만들지 않는다 — 패널 본체가 700줄 한계에 닿아 분리했다.
* ========================================================================== */
import type { DesignProfile, LongitudinalSection } from "../../B06_Section/B06_Section_Api_Fetch";
import type { ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
export function readAlignment(data: LongitudinalSection): ProfileAlignment | null {
const candidate = data.profile_alignment as ProfileAlignment | undefined;
if (!candidate?.base_pvi?.length || !candidate.samples?.length) return null;
if (!Number.isFinite(candidate.policy?.default_curve_radius_m)) return null;
if (!candidate.stations || !candidate.segments || !candidate.curves) return null;
candidate.edits = {
station_offsets: candidate.edits?.station_offsets ?? {},
curve_radii: candidate.edits?.curve_radii ?? {},
};
return candidate;
}
/** 저장분이 구버전이라 편집을 붙일 수 없는 상태인가 (재계산 안내용). */
export function hasLegacyAlignment(data: LongitudinalSection): boolean {
return Boolean(data.profile_alignment) && readAlignment(data) === null;
}
/** 편집 결과를 종단면도 렌더러가 받는 계획선 형태로 감싼다. */
export function toDesignProfile(
alignment: ProfileAlignment,
original: DesignProfile | undefined,
): DesignProfile {
const balance = alignment.balance;
return {
id: original?.id ?? "design_grade_line",
name: original?.name ?? "계획선",
basis: original?.basis ?? "station_alignment",
samples: alignment.samples,
balance_segments: [
{
index: 0,
start_chainage_m: alignment.samples[0]?.chainage_m ?? 0,
end_chainage_m: alignment.samples[alignment.samples.length - 1]?.chainage_m ?? 0,
cut_area_m2: balance.cut_area_m2,
fill_area_m2: balance.fill_area_m2,
balance_error_m2: balance.net_area_m2,
},
],
summary: {
...(original?.summary ?? {
max_grade_pct: 0,
vertical_curve_count: 0,
pvi_count: 0,
balance_segment_count: 1,
main_direction: "none",
suggested_elevation_offset_m: null,
warnings: [],
}),
cut_area_m2: balance.cut_area_m2,
fill_area_m2: balance.fill_area_m2,
balance_error_m2: balance.net_area_m2,
balanced: balance.within_tolerance,
},
};
}
export function normalizedLongitudinal(data: LongitudinalSection): LongitudinalSection {
return {
...data,
samples: data.samples.map((sample: LongitudinalSection["samples"][number]) => ({
...sample,
elevation_m: sample.elevation_m ?? sample.z ?? null,
})),
};
}