From 52858c5078e39cef4e5807c26bc663a3b1a5cf7b Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 25 Oct 2026 23:00:57 +0900 Subject: [PATCH 1/3] =?UTF-8?q?fix(534-4):=20E05=203D=EC=9A=94=EC=95=BD=20?= =?UTF-8?q?=E2=80=94=202D=20=EC=B5=9C=EC=86=8C=20=3D=203D=20=EC=99=80=20?= =?UTF-8?q?=EA=B0=99=EC=9D=80=20=EC=A1=B0=EA=B1=B4(=EC=9A=B0=EA=B8=B0=203D?= =?UTF-8?q?=20=EB=A5=BC=20=EA=B1=B4=EA=B8=B0=20=C2=B7=20=EC=A0=84=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=EC=B5=9C=EC=86=8C=EC=99=80=20=EA=B2=AC?= =?UTF-8?q?=EC=A3=BC=EB=8D=98=20=EA=B2=83)=20=C2=B7=20=ED=8C=90=EC=A0=95?= =?UTF-8?q?=20=3D=20E04=20=EC=97=94=EC=A7=84=20=ED=8C=90=EC=A0=95(?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=EC=95=88=EC=A0=84=EC=9C=A8=20=EA=B1=B4?= =?UTF-8?q?=EA=B8=B0=20=EA=B3=A0=EC=A0=95=EC=9D=B4=EB=8D=98=20=EA=B2=83)?= =?UTF-8?q?=20=C2=B7=20=EC=8B=9C=ED=97=98=203D=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=EB=B3=B8=EC=97=90=20condition=20=C2=B7=20verdict?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- E05_StabReport/E05_StabReport_Build.py | 13 +++++++++---- resources/tester/test_534_3_e05_report.py | 14 +++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/E05_StabReport/E05_StabReport_Build.py b/E05_StabReport/E05_StabReport_Build.py index e8c771ad7..1972d4844 100644 --- a/E05_StabReport/E05_StabReport_Build.py +++ b/E05_StabReport/E05_StabReport_Build.py @@ -136,6 +136,7 @@ def _row2d(row: dict[str, Any], method: str) -> dict[str, Any]: cond: sides[side]["fs"] for cond, sides in cases.items() if side in sides }, "fs_min": min(values) if values else None, + "min_by_condition": row.get("min") or {}, "method": method, "verdict": "ng" if "ng" in verdicts else "ok" if verdicts == {"ok"} else None, "representative": row.get("representative") or {}, @@ -553,19 +554,23 @@ def fill_3d(sheet: dict[str, Any], inputs: dict[str, Any]) -> tuple[str, str]: ground = inputs["ground"] labels = _labels(inputs["stations"]) rows2d = inputs["result2d"]["stations"] - crit = _criterion(ground, "dry") sections = [] for i, sec in enumerate(inputs["sections3d"]): r = 20 + i _copy_row(sheet, 20, r, "ABCDEGH") start, end = float(sec["start_m"]), float(sec["end_m"]) + cond = sec.get("condition") or "dry" # 2D 는 3D 와 같은 조건끼리 견줌 inside = [ - float(s["fs_min"]) + float(s["min_by_condition"][cond]) for s in rows2d - if s.get("fs_min") is not None and start - 1e-6 <= float(s["chainage_m"]) <= end + 1e-6 + if s["min_by_condition"].get(cond) is not None + and start - 1e-6 <= float(s["chainage_m"]) <= end + 1e-6 ] f3 = float(sec["f_min"]) - ok = f3 >= crit - 1e-9 + if sec.get("verdict") in ("ok", "ng"): # 판정 = E04 엔진 값(기준안전율도 E04) + ok = sec["verdict"] == "ok" + else: + ok = f3 >= _criterion(ground, cond) - 1e-9 _set(sheet, f"A{r}", f"{i + 1}구간" + (" (미리보기)" if sec.get("preview") else "")) _set(sheet, f"B{r}", _label_at(labels, start)) _set(sheet, f"C{r}", _label_at(labels, end)) diff --git a/resources/tester/test_534_3_e05_report.py b/resources/tester/test_534_3_e05_report.py index 559d192b0..597c484d3 100644 --- a/resources/tester/test_534_3_e05_report.py +++ b/resources/tester/test_534_3_e05_report.py @@ -157,7 +157,15 @@ def project(tmp_path, monkeypatch) -> Path: { "fingerprint": "3d-1", "settings": {}, - "summary": {"start_m": 0.0, "end_m": 200.0, "f_min": 1.42, "volume": 830.0}, + "summary": { + "start_m": 0.0, + "end_m": 200.0, + "f_min": 1.42, + "volume": 830.0, + "condition": "wet", + "reference_fs": 1.3, + "verdict": "ok", + }, } ), encoding="utf-8", @@ -215,8 +223,8 @@ def test_처음_만듦_측점수_NG_그림(project): assert s3["A26"]["값"] == "풍화토" and s3["B32"]["값"].startswith("0 ~ 100 m 위 지층") assert s3["A32"]["값"] == "붕적토" and s3["B13"]["값"] == 1.3 s6 = by["3D요약"]["칸"] - assert s6["D20"]["값"] == 1.42 and s6["H20"] == {"값": "N.G", "서식": build.ST_NG} - assert s6["E20"]["값"] == pytest.approx(1.11) # 0~200 m 안 2D 최소 + assert s6["D20"]["값"] == 1.42 and s6["H20"] == {"값": "O.K", "서식": build.ST_OK} # E04 판정 + assert s6["E20"]["값"] == pytest.approx(1.11) # 0~200 m 안 2D 우기 최소(3D 와 같은 조건) assert (build.initial_dir(project) / build.REPORT).is_file() assert saved["fingerprint"] == build.analysis_fingerprint(project) From 0a6066f19bba57ad7a1c175ad355675c2f788429 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 25 Oct 2026 23:03:48 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix(534-4):=20528=20E01=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=8B=9C=ED=97=98=20=E2=80=94=20=EC=9D=91=EB=8B=B5?= =?UTF-8?q?=20warnings=20=EC=B9=B8(532-1=20=EB=8D=A7=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20=EB=B3=B5=EC=82=AC=20=EA=B2=BD=EA=B3=A0)=EC=9D=84=20?= =?UTF-8?q?=EA=B8=B0=EB=8C=80=EA=B0=92=EC=97=90=20=EB=84=A3=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 낡은 기대값: 532-1 덧에서 E01 생성 응답에 warnings 를 더했는데 528 시험은 옛 응답 꼴을 봄. Co-Authored-By: Claude Opus 5.5 --- resources/tester/test_528_project_groups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/tester/test_528_project_groups.py b/resources/tester/test_528_project_groups.py index e63553e50..be54ebcd6 100644 --- a/resources/tester/test_528_project_groups.py +++ b/resources/tester/test_528_project_groups.py @@ -165,7 +165,7 @@ def test_e01_requires_b06(monkeypatch): call() assert e.value.status_code == 404 seen, call = _e01(monkeypatch, [{**src, "project_year": 2026, "section_complete": 1}]) - assert call() == {"project_id": "stab-id", "source_fingerprint": "f" * 40} + assert call() == {"project_id": "stab-id", "source_fingerprint": "f" * 40, "warnings": []} assert seen["copied"] == ("stab-id", "s" * 36) assert seen["kind"] == "STABILITY" and seen["source_project_id"] == "s" * 36 assert seen["name"] == "임도 안정성평가" From 7de68f0ca1aa4da710667ef2db9b24f75ea6fb98 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 25 Oct 2026 23:14:54 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix(532-5):=20E03=20=ED=9A=A1=EB=8B=A8=20?= =?UTF-8?q?=EA=B8=80(=EC=95=88=EC=A0=84=EC=9C=A8=20=C2=B7=20=EC=A4=91?= =?UTF-8?q?=EC=8B=AC)=EC=9D=B4=20=EC=B2=98=EC=9D=8C=20=EB=B3=B4=EA=B8=B0?= =?UTF-8?q?=20=ED=99=95=EB=8C=80=20=EB=B0=B0=EC=9C=A8=EB=A7=8C=ED=81=BC=20?= =?UTF-8?q?=EC=BB=A4=EC=A7=80=EB=8D=98=20=EA=B2=83=20=E2=80=94=20=EA=B8=80?= =?UTF-8?q?=EC=9E=90=EB=8A=94=20=EB=B0=B0=EC=9C=A8=20=EC=97=AD=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- E03_StabSection/E03_StabSection_UI_Section.ts | 16 +++++++++++++--- E03_StabSection/E03_StabSection_UI_Style.css | 6 +++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/E03_StabSection/E03_StabSection_UI_Section.ts b/E03_StabSection/E03_StabSection_UI_Section.ts index 7a50b1f15..8bbd73618 100644 --- a/E03_StabSection/E03_StabSection_UI_Section.ts +++ b/E03_StabSection/E03_StabSection_UI_Section.ts @@ -305,7 +305,14 @@ export function createSectionCanvas(onPick: (index: number | null) => void): Sec labels.append( svgEl( "text", - { x: ax + 8, y: ay - 10, class: "e03-label e03-label--fs", "data-role": "fs-label" }, + { + x: ax, + y: ay, + dx: "0.6em", + dy: "-0.7em", + class: "e03-label e03-label--fs", + "data-role": "fs-label", + }, `Fs = ${fmt(critical.fs)}`, ), ); @@ -313,7 +320,7 @@ export function createSectionCanvas(onPick: (index: number | null) => void): Sec labels.append( svgEl( "text", - { x: ax + 8, y: ay + 6, class: "e03-label" }, + { x: ax, y: ay, dx: "0.7em", dy: "0.5em", class: "e03-label" }, `Xc ${fmt(critical.center[0], 2)} · Zc ${fmt(critical.center[1], 2)} · R ${fmt(critical.radius, 2)} m`, ), ); @@ -351,7 +358,10 @@ export function createSectionCanvas(onPick: (index: number | null) => void): Sec maxScale: MAX_SCALE, home: focusHome(fit, view, analysis, width, height, MAX_SCALE), initial: zoom, - onChange: (state) => (zoom = state), + onChange: (state) => { + zoom = state; + labels.style.setProperty("--e03-label-k", String(1 / state.scale)); // 글자는 확대 안 함 + }, }); }; diff --git a/E03_StabSection/E03_StabSection_UI_Style.css b/E03_StabSection/E03_StabSection_UI_Style.css index 63c515748..c7bbb4419 100644 --- a/E03_StabSection/E03_StabSection_UI_Style.css +++ b/E03_StabSection/E03_StabSection_UI_Style.css @@ -420,14 +420,14 @@ .e03-label { fill: var(--color-text); - font-size: 12px; + font-size: calc(12px * var(--e03-label-k, 1)); paint-order: stroke; stroke: var(--e03-plot); - stroke-width: 3px; + stroke-width: calc(3px * var(--e03-label-k, 1)); } .e03-label--fs { - font-size: 14px; + font-size: calc(14px * var(--e03-label-k, 1)); font-weight: 700; }