feat(b05·b08): 선떼붙이기 — 연장 = 사면 낙차 × 거리 ÷ 단 직고(품셈 5-16-1 [주]②) · 떼 매수 = 사방기술교본 표 2-2-6 표 값(어긋남 둘 사유) · 떼 크기·단끊기 토질 칸 기본 없음 · 떼붙임 ㎡ 는 호표 없어 막힘 + 사유(브레인 ⓐ~ⓔ) · 녹화 병행시공 사유를 정보로
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
This commit is contained in:
@@ -2519,8 +2519,7 @@
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail",
|
||||
"empty_means": "선떼붙이기·조공의 단 사이 직고 — 교본은 범위로만 줌(선떼 직고 1~2m · 조공 1.0~1.2m) · 기본값 없음",
|
||||
"not_in_table": "아직 표에 안 쓰임 — 길이형(선떼·조공) 산출식이 아직 없음(선떼는 사방기술교본 표 2-2-6 으로 다음 차례)"
|
||||
"empty_means": "선떼붙이기·조공의 단 사이 직고 — 교본은 범위로만 줌(선떼 직고 1~2m · 조공 1.0~1.2m) · 기본값 없음 · 비면 선떼 연장(품셈 5-16-1 [주]② 대상지 직고 ÷ 단 직고 × 연장)이 안 섬"
|
||||
},
|
||||
{
|
||||
"key": "sod_grade",
|
||||
@@ -2530,8 +2529,27 @@
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail",
|
||||
"empty_means": "선떼붙이기의 급수 — 교본은 1~9급 범위만(6~7급을 많이 씀) · 기본값 없음",
|
||||
"not_in_table": "아직 표에 안 쓰임 — 선떼붙이기 산출식이 아직 없음(사방기술교본 표 2-2-6 급별 m당 매수로 다음 차례)"
|
||||
"empty_means": "선떼붙이기의 급수 — 교본은 1~9급 범위만(6~7급을 많이 씀) · 기본값 없음 · 비면 m당 떼 매수(사방기술교본 표 2-2-6)가 안 섬"
|
||||
},
|
||||
{
|
||||
"key": "sod_size",
|
||||
"label": "선떼 떼 크기",
|
||||
"input": "select",
|
||||
"choices": ["대형 40×40", "소형 18×18"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail",
|
||||
"empty_means": "사방기술교본 표 2-2-6 이 대형(40×40)·소형(18×18) 두 줄을 나란히 줌 — 우리가 고를 자리가 아니라 기본값 없음 · 비면 선떼 떼 매수가 안 섬"
|
||||
},
|
||||
{
|
||||
"key": "cutting_soil",
|
||||
"label": "단끊기 토질",
|
||||
"input": "select",
|
||||
"choices": ["보통토사", "경질ㆍ고사점토 및 자갈섞인 점토", "호박돌 섞인 토사"],
|
||||
"default": null,
|
||||
"required": false,
|
||||
"phase": "detail",
|
||||
"empty_means": "품셈 5-16-1 단끊기 표의 토질 셋 — B06 지반(토사/암)과 다른 축이라 자동으로 안 고름 · 비면 단끊기 조각만 막힘"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -431,6 +431,17 @@ def composite_quantities(
|
||||
entry["not_ready"] = True
|
||||
entry["why"] = why
|
||||
missing.append({"code": spec.get("code"), "reason": why})
|
||||
if suffix == "cutting_soil":
|
||||
# 단끊기 5-16-1 토질 셋 — 칸 값 그대로(B06 지반과 다른 축 · 2026-09-15 브레인 ⓑ).
|
||||
soil = str((structure.get("options") or {}).get("cutting_soil") or "")
|
||||
if soil:
|
||||
entry["kind"] = normalize_kind_key(soil)
|
||||
entry["code"] = f"{spec.get('code')}#{normalize_kind_key(soil)}"
|
||||
elif found:
|
||||
why = "단끊기 토질을 안 고름 — 품셈 5-16-1 표의 토질 셋 중 고를 것(기본값 없음)"
|
||||
entry["not_ready"] = True
|
||||
entry["why"] = why
|
||||
missing.append({"code": spec.get("code"), "reason": why})
|
||||
if suffix == "rebar_complexity":
|
||||
# 갈래는 원문이 정한다 — 화면·인계에 이름과 근거를 함께 실어 사람이 검증하게 한다.
|
||||
complexity, why = rebar_complexity(
|
||||
|
||||
@@ -72,6 +72,9 @@ DESTINATION = {
|
||||
"평떼": "unit_price",
|
||||
"줄떼": "unit_price",
|
||||
"비탈덮기": "unit_price",
|
||||
# 선떼붙이기(5-16) — 단끊기 m · 떼붙임 ㎡ 은 품 · 떼는 위 「떼」(자재).
|
||||
"선떼붙이기": "unit_price",
|
||||
"떼붙임": "unit_price",
|
||||
}
|
||||
|
||||
#: ⛔ **갈 곳 기본값 금지**(명세 13장 「빠진 것이 조용해짐」) — 표에 없는 이름은 막고 사유를 냄.
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
5-25 거적덮기(㎡당) · 5-28 비탈덮기(5-28-1 짚망 · 5-28-2 방초·야자섬유매트)
|
||||
교본 7-1 그림 7-8~7-12 는 사진·개념도(치수 없음) — 표준도가 아님.
|
||||
⭐ 면적 = 구간 안 사면 면적(B06 측점 사면길이 · 평균단면적법) × 고른 면(절토면/성토면/양쪽).
|
||||
⚠ 길이형(선떼·조공)은 다음 차례(선떼 = 사방기술교본 표 2-2-6 급별 m당 매수) · 나머지 공법은 사유.
|
||||
⭐ 선떼붙이기(길이형) — 연장 = 대상지 직고 ÷ 단 직고 × 연장(품셈 5-16-1 [주]②) · m당 떼 매수 =
|
||||
사방기술교본 표 2-2-6 **표 값**(단면식은 역산 · 어긋나면 표가 이김 · 2026-09-15 브레인 ⓔ).
|
||||
⚠ 조공은 다음 차례 · 나머지 공법은 사유.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -33,12 +35,27 @@ AREA_METHODS: dict[str, tuple[str, float | None, str]] = {
|
||||
),
|
||||
}
|
||||
SOD_SPEC = "0.3×0.3"
|
||||
LENGTH_METHODS = ("선떼붙이기", "조공")
|
||||
NOTE_LENGTH = (
|
||||
"{method}은(는) 길이형(10m·100m당) — 산출식 아직 없음 · 떼 매수는 품셈이"
|
||||
" 「사방기술교본 기준표」라 함(선떼 = 표 2-2-6 급별 m당 매수 · 다음 차례)"
|
||||
" · 단 직고·급수 칸은 기본값 없음(브레인 ⓒ)"
|
||||
LENGTH_METHODS = ("조공",)
|
||||
NOTE_LENGTH = "{method}은(는) 길이형(100m·m당) — 산출식 아직 없음(선떼붙이기 다음 차례)"
|
||||
CUT_RISE, FILL_RISE = "b06_cut_rise_area_m2", "b06_fill_rise_area_m2"
|
||||
RISES = {"절토면": (CUT_RISE,), "성토면": (FILL_RISE,), "양쪽": (CUT_RISE, FILL_RISE)}
|
||||
#: 사방기술교본 표 2-2-6 「각 급별 선떼붙이기 m당 떼사용 매수표」 — 1m당 **표 값** · 한 장 ㎡.
|
||||
SOD_TABLE: dict[str, tuple[str, float, tuple[float, ...]]] = {
|
||||
"대형 40×40": ("40×40", 0.16, (12.50, 11.25, 10.00, 8.75, 7.80, 6.25, 5.00, 3.75, 2.50)),
|
||||
"소형 18×18": ("18×18", 0.0324, (30.0, 27.0, 24.0, 21.0, 18.0, 15.0, 12.0, 9.0, 6.0)),
|
||||
}
|
||||
NOTE_SOD = (
|
||||
"선떼붙이기 — 연장 = 대상지 직고(B06 사면 낙차) ÷ 단 직고 × 연장(품셈 5-16-1 [주]②)"
|
||||
" · m당 떼 매수 = 사방기술교본 표 2-2-6 표 값(식은 역산) · 떼붙임 ㎡ = 매수 × 떼 한 장 면적"
|
||||
)
|
||||
NOTE_SOD_TABLE_GAP = (
|
||||
"⚠ 표 2-2-6 안 어긋남 — 5급 대형 표 7.80 ↔ 단면식 7.50 · 소형 2급 표 27.0 ↔ 단면 4.0"
|
||||
"(×6 = 24.0) · 표 값을 씀(표가 고쳐지면 그때 봄)"
|
||||
)
|
||||
NOTE_SOD_HAUL = (
|
||||
"떼운반·지게운반(5-16-2 표 「물량산출」)은 운반거리(200m 조견표)가 설계 입력이라 안 섬"
|
||||
)
|
||||
NOTE_SOD_MISSING = "선떼붙이기 {what} 칸이 비어 연장·떼 매수가 안 섬 — 칸에 적을 것(기본 없음)"
|
||||
NOTE_LATER = (
|
||||
"{method}은(는) 산출식이 아직 없음 — 12장 D 녹화 차례 뒤(㎡ 넷 먼저 · 2026-09-15 브레인 ⓓ)"
|
||||
)
|
||||
@@ -47,8 +64,8 @@ NOTE_COVER = (
|
||||
"비탈덮기 덮개를 안 고름 — 거적(5-25)·짚망(5-28-1)·방초·야자섬유매트(5-28-2) 중 고를 것"
|
||||
)
|
||||
NOTE_OVERLAP = (
|
||||
"⚠ 같은 사면이 초류종자살포·면고르기에도 들어 있음 — 겹친 몫을 자동으로 빼지 않음"
|
||||
"(파종 구간을 줄일지 설계자가 고름 · 2026-09-15 브레인 ⓑ)"
|
||||
"녹화와 초류종자살포는 병행시공(임도기술교본 7장) — 떼 면적을 파종에서 빼지 않음."
|
||||
" 실무도 같음(울진1공구 수량산출)"
|
||||
)
|
||||
NOTE_STAKE = (
|
||||
"평떼 5-22-3 [주] 「평떼(0.06인) 품에는 떼꽂이 포함」은 5-12 품에 걸린 것으로 읽음"
|
||||
@@ -97,6 +114,13 @@ def revegetation_from_designs(
|
||||
for key, attr in ((CUT, "cut_length_m"), (FILL, "fill_length_m")):
|
||||
points = [(s.chainage_m, float(getattr(s, attr))) for s in ordered]
|
||||
options[key] = round(_interval_area(points, start, end), 4)
|
||||
# 사면 낙차(직고) × 거리 — 선떼 연장의 밑수(5-16-1 [주]② 「대상지 직고」 · 양쪽 사면 합).
|
||||
for key, role in ((CUT_RISE, "cut"), (FILL_RISE, "fill")):
|
||||
points = [
|
||||
(s.chainage_m, sum(abs(g.rise_m) for g in s.segments if g.role == role))
|
||||
for s in ordered
|
||||
]
|
||||
options[key] = round(_interval_area(points, start, end), 4)
|
||||
notes.append(
|
||||
f"구간 {start:g}~{end:g}m 사면 면적 — 절토면 {options[CUT]:,.2f}㎡ · 성토면"
|
||||
f" {options[FILL]:,.2f}㎡ (B06 측점 사면길이 · 평균단면적법)"
|
||||
@@ -114,6 +138,8 @@ def revegetation(options: dict[str, Any]) -> tuple[list[Component], list[str]]:
|
||||
method = str(options.get("method") or "")
|
||||
if not method:
|
||||
return [], ["녹화 공법을 안 고름 — 공법을 고르면 섬"]
|
||||
if method == "선떼붙이기":
|
||||
return _sod_wall(options)
|
||||
if method not in AREA_METHODS:
|
||||
template = NOTE_LENGTH if method in LENGTH_METHODS else NOTE_LATER
|
||||
return [], [template.format(method=method), NOTE_FIGURES]
|
||||
@@ -137,6 +163,65 @@ def revegetation(options: dict[str, Any]) -> tuple[list[Component], list[str]]:
|
||||
return components, notes
|
||||
|
||||
|
||||
def _sod_length(options: dict[str, Any]) -> float | None:
|
||||
"""선떼 연장(m) = Σ 사면 낙차 × 거리 ÷ 단 직고 — 면·단 직고가 없으면 None."""
|
||||
keys = RISES.get(str(options.get("face") or ""))
|
||||
step = _num(options.get("step_height_m"))
|
||||
if keys is None or step <= 0:
|
||||
return None
|
||||
return sum(_num(options.get(key)) for key in keys) / step
|
||||
|
||||
|
||||
def _sod_wall(options: dict[str, Any]) -> tuple[list[Component], list[str]]:
|
||||
"""선떼붙이기 — 연장(m) · 떼(매) · 떼붙임(㎡)."""
|
||||
if str(options.get("face") or "") not in RISES:
|
||||
return [], [NOTE_FACE]
|
||||
missing = [
|
||||
label
|
||||
for key, label in (
|
||||
("step_height_m", "단 직고"),
|
||||
("sod_grade", "급수"),
|
||||
("sod_size", "떼 크기"),
|
||||
)
|
||||
if options.get(key) in (None, "", 0)
|
||||
]
|
||||
grade, size = str(options.get("sod_grade") or ""), str(options.get("sod_size") or "")
|
||||
if not missing and (size not in SOD_TABLE or not grade.rstrip("급").isdigit()):
|
||||
missing = ["급수·떼 크기"]
|
||||
if missing:
|
||||
return [], [NOTE_SOD_MISSING.format(what="·".join(missing))]
|
||||
length = _sod_length(options) or 0.0
|
||||
spec, sheet_area, per_m = SOD_TABLE[size]
|
||||
sheets = per_m[int(grade.rstrip("급")) - 1]
|
||||
notes = [NOTE_OVERLAP, NOTE_SOD, NOTE_SOD_TABLE_GAP, NOTE_SOD_HAUL, NOTE_FIGURES]
|
||||
rows = [
|
||||
(
|
||||
"선떼붙이기",
|
||||
"m",
|
||||
length,
|
||||
f"{options.get('face')} 사면 낙차 × 거리 ÷ 단 직고"
|
||||
f" {_num(options.get('step_height_m')):g}",
|
||||
"",
|
||||
),
|
||||
("떼", "매", length * sheets, f"연장 {length:,.2f} × {grade} {size} {sheets:g}매/m", spec),
|
||||
(
|
||||
"떼붙임",
|
||||
"㎡",
|
||||
length * sheets * sheet_area,
|
||||
f"떼 {length * sheets:,.1f}매 × 한 장 {sheet_area:g}㎡",
|
||||
"",
|
||||
),
|
||||
]
|
||||
components = [
|
||||
Component(item, unit, amount, destination, text, spec=item_spec)
|
||||
for item, unit, amount, text, item_spec in rows
|
||||
if (destination := routed(item, notes))
|
||||
]
|
||||
return components, notes
|
||||
|
||||
|
||||
def billing(options: dict[str, Any]) -> tuple[str, float]:
|
||||
"""내역 줄 — 녹화 면적 ㎡."""
|
||||
"""내역 줄 — 녹화 면적 ㎡ · 선떼붙이기는 연장 m."""
|
||||
if str(options.get("method") or "") == "선떼붙이기":
|
||||
return "m", _sod_length(options) or 0.0
|
||||
return "㎡", _area(options) or 0.0
|
||||
|
||||
@@ -570,6 +570,29 @@
|
||||
"why": "줄떼 5-23 — 떼(0.3×0.3 · 30㎝ 간격 3.33매/㎡)는 자재 축 · 붙임·떼꽂이 ㎡ 묶음(2026-09-15 브레인 녹화 ⓓ).",
|
||||
"needs": "일위대가 조립은 B09 몫 — B08 은 물량과 묶음만 넘김"
|
||||
},
|
||||
{
|
||||
"type_id": "revegetation",
|
||||
"when": {"method": "선떼붙이기"},
|
||||
"parts": [
|
||||
{
|
||||
"code": "FP-05-16-01",
|
||||
"name": "단끊기",
|
||||
"unit": "m",
|
||||
"from_components": ["선떼붙이기"],
|
||||
"kind_suffix": "cutting_soil"
|
||||
},
|
||||
{
|
||||
"code": "FP-05-16-02",
|
||||
"name": "선떼붙이기 떼붙임",
|
||||
"unit": "㎡",
|
||||
"from_components": ["떼붙임"],
|
||||
"not_ready": true,
|
||||
"why": "떼붙임 호표 없음 — 5-16-2 표가 「물량산출」이라 수량을 안 줌(수량은 섬 · 금액만 안 섬 · 2026-09-15 브레인 ⓓ)"
|
||||
}
|
||||
],
|
||||
"why": "선떼붙이기 5-16-2(10m당) = 단끊기 m 1(5-16-1 토질 갈래) + 떼붙임 ㎡ 「물량산출」 + 떼운반 — 떼 매수는 사방기술교본 표 2-2-6(급·떼 크기) · 떼는 자재 축.",
|
||||
"needs": "일위대가 조립은 B09 몫 — B08 은 물량과 묶음만 넘김"
|
||||
},
|
||||
{
|
||||
"type_id": "revegetation",
|
||||
"when": {"method": "비탈덮기", "cover_kind": "거적"},
|
||||
|
||||
@@ -42,11 +42,6 @@ MARKED: dict[str, tuple[dict, list[str]]] = {
|
||||
"weep_hole_area_m2",
|
||||
],
|
||||
),
|
||||
# 2026-09-15 녹화 ㎡ 넷 — 단 직고·선떼 급수는 길이형(선떼·조공) 산출식이 설 때 읽힘.
|
||||
"revegetation": (
|
||||
{"method": "평떼", "face": "양쪽", "b06_cut_area_m2": 40.0, "b06_fill_area_m2": 60.0},
|
||||
["step_height_m", "sod_grade"],
|
||||
),
|
||||
"soil_guard": (
|
||||
{"height_m": 1.0, "length_m": 10.0, "form": "떼"},
|
||||
[
|
||||
|
||||
@@ -48,7 +48,9 @@ def test_평떼_양쪽은_면적과_떼_11매() -> None:
|
||||
assert got[("평떼", "㎡")] == pytest.approx(100.0)
|
||||
assert got[("떼", "매")] == pytest.approx(1100.0)
|
||||
text = " ".join(row["notes"])
|
||||
assert "겹친 몫을 자동으로 빼지 않음" in text and row["notes"][0].startswith("⚠")
|
||||
# 병행시공(임도기술교본 7장 · 울진1공구) — 흠이 아니라 정보(⚠ 안 붙임 · 안티그래비티 확인)
|
||||
assert row["notes"][0].startswith("녹화와 초류종자살포는 병행시공(임도기술교본 7장)")
|
||||
assert "떼 면적을 파종에서 빼지 않음" in text and "⚠" not in row["notes"][0]
|
||||
assert "5-12 품에 걸린 것으로 읽음 — 5-22-3 떼꽂이는 따로 셈" in text
|
||||
parts = _parts(table)
|
||||
assert parts["FP-05-22-02"]["quantity"] == pytest.approx(100.0)
|
||||
@@ -80,10 +82,63 @@ def test_면을_안_고르면_사유() -> None:
|
||||
assert not row["components"] and any("절토면" in n and "성토면" in n for n in row["notes"])
|
||||
|
||||
|
||||
def test_길이형은_떼_매수표를_기다린다() -> None:
|
||||
row = _row(method="선떼붙이기", face="양쪽")["structures"][0]
|
||||
def test_조공은_아직_산출식이_없다() -> None:
|
||||
row = _row(method="조공", face="양쪽")["structures"][0]
|
||||
assert not row["components"]
|
||||
assert any("사방기술교본" in n for n in row["notes"])
|
||||
assert any("산출식 아직 없음" in n for n in row["notes"])
|
||||
|
||||
|
||||
SOD = {
|
||||
"method": "선떼붙이기",
|
||||
"face": "양쪽",
|
||||
"step_height_m": 1.5,
|
||||
"sod_grade": "5급",
|
||||
"sod_size": "대형 40×40",
|
||||
"cutting_soil": "보통토사",
|
||||
# 구간 안 사면 낙차 × 거리(m·m) — 절토 30 · 성토 60 ⇒ 연장 = 90 ÷ 1.5 = 60m
|
||||
"b06_cut_rise_area_m2": 30.0,
|
||||
"b06_fill_rise_area_m2": 60.0,
|
||||
}
|
||||
|
||||
|
||||
def test_선떼는_낙차_나누기_단_직고로_연장_표_2_2_6_매수() -> None:
|
||||
"""품셈 5-16-1 [주]② 연장 = 대상지 직고 ÷ 단 직고 × 연장 · 표 2-2-6 표 값(식 아님)."""
|
||||
table = _row(**SOD)
|
||||
row = table["structures"][0]
|
||||
got = {(c["name"], c["unit"]): c for c in row["components"]}
|
||||
assert (row["billing_unit"], row["billing_quantity"]) == ("m", pytest.approx(60.0))
|
||||
assert got[("선떼붙이기", "m")]["amount"] == pytest.approx(60.0)
|
||||
# 5급 대형 표 값 7.80매/m(단면식 3.0 × 2.5 = 7.50 과 어긋남 — 표가 이김)
|
||||
assert got[("떼", "매")]["amount"] == pytest.approx(60.0 * 7.80)
|
||||
assert got[("떼", "매")]["spec"] == "40×40"
|
||||
assert got[("떼붙임", "㎡")]["amount"] == pytest.approx(60.0 * 7.80 * 0.16)
|
||||
text = " ".join(row["notes"])
|
||||
assert "5급 대형 표 7.80 ↔ 단면식 7.50" in text and "소형 2급 표 27.0 ↔ 단면 4.0" in text
|
||||
parts = _parts(table)
|
||||
assert parts["FP-05-16-01#보통토사"]["quantity"] == pytest.approx(60.0)
|
||||
# 떼붙임은 수량만 — 호표가 없어 막힘 + 사유(금액 안 섬)
|
||||
assert parts["FP-05-16-02"]["quantity"] == pytest.approx(60.0 * 7.80 * 0.16)
|
||||
assert parts["FP-05-16-02"]["not_ready"]
|
||||
assert "떼붙임 호표 없음" in parts["FP-05-16-02"]["why"]
|
||||
|
||||
|
||||
def test_선떼_소형_2급은_표_값_27() -> None:
|
||||
table = _row(**{**SOD, "sod_grade": "2급", "sod_size": "소형 18×18"})
|
||||
got = {(c["name"], c["unit"]): c["amount"] for c in table["structures"][0]["components"]}
|
||||
assert got[("떼", "매")] == pytest.approx(60.0 * 27.0)
|
||||
assert got[("떼붙임", "㎡")] == pytest.approx(60.0 * 27.0 * 0.18 * 0.18)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("missing", ["step_height_m", "sod_grade", "sod_size"])
|
||||
def test_선떼_칸이_비면_사유(missing: str) -> None:
|
||||
row = _row(**{k: v for k, v in SOD.items() if k != missing})["structures"][0]
|
||||
assert not row["components"] and row["notes"]
|
||||
|
||||
|
||||
def test_단끊기_토질을_안_고르면_그_조각만_막힘() -> None:
|
||||
table = _row(**{k: v for k, v in SOD.items() if k != "cutting_soil"})
|
||||
part = _parts(table)["FP-05-16-01"]
|
||||
assert part["not_ready"] and "토질" in part["why"]
|
||||
|
||||
|
||||
def test_구간_안_사면_면적은_B06_측점에서_보간() -> None:
|
||||
@@ -104,6 +159,22 @@ def test_구간_안_사면_면적은_B06_측점에서_보간() -> None:
|
||||
assert filled["options"]["b06_fill_area_m2"] == pytest.approx(22.5)
|
||||
|
||||
|
||||
def test_구간_안_사면_낙차_면적도_B06_측점에서() -> None:
|
||||
from B08_Quantity.B08_Quantity_Engine_SlopeLength import SlopeSegment, StationSlope
|
||||
|
||||
def seg(role: str, rise: float) -> SlopeSegment:
|
||||
return SlopeSegment("left", role, 0.0, 1.0, rise, 1.0, 1.0)
|
||||
|
||||
slopes = [
|
||||
StationSlope(chainage_m=0.0, segments=(seg("cut", 2.0), seg("fill", -4.0))),
|
||||
StationSlope(chainage_m=20.0, segments=(seg("cut", 4.0), seg("cut", 1.0))),
|
||||
]
|
||||
structure = {"type_id": "revegetation", "start_m": 0.0, "end_m": 20.0, "options": {}}
|
||||
options = revegetation_from_designs(structure, [], slopes)["options"]
|
||||
assert options["b06_cut_rise_area_m2"] == pytest.approx((2.0 + 5.0) / 2 * 20)
|
||||
assert options["b06_fill_rise_area_m2"] == pytest.approx((4.0 + 0.0) / 2 * 20)
|
||||
|
||||
|
||||
def test_등록부_공법에서_초류종자_살포를_빼고_까닭을_보인다() -> None:
|
||||
options = {o.key: o for o in structure_type_map()["revegetation"].options}
|
||||
assert "초류종자 살포" not in options["method"].choices
|
||||
@@ -111,5 +182,12 @@ def test_등록부_공법에서_초류종자_살포를_빼고_까닭을_보인
|
||||
assert (
|
||||
options["face"].choices == ["절토면", "성토면", "양쪽"] and options["face"].default is None
|
||||
)
|
||||
for key in ("step_height_m", "sod_grade"):
|
||||
assert options[key].default is None and "아직 표에 안 쓰임" in options[key].not_in_table
|
||||
for key in ("step_height_m", "sod_grade", "sod_size", "cutting_soil"):
|
||||
assert options[key].default is None and not options[key].not_in_table
|
||||
assert options["sod_size"].choices == ["대형 40×40", "소형 18×18"]
|
||||
# 단끊기 토질은 품셈 5-16-1 표 갈래 이름 그대로(B06 지반 프리셋과 다른 축)
|
||||
assert options["cutting_soil"].choices == [
|
||||
"보통토사",
|
||||
"경질ㆍ고사점토 및 자갈섞인 점토",
|
||||
"호박돌 섞인 토사",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user