fix(평면): 평면 비탈 끝 · B07 계획평면도 = 벽 측점 횡단 최종 모양이 땅과 만나는 점 (PLAN 578-2 · 요구 438 · 439)

- B06 STRUCTURE_ROW_KEYS · 서버 _AREA_KEYS 에 slope_end_left_m · slope_end_right_m — 벽 트림 측점만 · 트림 사면 → 단마다 벽 앞 → 사이 성토부선 윤곽이 처음 땅에 닿는 오프셋
- 평면 발자국 finalSlopeEnd · B07 final_slope_end(짝) — 얹은 값 먼저 · 없으면 설계선 끝(구조물 없는 측점 그대로)
- 시험 test_578_2_plan_slope_end 새로 · test_346_2 거울에 벽 측점 줄

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-29 13:13:39 +09:00
co-authored by Claude Opus 5.5
parent 8fcc4c9fbe
commit bfa2b3a97f
7 changed files with 181 additions and 16 deletions
+22 -5
View File
@@ -3,8 +3,8 @@
* 평면 발자국 — 측점 횡단 설계 결과를 평면 선으로(도로 끝 좌 · 우 · 비탈 끝 깎기 · 쌓기 · 눈금) (346-2)
*
* ⚠⚠ 짝: `B07_DesignDetail/B07_DesignDetail_Engine_Cad_PlanSlope.py`
* (`route_frame` · `route_normal` · `side_is_cut` · `slope_end` · `slope_pieces` 와 그 아래
* 단조 3차 보간 · 촘촘히 · 접힘 버림 · 353-1 · 모서리 둥글림 · 364-3) — 한쪽만 고치면
* (`route_frame` · `route_normal` · `side_is_cut` · `slope_end` · `final_slope_end` ·
* `slope_pieces` 와 그 아래 단조 3차 보간 · 촘촘히 · 접힘 버림 · 353-1 · 모서리 둥글림 · 364-3) — 한쪽만 고치면
* 종단 · 횡단 편집 중 평면과 B07 계획평면도가 갈린다.
* `footprintRecord` = `B07_DesignDetail_Router_Support_Plan.slope_records` 의 측점 한 줄.
* 거울 시험: `resources/tester/test_346_2_plan_footprint_mirror.py`
@@ -35,6 +35,9 @@ export interface FootprintStation {
right?: FootprintPoint | null;
} | null;
design_line?: FootprintPoint[] | null;
/** 구조물 처리 뒤 비탈 끝(B06 `STRUCTURE_ROW_KEYS` · 벽 측점만 · 578-2). */
slope_end_left_m?: number | null;
slope_end_right_m?: number | null;
} | null;
samples: FootprintPoint[];
}
@@ -156,6 +159,20 @@ export function slopeEnd(
return end;
}
/** 구조물 처리 뒤 비탈 끝 — 벽 측점은 B06 이 얹은 `slope_end_<쪽>_m`(578-2) · 없으면 설계선 끝.
* 짝: `final_slope_end`. */
export function finalSlopeEnd(
design: NonNullable<FootprintStation["design"]>,
samples: FootprintPoint[],
edge: number,
side: Side,
): number {
const stored = design[`slope_end_${side}_m`];
return typeof stored === "number"
? stored
: slopeEnd(design.design_line ?? [], samples, edge, side);
}
/** 측점 한 자리 → `slope_pieces` 줄 · 도로 끝이 없으면 null. 짝: `slope_records` 한 줄. */
export function footprintRecord(station: FootprintStation): FootprintRecord | null {
const edges = station.design?.road_edges;
@@ -163,14 +180,14 @@ export function footprintRecord(station: FootprintStation): FootprintRecord | nu
const right = Number(edges?.right?.offset_m);
if (edges?.left?.offset_m == null || edges?.right?.offset_m == null) return null;
if (!Number.isFinite(left) || !Number.isFinite(right)) return null;
const line = station.design?.design_line ?? [];
const design = station.design ?? {};
const samples = station.samples ?? [];
const record: FootprintRecord = {
chainage_m: station.chainage_m,
left_edge_m: left,
left_end_m: slopeEnd(line, samples, left, "left"),
left_end_m: finalSlopeEnd(design, samples, left, "left"),
right_edge_m: right,
right_end_m: slopeEnd(line, samples, right, "right"),
right_end_m: finalSlopeEnd(design, samples, right, "right"),
};
for (const side of SIDES) {
const elevation = edges[side]?.elevation_m;