- 규칙: 구조물 · 관 기준 측점 = 정수 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
81 lines
3.5 KiB
TypeScript
81 lines
3.5 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile_UI_Structures_Pavement.ts
|
|
* 포장 구간과 물넘이포장의 겹침 정리(2026-08-28 사용자 확정).
|
|
*
|
|
* 물넘이포장은 그 자체가 콘크리트 노면이라 포장 구간이 그 위를 덮을 수 없다.
|
|
* · 포장 구간이 물넘이를 **통째로 품으면** → 알리고 앞·뒤 두 구간으로 나눈다
|
|
* (물넘이가 가운데 한 구간 — 합쳐서 3구간).
|
|
* · **끝만 걸치면** → 어디까지 겹치는지 알리고 저장을 멈춘다. 사용자가 값을 고친다.
|
|
* ========================================================================== */
|
|
|
|
import { FORD_PAVEMENT_DEFAULT_WIDTH_M } from "@config/config_frontend";
|
|
import { showConfirmDialog } from "@ui/ui_template_elements";
|
|
import type { PipeFacilityItem } from "./B05_Profile_UI_Structures_Panel";
|
|
|
|
/** 누가거리 비교 허용오차(m) — 정본이 0.01m로 끊어 쓴다. */
|
|
const EPS = 0.005;
|
|
|
|
export interface Span {
|
|
start: number;
|
|
end: number;
|
|
}
|
|
|
|
/** 물넘이포장이 차지하는 누가거리 구간 — 기준 측점 ± 월류 폭/2. */
|
|
export function fordSpans(pipes: PipeFacilityItem[]): Span[] {
|
|
return pipes
|
|
.filter((pipe) => pipe.facility === "ford_pavement")
|
|
.map((pipe) => {
|
|
const raw = Number(pipe.options?.ford_width_m);
|
|
const width = Number.isFinite(raw) && raw > 0 ? raw : FORD_PAVEMENT_DEFAULT_WIDTH_M;
|
|
return { start: pipe.chainage_m - width / 2, end: pipe.chainage_m + width / 2 };
|
|
})
|
|
.sort((left, right) => left.start - right.start);
|
|
}
|
|
|
|
const format = (value: number): string => `${value.toFixed(2)}m`;
|
|
|
|
/**
|
|
* 포장 구간에서 물넘이 몫을 덜어낸다.
|
|
* 반환: 저장할 구간 목록. `null`이면 저장하지 않는다(사용자가 값을 고쳐야 한다).
|
|
*/
|
|
export async function splitPavementRange(
|
|
start: number,
|
|
end: number,
|
|
pipes: PipeFacilityItem[],
|
|
): Promise<Span[] | null> {
|
|
const overlaps = fordSpans(pipes).filter(
|
|
(ford) => ford.end > start + EPS && ford.start < end - EPS,
|
|
);
|
|
if (!overlaps.length) return [{ start, end }];
|
|
|
|
// 끝만 걸친 물넘이 — 자르면 사용자가 찍은 구간이 조용히 줄어든다. 값을 고치게 안내한다.
|
|
const partial = overlaps.find((ford) => ford.start <= start + EPS || ford.end >= end - EPS);
|
|
if (partial) {
|
|
await showConfirmDialog(
|
|
`지정한 포장 구간(${format(start)}~${format(end)})이 물넘이포장` +
|
|
`(${format(partial.start)}~${format(partial.end)})의 끝에 걸칩니다.\n` +
|
|
"물넘이는 그 자체가 포장이라 겹칠 수 없습니다 — 시작·종료 측점을 고쳐 주세요.",
|
|
"확인",
|
|
);
|
|
return null;
|
|
}
|
|
|
|
const segments: Span[] = [];
|
|
let cursor = start;
|
|
for (const ford of overlaps) {
|
|
// 경계도 정수 m(167) — 물넘이를 안 덮게 앞 구간 끝은 내림 · 뒤 구간 시작은 올림
|
|
const before = Math.floor(ford.start + EPS);
|
|
if (before - cursor > EPS) segments.push({ start: cursor, end: before });
|
|
cursor = Math.ceil(ford.end - EPS);
|
|
}
|
|
if (end - cursor > EPS) segments.push({ start: cursor, end });
|
|
|
|
const inside = overlaps.map((ford) => `${format(ford.start)}~${format(ford.end)}`).join(", ");
|
|
const proceed = await showConfirmDialog(
|
|
`포장 구간 안에 물넘이포장(${inside})이 있습니다.\n` +
|
|
`물넘이는 그 자체가 포장이라 그 몫을 빼고 ${segments.length}개 구간으로 나눠 저장합니다.`,
|
|
"나눠 저장",
|
|
);
|
|
return proceed ? segments : null;
|
|
}
|