- 겹친 사면(초류종자살포·면고르기)은 자동으로 안 빼고 맨 앞 사유 · 평떼 떼꽂이 5-22-3 [주] 읽기 사유 - 혼합석 사유 정정: 토사 = B06 측점 토사 토글(구성비는 암 몫만) · 사전터파기 「산림품셈에 노면 사전 터파기 공종 없음 — 9-3-2 토사깍기(기계)로 이음」 - UnitQuantity 700줄 — 늦은 import 를 한 벌(_lazy)로 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
166 lines
7.3 KiB
Python
166 lines
7.3 KiB
Python
"""혼합석(쇄석) 부설 — **법령 조건 자동 · 연약·습윤 칸 · 「비포장 전 구간」 고르개** (2026-09-15).
|
||
|
||
근거
|
||
① 법령 별표2 Ⅰ.2.바.(2) — 종단 8% 초과 사질·점토 구간 · 8% 이하 연약·습윤 구간에 쇄석·자갈 부설
|
||
(최소 요구 · 조건이 또렷함 ⇒ 기본)
|
||
② 임도기술교본 3-2 — 「콘크리트 포장 구간 이외에는 혼합석 부설 다짐 후 0.10m 내외」
|
||
(더 넓은 권장 ⇒ 고르개)
|
||
③ 임도기술교본 10-1 · 부록 7-2 — 포설 전 10㎝ 터파기 · 적용범위 「노면의 토사구간」
|
||
④ 품셈 11-4 쇄석·혼합석 부설(㎥ · 백호 부설만) · 1-2-3 체적환산표(혼합석 줄 없음)
|
||
⚠ 면적은 측점 사이 평균(끝 둘 중 하나만 해당이면 반만) — 토적표 평균단면적법과 같은 결.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
from B08_Quantity.B08_Quantity_Engine_UnitQuantity_Base import _num
|
||
|
||
LEGAL_GRADE_PCT = 8.0
|
||
THICKNESS_SUGGESTED_M = 0.10 # 교본 3-2 「다짐 후 0.10m 내외」
|
||
PRE_EXCAVATION_M = 0.10 # 교본 10-1 「포설 전 10㎝ 터파기」
|
||
C_SUGGESTED, L_SUGGESTED = 0.85, 1.25 # 실무 소광 관측
|
||
|
||
NOTE_LEGAL = (
|
||
"법령 별표2 Ⅰ.2.바.(2) 조건으로 자동 — 종단 8% 초과 토사 측점 + 8% 이하 중 연약·습윤 칸 구간"
|
||
" · 교본 3-2 는 「콘크리트 포장 구간 이외」 전부(산출 조건 「비포장 전 구간」으로 넓힘)"
|
||
)
|
||
NOTE_ALL = (
|
||
"비포장 전 구간 — 임도기술교본 3-2 「콘크리트 포장 구간 이외에는 혼합석 부설」 · 법령 별표2"
|
||
" Ⅰ.2.바.(2) 는 종단 8% 초과 사질·점토 / 8% 이하 연약·습윤 구간만 요구"
|
||
)
|
||
NOTE_SOIL = (
|
||
"법령은 사질·점토를 가르는데 우리 프리셋은 토사 하나 — 토사 전부를 해당으로 봄(암은 비해당)"
|
||
" · 토사 = B06 측점 토사 토글(구성비는 암 몫만 가름)"
|
||
)
|
||
NOTE_GRADE = "종단 경사 = 종단 계획선에서 측점을 감싼 구간 경사 중 큰 값(B05 포장 제안과 같은 식)"
|
||
NOTE_WIDTH = "폭 = 차도 표준 폭 + 확폭(노견 제외 · 실무 소광 「혼합석부설 B=3.0」)"
|
||
NOTE_COMPACTION = (
|
||
"다짐 줄 없음 — 품셈 11-4 는 부설만이고 산림품셈에 쇄석 다짐 공종이 없음"
|
||
" · 9-16-2 노체다짐은 「대규모 성토지 층다짐」 조건이라 안 이음"
|
||
)
|
||
NOTE_EXCAVATION = (
|
||
"사전 터파기 — 교본 10-1 「포설 전 10㎝ 터파기」 · 부록 7-2 적용범위 「노면의 토사구간」이라"
|
||
" 토사 측점만 · 산림품셈에 노면 사전 터파기 공종 없음 — 9-3-2 토사깍기(기계)로 이음"
|
||
" · 파낸 흙의 운반·사토는 유토곡선 밖이라 안 셈"
|
||
)
|
||
|
||
|
||
def _factor_note(c: float, l_factor: float, suggested: bool) -> str:
|
||
head = (
|
||
f"C {c:g} · L {l_factor:g} — 제안값 실무 소광 관측"
|
||
if suggested
|
||
else f"C {c:g} · L {l_factor:g} — 산출 조건 칸"
|
||
)
|
||
return (
|
||
f"{head} · 자재 = 다짐 후 부피 ÷ C × L · 원문 표에 혼합석 줄 없음(품셈 1-2-3 가까운 줄"
|
||
" 역(礫) L 1.10~1.20 · C 1.05~1.10) · ⚠ 소광 C 0.85(다지면 줄어듦)와 원문 역 C(늘어남)는"
|
||
" 방향이 반대 — 같은 C 라도 뜻이 다를 수 있음"
|
||
)
|
||
|
||
|
||
def _qualifies(
|
||
chainage: float,
|
||
design: dict[str, Any],
|
||
grades: dict[float, float],
|
||
soft_wet: list[tuple[float, float]],
|
||
all_unpaved: bool,
|
||
) -> bool | None:
|
||
"""이 측점에 까는가 — 경사를 모르면 `None`(판정 못 함)."""
|
||
if design.get("paved"):
|
||
return False
|
||
if all_unpaved:
|
||
return True
|
||
grade = grades.get(round(chainage, 3))
|
||
if grade is None:
|
||
return None
|
||
if grade > LEGAL_GRADE_PCT:
|
||
return design.get("ground_type") == "soil"
|
||
return any(start <= chainage <= end for start, end in soft_wet)
|
||
|
||
|
||
def gravel_surfacing(
|
||
designs: list[dict[str, Any]] | None,
|
||
grades: dict[float, float] | None,
|
||
settings: dict[str, Any],
|
||
) -> dict[str, Any]:
|
||
"""노선 혼합석 부설 한 벌 — 면적·부피·사전 터파기·사유."""
|
||
grades = {round(float(k), 3): float(v) for k, v in (grades or {}).items()}
|
||
all_unpaved = bool(settings.get("gravel_all_unpaved"))
|
||
soft_wet = [
|
||
tuple(sorted((_num(r.get("from_m")), _num(r.get("to_m")))))
|
||
for r in settings.get("gravel_soft_wet_ranges") or []
|
||
if isinstance(r, dict)
|
||
]
|
||
stations = sorted(
|
||
(
|
||
(_num(item.get("chainage_m")), item["design"])
|
||
for item in designs or ()
|
||
if isinstance(item, dict) and isinstance(item.get("design"), dict)
|
||
),
|
||
key=lambda row: row[0],
|
||
)
|
||
weights: list[tuple[float, float, float]] = [] # (측점, 폭×해당, 폭×해당×토사)
|
||
unknown = 0
|
||
for chainage, design in stations:
|
||
hit = _qualifies(chainage, design, grades, soft_wet, all_unpaved)
|
||
unknown += hit is None
|
||
width = (
|
||
_num(design.get("carriageway_standard_width_m"))
|
||
+ _num(design.get("widening_left_m"))
|
||
+ _num(design.get("widening_right_m"))
|
||
)
|
||
on = width if hit else 0.0
|
||
weights.append((chainage, on, on if design.get("ground_type") == "soil" else 0.0))
|
||
area = soil_area = 0.0
|
||
for (s0, w0, t0), (s1, w1, t1) in zip(weights, weights[1:]):
|
||
area += (w0 + w1) / 2 * (s1 - s0)
|
||
soil_area += (t0 + t1) / 2 * (s1 - s0)
|
||
|
||
thickness = _num(settings.get("gravel_thickness_m")) or THICKNESS_SUGGESTED_M
|
||
c = _num(settings.get("gravel_conversion_c")) or C_SUGGESTED
|
||
l_factor = _num(settings.get("gravel_conversion_l")) or L_SUGGESTED
|
||
suggested = not (settings.get("gravel_conversion_c") or settings.get("gravel_conversion_l"))
|
||
notes = [NOTE_ALL if all_unpaved else NOTE_LEGAL, NOTE_SOIL, NOTE_GRADE, NOTE_WIDTH]
|
||
notes.append(
|
||
f"두께(다짐 후) {thickness:g}m — "
|
||
+ (
|
||
"산출 조건 칸"
|
||
if settings.get("gravel_thickness_m")
|
||
else "제안값 교본 3-2 「0.10m 내외」"
|
||
)
|
||
)
|
||
notes += [_factor_note(c, l_factor, suggested), NOTE_COMPACTION, NOTE_EXCAVATION]
|
||
if unknown:
|
||
notes.append(f"종단 경사를 못 읽은 측점 {unknown}곳은 안 깜(판정 못 함)")
|
||
compacted = area * thickness
|
||
return {
|
||
"all_unpaved": all_unpaved,
|
||
"area_m2": area,
|
||
"soil_area_m2": soil_area,
|
||
"thickness_m": thickness,
|
||
"compacted_m3": compacted,
|
||
"loose_m3": compacted / c * l_factor,
|
||
"excavation_soil_m3": soil_area * PRE_EXCAVATION_M,
|
||
"notes": notes,
|
||
# 칸이 비면 쓰는 제안값 — 화면이 회색으로 보임(값의 정의처는 여기 한 곳).
|
||
"suggested": {"thickness_m": THICKNESS_SUGGESTED_M, "c": C_SUGGESTED, "l": L_SUGGESTED},
|
||
}
|
||
|
||
|
||
def gravel_material_rows(result: dict[str, Any] | None) -> list[dict[str, Any]]:
|
||
"""혼합석 자재(흐트러진 부피) → 자재총괄 성분 한 줄 — 부피가 없으면 빈 목록."""
|
||
amount = _num((result or {}).get("loose_m3"))
|
||
if amount <= 0:
|
||
return []
|
||
return [
|
||
{
|
||
"name": "혼합석",
|
||
"spec": "",
|
||
"unit": "㎥",
|
||
"amount": amount,
|
||
"destination": "material",
|
||
"source": "혼합석 부설",
|
||
}
|
||
]
|