- logic 새 파일 다섯 — Cross_Wall_Geom(벽 1매) · Cross_Wall_Hatch_Geom(무늬 띠 · 물빼기 · 도수로 띠 · 원지반선) · Cross_Excavation_Geom(벽 터파기) · Cross_Design_Surface_Geom(암선 · 포장층) · Cross_Revetment_Geom(독립 기슭막이 배치) - logic 으로 옮김 — Body_Guard → Cross_Body_Guard · Structure_Layouts · Route_Carry_Patch(내용 그대로 · import 경로만) - inferStationInterval → common_util_station(글자표 없는 자리 · common_util_svg 는 다시 내보냄) — Node 묶음 ui_template_locale 끌림 끊음 - 부르는 쪽 import 줄 · 등록부 ts 경로 · 시험 · 도우미 경로 - test_472_3 GEOMETRY_PULLS 다섯 줄 걷음 · Wall_Hatch · Excavation · Design_Surface 세 줄은 Culvert · Box · Ford 그림 파일(518-2)이 그리기 함수로 부르는 동안 남김 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 lines
3.1 KiB
TypeScript
72 lines
3.1 KiB
TypeScript
/* =============================================================================
|
|
* B06_Section_Cross_Design_Surface_Geom.ts
|
|
* 암선 · 포장층 **기하**(m 좌표) — 그리기는 `../B06_Section_UI_Cross_Design_Surface`(472-3).
|
|
* ========================================================================== */
|
|
|
|
import type { PavementEntry } from "@util/common_util_structure_pavement";
|
|
import type { CrossDesign } from "../B06_Section_Api_Fetch";
|
|
|
|
export type Edge = { offset_m: number; elevation_m: number };
|
|
|
|
/** 암선 — 유효 지반 샘플을 `offsetM` 만큼 올린 꺾은선들(빈 · 무효 샘플에서 끊음 · 두 점 이상만). */
|
|
export function rockBoundarySegments(
|
|
samples: Array<{ offset_m?: number; elevation_m?: number | null; valid: boolean }>,
|
|
offsetM: number,
|
|
): Edge[][] {
|
|
const segments: Edge[][] = [];
|
|
let current: Edge[] = [];
|
|
for (const sample of samples) {
|
|
const elevation = sample.elevation_m;
|
|
if (sample.valid === false || elevation === null || !Number.isFinite(elevation ?? NaN)) {
|
|
if (current.length > 1) segments.push(current);
|
|
current = [];
|
|
continue;
|
|
}
|
|
current.push({ offset_m: sample.offset_m ?? 0, elevation_m: (elevation as number) + offsetM });
|
|
}
|
|
if (current.length > 1) segments.push(current);
|
|
return segments;
|
|
}
|
|
|
|
/** 확폭 끈 구간 — 규격 폭 끝(좌 = left − 확폭좌 · 우 = right + 확폭우 · 표고는 두 끝 사이 직선). */
|
|
function standardEdges(edges: { left: Edge; right: Edge }, design: CrossDesign) {
|
|
const { left, right } = edges;
|
|
const span = right.offset_m - left.offset_m || 1;
|
|
const at = (offset: number): Edge => ({
|
|
offset_m: offset,
|
|
elevation_m:
|
|
left.elevation_m + ((right.elevation_m - left.elevation_m) * (offset - left.offset_m)) / span,
|
|
});
|
|
return {
|
|
left: at(left.offset_m - (design.widening_left_m ?? 0)),
|
|
right: at(right.offset_m + (design.widening_right_m ?? 0)),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 포장층 — 노면선(= 포장 윗면) 아래로 두께만큼. 노면공 범위(`section.pavement`)면 그 두께 ·
|
|
* 확폭 켬/끔(여러 건은 아래로 차례로 쌓음) · 없으면 카드 포장 켬일 때 표준 두께.
|
|
* 층마다 네 꼭짓점(좌상 · 우상 · 우하 · 좌하).
|
|
*/
|
|
export function pavementLayers(
|
|
design: CrossDesign,
|
|
pavement?: readonly PavementEntry[] | null,
|
|
): Array<{ entry: PavementEntry | null; corners: Edge[] }> {
|
|
const edges = design.carriageway_edges ?? design.road_edges;
|
|
if (!edges) return [];
|
|
const layers = pavement?.length ? pavement : design.paved ? [null] : [];
|
|
let depth = 0;
|
|
return layers.map((entry) => {
|
|
const thickness = entry?.thickness_m ?? design.pavement_thickness_m ?? 0.2;
|
|
const { left, right } = entry && !entry.widening_on ? standardEdges(edges, design) : edges;
|
|
const corners = [
|
|
{ offset_m: left.offset_m, elevation_m: left.elevation_m - depth },
|
|
{ offset_m: right.offset_m, elevation_m: right.elevation_m - depth },
|
|
{ offset_m: right.offset_m, elevation_m: right.elevation_m - depth - thickness },
|
|
{ offset_m: left.offset_m, elevation_m: left.elevation_m - depth - thickness },
|
|
];
|
|
depth += thickness;
|
|
return { entry, corners };
|
|
});
|
|
}
|