From 4d8eac4d2e372096e3fc8884934a3a4f5a329d30 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 26 Oct 2026 03:32:37 +0900 Subject: [PATCH] =?UTF-8?q?feat(536-1):=20E05=20=EB=B3=B4=EA=B3=A0?= =?UTF-8?q?=EC=84=9C=20=EC=95=94=EB=B0=98=EA=B2=80=ED=86=A0=20=EC=8B=9C?= =?UTF-8?q?=ED=8A=B8(=EC=9E=88=EC=9D=84=20=EB=95=8C=EB=A7=8C)=20=E2=80=94?= =?UTF-8?q?=20E06=20=ED=95=B4=EC=84=9D=20=EC=A1=B0=EA=B1=B4=20=C2=B7=20?= =?UTF-8?q?=EC=A0=88=EB=A6=AC=EA=B5=B0=20=C2=B7=20=EC=B8=A1=EC=A0=90=20?= =?UTF-8?q?=EC=9C=84=ED=97=98=20=EB=AA=A8=EB=93=9C=20=C3=97=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20Fs=20=C2=B7=20=ED=8C=90=EC=A0=95=20=C2=B7=20?= =?UTF-8?q?=EC=96=91=EC=8B=9D=20s11=20=C2=B7=20=EC=9E=90=EB=A6=AC=ED=91=9C?= =?UTF-8?q?=20=C2=B7=20E06=20=EC=A0=80=EC=9E=A5=EB=B3=B8=EC=97=90=20?= =?UTF-8?q?=EC=A0=88=EB=A6=AC=EA=B5=B0?= 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 | 12 +- E05_StabReport/E05_StabReport_Print.py | 1 + E05_StabReport/E05_StabReport_Rock.py | 214 +++++++++ E06_StabRock/E06_StabRock_Router.py | 1 + .../master_template/report/stab_report.json | 446 ++++++++++++++++++ .../report/stab_report_slots.md | 12 +- .../tester/test_534_3_stab_report_form.py | 10 +- resources/tester/test_536_1_e06_rock.py | 48 ++ 8 files changed, 736 insertions(+), 8 deletions(-) create mode 100644 E05_StabReport/E05_StabReport_Rock.py diff --git a/E05_StabReport/E05_StabReport_Build.py b/E05_StabReport/E05_StabReport_Build.py index 241c49336..0105cd5e1 100644 --- a/E05_StabReport/E05_StabReport_Build.py +++ b/E05_StabReport/E05_StabReport_Build.py @@ -3,13 +3,14 @@ 입력 = E02 지반 조건(`ground.json`) · E03 2D 파생 저장본(`stab2d_summary` 가장 최근 · 측점별 `stab2d_station`) · 대표 단면(E03 자동 + `representative.json` 켬/끔) · E04 3D 저장본 요약 (있으면) · E07 광역 저장본(있으면) · E03 보강 검토 저장본(있으면 · 없으면 s8 뺌) · +E06 암반 해석 저장본(있으면 · 없으면 s11 뺌) · E01 복사본(측점 · 횡단 · 노선). 양식 = `resources/master_template/report/stab_report.json` 칸 자리 = 같은 폴더 `stab_report_slots.md`. 몫: 사용자(표지 s1 · 개요 s2) = 처음 만들 때만 채움 · 프로그램(목차 s9 · 입력조건 s3 · 측점표 s4 · 대표단면 s5 · 3D요약 s6 · 광역요약 s7 · 보강검토 s8 · -부록_절편 s10) = [보고서 갱신] 때 양식에서 통째로 다시 씀. 대표 단면 · 부록 = `_Section` · +암반검토 s11 · 부록_절편 s10) = [보고서 갱신] 때 양식에서 통째로 다시 씀. 대표 단면 · 부록 = `_Section` · 목차 쪽 번호 · 머리말/꼬리말 · 긴 표 쪽 나눔 = `_Print` · 칸 공용 = `_Cells`. 판정 글 칸 = 엔진 판정 값 + N.G 서식 10 · O.K 서식 11 을 직접 붙임 (인쇄 HTML · xlsx 는 조건부 서식을 안 먹음). @@ -38,6 +39,7 @@ from E05_StabReport import E05_StabReport_Area as area from E05_StabReport import E05_StabReport_Figure as figure from E05_StabReport import E05_StabReport_Print as printer from E05_StabReport import E05_StabReport_Reinforce as reinforce +from E05_StabReport import E05_StabReport_Rock as rock from E05_StabReport import E05_StabReport_Section as section from E05_StabReport.E05_StabReport_Cells import ( # noqa: F401 — 시험 · 다른 모듈이 build.* 로 씀 A1, @@ -60,7 +62,7 @@ FORM_PATH = ROOT / "resources" / "master_template" / "report" / "stab_report.jso STAGE = "E05_StabReport" REPORT, META = "report.json", "report_meta.json" USER_SHEETS = ("s1", "s2") -PROGRAM_SHEETS = ("s9", "s3", "s4", "s5", "s6", "s7", "s8", "s10") +PROGRAM_SHEETS = ("s9", "s3", "s4", "s5", "s6", "s7", "s8", "s11", "s10") REPRESENTATIVE = Path("E03_StabSection") / "representative.json" BAND_KEY = "fig/3d_band.png" @@ -167,6 +169,7 @@ def analysis_fingerprint(project_root: Path) -> str: else [], "area": area.stamp(project_root), "reinforce": reinforce.stamp(project_root), + "rock": rock.stamp(project_root), "form": hashlib.sha1(FORM_PATH.read_bytes()).hexdigest(), } text = json.dumps(body, ensure_ascii=False, sort_keys=True, default=str) @@ -217,6 +220,7 @@ def gather(project_root: Path) -> dict[str, Any]: "sections3d": sorted(sections3d, key=lambda s: s["start_m"]), "area": area.read(project_root), "reinforce": reinforce.read(project_root), + "rock": rock.read(project_root), "fingerprint": analysis_fingerprint(project_root), } @@ -445,6 +449,10 @@ def build_program(book: dict[str, Any], inputs: dict[str, Any]) -> list[tuple[st reinforce.fill_reinforce(by["s8"], inputs["reinforce"], _labels(inputs["stations"])) else: # 보강 검토가 없으면 시트를 뺌 book["시트"] = [s for s in book["시트"] if s["id"] != "s8"] + if inputs.get("rock"): + rock.fill_rock(by["s11"], inputs["rock"], _labels(inputs["stations"])) + else: # 암반 해석이 없으면 시트를 뺌 + book["시트"] = [s for s in book["시트"] if s["id"] != "s11"] printer.fill_toc(by["s9"], book, None) # 쪽 번호 = 저장 전 `printer.number_toc` return jobs diff --git a/E05_StabReport/E05_StabReport_Print.py b/E05_StabReport/E05_StabReport_Print.py index 2da6e4f76..ff06e3dbf 100644 --- a/E05_StabReport/E05_StabReport_Print.py +++ b/E05_StabReport/E05_StabReport_Print.py @@ -31,6 +31,7 @@ TITLES = { "s6": "3D 해석 요약", "s7": "광역 자연사면 위험 요약", "s8": "보강 검토 — 비탈 완화 · 소단 · 벽 외적 안정", + "s11": "암반 비탈면 검토 — 평사투영 · 평면 · 쐐기 안전율", "s10": "대표 단면 절편 계산표", } APPENDIX = {"s10"} diff --git a/E05_StabReport/E05_StabReport_Rock.py b/E05_StabReport/E05_StabReport_Rock.py new file mode 100644 index 000000000..c7ef1fe90 --- /dev/null +++ b/E05_StabReport/E05_StabReport_Rock.py @@ -0,0 +1,214 @@ +"""E05 보고서 s11 암반검토 — E06 암반 해석 저장본(절리 · Markland · Hoek-Bray) → 시트 (PLAN 536-1). + +칸 자리 = `resources/master_template/report/stab_report_slots.md` s11. +저장본이 없으면 시트를 뺌(있을 때만) — `build_program` 이 책에서 지움. +""" + +from __future__ import annotations + +import copy +from pathlib import Path +from typing import Any + +from fastapi import HTTPException + +from E05_StabReport.E05_StabReport_Cells import _set, _verdict, mark +from E06_StabRock import E06_StabRock_Model as rock_model +from E06_StabRock.E06_StabRock_Router import _result + +CONDITION_NAMES = {"dry": "건기", "wet": "우기", "seismic": "지진"} +SIDE_NAMES = {"left": "좌", "right": "우"} +PROJECTION_NAMES = {"equal_angle": "등각(Wulff)", "equal_area": "등면적(Schmidt)"} +VERDICT_NAMES = {"NG": "N.G", "check": "검토", "OK": "O.K", "none": "위험 모드 없음"} +SLIDE_NAMES = {"1": "한 면({a}) 미끄러짐", "2": "한 면({b}) 미끄러짐", "12": "두 면 미끄러짐"} +COLS = "ABCDEFGH" +FIRST = 11 # 이 행부터 절리 · 측점 표를 다시 깔음 + + +def read(project_root: Path) -> dict[str, Any] | None: + """보고서에 쓰는 E06 결과(지금 입력 지문 것 · 없으면 가장 최근) + 낡음 표시.""" + try: + out = _result(Path(project_root), None, None) + except HTTPException: + return None + return {**out["result"], "stale": out["stale"]} if out["result"] else None + + +def stamp(project_root: Path) -> list | None: + """해석 지문용 — 결과 지문 · 낡음.""" + rock = read(project_root) + return [rock["fingerprint"], rock["stale"]] if rock else None + + +def _row_styles(sheet: dict[str, Any], r: int) -> dict[str, dict]: + return {c: copy.deepcopy(sheet["칸"].get(f"{c}{r}") or {}) for c in COLS} + + +def _summary(rock: dict[str, Any]) -> str: + s = rock["summary"] + v = s["verdicts"] + text = ( + f"깎기 비탈 {s['slopes']} · " + + " · ".join(f"{VERDICT_NAMES[k]} {v[k]}" for k in VERDICT_NAMES if v.get(k)) + + f" — 위험 모드 평면 {s['modes']['planar']} · 쐐기 {s['modes']['wedge']} · " + f"전도 {s['modes']['toppling']}" + ) + if rock["stale"]: + text += " · 입력이 해석 뒤 바뀜 — E06 [해석] 뒤 [보고서 갱신]" + return text + + +def fill_rock(sheet: dict[str, Any], rock: dict[str, Any], labels: dict) -> None: + """s11 — 1. 조건 · 요약(5~9 행) · 2. 절리군(한 줄씩 · 13 행 서식) · 3. 측점(17 행 서식).""" + s = rock["settings"] + d = rock_model.DEFAULT_SETTINGS + lateral = (s["lateral_planar_deg"], s["lateral_toppling_deg"]) + _set( + sheet, + "B5", + mark( + f"{PROJECTION_NAMES.get(s['projection'], s['projection'])} 하반구 · " + f"측방 한계 평면 {lateral[0]:g}° · 전도 {lateral[1]:g}°", + lateral == (d["lateral_planar_deg"], d["lateral_toppling_deg"]), + ), + ) + _set( + sheet, + "B6", + f"{s['gamma_r']:g} kN/m³ (사용자 입력)" + if s.get("gamma_r") + else "E02 측점 암 물성 γt (문헌 추정치 · 사용자 확정 전)", + ) + _set( + sheet, + "B7", + mark( + f"인장균열 깊이 · 활동면 높이의 {s['water_fill_wet']:g} 까지 지하수 " + "(KDS 11 70 05 표 4.3-3 암반 = ½ 심도)", + s["water_fill_wet"] == d["water_fill_wet"], + ), + ) + crack = s["crack"] + crack_text = { + "none": "인장균열 없음", + "critical": "인장균열 = 임계(최소 안전율 자리)", + "depth": f"인장균열 깊이 {crack.get('z') or 0:g} m", + }[crack["mode"]] + bolt = s["bolt"] + bolt_text = ( + f"볼트 {bolt['force']:g} (평면 kN/m · 쐐기 kN) · 수평 아래 {bolt['plunge']:g}°" + if bolt["force"] + else "볼트 없음" + ) + _set(sheet, "B8", f"{crack_text} · {bolt_text}") + _set(sheet, "B9", _summary(rock)) + + tpl = {r: _row_styles(sheet, r) for r in (11, 12, 13, 15, 16, 17)} + merged = [m for m in sheet["병합"] if m.startswith(("A11:", "A15:"))] + for a1 in [k for k in sheet["칸"] if int("".join(ch for ch in k if ch.isdigit())) >= FIRST]: + del sheet["칸"][a1] + sheet["병합"] = [m for m in sheet["병합"] if m not in merged] + heights = {k: v for k, v in sheet["행"].items() if int(k) >= FIRST} + sheet["행"] = {k: v for k, v in sheet["행"].items() if int(k) < FIRST} + + def put_row(r: int, src: int) -> None: + for c, cell in tpl[src].items(): + if cell: + sheet["칸"][f"{c}{r}"] = copy.deepcopy(cell) + if str(src) in heights: + sheet["행"][str(r)] = dict(heights[str(src)]) + + def head(r: int, src: int) -> int: + put_row(r, src) + sheet["병합"].append(f"A{r}:H{r}") + put_row(r + 1, src + 1) + return r + 2 + + # 2. 절리군 + r = head(FIRST, 11) + sets = _sets(rock) + for j in sets: + put_row(r, 13) + _set(sheet, f"A{r}", j.get("name") or j["id"]) + for col, key in zip("BCDEF", ("dip_direction", "dip", "phi", "c", "persistence_m")): + value = j.get(key) + _set(sheet, f"{col}{r}", float(value) if value is not None else "-") + _set(sheet, f"G{r}", _station_text(labels, j.get("from_m"))) + _set(sheet, f"H{r}", _station_text(labels, j.get("to_m"))) + r += 1 + if not sets: + put_row(r, 13) + _set(sheet, f"A{r}", "절리군 없음") + r += 1 + + # 3. 측점별 판정 + r = head(r + 1, 15) + for entry in rock["stations"]: + r = _station_rows(sheet, put_row, r, entry, labels) + + +def _sets(rock: dict[str, Any]) -> list[dict[str, Any]]: + """해석에 쓴 절리군 — 옛 저장본(sets 없음)은 측점 결과에 실린 것(지속성 · 구간 없음).""" + if "sets" in rock: + return rock["sets"] + seen: dict[str, dict] = {} + for entry in rock["stations"]: + for j in entry["joints"]: + seen.setdefault(j["id"], j) + return list(seen.values()) + + +def _station_text(labels: dict, chainage: Any) -> Any: + if chainage is None: + return "-" + ch = float(chainage) + return labels.get(round(ch, 3)) or f"{ch:.2f}" + + +def _station_rows(sheet, put_row, r: int, entry: dict[str, Any], labels: dict) -> int: + slope = entry["slope"] + ch = float(entry["chainage_m"]) + name = entry.get("label") or labels.get(round(ch, 3)) or f"{ch:.2f}" + side = ( + f"{SIDE_NAMES.get(slope['side'], slope['side'])} · {slope['dip']:g}° / " + f"{slope['dip_direction']:g}° · 높이 {slope['height_m']:.1f} m" + ) + jname = {j["id"]: j.get("name") or j["id"] for j in entry["joints"]} + rows: list[tuple[str, str, Any, Any, bool | None, str]] = [] + for case in entry["cases"]: + ids = [jname.get(i, i) for i in case["ids"]] + mode = f"평면 {ids[0]}" if case["mode"] == "planar" else f"쐐기 {ids[0]} × {ids[1]}" + notes = [] + if not case["formed"]: + notes.append("블록 안 생김") + if case.get("sliding") == "lift": + notes.append("들림") + elif case.get("sliding") in SLIDE_NAMES: + notes.append(SLIDE_NAMES[case["sliding"]].format(a=ids[0], b=ids[-1])) + if case.get("persistence_short"): + notes.append("지속성 < 활동면") + cond = CONDITION_NAMES.get(case["condition"], case["condition"]) + rows.append( + (mode, cond, case["F"], case.get("required"), case.get("ok"), " · ".join(notes)) + ) + for jid in entry["kinematic"]["toppling"]: + rows.append( + (f"전도 {jname.get(jid, jid)}", "-", None, None, None, "기하 판정만 — 현장 확인") + ) + if not rows: + rows.append(("없음", "-", None, None, None, "위험 모드 없음(Markland)")) + for mode, cond, fs, need, ok, note in rows: + put_row(r, 17) + _set(sheet, f"A{r}", name) + _set(sheet, f"B{r}", side) + _set(sheet, f"C{r}", mode) + _set(sheet, f"D{r}", cond) + _set(sheet, f"E{r}", float(fs) if fs is not None else "-") + _set(sheet, f"F{r}", float(need) if need is not None else "-") + if ok is None: + _set(sheet, f"G{r}", "검토" if mode.startswith("전도") else "-") + else: + _verdict(sheet, f"G{r}", ok) + _set(sheet, f"H{r}", note or None) + r += 1 + return r diff --git a/E06_StabRock/E06_StabRock_Router.py b/E06_StabRock/E06_StabRock_Router.py index 559e41d2d..e6547ea12 100644 --- a/E06_StabRock/E06_StabRock_Router.py +++ b/E06_StabRock/E06_StabRock_Router.py @@ -165,6 +165,7 @@ def _run(root: Path) -> dict[str, Any]: value = { "fingerprint": fp, "settings": joints["settings"], + "sets": joints["sets"], "summary": _summary(stations), "stations": stations, } diff --git a/resources/master_template/report/stab_report.json b/resources/master_template/report/stab_report.json index 8ee581788..4128cb5bc 100644 --- a/resources/master_template/report/stab_report.json +++ b/resources/master_template/report/stab_report.json @@ -3687,6 +3687,452 @@ } } }, + { + "id": "s11", + "이름": "암반검토", + "칸": { + "A1": { + "값": "암반 비탈면 검토 (평사투영 · 한계평형)", + "서식": 1 + }, + "B1": { + "서식": 1 + }, + "C1": { + "서식": 1 + }, + "D1": { + "서식": 1 + }, + "E1": { + "서식": 1 + }, + "F1": { + "서식": 1 + }, + "G1": { + "서식": 1 + }, + "H1": { + "서식": 1 + }, + "A2": { + "값": "절리 = 현장 조사값(사용자 입력) · Markland 운동학 판정 · Hoek-Bray 평면 · 쐐기 안전율(KDS 11 70 05) · 문헌 추정치", + "서식": 2 + }, + "B2": { + "서식": 2 + }, + "C2": { + "서식": 2 + }, + "D2": { + "서식": 2 + }, + "E2": { + "서식": 2 + }, + "F2": { + "서식": 2 + }, + "G2": { + "서식": 2 + }, + "H2": { + "서식": 2 + }, + "A4": { + "값": "1. 해석 조건 · 판정 요약", + "서식": 3 + }, + "B4": { + "서식": 3 + }, + "C4": { + "서식": 3 + }, + "D4": { + "서식": 3 + }, + "E4": { + "서식": 3 + }, + "F4": { + "서식": 3 + }, + "G4": { + "서식": 3 + }, + "H4": { + "서식": 3 + }, + "A5": { + "값": "투영 · 측방 한계", + "서식": 4 + }, + "B5": { + "서식": 5 + }, + "C5": { + "서식": 5 + }, + "D5": { + "서식": 5 + }, + "E5": { + "서식": 5 + }, + "F5": { + "서식": 5 + }, + "G5": { + "서식": 5 + }, + "H5": { + "서식": 5 + }, + "A6": { + "값": "암 단위중량", + "서식": 4 + }, + "B6": { + "서식": 5 + }, + "C6": { + "서식": 5 + }, + "D6": { + "서식": 5 + }, + "E6": { + "서식": 5 + }, + "F6": { + "서식": 5 + }, + "G6": { + "서식": 5 + }, + "H6": { + "서식": 5 + }, + "A7": { + "값": "우기 지하수", + "서식": 4 + }, + "B7": { + "서식": 5 + }, + "C7": { + "서식": 5 + }, + "D7": { + "서식": 5 + }, + "E7": { + "서식": 5 + }, + "F7": { + "서식": 5 + }, + "G7": { + "서식": 5 + }, + "H7": { + "서식": 5 + }, + "A8": { + "값": "인장균열 · 볼트", + "서식": 4 + }, + "B8": { + "서식": 5 + }, + "C8": { + "서식": 5 + }, + "D8": { + "서식": 5 + }, + "E8": { + "서식": 5 + }, + "F8": { + "서식": 5 + }, + "G8": { + "서식": 5 + }, + "H8": { + "서식": 5 + }, + "A9": { + "값": "판정 요약", + "서식": 4 + }, + "B9": { + "서식": 5 + }, + "C9": { + "서식": 5 + }, + "D9": { + "서식": 5 + }, + "E9": { + "서식": 5 + }, + "F9": { + "서식": 5 + }, + "G9": { + "서식": 5 + }, + "H9": { + "서식": 5 + }, + "A11": { + "값": "2. 절리군 (현장 조사값)", + "서식": 3 + }, + "B11": { + "서식": 3 + }, + "C11": { + "서식": 3 + }, + "D11": { + "서식": 3 + }, + "E11": { + "서식": 3 + }, + "F11": { + "서식": 3 + }, + "G11": { + "서식": 3 + }, + "H11": { + "서식": 3 + }, + "A12": { + "값": "절리군", + "서식": 6 + }, + "B12": { + "값": "경사방향 (°)", + "서식": 6 + }, + "C12": { + "값": "경사 (°)", + "서식": 6 + }, + "D12": { + "값": "φj (°)", + "서식": 6 + }, + "E12": { + "값": "cj (kPa)", + "서식": 6 + }, + "F12": { + "값": "지속성 (m)", + "서식": 6 + }, + "G12": { + "값": "구간 시작", + "서식": 6 + }, + "H12": { + "값": "구간 끝", + "서식": 6 + }, + "A13": { + "서식": 7 + }, + "B13": { + "서식": 16 + }, + "C13": { + "서식": 16 + }, + "D13": { + "서식": 16 + }, + "E13": { + "서식": 16 + }, + "F13": { + "서식": 13 + }, + "G13": { + "서식": 7 + }, + "H13": { + "서식": 7 + }, + "A15": { + "값": "3. 측점별 판정 — 위험 모드 × 조건", + "서식": 3 + }, + "B15": { + "서식": 3 + }, + "C15": { + "서식": 3 + }, + "D15": { + "서식": 3 + }, + "E15": { + "서식": 3 + }, + "F15": { + "서식": 3 + }, + "G15": { + "서식": 3 + }, + "H15": { + "서식": 3 + }, + "A16": { + "값": "측점", + "서식": 6 + }, + "B16": { + "값": "비탈 (경사 / 방향 · 높이)", + "서식": 6 + }, + "C16": { + "값": "파괴 형태", + "서식": 6 + }, + "D16": { + "값": "조건", + "서식": 6 + }, + "E16": { + "값": "Fs", + "서식": 6 + }, + "F16": { + "값": "기준", + "서식": 6 + }, + "G16": { + "값": "판정", + "서식": 6 + }, + "H16": { + "값": "비고", + "서식": 6 + }, + "A17": { + "서식": 7 + }, + "B17": { + "서식": 5 + }, + "C17": { + "서식": 7 + }, + "D17": { + "서식": 7 + }, + "E17": { + "서식": 8 + }, + "F17": { + "서식": 8 + }, + "G17": { + "서식": 7 + }, + "H17": { + "서식": 5 + } + }, + "병합": [ + "A1:H1", + "A2:H2", + "A4:H4", + "B5:H5", + "B6:H6", + "B7:H7", + "B8:H8", + "B9:H9", + "A11:H11", + "A15:H15" + ], + "열": { + "A": { + "폭": 14 + }, + "B": { + "폭": 26 + }, + "C": { + "폭": 16 + }, + "D": { + "폭": 7 + }, + "E": { + "폭": 8 + }, + "F": { + "폭": 8 + }, + "G": { + "폭": 8 + }, + "H": { + "폭": 24 + } + }, + "행": { + "1": { + "높이": 36 + }, + "2": { + "높이": 30 + }, + "4": { + "높이": 22 + }, + "11": { + "높이": 22 + }, + "12": { + "높이": 22 + }, + "15": { + "높이": 22 + }, + "16": { + "높이": 22 + } + }, + "보기": { + "눈금선": false + }, + "인쇄": { + "용지": "A4", + "방향": "portrait", + "맞춤": { + "폭": 1, + "높이": 0 + }, + "여백": { + "위": 15, + "아래": 15, + "왼": 10, + "오른": 10 + } + } + }, { "id": "s10", "이름": "부록_절편", diff --git a/resources/master_template/report/stab_report_slots.md b/resources/master_template/report/stab_report_slots.md index 9a9aadc3c..f9028a20b 100644 --- a/resources/master_template/report/stab_report_slots.md +++ b/resources/master_template/report/stab_report_slots.md @@ -4,8 +4,8 @@ ## 공통 -- 몫: 사용자 몫(표지 · 개요) = 처음 만들 때만 채움 · 다시 만들 때(보고서 갱신) 안 건드림. 프로그램 몫(목차 · 입력조건 · 측점표 · 대표단면 · 3D요약 · 광역요약 · 보강검토 · 부록_절편) = 갱신 때 통째 다시 씀 · 작업본에 없는 프로그램 몫 시트는 양식 차례 자리에 끼움 · 새 서식은 작업본 서식 표 끝에 붙여 번호를 바꿈. -- 시트 차례: 표지 · 목차 · 개요 · 입력조건 · 측점표 · 대표단면 · 3D요약 · 광역요약 · (보강검토) · 부록_절편. +- 몫: 사용자 몫(표지 · 개요) = 처음 만들 때만 채움 · 다시 만들 때(보고서 갱신) 안 건드림. 프로그램 몫(목차 · 입력조건 · 측점표 · 대표단면 · 3D요약 · 광역요약 · 보강검토 · 암반검토 · 부록_절편) = 갱신 때 통째 다시 씀 · 작업본에 없는 프로그램 몫 시트는 양식 차례 자리에 끼움 · 새 서식은 작업본 서식 표 끝에 붙여 번호를 바꿈. +- 시트 차례: 표지 · 목차 · 개요 · 입력조건 · 측점표 · 대표단면 · 3D요약 · 광역요약 · (보강검토) · (암반검토) · 부록_절편. - PDF: 표지 = 쪽 번호 · 머리말 없음 · 본문 = 머리말(왼 사업명 = 표지 `C8` · 오른 보고서 이름) · 꼬리말 「- n / N -」(목차 = 1 쪽). - 사용자 확정 전 표기 한 규칙 — 기본값 그대로 = 「(기본값 · 사용자 확정 전)」 · 바꿈 = 「(사용자 입력)」 · 물성 = 「문헌 추정치 · 사용자 확정 전」. - 서식 번호(`서식` 표): 1 title · 2 sub · 3 section · 4 label · 5 text · 6 head · 7 body(가운데 글) · 8 fs(0.00) · 9 int(0) · 10 ng(N.G 빨강 채움) · 11 ok(O.K 초록) · 12 notice · 13 num1(#,##0.0) · 14 num0(#,##0) · 15 para(위 맞춤 긴 글) · 16 prop(0.0) · 17 chain(#,##0.00) · 18 head8 · 19 num8(0.00) · 20 num8(0.0) · 21 int8 · 22 목차 내용 · 23 목차 쪽 · 24 목차 장 · 25 sum8(0.00 · 회색) · 26 표지 제목. @@ -117,6 +117,14 @@ - 6 행 · 10 행 서식을 줄마다 복사 · 저장본 = (측점 · 종류 · 비탈)마다 가장 최근 하나. +## s11 암반검토 (프로그램 몫 · E06 암반 해석 저장본 · 없으면 시트를 뺌) + +| 칸 | 내용 | +| --- | --- | +| `B5`~`B9` (각 B:H 병합 · 서식 5) | 투영 · 측방 한계 · 암 단위중량 · 우기 지하수(KDS 11 70 05 표 4.3-3 암반 ½ 심도) · 인장균열 · 볼트 · 판정 요약(낡으면 「E06 [해석] 뒤 [보고서 갱신]」) — 기본값 그대로 = 사용자 확정 전 표기 | +| 11 · 12 행 꼴(제목 3 · 머리 6) 다음 절리군 하나 = 한 줄(13 행 서식) | A 이름(7) · B 경사방향 · C 경사 · D φj · E cj(16) · F 지속성(13) · G · H 구간 시작 · 끝(7) · 모르면 「-」 · 없으면 「절리군 없음」 | +| 절리 줄 다음 한 줄 띄고 15 · 16 행 꼴 · 그 아래 측점 비탈 × 위험 모드 × 조건 = 한 줄(17 행 서식) | A 측점(7) · B 비탈 글(쪽 · 경사 / 방향 · 높이)(5) · C 파괴 형태(평면 · 쐐기 · 전도 + 절리)(7) · D 조건(7) · E Fs · F 기준(8) · G 판정(7 → 10 · 11 · 전도 「검토」) · H 비고(블록 안 생김 · 미끄러짐 면 · 지속성)(5) · 위험 모드 없는 비탈 = 「없음」 한 줄 | + ## s10 부록_절편 (프로그램 몫 · 대표 단면마다 한 쪽) 양식 1~5 행 = 덩이 꼴(1 제목 · 2 단위 · 3 머리 · 4 절편 줄 서식 · 5 합계 서식). 대표 단면마다 지배 조건(Fs / 기준 가장 낮음) 임계면의 절편표. diff --git a/resources/tester/test_534_3_stab_report_form.py b/resources/tester/test_534_3_stab_report_form.py index 5e983c265..4a4bb2c51 100644 --- a/resources/tester/test_534_3_stab_report_form.py +++ b/resources/tester/test_534_3_stab_report_form.py @@ -37,7 +37,7 @@ STYLE_KEYS = { PRINT_KEYS = {"용지", "방향", "배율", "맞춤", "여백", "머리행", "쪽나눔"} A1 = re.compile(r"^([A-Z]{1,3})(\d+)$") NAMES = [ - "표지", "목차", "개요", "입력조건", "측점표", "대표단면", "3D요약", "광역요약", "보강검토", + "표지", "목차", "개요", "입력조건", "측점표", "대표단면", "3D요약", "광역요약", "보강검토", "암반검토", "부록_절편", ] # fmt: skip @@ -151,7 +151,7 @@ def test_양식_계약(): book = _form() _contract(book) assert [s["이름"] for s in book["시트"]] == NAMES - ids = ["s1", "s9", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s10"] + ids = ["s1", "s9", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s11", "s10"] assert [s["id"] for s in book["시트"]] == ids @@ -174,6 +174,7 @@ def test_양식_인쇄_쪽나눔_머리행_그림(): "3D요약": 1, "광역요약": 0, "보강검토": 0, + "암반검토": 0, } # N.G 빨강 조건부 서식 — 측점표 판정 열 · 서식 표에 N.G 칸 서식(빌더가 인쇄 · xlsx 용으로 직접 씀) assert by["측점표"]["조건부서식"][0]["범위"][0]["c0"] == 9 @@ -237,9 +238,10 @@ def test_견본_pdf_쪽수_머리행(png): ) sections = [i for i, t in enumerate(texts) if "대표 단면" in t and "안전율 Fs" in t] assert len(sections) == 2 # 단면마다 한 쪽 - # 표지 1 + 목차 1 + 개요 1 + 입력조건 1 + 측점표 n + 대표단면 2 + 3D 1 + 광역 1 + 보강 1 + 부록 1 + # 표지 1 + 목차 1 + 개요 1 + 입력조건 1 + 측점표 n + 대표단면 2 + 3D 1 + 광역 1 + 보강 1 + 암반 1 + # + 부록 1 # (양식 빈 판) - assert len(pages) == 1 + 1 + 1 + 1 + len(stab) + 2 + 1 + 1 + 1 + 1 + assert len(pages) == 1 + 1 + 1 + 1 + len(stab) + 2 + 1 + 1 + 1 + 1 + 1 assert all(float(pages[i].mediabox.width) > float(pages[i].mediabox.height) for i in stab) html = spreadsheet.print_htmls([{"book": book, "figures": {k: png for k in figs}}])[0] assert html.count("