From 1f00e13852595b7d886ec4892dc0797519825756 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 19 Oct 2026 07:26:10 +0900 Subject: [PATCH] =?UTF-8?q?fix(467=20B1=20=EB=8D=A7=20=EA=B0=99=EC=9D=80?= =?UTF-8?q?=20=EC=9E=90=EB=A6=AC):=20=EB=85=B8=EC=84=A0=20=EC=B4=88?= =?UTF-8?q?=EC=95=88=20=EC=97=86=EB=8A=94=20=EC=B0=A8=EB=A1=80=20=3D=20?= =?UTF-8?q?=EA=B0=99=EC=9D=80=20=EC=9E=90=EB=A6=AC=20=EC=95=9E=20=ED=9A=A1?= =?UTF-8?q?=EB=8B=A8(=EC=97=86=EC=9C=BC=EB=A9=B4=20=EA=B7=B8=20=EC=9E=90?= =?UTF-8?q?=EB=A6=AC=20=EC=98=9B=20=ED=9A=A1=EB=8B=A8)=20=EA=B8=B0?= =?UTF-8?q?=ED=95=98=20=C2=B7=20=ED=91=9C=EB=B3=B8=20=EA=B7=B8=EB=8C=80?= =?UTF-8?q?=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 격자 측점에 구조물을 놓고 빼면 열쇠가 바뀌어 브라우저 표본으로 갈렸음(검증_sub5 440 m · 소단 놓고 뺌 = 누가토량 0.04 ㎥ 갈림) - 시험 test_272_swap_keeps_canon 에 격자 구조물 놓고 뺌 = 정본 표본 · 기하 Co-Authored-By: Claude Opus 5.5 --- B06_Section/logic/B06_Section_Station_Swap.ts | 52 +++++++++++-------- resources/tester/helper_272_swap_canon.mjs | 14 +++++ resources/tester/test_272_swap_keeps_canon.py | 7 +++ 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/B06_Section/logic/B06_Section_Station_Swap.ts b/B06_Section/logic/B06_Section_Station_Swap.ts index 12e587877..ac3583929 100644 --- a/B06_Section/logic/B06_Section_Station_Swap.ts +++ b/B06_Section/logic/B06_Section_Station_Swap.ts @@ -6,8 +6,9 @@ * 받음 — 설계 · 구조물 제원 · 이름 그대로 · 자리(누가거리 · 좌표 · 방위 · 확폭)만 새것(433-4). * · 지반 표본 · 상단측 · 중심고 = 자리 · 축이 같은 앞 횡단이면 앞 값(서버 샘플링 정본 · 덧 측점만 넣어도 나머지 * 측점 면적이 브라우저 지형으로 안 바뀜 · 433-11) · 새 측점 · 옮긴 측점만 지반 표본(채워 왔으면). - * · 노선 초안 없는 차례(관 · 구조물 · 추가 측점만) = 같은 열쇠 · 누가거리 0.01 m 안 앞 횡단의 기하 · 표본 그대로 - * (축 허용 1e-3 · 브라우저 측점 틀 ↔ 서버 틀 mm 차가 정본 표본을 안 덮음 · 467 · 요구 272). + * · 노선 초안 없는 차례(관 · 구조물 · 추가 측점만) = 같은 자리(누가거리 · 좌표 0.01 m · 축 1e-3) 앞 횡단 — 없으면 + * 그 자리 옛 횡단(격자에 구조물을 놓고 뺌) — 의 기하 · 표본 그대로(브라우저 측점 틀 ↔ 서버 틀 mm 차가 정본 표본을 + * 안 덮음 · 467 · 요구 272) · 설계는 지금 규칙. * · 새 측점 = 지반 표본 + 기본 설계(계획고 0 → 낡음 → 브라우저 다시 셈이 곧 채움). * · 상단측 = 새 지반 표본으로 다시 셈한 측점은 다시(단면 유형 기본값 재료 · 서버 횡단 파일 `uphill_side` 짝 · 428). * · 0.5 m 넘게 옮긴 관 · 구조물 측점 = 기본 설계 + 사용자 칸(만진 칸 · 지반 등 입력 `ROW_CARRY_KEYS`) — 서버가 @@ -215,12 +216,15 @@ export function swapCrossSections( moved = true; if (prior && text(prior.chainage_m) !== text(station.chainageM)) moves.set(text(prior.chainage_m), text(station.chainageM)); - // 노선 초안 없는 차례 · 같은 열쇠 · 같은 자리 = 앞 횡단 기하 · 표본 그대로(467 · 되돌리면 정본과 같음) - const canon = - !routeDraft && - !!prior && - byKey.get(station.key) === prior && - samePlace(prior, station, CANON_AXIS_TOL); + // 노선 초안 없는 차례 · 같은 자리 = 앞 횡단(없으면 그 자리 옛 횡단 · 격자에 구조물을 놓고 뺌) 기하 · 표본 그대로 + // (467 · 되돌리면 정본과 같음) + const atPlace = (section: CrossSection | undefined): section is CrossSection => + !!section?.samples?.length && samePlace(section, station, CANON_AXIS_TOL); + const canon = routeDraft + ? undefined + : atPlace(prior) + ? prior + : detail.cross_sections.find(atPlace); // 자리 같은 앞 횡단 = 서버 표본 그대로(433-11) · 아니면 새 지반 표본(채워 왔으면) const fresh = !canon && !!station.ground && !(prior?.samples?.length && samePlace(prior, station)); @@ -243,18 +247,20 @@ export function swapCrossSections( label: formatStation(station.chainageM), kind, ...(onGrid ? { grid: true } : {}), - center_z: fresh - ? (station.ground?.centerZ ?? prior?.center_z ?? null) - : (prior?.center_z ?? null), - ...(canon && prior + center_z: canon + ? canon.center_z + : fresh + ? (station.ground?.centerZ ?? prior?.center_z ?? null) + : (prior?.center_z ?? null), + ...(canon ? { - azimuth_deg: prior.azimuth_deg, - plan_radius_m: prior.plan_radius_m, - curve_outer_side: prior.curve_outer_side, - curve_widening_m: prior.curve_widening_m, - center_x: prior.center_x, - center_y: prior.center_y, - frame: prior.frame, + azimuth_deg: canon.azimuth_deg, + plan_radius_m: canon.plan_radius_m, + curve_outer_side: canon.curve_outer_side, + curve_widening_m: canon.curve_widening_m, + center_x: canon.center_x, + center_y: canon.center_y, + frame: canon.frame, } : { azimuth_deg: station.azimuthDeg, @@ -267,8 +273,12 @@ export function swapCrossSections( }), }; longStations.push({ ...place, ...(prior?.structure ? { structure: prior.structure } : {}) }); - const samples = fresh ? groundSamples(station) : (prior?.samples ?? []); - const uphill = fresh ? uphillSide(station) : (prior?.uphill_side ?? null); + const samples = canon ? canon.samples : fresh ? groundSamples(station) : (prior?.samples ?? []); + const uphill = canon + ? (canon.uphill_side ?? null) + : fresh + ? uphillSide(station) + : (prior?.uphill_side ?? null); if (!prior) return { ...place, uphill_side: uphill, samples, design: freshDesign(uphill) }; const reseed = (station.kind === "pipe" || station.kind === "structure") && diff --git a/resources/tester/helper_272_swap_canon.mjs b/resources/tester/helper_272_swap_canon.mjs index 33516b1ba..ca96b8122 100644 --- a/resources/tester/helper_272_swap_canon.mjs +++ b/resources/tester/helper_272_swap_canon.mjs @@ -169,6 +169,20 @@ const out = {}; }; } +/* 1-2. 격자 측점(40 m)에 구조물을 놓고 뺌 — 열쇠가 바뀌어도 같은 자리 = 정본 표본 · 기하 */ +{ + const onGrid = stationsAt(45).map((s) => + s.key === "grid:2" ? { ...s, key: "structure:s1", kind: "structure", id: "s1" } : s, + ); + const placed = m.swapCrossSections(canonDetail(), onGrid, KEYS, 20, false); + const removed = m.swapCrossSections(placed.detail, stationsAt(45), keysOf(onGrid), 20, false); + out.gridStructure = { + placed: report(placed.detail)["40.00"], + removed: report(removed.detail)["40.00"], + removedBytes: bytesSame(removed.detail, [45, 40]), + }; +} + /* 2. 가게 길(swapSectionStations) — 가게 routeDraft 로 가름: 없음 · 있음 · 초안 버린 직후 */ const seed = (P, R) => { m.writeState("section-detail", canonDetail(), P, R); diff --git a/resources/tester/test_272_swap_keeps_canon.py b/resources/tester/test_272_swap_keeps_canon.py index c5c91f970..32e6204e4 100644 --- a/resources/tester/test_272_swap_keeps_canon.py +++ b/resources/tester/test_272_swap_keeps_canon.py @@ -82,6 +82,13 @@ def test_되돌림_정본과_바이트_같음(out): assert back["45.00"]["browser"] # 관 측점 = 브라우저 표본(정본은 저장 뒤 서버 값) +def test_격자에_구조물_놓고_뺌_같은_자리_정본(out): + g = out["gridStructure"] + assert g["placed"]["same"] and not g["placed"]["browser"] # 열쇠 바뀜(구조물) · 같은 자리 = 정본 + assert g["removed"]["same"] and not g["removed"]["browser"] # 다시 격자 = 정본 표본 · 기하 + assert g["removedBytes"] + + def test_노선_초안_차례는_옛_규칙(out): draft = out["pure"]["draft"] for at in CURVES: # 축 차 > 1e-4 = 새 표본