Files
Aislo/old_code/B08_Quantity/B08_Quantity_Engine_StructureFigure_Small.py
T
eomsangdonandClaude Opus 5 8472fc9f40 refactor(B08,B09): 폴더째 old_code 로 옮기고 빈 화면 둘만 남김 (PLAN 7-3)
B08_Quantity 86 · B09_Estimation 111 파일을 old_code/ 로 옮김(지우지 않음).
화면은 메뉴·주소·단계 막대만 남은 빈 틀 둘 — main.py 라우터 13 개는 끊음.
B07 이 빌려 쓰던 비탈 길이·면적은 필요한 함수만 B07_DesignDetail_Engine_SlopeGeometry
로 옮겨 적음(면적 적분·노면 면적·측점 묶음은 안 옮김) · 시험 하나를 새로 둠.
B07 구조물도 조립(Cad_StandardSheet)은 2026-09-13 에 이미 도면 목록에서 빠져
부르는 곳이 없어 old_code 로 같이 보냄 — 구조물 그림은 되살리지 않음.
B06 구조물 몫 조회는 빈 값으로 두어 화면이 그대로 서게 함.
B08·B09 를 부르던 시험 25 개도 old_code/resources/tester 로 옮김.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
2026-09-22 12:27:45 +09:00

322 lines
13 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.
"""구조물도 상단 그림 — **골막이 · 떼흙막이 · 바닥막이** (정본 개소당·㎡당 구조물, PLAN 12장).
⚠ 치수는 **표가 쓴 그 한 벌**에서 읽음 — 골막이 `erosion_check_section` ·
떼흙막이 `SOIL_GUARD_SOD.dims` · 바닥막이 `BED_SILL_FORMS` + 산출 조건 기초잡석 두께.
⚠ 사유 글자도 표 사유와 같은 상수(`BED_SILL_TRENCH_NOTE` 등).
⚠ 좌표는 m · 위가 +y · 모양 목록 규약은 `B08_Quantity_Engine_StructureFigure` 와 같음.
"""
from __future__ import annotations
import math
from typing import Any
from B08_Quantity.B08_Quantity_Engine_StructureFigure import (
_LABEL_SIZE,
SCALE_MM_PER_M,
_path,
_text,
)
def _title(sheet: dict[str, Any], y: float) -> dict[str, Any]:
return _text(
f"{sheet.get('title') or ''} (축척 1/{int(1000 / SCALE_MM_PER_M)})",
(0.0, y),
"left",
_LABEL_SIZE,
)
def _front_with_trench(
top: float, bottom: float, height: float, depth: float, x0: float = 0.0
) -> list[dict[str, Any]]:
"""정면 사다리꼴(윗변 `top` · 밑변 `bottom` 가운데 정렬) + 사면 둘·밑변을 따라 판 띠(점선)."""
inset = (top - bottom) / 2
corners = [(x0, height), (x0 + inset, 0.0), (x0 + inset + bottom, 0.0), (x0 + top, height)]
shapes = [_path(corners + [corners[0]], "wall")]
if depth > 0:
# 사면 둘·밑변을 바깥으로 `depth` 만큼 민 선 — 이웃 변의 교점으로 잇음.
normals = []
for (ax, ay), (bx, by) in zip(corners[:3], corners[1:4]):
length = math.hypot(bx - ax, by - ay)
normals.append(((by - ay) / length, -(bx - ax) / length))
offset = []
for index, (px, py) in enumerate(corners):
used = [normals[i] for i in (index - 1, index) if 0 <= i < 3]
nx = sum(n[0] for n in used)
ny = sum(n[1] for n in used)
dot = used[0][0] * nx + used[0][1] * ny
offset.append((px + nx * depth / dot, py + ny * depth / dot))
shapes.append(_path(offset, "guide", dash=True))
return shapes
def _circle(cx: float, cy: float, r: float) -> list[tuple[float, float]]:
return [
(cx + r * math.cos(math.tau * i / 24), cy + r * math.sin(math.tau * i / 24))
for i in range(25)
]
def _rect(x0: float, y0: float, x1: float, y1: float) -> list[tuple[float, float]]:
return [(x0, y0), (x0, y1), (x1, y1), (x1, y0), (x0, y0)]
def inlet_basin_figure(sheet: dict[str, Any], entry: dict[str, Any]) -> list[dict[str, Any]]:
"""집수정(□형) — 긴 벽 정면(바닥기초 · 관 · 방수로 · 터파기) + 평면(바깥·안 벽).
치수는 관측 줄 `section`(표 수량이 나온 그 치수). 관·방수로 **자리**는 원문 입체도 모식.
"""
section = entry["section"]
inner, wall, base = section["inner"], section["wall_m"], section["base_m"]
spill, dig = section["spillway"], section["dig"]
length, width = inner["length_m"] + 2 * wall, inner["width_m"] + 2 * wall
height = inner["height_m"]
top = base + height
radius = section["pipe_d_m"] / 2
mid = length / 2
notch_half_top, notch_half_bottom = spill["top_m"] / 2, spill["bottom_m"] / 2
# 긴 벽 정면 — 윗변 가운데에 방수로 한 곳(모두 `count` 곳).
outline = [
(0.0, 0.0),
(0.0, top),
(mid - notch_half_top, top),
(mid - notch_half_bottom, top - spill["depth_m"]),
(mid + notch_half_bottom, top - spill["depth_m"]),
(mid + notch_half_top, top),
(length, top),
(length, 0.0),
(0.0, 0.0),
]
dig_len = length + dig["extra_length_m"]
shapes = [
_path(outline, "wall"),
_path([(0.0, base), (length, base)], "guide"),
_path(_circle(mid, base + radius, radius), "guide"),
_path(
_rect(-dig["extra_length_m"] / 2, 0.0, length + dig["extra_length_m"] / 2, top),
"guide",
dash=True,
),
]
# 평면 — 바깥 벽 · 안 벽 · 터파기 평면(점선).
px = length + 1.2
shapes += [
_path(_rect(px, 0.0, px + length, width), "wall"),
_path(_rect(px + wall, wall, px + length - wall, width - wall), "guide"),
_path(
_rect(
px - dig["extra_length_m"] / 2,
(width - dig["width_m"]) / 2,
px + length + dig["extra_length_m"] / 2,
(width + dig["width_m"]) / 2,
),
"guide",
dash=True,
),
]
right = px + length + 0.5
shapes += [
_title(sheet, max(top, dig["width_m"]) + 0.55),
_text("정면(긴 벽)", (mid, top + 0.15), "center"),
_text("평면", (px + length / 2, width + 0.15 + (dig["width_m"] - width) / 2), "center"),
_text(
f"안 {inner['length_m']:g}×{inner['width_m']:g}×{height:g} · 벽 {wall:g} · 바닥기초"
f" {length:g}×{width:g}×{base:g} m",
(right, top * 0.9),
"left",
),
_text(f"관 Ø{section['pipe_d_m']:g}", (right, top * 0.65), "left"),
_text(
f"방수로 {spill['count']}곳 (상장 {spill['top_m']:g} · 하장 {spill['bottom_m']:g}"
f" · 고 {spill['depth_m']:g})",
(right, top * 0.4),
"left",
),
_text(
f"터파기 {dig_len:g} × {dig['width_m']:g} × 깊이 {top:g} m",
(right, top * 0.15),
"left",
),
_text("관·방수로 자리는 원문 입체도 모식 — 치수는 산출식", (0.0, -0.3), "left"),
]
return shapes
def pavement_figure(sheet: dict[str, Any], entry: dict[str, Any]) -> list[dict[str, Any]]:
"""물넘이포장 — ㎡당 한 칸 단면: 슬래브 두께(규격) · 와이어메쉬(2/3T) · 터파기(두께만큼)."""
thickness = float(entry["spec"]["thickness_cm"]) / 100
mesh = thickness * entry["section"]["mesh_from_bottom_ratio"]
width = 1.0
shapes = [
_path(_rect(0.0, 0.0, width, thickness), "wall"),
_path([(0.05, mesh), (width - 0.05, mesh)], "guide", dash=True),
_path(_rect(-0.12, 0.0, width + 0.12, thickness), "guide", dash=True),
]
right = width + 0.4
shapes += [
_title(sheet, thickness + 0.45),
_text("폭 1 m 당(표는 ㎡당)", (width / 2, thickness + 0.12), "center"),
_text(f"콘크리트 T={thickness:g} m", (right, thickness * 0.8), "left"),
_text(f"와이어메쉬 — 밑에서 {mesh:.3f} m (2/3T)", (right, mesh - 0.02), "left"),
_text(f"터파기 깊이 {thickness:g} m (= 두께)", (right, 0.0), "left"),
]
for index, note in enumerate(entry.get("notes") or []):
shapes.append(_text(str(note), (0.0, -0.25 - index * 0.14), "left"))
return shapes
def erosion_check_figure(sheet: dict[str, Any]) -> list[dict[str, Any]]:
"""골막이 — 정면(사다리꼴 · 방수로 관 · 바닥파기 띠) + 옆 단면(상부·하부 두께)."""
from B08_Quantity.B08_Quantity_Engine_UnitQuantity_Revetment import erosion_check_section
geo = erosion_check_section(float(sheet.get("height_m") or 0.0), sheet.get("options") or {})
top, bottom, height = geo["top_m"], geo["bottom_m"], geo["height_m"]
shapes = _front_with_trench(top, bottom, height, geo["trench_depth"])
if geo["spillway"]:
shapes.append(_path(_circle(top / 2, geo["pipe_r"], geo["pipe_r"]), "guide"))
# 옆 단면 — 뒷면 수직 · 앞면이 하부 두께에서 상부 두께로 좁아짐(표의 두께식 그대로).
x0 = top + 1.2
shapes.append(
_path(
[
(x0, 0.0),
(x0, height),
(x0 + geo["top_t"], height),
(x0 + geo["bottom_t"], 0.0),
(x0, 0.0),
],
"wall",
)
)
right = x0 + geo["bottom_t"] + 0.3
shapes += [
_title(sheet, height + 0.55),
_text(f"상장 ⓐ {top:g} m", (top / 2, height + 0.14), "center"),
_text(f"하장 ⓑ {bottom:g} m", (top / 2, -geo["trench_depth"] - 0.18), "center"),
_text(f"H = {height:g} m", (-0.3 - geo["trench_depth"], height / 2), "right"),
_text(
f"상부 {geo['top_t']:.2f} · 하부 {geo['bottom_t']:.2f} · 평균 {geo['thickness']:.2f} m"
f" (뒷길이 {geo['back_cm']}㎝ + 0.1H / 0.4H)",
(right, height * 0.85),
"left",
),
_text(f"반수면 1:{geo['slope']:g}", (right, height * 0.62), "left"),
_text(
f"바닥파기 폭 {geo['trench_width']:.2f} × 깊이 {geo['trench_depth']:g} m"
f" (사면장 {geo['slant']:g} × 2 + 하장)",
(right, height * 0.39),
"left",
),
]
if geo["spillway"]:
shapes.append(
_text(
f"방수로 파형강관 Ø{geo['pipe_r'] * 2:g} — 정면적에서 뺌",
(right, height * 0.16),
"left",
)
)
return shapes
def soil_guard_figure(sheet: dict[str, Any]) -> list[dict[str, Any]]:
"""떼흙막이 — 정본 평균 붙박이 치수의 정면(떼 두께 · 바닥파기 띠)."""
from B08_Quantity.B08_Quantity_Engine_UnitQuantity_Revetment import SOIL_GUARD_SOD
d = SOIL_GUARD_SOD["dims"]
top, bottom, height = d["top_m"], d["bottom_m"], d["height_m"]
shapes = _front_with_trench(top, bottom, height, d["trench_depth_m"])
# 머리떼 — 윗변 위 떼 한 켜(두께 = 떼 폭 0.2 로 보임).
shapes.append(
_path(
[(0.0, height), (0.0, height + d["sod_m"]), (top, height + d["sod_m"]), (top, height)],
"guide",
)
)
right = top + 0.4
shapes += [
_title(sheet, height + d["sod_m"] + 0.45),
_text(f"상단 {top:g} m", (top / 2, height + d["sod_m"] + 0.12), "center"),
_text(f"하단 {bottom:g} m", (top / 2, -d["trench_depth_m"] - 0.15), "center"),
_text(f"H = {height:g} m", (-0.3, height / 2), "right"),
_text(
f"떼 20×20㎝ · 폭 {d['sod_m']:g} · 기슭(사면장) {d['slant_m']:g} m",
(right, height * 0.9),
"left",
),
_text(
f"바닥파기 폭 {d['trench_width_m']:g} × 깊이 {d['trench_depth_m']:g} m"
" (기슭 × 2 + 하단)",
(right, height * 0.45),
"left",
),
_text("치수 — 정본 「떼흙막이」 평균 붙박이(개소 제원을 안 봄)", (right, 0.0), "left"),
]
return shapes
def bed_sill_figure(
sheet: dict[str, Any], rubble_thickness_m: float | None
) -> list[dict[str, Any]]:
"""바닥막이(돌붙임) — ㎡당 한 칸의 단면: 돌 켜 · (찰) 버림 · 기초잡석 · 터파기(돌 두께만)."""
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import RUBBLE_BASE_THICKNESS_M
from B08_Quantity.B08_Quantity_Engine_UnitQuantity_Revetment import (
BED_SILL_FORMS,
BED_SILL_TRENCH_NOTE,
)
form = str((sheet.get("options") or {}).get("form") or "").strip()
table = BED_SILL_FORMS[form]
back = table["back_len_m"]
blinding = table["blinding_m3_per_m2"] or 0.0 # ㎥/㎡ = 두께(m)
rubble = RUBBLE_BASE_THICKNESS_M if rubble_thickness_m is None else float(rubble_thickness_m)
rubble = rubble if blinding > 0 else 0.0 # 표도 버림이 선 곳에만 기초잡석을 세움
width = 1.0
shapes = [_path([(0.0, 0.0), (0.0, back), (width, back), (width, 0.0), (0.0, 0.0)], "wall")]
if blinding > 0:
shapes.append(
_path([(0.0, 0.0), (0.0, -blinding), (width, -blinding), (width, 0.0)], "guide")
)
if rubble > 0:
shapes.append(
_path(
[
(0.0, -blinding),
(0.0, -blinding - rubble),
(width, -blinding - rubble),
(width, -blinding),
],
"guide",
dash=True,
)
)
# 터파기 — 표 식 그대로 면적 × 돌 두께(윗면에서 돌 켜 밑까지).
shapes.append(
_path(
[(-0.15, back), (-0.15, 0.0), (width + 0.15, 0.0), (width + 0.15, back)],
"guide",
dash=True,
)
)
right = width + 0.4
shapes += [
_title(sheet, back + 0.4),
_text(
f"{form} — 두께(뒷길이) {back:g} m · {table['stone_spec']}",
(right, back * 0.75),
"left",
),
_text("폭 1 m 당(표는 ㎡당)", (width / 2, back + 0.12), "center"),
_text(f"터파기 깊이 {back:g} m (면적 × 두께)", (right, back * 0.3), "left"),
]
if blinding > 0:
shapes.append(_text(f"버림 T={blinding:g} m", (right, -blinding / 2), "left"))
if rubble > 0:
shapes.append(
_text(f"기초잡석 T={rubble:g} m — 산출 조건", (right, -blinding - rubble / 2), "left")
)
shapes.append(_text(BED_SILL_TRENCH_NOTE, (0.0, -blinding - rubble - 0.25), "left"))
return shapes