Files
Aislo/B05_Profile/B05_Profile_UI_Profile_Guard.ts
T
eomsangdonandClaude Opus 5.5 93e86f87c6 fix(b05,b06): 측점 한 벌 — 정수 m · 같은 m 측점 하나 · 목록 전체 다시 맞춤 (272)
- 규칙: 구조물 · 관 기준 측점 = 정수 m 사사오입(일반 측점 1 m 붙기 뺌) · 측점 심는 자리 TS 짝(plantedChainages ↔ resolve_extra_stations) · 같은 m 면 구조물 측점 하나(격자 자리 grid) · 떠나면 일반 측점(oneStationList ↔ _merge_irregular_into_longitudinal)
- 서버: B05 [저장] · B06 저장 · [측점 만들기]가 목록 전체 다시 맞춤(빈 목록도 · 옛 글 · 횡단 파일 글) · 계획선 측점 줄 다시 셈 · 정본에 없는 횡단 행은 0.5 m 안 새 측점으로 옮기고 나머지 지움 · 옛 소수 측점 꼭짓점 · 편집은 정수 자리로 · 맞춤 실패는 저장을 안 막음
- 화면: 종단 그래프 · 3D · 표 · ▲▼ 한 목록(초안 반영) · C군 구간형 · 독립 기슭막이 시작 · 끝 측점 · B06 카드는 초안에 없는 옛 구조물 측점 숨김 · 고름은 같은 m 구조물 측점 먼저 · 폼 거리 칸 정수 표기 · C군 계산 구간 · 포장 나눔 경계 정수
- 옛 자료: [정수 맞춤] 단추 없앰 · 종단 보기 열 때 한 번 자동 정수 · 알림 한 줄 · [저장]하면 남음
- 시험: test_272_1 · test_272_2 새로 · 234_1 · 238_1 · b05_extra_stations_supplier · b06_patch_station · b05_station_roundtrip · b05_b06_save_roundtrip 맞춤

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLCk2y5xE8YGVgjbTntWsY
2026-10-11 19:53:24 +09:00

62 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =============================================================================
* B05_Profile_UI_Profile_Guard.ts
* 종단도가 편집 · 경고에 쓰는 **셈만** — 계획선 샘플 보간, 평면 최소곡선반지름 경고
* (구조물 측점 맞추기는 측점 한 벌 `oneStationList` 로 갈음 · 272).
*
* 종단도 한 벌(`A00_Common/design/design_profile.ts`)이 700줄을 넘겨 떼어낸 조각이다
* (계획서 24-2c). 본문 로직과 수치는 그대로이고 화면 상태를 인자로 받는다.
* ========================================================================== */
import type { SectionDetailResponse } from "../B06_Section/B06_Section_Api_Fetch";
import type { ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
/** 계획선 샘플에서 chainage로 계획고·지반고를 되짚는 보간기(최소고 판정 입력). */
export function sampleAt(
alignment: ProfileAlignment | null,
chainageM: number,
field: "elevation_m" | "ground_elevation_m",
): number | null {
const samples = alignment?.samples;
if (!samples?.length) return null;
if (chainageM <= samples[0].chainage_m) return samples[0][field];
for (let i = 1; i < samples.length; i += 1) {
if (chainageM <= samples[i].chainage_m) {
const span = samples[i].chainage_m - samples[i - 1].chainage_m;
const t = span <= 1e-12 ? 0 : (chainageM - samples[i - 1].chainage_m) / span;
return samples[i - 1][field] + (samples[i][field] - samples[i - 1][field]) * t;
}
}
return samples[samples.length - 1][field];
}
/**
* 법정 평면 최소곡선반지름을 밑도는 측점을 센다(별표2 Ⅰ.2.다.(1), 2026-09-06).
* 반경은 횡단 측점마다 실려 오고(`plan_radius_m`), 하한은 계획선 정책이 들고 있다.
* **경고만** 낸다 — 노선을 고칠지는 사용자 판단이다.
*/
export function planCurveWarning(
alignment: ProfileAlignment | null,
detail: SectionDetailResponse | null,
): {
count: number;
worstRadiusM: number;
limitM: number;
hairpin: number;
} | null {
const limit = alignment?.policy.min_plan_radius_m ?? 0;
const sections = detail?.cross_sections ?? [];
if (!limit || !sections.length) return null;
const hairpinLimit = alignment?.policy.hairpin_min_radius_m ?? 0;
let count = 0;
let hairpin = 0;
let worst = Number.POSITIVE_INFINITY;
sections.forEach((section) => {
const radius = section.plan_radius_m;
if (typeof radius !== "number" || !Number.isFinite(radius) || radius >= limit) return;
count += 1;
worst = Math.min(worst, radius);
if (hairpinLimit > 0 && radius < hairpinLimit) hairpin += 1;
});
return count ? { count, worstRadiusM: worst, limitM: limit, hairpin } : null;
}