Files
2026-04-03 09:08:08 +09:00

91 lines
3.6 KiB
Python
Raw Permalink 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.
from __future__ import annotations
from typing import Any
from civilplan_mcp.db.bootstrap import load_json_data
from civilplan_mcp.models import ProjectDomain
from civilplan_mcp.tools._base import wrap_response
TERRAIN_FACTORS = {
"평지": {"cut_section_m2": 5, "fill_section_m2": 3, "cut_ratio": 0.3, "fill_ratio": 0.3},
"구릉": {"cut_section_m2": 18, "fill_section_m2": 12, "cut_ratio": 0.5, "fill_ratio": 0.5},
"산지": {"cut_section_m2": 35, "fill_section_m2": 22, "cut_ratio": 0.6, "fill_ratio": 0.4},
}
def estimate_quantities(
*,
road_class: str,
length_m: float,
width_m: float,
terrain: str,
pavement_type: str,
include_water_supply: bool,
include_sewage: bool,
include_retaining_wall: bool,
include_bridge: bool,
bridge_length_m: float,
) -> dict[str, Any]:
road_standards = load_json_data("road_standards.json")
standard = road_standards[road_class]
terrain_factor = TERRAIN_FACTORS[terrain]
pavement_area = round(length_m * width_m, 1)
surface_volume = pavement_area * (standard["ascon_surface_mm"] / 1000)
base_volume = pavement_area * (standard["ascon_base_mm"] / 1000)
quantities = {
"토공": {
"절토_m3": round(length_m * terrain_factor["cut_section_m2"] * terrain_factor["cut_ratio"]),
"성토_m3": round(length_m * terrain_factor["fill_section_m2"] * terrain_factor["fill_ratio"]),
"사토_m3": round(length_m * 2),
},
"포장": {
"아스콘표층_t": round(surface_volume * 2.35),
"아스콘기층_t": round(base_volume * 2.35),
"보조기층_m3": round(pavement_area * (standard["subbase_mm"] / 1000)),
"동상방지층_m3": round(pavement_area * (standard["frost_mm"] / 1000)),
},
"배수": {
"L형측구_m": round(length_m * 2),
"횡단암거D800_m": round(length_m / (150 if terrain == "구릉" else 100 if terrain == "산지" else 200)) * 10,
"집수정_ea": max(2, round(length_m / 75)),
},
"교통안전": {
"차선도색_m": round(length_m * max(1, width_m / 2)),
"표지판_ea": max(4, round(length_m / 100)),
"가드레일_m": round(length_m * 0.2),
},
}
if include_water_supply:
quantities["상수도"] = {"PE관DN100_m": round(length_m), "제수밸브_ea": 3, "소화전_ea": 3}
if include_sewage:
quantities["하수도"] = {
"오수관VR250_m": round(length_m),
"우수관D400_m": round(length_m),
"오수맨홀_ea": round(length_m / 50) + 1,
"우수맨홀_ea": round(length_m / 50),
}
if include_retaining_wall:
quantities["구조물"] = {"L형옹벽H2m_m": round(length_m * 0.22), "씨드스프레이_m2": round(length_m * 1.12)}
if include_bridge:
quantities.setdefault("구조물", {})["교량상부공_m"] = round(bridge_length_m)
result = {
"disclaimer": "개략 산출 (±20~30% 오차). 실시설계 대체 불가.",
"road_spec": {
"length_m": length_m,
"width_m": width_m,
"carriage_m": width_m - standard["shoulder"] * 2,
"pavement_area_m2": pavement_area,
},
"quantities": quantities,
"calculation_basis": {
"아스콘표층": f"{pavement_area}× {standard['ascon_surface_mm'] / 1000:.2f}m × 2.35t/m³",
"오수맨홀": f"{round(length_m)}m ÷ 50m + 1",
},
"inputs": {"pavement_type": pavement_type},
}
return wrap_response(result, ProjectDomain.토목_도로)