Files
Aislo/resources/tester/test_69_b08_earthwork_tabs.py
T

218 lines
8.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""B08 토공 탭 (PLAN 69-2 · 69-3) — 토적표 견본 칸 · 면 계열 · 운반 시트 · 토공집계표 식.
정답지 ① 사용자 견본 두 행(120 · 120+18) ② 거창 실무 워크북 토적표 131행(70) ·
③ 같은 워크북 토공집계표 · 평균운반거리 · 종방향무대운반거리 시트 식.
"""
from __future__ import annotations
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from B07_DesignDetail.B07_DesignDetail_Engine_Cross_Quantity import derived_cells # noqa: E402
from B08_Quantity.B08_Quantity_Engine_Earthwork import ( # noqa: E402
FACE_KEYS,
StationArea,
build_rows,
build_table,
)
from B08_Quantity.B08_Quantity_Engine_Earthwork_Summary import ( # noqa: E402
excel_round,
haul_lists,
summary_rows,
)
# 견본 보정량 36.2 / 41.1 · 55.2 / 48.0 에서 거꾸로 — 토사 0.88 · 연암 1.15
SAMPLE_FACTORS = {
"soil": {"compacted": 0.88},
"ripping_rock": {"compacted": 1.15},
"blasting_rock": {"compacted": 1.3},
}
SAMPLE_FACES = (
# grading_fill · grading_cut · tree_fill · tree_cut · grubbing · road
(4.4, 1.3, 4.7, 4.6, 1.3, 4.0),
(6.9, 0.4, 10.1, 4.6, 4.8, 5.7),
)
def _faces(values: tuple[float, ...]) -> dict[str, float | None]:
return dict(zip(FACE_KEYS, (*values, None)))
def 견본_두_측점() -> list[StationArea]:
return [
StationArea(
chainage_m=120.0,
cut_soil_area_m2=3.28,
cut_rock_area_m2=1.61,
ditch_soil_area_m2=0.0,
ditch_rock_area_m2=0.18,
fill_area_m2=1.9,
cut_rock_kind="ripping_rock",
faces=_faces(SAMPLE_FACES[0]),
),
StationArea(
chainage_m=138.0,
cut_soil_area_m2=1.29,
cut_rock_area_m2=3.72,
ditch_soil_area_m2=0.0,
ditch_rock_area_m2=0.0,
fill_area_m2=19.13,
cut_rock_kind="ripping_rock",
faces=_faces(SAMPLE_FACES[1]),
),
]
def test_견본_120_18_행() -> None:
first, row = build_rows(견본_두_측점(), SAMPLE_FACTORS)
assert row.distance_m == pytest.approx(18)
assert round(row.cut_soil_volume_m3, 1) == 41.1
assert round(row.cut_soil_adjusted_m3, 1) == 36.2
assert round(row.cut_rock_volume_m3, 1) == 48.0
assert round(row.cut_rock_adjusted_m3, 1) == 55.2
assert round(row.ditch_rock_volume_m3, 1) == 1.6
assert round(row.ditch_rock_adjusted_m3, 1) == 1.9
assert round(row.adjusted_total_m3, 1) == 91.4 # 절토 보정량만
assert round(row.fill_volume_m3, 1) == 189.3
assert round(row.diverted_m3, 1) == 91.4
assert round(row.balance_m3, 1) == -97.9
assert round(row.cumulative_m3, 1) == -97.9
areas = [round(row.faces[key]["area_m2"], 1) for key in FACE_KEYS[:6]]
assert areas == [101.7, 15.3, 133.2, 82.8, 54.9, 87.3]
def test_첫_측점은_면_거리만() -> None:
first = build_rows(견본_두_측점(), SAMPLE_FACTORS)[0]
assert [first.faces[key]["length_m"] for key in FACE_KEYS[:6]] == list(SAMPLE_FACES[0])
assert all(first.faces[key]["area_m2"] is None for key in FACE_KEYS)
def test_거창_토적표_131행() -> None:
"""워크북 130(+10) → 131(70) — 절토 · 측구 · 성토 · 지장목 성토 면적 같은 입력 다시 셈."""
stations = [
StationArea(
chainage_m=0.0,
cut_soil_area_m2=6.72,
ditch_soil_area_m2=0.18,
ditch_rock_area_m2=0.0,
fill_area_m2=0.19,
faces=_faces((0.1, 4.7, 2.4, 6.3, 0, 0)),
),
StationArea(
chainage_m=10.0,
cut_soil_area_m2=3.15,
ditch_soil_area_m2=0.18,
ditch_rock_area_m2=0.0,
fill_area_m2=15.02,
faces=_faces((8.0, 3.8, 11.3, 4.5, 0, 0)),
),
]
row = build_rows(stations)[1]
assert row.cut_soil_volume_m3 == pytest.approx(49.35) # E131
assert row.cut_soil_adjusted_m3 == pytest.approx(44.415) # F131 44.41
assert row.ditch_soil_volume_m3 == pytest.approx(1.8) # K131
assert row.fill_volume_m3 == pytest.approx(76.05) # R131
assert row.faces["tree_removal_fill"]["area_m2"] == pytest.approx(68.5) # AG131
# 워크북 면적은 거리 소수 둘째 자리로 셈 — 표기 거리로는 ±0.5 안
assert row.faces["grading_fill"]["area_m2"] == pytest.approx(40.7, abs=0.5) # Y131
assert row.faces["tree_removal_cut"]["area_m2"] == pytest.approx(54.4, abs=0.5) # AI131
def test_면_거리는_B07_횡단도_수량과_같음() -> None:
design = {
"design_line": [
{"offset_m": o, "elevation_m": z}
for o, z in ((-8, 102), (-2, 100), (2, 100), (6, 102.5))
],
"road_edges": {"left": {"offset_m": 2}, "right": {"offset_m": -2}},
"cut_slope_ratio": 0.8,
"fill_slope_ratio": 1.5,
"roadbed_width_m": 4.0,
}
area = StationArea.from_design(120.0, design)
cells = derived_cells(120.0, design)
for key in ("grading_fill", "grading_cut", "tree_removal_fill", "tree_removal_cut"):
assert area.faces[key] == cells.get(key)
assert area.faces["road_surface"] == 4.0
assert area.faces["grubbing"] is None # B07 에 값 없음
def test_엑셀_ROUND() -> None:
assert excel_round(2.5) == 3
assert excel_round(-97.5) == -98
assert excel_round(1.005, 2) == 1.01
HAUL_PLAN = {
"blocks": [
{
"bands": [
{"equipment": "free_haul", "volume_m3": 50, "haul_distance_m": 10},
{"equipment": "dozer", "volume_m3": 20, "haul_distance_m": 40},
{"equipment": "dump_truck", "volume_m3": 68, "haul_distance_m": 35},
]
},
{"bands": [{"equipment": "free_haul", "volume_m3": 32, "haul_distance_m": 13}]},
],
"transfers": [{"equipment": "dump_truck", "volume_m3": 2, "haul_distance_m": 61}],
}
def test_운반_시트() -> None:
haul = haul_lists(HAUL_PLAN)
free = haul["free_haul"]
assert [(r["q"], r["l"]) for r in free["rows"]] == [(50, 10), (32, 13)]
assert free["q"] == 82 and free["ql"] == 50 * 10 + 32 * 13
assert free["average_m"] == excel_round((500 + 416) / 82, 2)
dump = haul["dump_truck"]
assert dump["q"] == 70 and dump["ql"] == 68 * 35 + 2 * 61 # 덤프 띠 + 떨어진 구간 운반
assert haul["dozer"]["average_m"] == 40
assert haul_lists(None)["dump_truck"] == {"rows": [], "q": 0, "ql": 0, "average_m": None}
def test_토공집계표_식() -> None:
table = build_table(견본_두_측점(), SAMPLE_FACTORS)
t = table["totals"]
rows = summary_rows(t, haul_lists(HAUL_PLAN))
value = {(r["group"], r["kind"], r["spec"]): r["value"] for r in rows}
assert value[("흙깍기", "토사", "기계(굴삭기)")] == excel_round(t["cut_soil_volume_m3"])
# 연암 · 경암 = 암 × 기본 90 : 10(122)
rock, ditch = t["cut_rock_volume_m3"], t["ditch_rock_volume_m3"]
assert value[("흙깍기", "연암", "굴삭기 + 브레카")] == excel_round(rock * 0.9) == 43
assert value[("흙깍기", "경암", "발파 + 굴삭기")] == excel_round(rock - rock * 0.9) == 5
assert value[("측구 터파기", "연암", "굴삭기 + 브레카")] == excel_round(ditch * 0.9)
assert value[("측구 터파기", "경암", "발파 + 굴삭기")] == excel_round(ditch - ditch * 0.9)
assert value[("보정량계", "", "")] == 91
assert value[("성토", "", "")] == 189
assert value[("종방향유용토", "", "백호우")] == 82
assert value[("토사운반", "", "BH+DT+BH")] == 70
assert value[("토사운반", "", "19 TON B/D")] == 20
assert value[("유용토 소계", "", "")] == pytest.approx(t["diverted_m3"] + 82)
assert value[("잔토처리", "", "백호우")] == -98
assert value[("성토면다짐", "", "")] == excel_round(101.7 * 0.8)
assert value[("초류종자살포", "", "씨드스프레이")] == excel_round(101.7 * 0.5 + 15.3)
tree = excel_round(133.2 * 0.5 + 82.8, 2)
assert value[("지장목제거", "", "")] == excel_round(tree * 0.8)
assert value[("표토제거", "", "")] is None
assert len(rows) == 33 # 시트 C5:C37
def test_토적표_머리_글자는_사용자_견본대로():
# 「[절토] <토사> · <연암> · 측구파기 <토사> · <암>」 — 값 · 계산은 그대로
ui = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Earthwork.ts").read_text(encoding="utf-8")
for head in (
'["절토", "연암"]',
'["절토", "경암"]',
'["측구파기", "토사"]',
'["측구파기", "암"]',
"리핑암 · 발파암 합",
):
assert head in ui, head
assert "암석" not in ui and "측구터파기" not in ui