fix(b06): 물넘이 연동 범위 안 측점에 자기 관도 함께 얹음 — 키별 하나씩 · 같은 키는 소유 먼저 · 흙막이는 자기 관에 밀림 (299-1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
This commit is contained in:
@@ -580,6 +580,12 @@ export function buildCulvertSets(
|
||||
return sets;
|
||||
}
|
||||
|
||||
/** 차례 비교(파이썬 튜플 `<` 와 같음) — 처음 다른 자리에서 작은 쪽이 먼저. */
|
||||
function rankBefore(a: readonly number[], b: readonly number[]): boolean {
|
||||
const at = a.findIndex((value, index) => value !== b[index]);
|
||||
return at >= 0 && a[at] < b[at];
|
||||
}
|
||||
|
||||
/** 측점 자료에 세트를 얹는다(파이썬 `attach_culvert_sets`). 얹은 개수를 돌려준다. */
|
||||
export function attachCulvertSets(
|
||||
sections: Array<Record<string, unknown>>,
|
||||
@@ -607,25 +613,35 @@ export function attachCulvertSets(
|
||||
for (const section of sections) {
|
||||
const chainage = num(section.chainage_m, null);
|
||||
if (chainage === null) continue;
|
||||
// ⚠ 키가 다른 시설은 같은 측점에 함께 얹는다(299-1 · 짝: 파이썬 `attach_culvert_sets`) — 첫 시설
|
||||
// 하나에서 멈추면 물넘이포장 연동 범위 안 측점의 **자기 관**이 빠졌다. 같은 키끼리는 소유 측점
|
||||
// 것 → 흙막이 아닌 자기 시설 → 가까운 것 → 관 지점 차례.
|
||||
const best = new Map<string, { rank: number[]; value: CulvertSetSpec }>();
|
||||
let order = 0;
|
||||
for (const [pipeChainage, spec] of sets) {
|
||||
order += 1;
|
||||
// 연동 대상 종류만 폭의 절반까지 옆 측점에 걸친다.
|
||||
let reach = CHAINAGE_TOLERANCE_M;
|
||||
if (SPAN_LINKED_TYPES.has(String(spec.type))) reach += (num(spec.span_m, 0) ?? 0) / 2;
|
||||
if (Math.abs(chainage - pipeChainage) <= reach || owner.get(pipeChainage) === chainage) {
|
||||
// ⚠ 스펙에 **그 시설이 놓인 누가거리**를 함께 얹는다(2026-09-08, 짝: 파이썬
|
||||
// `attach_culvert_sets`). 세트는 폭의 절반까지 옆 측점에도 붙으므로, 이것이 없으면
|
||||
// 소비처가 「소유 측점」을 못 가려 **같은 시설을 여러 측점에서 센다**.
|
||||
section[SECTION_KEYS[String(spec.type)] ?? "culvert"] = {
|
||||
...spec,
|
||||
chainage_m: pipeChainage,
|
||||
};
|
||||
// 세월교 · 박스 흙막이(73-4) — 배관 흙막이와 같은 자리(`culvert`)에 함께 얹음.
|
||||
if (spec.guard)
|
||||
section.culvert = { ...(spec.guard as CulvertSetSpec), chainage_m: pipeChainage };
|
||||
attached += 1;
|
||||
break;
|
||||
const owned = owner.get(pipeChainage) === chainage;
|
||||
if (!(Math.abs(chainage - pipeChainage) <= reach || owned)) continue;
|
||||
const entries: Array<[string, CulvertSetSpec, number]> = [
|
||||
[SECTION_KEYS[String(spec.type)] ?? "culvert", spec, 0],
|
||||
];
|
||||
// 세월교 · 박스 흙막이(73-4) — 배관 흙막이와 같은 자리(`culvert`) · 자기 관과 부딪히면 관 먼저.
|
||||
if (spec.guard) entries.push(["culvert", spec.guard as CulvertSetSpec, 1]);
|
||||
for (const [key, value, isGuard] of entries) {
|
||||
const rank = [owned ? 0 : 1, isGuard, Math.abs(chainage - pipeChainage), order];
|
||||
const held = best.get(key)?.rank;
|
||||
// ⚠ 스펙에 **그 시설이 놓인 누가거리**를 함께 얹는다(2026-09-08). 세트는 폭의 절반까지
|
||||
// 옆 측점에도 붙으므로, 이것이 없으면 소비처가 「소유 측점」을 못 가려 **같은 시설을 여러
|
||||
// 측점에서 센다**.
|
||||
if (!held || rankBefore(rank, held))
|
||||
best.set(key, { rank, value: { ...value, chainage_m: pipeChainage } });
|
||||
}
|
||||
}
|
||||
for (const [key, { value }] of best) section[key] = value;
|
||||
if (best.size) attached += 1;
|
||||
}
|
||||
return attached;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user