- 메인 탭 「거리이정표」 · 하위 탭 [거리이정표] 표 + 경로 탭(이름 = 업체 이름) · [+ 추가] · [삭제] - 경로 탭 = 구간 km(더블클릭) · 도로 구분 ▾ · 표 줄(항목 · 목적지 · 비고) · 경로 그림 하나 - 좌측 패널 카드 = 공사지(중점 측점 · 기본 노선 ÷ 2) · 기준점(있음 · 이름 · 주소 · 방위) - 표 합 = 파이썬 · TS 짝(거울 시험) · 정본 = storage B08_Quantity/milestone · [저장] 한 줄에서 PUT Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz
128 lines
4.1 KiB
TypeScript
128 lines
4.1 KiB
TypeScript
/* =============================================================================
|
||
* B08_Quantity_Milestone_Calc.ts
|
||
* B08 거리이정표 표 합(PLAN 244-1) — 화면 없음 · 저장 안 함 · import 없음(시험이 node 로 돌림).
|
||
*
|
||
* ⚠ 짝 = `B08_Quantity_Milestone_Calc.py`(같은 식) — 한쪽을 고치면 다른 쪽도 ·
|
||
* 거울 시험 `resources/tester/test_244_1_b08_milestone.py`.
|
||
* 조작 중은 이 파일이 바로 셈 · [저장] · 읽기 때 서버가 파이썬 짝으로 다시 셈.
|
||
*
|
||
* 표 한 줄 = 경로(업체) 구간 + (기준점 거침이면 기준점 → 시점 공통 구간) + (목적지 = 중점이면
|
||
* 시점 → 중점 = 중점 측점 km) · 도로 구분 셋마다 합 · 포장 = 2차 + 1차 · 합계 = 포장 + 비포장 ·
|
||
* 끝수 = 소수 셋째 자리(반올림)
|
||
* ========================================================================== */
|
||
|
||
export const ROADS = ["2차포장", "1차포장", "비포장"] as const;
|
||
export type Road = (typeof ROADS)[number];
|
||
/** 8방 — 기준점(없으면 공사지) 기준 지도 방위 */
|
||
export const DIRS = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"] as const;
|
||
export type Dir = (typeof DIRS)[number];
|
||
export type Dest = "start" | "mid";
|
||
|
||
export interface Leg {
|
||
road: Road;
|
||
km: number | null;
|
||
}
|
||
|
||
export interface MilestoneRow {
|
||
item: string;
|
||
dest: Dest;
|
||
note: string;
|
||
}
|
||
|
||
export interface MilestoneRoute {
|
||
id: string;
|
||
/** 업체 이름 = 하위 탭 이름 */
|
||
name: string;
|
||
address: string;
|
||
/** 기준점 거침(기준점 없으면 무시 · 시점으로 바로) */
|
||
via_base: boolean;
|
||
dir: Dir | null;
|
||
lon?: number | null;
|
||
lat?: number | null;
|
||
/** 업체 → 기준점(거침) · 시점 구간 */
|
||
legs: Leg[];
|
||
rows: MilestoneRow[];
|
||
}
|
||
|
||
export interface MilestoneData {
|
||
site: { mid_station_m: number | null; mid_road: Road };
|
||
base: {
|
||
enabled: boolean;
|
||
name: string;
|
||
address: string;
|
||
dir: Dir | null;
|
||
lon?: number | null;
|
||
lat?: number | null;
|
||
/** 기준점 → 시점 공통 구간 */
|
||
legs: Leg[];
|
||
};
|
||
routes: MilestoneRoute[];
|
||
}
|
||
|
||
export interface MilestoneTableRow {
|
||
route: string;
|
||
index: number;
|
||
item: string;
|
||
company: string;
|
||
dest: Dest;
|
||
s2: number;
|
||
s1: number;
|
||
un: number;
|
||
paved: number;
|
||
unpaved: number;
|
||
total: number;
|
||
note: string;
|
||
}
|
||
|
||
const KEYS: Record<string, "s2" | "s1" | "un"> = { "2차포장": "s2", "1차포장": "s1", 비포장: "un" };
|
||
|
||
/** 소수 셋째 자리 반올림(파이썬 짝 floor(x × 1000 + 0.5) 과 같음) */
|
||
export const r3 = (value: number): number => Math.floor(value * 1000 + 0.5) / 1000;
|
||
|
||
function addLegs(sums: Record<"s2" | "s1" | "un", number>, legs: Leg[] | undefined): void {
|
||
for (const leg of legs ?? []) {
|
||
const key = KEYS[leg.road];
|
||
if (key) sums[key] += Number(leg.km ?? 0);
|
||
}
|
||
}
|
||
|
||
/** 시점 → 중점 km — 사용자 측점(없으면 기본 = 노선 ÷ 2) ÷ 1000 */
|
||
export function midKm(data: MilestoneData, midDefaultM: number | null): number {
|
||
const station = data.site?.mid_station_m ?? midDefaultM;
|
||
return Number(station ?? 0) / 1000;
|
||
}
|
||
|
||
/** 표 줄 — 경로 차례 · 경로 안 줄 차례 */
|
||
export function computeMilestone(
|
||
data: MilestoneData,
|
||
midDefaultM: number | null,
|
||
): MilestoneTableRow[] {
|
||
const base = data.base;
|
||
const mid: Leg = { road: data.site?.mid_road ?? "비포장", km: midKm(data, midDefaultM) };
|
||
const out: MilestoneTableRow[] = [];
|
||
for (const route of data.routes ?? []) {
|
||
(route.rows ?? []).forEach((row, index) => {
|
||
const sums = { s2: 0, s1: 0, un: 0 };
|
||
addLegs(sums, route.legs);
|
||
if (base?.enabled && route.via_base !== false) addLegs(sums, base.legs);
|
||
if (row.dest === "mid") addLegs(sums, [mid]);
|
||
const paved = sums.s2 + sums.s1;
|
||
out.push({
|
||
route: route.id,
|
||
index,
|
||
item: row.item ?? "",
|
||
company: route.name ?? "",
|
||
dest: row.dest ?? "start",
|
||
s2: r3(sums.s2),
|
||
s1: r3(sums.s1),
|
||
un: r3(sums.un),
|
||
paved: r3(paved),
|
||
unpaved: r3(sums.un),
|
||
total: r3(paved + sums.un),
|
||
note: row.note ?? "",
|
||
});
|
||
});
|
||
}
|
||
return out;
|
||
}
|