Merge remote-tracking branch 'origin/sub_laptop_8' into main_laptop_1
This commit is contained in:
@@ -1850,11 +1850,56 @@
|
||||
"pipe:p35100": 7.9
|
||||
},
|
||||
"warnings": [
|
||||
"chainage 1080.0m: 인접 직선이 짧아 종단곡선 길이를 0.1m(반경 1m)로 줄였습니다.",
|
||||
"chainage 340.0m: 인접 직선이 짧아 종단곡선 길이를 9.9m(반경 26m)로 줄였습니다.",
|
||||
"chainage 351.0m: 인접 직선이 짧아 종단곡선 길이를 8.1m(반경 25m)로 줄였습니다.",
|
||||
"chainage 360.0m: 인접 직선이 짧아 종단곡선 길이를 8.1m(반경 231m)로 줄였습니다.",
|
||||
"종단기울기 56.60%가 기준 14.00%를 초과하는 구간이 34개 있습니다."
|
||||
"100.0m: 종단곡선 R 57m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"1000.0m: 종단곡선 R 73m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"1020.0m: 종단곡선 R 31m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"1060.0m: 종단곡선 R 25m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"1080.0m: 인접 직선이 짧아 종단곡선 길이를 0.1m(반경 1m)로 줄였습니다.",
|
||||
"1080.0m: 종단곡선 R 1m · L 0.1m — 법정 최소 R 100m · L 20m 미달",
|
||||
"140.0m: 종단곡선 R 53m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"20.0m: 종단곡선 R 205m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"200.0m: 종단곡선 R 154m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"220.0m: 종단곡선 R 285m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"240.0m: 종단곡선 R 61m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"260.0m: 종단곡선 R 24m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"280.0m: 종단곡선 R 21m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"300.0m: 종단곡선 R 196m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"320.0m: 종단곡선 R 118m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"340.0m: 인접 직선이 짧아 종단곡선 길이를 9.9m(반경 26m)로 줄였습니다.",
|
||||
"340.0m: 종단곡선 R 26m · L 9.9m — 법정 최소 R 100m · L 20m 미달",
|
||||
"351.0m: 인접 직선이 짧아 종단곡선 길이를 8.1m(반경 25m)로 줄였습니다.",
|
||||
"351.0m: 종단곡선 R 25m · L 8.1m — 법정 최소 R 100m · L 20m 미달",
|
||||
"360.0m: 인접 직선이 짧아 종단곡선 길이를 8.1m(반경 231m)로 줄였습니다.",
|
||||
"40.0m: 종단곡선 R 55m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"400.0m: 종단곡선 R 105m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"420.0m: 종단곡선 R 100m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"440.0m: 종단곡선 R 117m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"460.0m: 종단곡선 R 48m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"480.0m: 종단곡선 R 46m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"520.0m: 종단곡선 R 24m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"540.0m: 종단곡선 R 41m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"560.0m: 종단곡선 R 53m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"580.0m: 종단곡선 R 123m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"600.0m: 종단곡선 R 40m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"620.0m: 종단곡선 R 88m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"640.0m: 종단곡선 R 147m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"660.0m: 종단곡선 R 28m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"680.0m: 종단곡선 R 14m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"700.0m: 종단곡선 R 49m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"720.0m: 종단곡선 R 38m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"740.0m: 종단곡선 R 55m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"760.0m: 종단곡선 R 36m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"780.0m: 종단곡선 R 54m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"80.0m: 종단곡선 R 58m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"800.0m: 종단곡선 R 13m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"820.0m: 종단곡선 R 45m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"840.0m: 종단곡선 R 29m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"880.0m: 종단곡선 R 29m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"900.0m: 종단곡선 R 115m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"920.0m: 종단곡선 R 44m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"940.0m: 종단곡선 R 66m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"960.0m: 종단곡선 R 23m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"980.0m: 종단곡선 R 42m · L 15.0m — 법정 최소 R 100m · L 20m 미달"
|
||||
],
|
||||
"violations": 34
|
||||
},
|
||||
@@ -2783,6 +2828,7 @@
|
||||
"1000.0m: 종단곡선 R 73m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"1020.0m: 종단곡선 R 31m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"1060.0m: 종단곡선 R 25m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"1080.0m: 인접 직선이 짧아 종단곡선 길이를 0.1m(반경 1m)로 줄였습니다.",
|
||||
"1080.0m: 종단곡선 R 1m · L 0.1m — 법정 최소 R 100m · L 20m 미달",
|
||||
"140.0m: 종단곡선 R 53m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"20.0m: 종단곡선 R 205m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
@@ -2793,8 +2839,11 @@
|
||||
"280.0m: 종단곡선 R 21m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"300.0m: 종단곡선 R 196m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"320.0m: 종단곡선 R 118m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"340.0m: 인접 직선이 짧아 종단곡선 길이를 9.9m(반경 26m)로 줄였습니다.",
|
||||
"340.0m: 종단곡선 R 26m · L 9.9m — 법정 최소 R 100m · L 20m 미달",
|
||||
"351.0m: 인접 직선이 짧아 종단곡선 길이를 8.1m(반경 25m)로 줄였습니다.",
|
||||
"351.0m: 종단곡선 R 25m · L 8.1m — 법정 최소 R 100m · L 20m 미달",
|
||||
"360.0m: 인접 직선이 짧아 종단곡선 길이를 8.1m(반경 231m)로 줄였습니다.",
|
||||
"40.0m: 종단곡선 R 55m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"400.0m: 종단곡선 R 105m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"420.0m: 종단곡선 R 100m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
@@ -2824,12 +2873,7 @@
|
||||
"920.0m: 종단곡선 R 44m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"940.0m: 종단곡선 R 66m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"960.0m: 종단곡선 R 23m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"980.0m: 종단곡선 R 42m · L 15.0m — 법정 최소 R 100m · L 20m 미달",
|
||||
"chainage 1080.0m: 인접 직선이 짧아 종단곡선 길이를 0.1m(반경 1m)로 줄였습니다.",
|
||||
"chainage 340.0m: 인접 직선이 짧아 종단곡선 길이를 9.9m(반경 26m)로 줄였습니다.",
|
||||
"chainage 351.0m: 인접 직선이 짧아 종단곡선 길이를 8.1m(반경 25m)로 줄였습니다.",
|
||||
"chainage 360.0m: 인접 직선이 짧아 종단곡선 길이를 8.1m(반경 231m)로 줄였습니다.",
|
||||
"종단기울기 56.60%가 기준 14.00%를 초과하는 구간이 34개 있습니다."
|
||||
"980.0m: 종단곡선 R 42m · L 15.0m — 법정 최소 R 100m · L 20m 미달"
|
||||
],
|
||||
"violations": 34
|
||||
},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""472-1 기준값 — 고정 자료(`fixtures/golden_472`) 하나로 길 넷의 값을 뜸(시험 · 값 뜨기 함께 씀).
|
||||
|
||||
stored GET 상세(정본 그대로) → 누가토량(서버 Node 묶음 `computeMassHaul`)
|
||||
server_save [저장] 서버 재계산 — 정본 상세 → `enforce_design_lines` →
|
||||
`_enforce_stored_designs` → server-calc
|
||||
server_save [저장] 서버 재계산 — 정본 상세 → 종단 경고 다시 셈(`refresh_alignment` · 472 덧) →
|
||||
`enforce_design_lines` → `_enforce_stored_designs` → server-calc
|
||||
server_route 노선 저장 체인(같은 노선 · DB 없이) — `run_section_generation`(고정 geojson · npz)
|
||||
→ `_carry_profile` 같은 노선 갈래(옛 base_pvi · 편집) → `_apply_alignment_edits` →
|
||||
측점 열쇠 이월(`carry_cross_inputs`) → `compute_default_designs` → 상세 읽기 →
|
||||
@@ -125,19 +125,21 @@ def _context() -> dict[str, Any]:
|
||||
|
||||
|
||||
def _save_tail(detail: dict[str, Any], root: Path) -> tuple[list, dict | None]:
|
||||
"""[저장] 재계산 본문(`_recompute`) — 설계선 · 넓힘 · 보정 → Node 면적 · 누가토량 얹음."""
|
||||
"""[저장] 재계산(`_recompute`) — 종단 경고 · 설계선 · 넓힘 · 보정 → Node 면적 · 누가토량."""
|
||||
from B06_Section.B06_Section_Router_Design import enforce_design_lines
|
||||
from B06_Section.B06_Section_Server_Calc_Prebuild import (
|
||||
_AREA_KEYS,
|
||||
_NPM_SCRIPT,
|
||||
BUNDLE,
|
||||
_enforce_stored_designs,
|
||||
refresh_alignment,
|
||||
)
|
||||
from common_util.common_util_node_bundle import run_bundle_json
|
||||
from common_util.common_util_surface_sampler import build_surface_sampler
|
||||
|
||||
longitudinal = detail["longitudinal"]
|
||||
sections = detail["cross_sections"]
|
||||
refresh_alignment(longitudinal)
|
||||
enforce_design_lines(longitudinal, sections, root, None)
|
||||
unclosed = any((s.get("design") or {}).get("slope_unclosed") for s in sections)
|
||||
sampler = (
|
||||
@@ -163,9 +165,9 @@ def _save_tail(detail: dict[str, Any], root: Path) -> tuple[list, dict | None]:
|
||||
|
||||
def server_save(root: Path) -> dict[str, Any]:
|
||||
detail = copy.deepcopy(read("detail.json"))
|
||||
alignment = detail["longitudinal"].get("profile_alignment") or {}
|
||||
keys = _keys(detail["longitudinal"], detail["cross_sections"], root)
|
||||
sections, haul = _save_tail(detail, root)
|
||||
alignment = detail["longitudinal"].get("profile_alignment") or {}
|
||||
return values_of(
|
||||
sections, keys, haul, alignment.get("warnings") or [], alignment.get("violations") or []
|
||||
)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/* 472 덧 종단 경고 거울 헬퍼 — `logic/B05_Profile_UI_Profile_Alignment.ts` `buildAlignment` 를 그 자리에서
|
||||
* 트랜스파일해 돌림. 입력 argv[2] JSON { base, cases: [edits] } · 표준출력 JSON [{ warnings, violations }].
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
|
||||
const cache = new Map();
|
||||
function loadTs(file) {
|
||||
const full = path.resolve(file);
|
||||
if (cache.has(full)) return cache.get(full);
|
||||
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
|
||||
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
||||
}).outputText;
|
||||
const box = { exports: {} };
|
||||
cache.set(full, box.exports);
|
||||
const localRequire = (request) =>
|
||||
request.startsWith(".")
|
||||
? loadTs(path.join(path.dirname(full), `${request}.ts`))
|
||||
: require(request);
|
||||
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
|
||||
return box.exports;
|
||||
}
|
||||
|
||||
const align = loadTs(
|
||||
path.join(__dirname, "..", "..", "B05_Profile", "logic", "B05_Profile_UI_Profile_Alignment.ts"),
|
||||
);
|
||||
const input = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
input.cases.map((edits) => {
|
||||
const built = align.buildAlignment(input.base, edits);
|
||||
return { warnings: built.warnings, violations: built.violations.length };
|
||||
}),
|
||||
),
|
||||
);
|
||||
@@ -44,10 +44,15 @@ class Known:
|
||||
|
||||
|
||||
KNOWN: dict[tuple[str, str], list[Known]] = {
|
||||
(
|
||||
"server_save",
|
||||
"stored",
|
||||
): [], # [저장] 재계산 = 정본 그대로(사용자 원칙 — 입력 안 바뀌면 값 안 바뀜)
|
||||
# [저장] 재계산 = 정본 그대로(사용자 원칙 — 입력 안 바뀌면 값 안 바뀜) · 경고만 지금 코드
|
||||
("server_save", "stored"): [
|
||||
Known(
|
||||
"W0",
|
||||
{"warnings": None},
|
||||
"정본 종단 경고 = 10-17 저장 때 코드(법정 R · L 미달 46 줄 전) · "
|
||||
"[저장] 재계산이 지금 코드로 다시 씀(472 덧 · 기하 그대로)",
|
||||
),
|
||||
],
|
||||
("server_route", "stored"): [
|
||||
Known(
|
||||
"R7",
|
||||
@@ -58,7 +63,7 @@ KNOWN: dict[tuple[str, str], list[Known]] = {
|
||||
"W0",
|
||||
{"warnings": None},
|
||||
"정본 종단 경고 = 10-17 저장 때 코드(법정 R · L 미달 46 줄 전) · "
|
||||
"[저장] 재계산은 종단 경고를 안 씀",
|
||||
"노선 저장 체인은 지금 코드",
|
||||
),
|
||||
],
|
||||
("browser", "server_route"): [
|
||||
@@ -76,12 +81,6 @@ KNOWN: dict[tuple[str, str], list[Known]] = {
|
||||
"측점 자리 ≤ 1 mm → 표본 · 면적 ≤ 0.07 ㎡ · 층따기 밑수 ≤ 0.52 m · "
|
||||
"누가토량 끝값 0.69 ㎥(−17,570.01 ↔ −17,570.70)",
|
||||
),
|
||||
Known(
|
||||
"W1",
|
||||
{"warnings": None},
|
||||
"종단 경고 글 두 벌(X5 · P8) — TS 「340.0m: …」 · 파이썬 「chainage 340.0m: …」 · "
|
||||
"최대 기울기 총괄 줄은 파이썬만",
|
||||
),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
"""PLAN 472 덧 (요구 272) — [저장] · [확정] 재계산이 종단 경고를 저장 입력으로 다시 씀.
|
||||
|
||||
증상 — 검증_랩탑메인 정본 종단 경고 5 줄(10-17 옛 코드) · 지금 코드로 셈하면 50 줄 ·
|
||||
[저장] · [확정] 재계산(`B06_Section_Server_Calc_Prebuild._recompute`)이 경고를 다시 안 셈.
|
||||
고침 — `_recompute` 맨 앞 `_refresh_alignment_file` → `refresh_alignment`(저장 base_pvi · 편집 ·
|
||||
정책 · 기준 → `rebuild_alignment_profile` 의 경고만) · 기하는 저장값 그대로 · 같으면 안 씀.
|
||||
경고 글 = TS `buildAlignment` 와 한 벌(거울). 고정 자료 = `fixtures/golden_472/detail.json`.
|
||||
|
||||
./venv/Scripts/python.exe -m pytest resources/tester/test_472_save_warnings.py -q
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import inspect
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
ROOT = HERE.parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from B05_Profile.B05_Profile_Engine_Grade import ground_profile # noqa: E402
|
||||
from B05_Profile.B05_Profile_Engine_Grade_Alignment import chainage_key # noqa: E402
|
||||
from B05_Profile.B05_Profile_Engine_Grade_Profile import rebuild_alignment_profile # noqa: E402
|
||||
from B06_Section import B06_Section_Server_Calc_Prebuild as prebuild # noqa: E402
|
||||
|
||||
FIXTURE = HERE / "fixtures" / "golden_472"
|
||||
DETAIL = json.loads((FIXTURE / "detail.json").read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def _longitudinal() -> dict:
|
||||
return copy.deepcopy(DETAIL["longitudinal"])
|
||||
|
||||
|
||||
def test_정본_경고는_옛_코드_5줄() -> None:
|
||||
assert len(DETAIL["longitudinal"]["profile_alignment"]["warnings"]) == 5
|
||||
|
||||
|
||||
def test_다시_셈_경고만_새로_기하는_그대로() -> None:
|
||||
longitudinal = _longitudinal()
|
||||
before = copy.deepcopy(longitudinal)
|
||||
summary = prebuild.refresh_alignment(longitudinal)
|
||||
warnings = longitudinal["profile_alignment"]["warnings"]
|
||||
assert len(warnings) == 50
|
||||
assert sum("법정 최소 R" in w for w in warnings) == 46 # 432 법정 R · L 미달
|
||||
assert not [w for w in warnings if w.startswith("chainage ")]
|
||||
assert summary is not None and summary["warnings"] == warnings
|
||||
assert summary["id"] == before["design_profiles"][0]["id"]
|
||||
assert longitudinal["design_profiles"][0]["summary"]["warnings"] == warnings
|
||||
# 경고 밖 = 저장값 그대로(계획고 · 곡선 · 표본 · 위반 · 정책 — 6 자리 반올림 끝자리도)
|
||||
longitudinal["profile_alignment"]["warnings"] = before["profile_alignment"]["warnings"]
|
||||
longitudinal["design_profiles"][0]["summary"]["warnings"] = before["design_profiles"][0][
|
||||
"summary"
|
||||
]["warnings"]
|
||||
assert longitudinal == before
|
||||
|
||||
|
||||
def test_선형_없는_옛_종단은_그대로() -> None:
|
||||
longitudinal = _longitudinal()
|
||||
longitudinal["profile_alignment"].pop("base_pvi")
|
||||
keep = copy.deepcopy(longitudinal)
|
||||
assert prebuild.refresh_alignment(longitudinal) is None
|
||||
assert longitudinal == keep
|
||||
|
||||
|
||||
def test_파일_다시_씀_같으면_안_씀(tmp_path) -> None:
|
||||
path = tmp_path / "B06_Section" / "longitudinal" / "longitudinal.json"
|
||||
path.parent.mkdir(parents=True)
|
||||
path.write_text(json.dumps(_longitudinal()), encoding="utf-8")
|
||||
relative = "B06_Section/longitudinal/longitudinal.json"
|
||||
first = prebuild._refresh_alignment_file(tmp_path, relative)
|
||||
stored = json.loads(path.read_text(encoding="utf-8"))
|
||||
assert first is not None and len(stored["profile_alignment"]["warnings"]) == 50
|
||||
written = path.stat().st_mtime_ns
|
||||
assert prebuild._refresh_alignment_file(tmp_path, relative) == first
|
||||
assert path.stat().st_mtime_ns == written # 같은 값 — 다시 안 씀
|
||||
assert prebuild._refresh_alignment_file(tmp_path, "없음/longitudinal.json") is None
|
||||
|
||||
|
||||
def test_재계산_맨_앞에서_선형_다시_셈() -> None:
|
||||
source = inspect.getsource(prebuild._recompute)
|
||||
assert "_refresh_alignment_file" in source and "update_longitudinal_grade_summary" in source
|
||||
assert source.index("_refresh_alignment_file") < source.index("get_section_detail(")
|
||||
|
||||
|
||||
def test_TS_거울_같은_경고_목록(tmp_path) -> None:
|
||||
longitudinal = _longitudinal()
|
||||
alignment = longitudinal["profile_alignment"]
|
||||
# 옛 정책엔 법정 R · L 이 없음 — 두 쪽 다 기준으로 채운 정책(433-13 · TS `readAlignment`)
|
||||
policy = rebuild_alignment_profile(longitudinal, alignment["edits"])[0]["policy"]
|
||||
assert (
|
||||
policy["min_vertical_radius_m"] == 100.0
|
||||
and "min_vertical_radius_m" not in alignment["policy"]
|
||||
)
|
||||
chainage, ground = ground_profile(longitudinal)
|
||||
curve = alignment["curves"][1]
|
||||
station = longitudinal["stations"][5]
|
||||
cases = [
|
||||
alignment["edits"],
|
||||
{"station_offsets": {}, "curve_radii": {chainage_key(curve["chainage_m"]): 500.0}},
|
||||
{"station_offsets": {chainage_key(station["chainage_m"]): 3.0}, "curve_radii": {}},
|
||||
]
|
||||
base = {
|
||||
"policy": policy,
|
||||
"onlyExplicitCurves": bool(alignment.get("only_explicit_curves")),
|
||||
"basePvi": alignment["base_pvi"],
|
||||
"chainage": chainage.tolist(),
|
||||
"ground": ground.tolist(),
|
||||
"stations": [
|
||||
{"station_id": s.get("station_id"), "chainage_m": s["chainage_m"]}
|
||||
for s in longitudinal["stations"]
|
||||
],
|
||||
}
|
||||
source = tmp_path / "in.json"
|
||||
source.write_text(json.dumps({"base": base, "cases": cases}), encoding="utf-8")
|
||||
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||||
["node", str(HERE / "helper_472_save_warnings.cjs"), str(source)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
timeout=60,
|
||||
)
|
||||
assert proc.returncode == 0, proc.stderr
|
||||
for edits, got in zip(cases, json.loads(proc.stdout), strict=True):
|
||||
py, _profile = rebuild_alignment_profile(copy.deepcopy(longitudinal), edits)
|
||||
assert got["warnings"] == py["warnings"]
|
||||
assert got["violations"] == len(py["violations"])
|
||||
Reference in New Issue
Block a user