From 77fb819ab792cdcf24601626ef98295a00b6dde4 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 15 Sep 2026 05:58:50 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix(b08):=20=EC=86=8C=EB=8B=A8=EC=9D=B4=20?= =?UTF-8?q?=EC=84=A0=20=EC=82=AC=EB=A9=B4=EC=9D=98=20=EC=82=AC=EB=A9=B4?= =?UTF-8?q?=EA=B8=B8=EC=9D=B4=EA=B0=80=20=EC=B2=AB=20=EC=86=8C=EB=8B=A8?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=81=8A=EA=B8=B0=EB=8D=98=20=EA=B2=83=20?= =?UTF-8?q?=E2=80=94=20=EA=B2=A9=EC=9E=90=EB=A1=9C=20=EC=AA=BC=EA=B0=9C?= =?UTF-8?q?=EC=A7=84=20=ED=8F=89=ED=83=84=20=EC=A1=B0=EA=B0=81=EC=9D=84=20?= =?UTF-8?q?=EB=AA=A8=EC=95=84=20=EC=86=8C=EB=8B=A8=20=ED=8F=AD=EA=B3=BC=20?= =?UTF-8?q?=EB=8C=80=EC=A1=B0=20=C2=B7=20=EC=95=88=EC=AA=BD=20=EA=B8=B0?= =?UTF-8?q?=EC=9A=B8=EA=B8=B0=20=EB=B0=98=EC=98=81=20=C2=B7=20=EC=86=8C?= =?UTF-8?q?=EB=8B=A8=20=EA=B5=AC=EC=A1=B0=EB=AC=BC=EC=9D=80=20=EC=9B=90?= =?UTF-8?q?=EB=8B=A8=EC=9C=84=20=E3=80=8C=EC=82=B0=EC=B6=9C=EC=8B=9D=20?= =?UTF-8?q?=EC=97=86=EC=9D=8C=E3=80=8D=20=EA=B1=B0=EC=A7=93=20=EB=A7=89?= =?UTF-8?q?=ED=9E=98=20=EB=8C=80=EC=8B=A0=20=EA=B1=B4=EB=84=88=EB=9C=80=20?= =?UTF-8?q?+=20=EA=B9=8C=EB=8B=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 936be972 전 측점 소단 가정(읽기만): 면고르기·파종 성토면 3,136.23 → 16,979.02㎡(소단 없음 15,919.95) · 측점 20 성토 사면길이 3.0 → 14.31m Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq --- .../B08_Quantity_Engine_SlopeLength.py | 19 +++++-- B08_Quantity/B08_Quantity_Router_Material.py | 10 ++++ .../tester/test_b08_slope_length_berm.py | 51 +++++++++++++++++++ 3 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 resources/tester/test_b08_slope_length_berm.py diff --git a/B08_Quantity/B08_Quantity_Engine_SlopeLength.py b/B08_Quantity/B08_Quantity_Engine_SlopeLength.py index 9f404359..11837f9e 100644 --- a/B08_Quantity/B08_Quantity_Engine_SlopeLength.py +++ b/B08_Quantity/B08_Quantity_Engine_SlopeLength.py @@ -166,19 +166,28 @@ def _side_segments( berm = design.get("berm") or {} berm_width = _num(berm.get("width_m")) or 0.0 + # 소단 안쪽 기울기(°) 만큼은 평탄부로 봄 — 기울인 소단이 비탈로 읽혀 끊기지 않게. + berm_grade = math.tan(math.radians(_num(berm.get("slope_deg")) or 0.0)) + # 설계선 표고는 넷째 자리 반올림 — 기울인 소단 조각이 그만큼 더 가파르게 읽힘(0.0069/0.1953). + berm_slack = 2e-4 if berm_width > 0 else 0.0 segments: list[SlopeSegment] = [] started = False + # ⚠ 설계선이 격자(0.5m)로 찍혀 소단 평탄부가 **여러 조각**으로 쪼개짐 — 이어진 평탄 조각을 모아 + # 합이 소단 폭일 때만 소단으로 넘김(2026-09-15 · 한 조각만 보다가 첫 소단에서 사면이 끊겼음). + flat_run = 0.0 for start, end, run, rise in _outward(line, float(edge), side): if run <= 1e-9: continue - if abs(rise) <= _FLAT_RISE_M: - # 평탄부 — 측구 바닥·소단. 사면이 시작된 뒤라면 소단으로 보고 이어 간다. - if started and berm_width > 0 and abs(run - berm_width) < 0.05: - continue + if abs(rise) <= _FLAT_RISE_M + run * berm_grade + berm_slack: + # 평탄부 — 측구 바닥·소단. 사면이 시작된 뒤라면 모아 두고 다음 조각에서 판정. if started: - break # 사면이 끝나고 평지를 만난 것이다 + flat_run += run continue + if flat_run > 0: + if not (berm_width > 0 and abs(flat_run - berm_width) < 0.05): + break # 사면이 끝나고 평지를 만난 것이다 + flat_run = 0.0 ratio = run / abs(rise) # 절토는 바깥으로 갈수록 오르고, 성토는 내려간다. role = "cut" if rise > 0 else "fill" diff --git a/B08_Quantity/B08_Quantity_Router_Material.py b/B08_Quantity/B08_Quantity_Router_Material.py index b3da9e31..f2989f4a 100644 --- a/B08_Quantity/B08_Quantity_Router_Material.py +++ b/B08_Quantity/B08_Quantity_Router_Material.py @@ -54,6 +54,11 @@ from common_util.common_util_structure_lengths import structure_lengths from config.config_db import run_with_connection logger = logging.getLogger(__name__) +#: 소단 — 원단위 줄을 안 세우는 까닭(2026-09-15 조사). +BERM_COUNTED = ( + "횡단 설계의 계단으로 토공(절·성토)·사면 면적(면고르기·파종·녹화)에 이미 들어감" + " — 따로 줄 안 세움" +) router = APIRouter(prefix="/api/projects", tags=["B08 Quantity"]) @@ -95,6 +100,11 @@ def _collect_structures( f"{definition.name}: {definition.design_owner} 가 이미 셈 — 중복 계상 방지" ) continue + if type_id == "berm": + # 소단 계단은 횡단 설계가 절·성토 면적·사면길이에 이미 넣음 — 줄을 세우면 + # 「산출식 없음」 거짓 막힘이 내역에 섬(2026-09-15 조사 · 임도 소단 품셈 공종 없음). + skipped.append(f"{definition.name}: {BERM_COUNTED}") + continue if definition.reference_only: skipped.append(f"{definition.name}: 전문 상세설계 대상 — 배치까지만") continue diff --git a/resources/tester/test_b08_slope_length_berm.py b/resources/tester/test_b08_slope_length_berm.py new file mode 100644 index 00000000..4ae1cd09 --- /dev/null +++ b/resources/tester/test_b08_slope_length_berm.py @@ -0,0 +1,51 @@ +"""소단이 선 사면의 사면길이 — 첫 소단에서 끊기지 않을 것 (2026-09-15 소단 착수 전 조사). + +잰 것(936be972 읽기만) — 전 측점에 소단(0.5m · 3m · 0°)을 놓자 성토 사면길이가 측점 20 에서 +8.91 → 3.0m 로 끊겨 면고르기·파종 성토면 15,919.95 → 3,136.23㎡(−80%)로 줄었음. +까닭 — 설계선이 0.5m 격자로 찍혀 소단 평탄부 0.5m 가 0.195 + 0.305 두 조각으로 쪼개짐 → +「평탄부 한 조각 = 소단 폭」 판정이 안 맞아 거기서 사면이 끝난 것으로 봄. 안쪽 기울기(°)를 주면 +평탄부가 아예 평탄으로 안 읽혀 같은 자리에서 끊김. +""" + +from __future__ import annotations + +import pytest + +from B06_Section.B06_Section_Engine_Design import compute_cross_design +from B08_Quantity.B08_Quantity_Engine_SlopeLength import station_slope +from common_util.common_util_cross_berm import BermSpec + +# 노면보다 8m 낮은 평지 — 양쪽 성토 사면이 길게 섬. +SAMPLES = [{"offset_m": x / 2, "elevation_m": -8.0} for x in range(-160, 161)] + + +def _design(berm: BermSpec | None) -> dict: + return compute_cross_design( + SAMPLES, 0.0, ground_type="soil", section_mode="both_fill", berm=berm + ) + + +@pytest.mark.parametrize("slope_deg", [0.0, 2.0]) +def test_소단이_있어도_사면길이가_끝까지_이어진다(slope_deg: float) -> None: + plain = station_slope(0.0, _design(None)) + stepped_design = _design(BermSpec(0.5, 3.0, slope_deg)) + stepped = station_slope(0.0, stepped_design) + assert plain.fill_length_m > 15 # 양쪽 합 — 시험이 뜻을 가지는 크기 + # 소단 평탄부는 사면길이에 안 들고, 비탈 조각은 끝까지 셈 — 같은 낙차라 거의 같음. + assert stepped.fill_length_m == pytest.approx(plain.fill_length_m, rel=0.05) + assert stepped.fill_height_m == pytest.approx(plain.fill_height_m, abs=0.2) + + +def test_소단_구조물은_원단위_줄을_안_세우고_까닭을_남긴다(monkeypatch, tmp_path) -> None: + """소단 계단은 횡단 설계가 절·성토 면적·사면길이에 이미 넣음 — 따로 줄을 세우면 「산출식 없음」 + 거짓 막힘(formula_missing)이 내역에 섬(2026-09-15 조사).""" + from B05_Profile.B05_Profile_Structures_Schema import StructureInstance + from B08_Quantity import B08_Quantity_Router_Material as material + + berm = StructureInstance( + structure_id="b", type_id="berm", placement="interval", start_m=100.0, end_m=120.0 + ) + monkeypatch.setattr(material, "load_structures", lambda root: (1, [berm])) + targets, _names, skipped = material._collect_structures(str(tmp_path)) + assert targets == [] + assert any("소단" in note and "토공" in note and "사면" in note for note in skipped) From 6e5c1b691f1f0b2c25c5395cfb5e636d1acc1477 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 15 Sep 2026 05:58:50 +0900 Subject: [PATCH 2/4] =?UTF-8?q?chore(plan):=20=EB=9E=A9=ED=83=91=20?= =?UTF-8?q?=EC=84=9C=EB=B8=8C=20=EA=B3=84=ED=9A=8D=EC=84=9C=20=E2=80=94=20?= =?UTF-8?q?=EC=86=8C=EB=8B=A8=20=EC=A1=B0=EC=82=AC=20=C2=B7=20=ED=9D=A0=20?= =?UTF-8?q?=EB=91=98=20=C2=B7=20=EB=85=B9=ED=99=94=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EB=B3=B4=EB=A5=98=20=EA=B9=8C=EB=8B=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq --- PLAN_랩탑서브.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PLAN_랩탑서브.md b/PLAN_랩탑서브.md index 8e38c27e..e9053795 100644 --- a/PLAN_랩탑서브.md +++ b/PLAN_랩탑서브.md @@ -61,5 +61,10 @@ - [ ] 선떼붙이기(길이형) — 표 2-2-6 급별 m당 매수 · 단끊기 연장 = 직고 ÷ 단 직고 × 연장(5-16-1 [주]②) - [ ] 조공·씨뿌리기·편책·녹생토·나무심기 - [ ] 소단 — 임도 조문(사면길이 2~3m 마다 폭 50~100㎝) · 사방 기준 아님 + - 12장 D 표(PLAN.md) 고칠 것 — 소단 근거 「사방사업 세부기준 제3조1호(절·성토고 3~5m · 폭 0.5m 이상)」 → 임도 「시행규칙 별표2 Ⅰ.2.차.(5) 절토·성토한 경사면이 붕괴 또는 밀려 내려갈 우려가 있는 지역에는 사면길이 2~3m 마다 폭 50~100㎝」(조건부 · 우려 지역) + - 지금 서는 자리(조사) — 등록부 「소단」(C군 구간 · 폭 0.5 · 간격 3 · 안쪽 0° — 별표2 범위 안 가장 적게 파는 조합) → B06 계단 기하(`common_util_cross_berm`) → 절·성토 면적(토공)·사면길이에 들어감 · 자동 배치 없음(설계자가 놓음) · 품셈에 임도 소단 공종 없음 + - [X] 흠 둘 고침 — ① 설계선 0.5m 격자에 소단 평탄부가 쪼개져 사면길이가 첫 소단에서 끊김(측점 20 성토 8.91 → 3.0m) → 이어진 평탄 조각을 모아 소단 폭과 대조 · 안쪽 기울기 반영 ② 소단 구조물이 원단위에 「산출식 없음」 거짓 막힘으로 섬 → 건너뜀 + 까닭. 검증완료(시험 · 936be972 읽기만) + - 936be972 전 측점 소단(0.5·3·0°) 가정 전후(읽기만) — 성토 18,247.12 → 41,179.33㎥(+125.7%) · 절토 6,686.30 → 6,719.03㎥ · 면고르기·파종·지장목 성토면 15,919.95 → 16,979.02㎡(+6.7% · 고치기 전엔 3,136.23 −80%) · 절토면 5,588.88 → 6,258.46㎡(+12.0%) · 미폐합 측점 2 → 26 + - ⚠ 녹화 화면 확인 보류 — 구조물 저장이 B06 이후 단계를 STALE 로 돌림(`_invalidate_downstream`) · 지워도 단계 상태는 안 돌아옴 - [ ] 개소형 — 대피소·작업장·차돌림곳·노출형 횡단수로 - [ ] 부대 — 가드레일·반사경·표지(그림 11-6~11-8 표준도 확인 · 번호판 500m 제안) From c169fa8b0c62034161eb7826eb5f67fc953aeb8b Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 15 Sep 2026 06:00:59 +0900 Subject: [PATCH 3/4] =?UTF-8?q?chore(plan):=20=EB=9E=A9=ED=83=91=20?= =?UTF-8?q?=EC=84=9C=EB=B8=8C=20=EA=B3=84=ED=9A=8D=EC=84=9C=20=E2=80=94=20?= =?UTF-8?q?=E3=80=8C=ED=99=94=EB=A9=B4=EC=9D=84=20STmate=20=EC=99=80=20?= =?UTF-8?q?=EC=B5=9C=EB=8C=80=ED=95=9C=20=EA=B0=80=EA=B9=9D=EA=B2=8C?= =?UTF-8?q?=E3=80=8D=20=EC=B7=A8=EC=86=8C(=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=A7=80=EC=8B=9C)=20=C2=B7=20=ED=99=94=EB=A9=B4=20=EB=AA=A8?= =?UTF-8?q?=EC=96=91=20=EB=95=8C=EB=AC=B8=EC=97=90=20=EC=84=A0=20=EC=A4=84?= =?UTF-8?q?=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq --- PLAN_랩탑서브.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/PLAN_랩탑서브.md b/PLAN_랩탑서브.md index e9053795..f8cfefdc 100644 --- a/PLAN_랩탑서브.md +++ b/PLAN_랩탑서브.md @@ -2,6 +2,17 @@ 임시 · 2026-09-15 시놀로지 덮어쓰기 때문 · 사용자 확인 전 (브레인 지시 · git 에 명시 커밋 · 브레인이 나중에 PLAN.md 한 벌로 합침 · PLAN.md 는 읽기만) +## ⚠ 2026-09-15 사용자 지시 — 「화면을 STmate 와 최대한 가깝게」 취소 (브레인 전달) + +화면 모양만 취소 · 계산·수량·금액의 STmate 재현(골든셋 검산)은 그대로. 화면 모양 때문에 잡아 둔 줄 표시(PLAN.md 는 읽기만이라 여기 적음 · 합칠 때 반영): + +- 랩탑 서브 몫 열린 줄 — **없음**(이 파일의 12장 D·B08 훑기 줄은 전부 수량·금액 일감 · 화면 모양 줄 아님) +- PLAN.md 12장 「화면 — STmate 를 본뜬 B08·B09 프론트엔드」에서 화면 모양 때문에 선 줄(표시만) + - 🏷 화면모양 — 장 제목 「STmate 를 본뜬」 · 사용자 방침 「최대한 가깝게 구성」 · 「만들 화면 — STmate 이름을 짝지어」 표(`wQtyList`·`wBoq`·`wExpnd`·`wM_Edit_iLWi`·`wM_Edit_San`·`wM_JabPum`·`wM_KanJub`·`wM_Boxa`) + - 🏷 화면모양 — 「지킬 것 · STmate 를 본뜨되 값은 우리 명세대로 — 화면만 닮음」 + - 🏷 화면모양(닫힘 · 되돌릴 일 없음) — 내역서·일위대가표·단산 목록표 틀 · 집계표 넷 · 목록표 일곱 · 옛 탭 여섯 → 새 틀 · 자재단가대비표 「변동없음 / 1~5 단가 / 최소단가」 고르개 + - ❓ 갈래 판정 필요(브레인) — 「범위 — 전체를 비슷하게 · STmate 가 가진 것을 되도록 다 갖춤」 · 열린 줄 「내역 종류 전부(`PM_Prn_Ord` 목록 그대로)」 — 기능 범위인지 화면 모양인지 · 「원가계산 4형식 다」는 계산이라 그대로로 읽음 + ## 12장 — B08 훑기 고칠 차례 이어 (PLAN.md 12장 「고칠 차례(브레인 2026-09-14)」) - [X] ㉳ (가) 미교차 측점 지반 샘플을 지표면 끝까지 넓힘(+5m 씩 · 상한 = 지표면 끝) 8bf24c26. 검증완료 From 6b860feac7c6f39331ff007b5eaec2bc19118f44 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 15 Sep 2026 06:01:19 +0900 Subject: [PATCH 4/4] =?UTF-8?q?chore(plan):=20STmate=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=20=EB=B3=B8=EB=9C=A8=EA=B8=B0=20=EC=B7=A8=EC=86=8C=EB=A1=9C=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=ED=95=B4=20=EB=91=94=20=EC=A4=84=20=E2=80=94?= =?UTF-8?q?=20=EB=8D=B0=EC=8A=A4=ED=81=AC=ED=83=91=20=EC=84=9C=EB=B8=8C=20?= =?UTF-8?q?=EC=9E=90=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2026-09-15 사용자 지시로 「화면을 STmate 와 최대한 가깝게」가 취소됨. 계산·수량·금액은 그대로(STmate 재현은 여전히 검산 기준) · 화면 모양 자리만 표시. · CostSheet.py — DFM TWM_KANJUB 그대로인 칸 번호·제목 · 부가세 고르개 「(0)…」 표기 · 서식 줄 차례(나./ㄱ./1)). 값에는 안 닿아 걷어도 금액이 안 변함 · CostSheet_Forms.py — 오직 화면 모양만 있는 모듈(금액 0건) · 문구는 랩탑 메인 몫이라 안 건드림 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA --- PLAN_데스크탑서브.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/PLAN_데스크탑서브.md b/PLAN_데스크탑서브.md index 97603bd0..eda1a681 100644 --- a/PLAN_데스크탑서브.md +++ b/PLAN_데스크탑서브.md @@ -79,6 +79,21 @@ (수량은 B08 정본 그대로 · `BORROWED_BASIS_PER` 꼴) - 곁 — 12-19·12-20 [주] **「공사기간에 따른 손율」을 지금 안 걸고 있음**(유로폼 사용횟수와 다른 자리) +## ⚠ 「STmate 화면 본뜨기」 취소(2026-09-15 사용자)로 **표시해 둔 줄** — 내 자리에서 + +계산·수량·금액은 그대로(STmate **재현**은 여전히 검산 기준). **화면 모양 때문에 잡아 둔 것만** 적음. + +- `B09_Estimation_CostSheet.py` — 머리에 「STmate 「제잡비 계산」(wM_KanJub) **일반형식 서식 차례**」로 + 못박혀 있음. 안에 든 것 셋이 화면 모양 자리임 + - **기준 입력판 칸 번호·제목이 DFM `TWM_KANJUB` 그대로** — `"4.고 용 보 험 료"` · `"11.공급가절사기준"` · + `"12.부 가 가 치 세"` 처럼 번호와 띄어쓰기까지 STmate 표기 + - **부가세 고르개 표기** `VAT_MODE_LABELS` — `"(0) 공급가액의 10%"` 같은 STmate 번호 표기 + - **서식 줄 차례·표기**(`sheet_rows` 의 나./ㄱ./1)) — STmate 서식을 따라 늘어놓은 것 + - ⇒ **값에는 안 닿음.** 이름표·차례만이라 걷어도 금액이 안 변함. 걷을지는 판정 대기 +- `B09_Estimation_CostSheet_Forms.py` — **오직 화면 모양만** 있는 모듈(수공·실적일반·실적수공 **서식 차례**, + 금액 0건). STmate 본뜨기가 목표에서 빠지면 **모듈째 다시 볼 자리**임. + ⚠ 다만 그 파일 문구는 **랩탑 메인 몫**이라 내가 안 건드림 — 브레인이 그쪽에 함께 알릴 것 + ## 남은 것 - [ ] **`UnitPrice.py` 1403줄** — 700줄 규칙 밖. 쪼개기 **따로 배정 필요**