- 집수정 □형 Ø800 — 관측 줄에 원문 치수(소광리 「집수정구조도(800)」 설계조건 칸·산출식)를 싣고 그 치수로 표 수량이 원문 식대로 다시 나오는지 시험 원문 값으로: 콘크리트 2.84 → 2.83752 · 합판거푸집 21.28 → 21.2843 · 철근 D13 4.78 → 4.776 · 면목 12.67 → 12.6728(터파기·되메우기·잔토 그대로) 그림: 긴 벽 정면(바닥기초·관·방수로·터파기) + 평면 · 관·방수로 자리는 원문 입체도 모식이라 적음 - 물넘이포장 — 슬래브 T(규격) · 와이어메쉬 2/3T(소광리 「포장」 그림) · 터파기 · 새 사유 「원문 둘이 다름: 소광리 포장 와이어매쉬 1.0·비닐 2㎡ ↔ 이 표(울진 1공구) 1.16·비닐 없음」을 표·그림이 같이 씀 - 날개벽 5종 — 원문 탭에 구조도 그림이 없고 날개 모양이 손으로 적은 수뿐이라 까닭 · 돌집수정 ㄷ·ㄴ형 — 집계표 관측값이라 치수 원문 없음 까닭 - 사유 문구(브레인 판정): 개거 150×200 「원문 둘이 다름(산출식 0.3×0.1 ↔ 그림 홈 150×200 + 밑 보 400×200)」 · 바닥막이 「옹벽은 버림·잡석까지 팜 — 바닥막이는 정본이 돌 두께만이라 다름」 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
322 lines
13 KiB
Python
322 lines
13 KiB
Python
"""구조물도 상단 그림 — **골막이 · 떼흙막이 · 바닥막이** (정본 개소당·㎡당 구조물, 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
|