Files
Aislo/resources/tester/test_b08_structure_figure.py
T
eomsangdonandClaude Opus 5 a9ddcd5b1b feat(b08): 구조물도 그림 — 뒷길이 미정 장도 표가 선 기본값으로 그림 · 표 사유와 같은 말
- 뒷길이를 안 고른 돌쌓기 장: 표가 쓴 그 뒷길이(양식 장은 양식이 푼 값, 전개 장은 기본 45㎝)로 그림
- 「⚠ 뒷길이를 안 골라 기본 N㎝ 로 섰습니다」 한 줄을 한 곳에 두고 표 사유·그림이 같이 씀(골막이 문구도 같은 함수)
- 돌쌓기 표 사유에 그 한 줄이 새로 붙음 — 전에는 기본값인 줄 표에 안 드러났음
- 그림 까닭은 정말 못 그리는 장(큰돌쌓기 직경 축·옹벽)만

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
2026-09-14 04:42:28 +09:00

103 lines
3.7 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장).
⚠ 옛 B07 그림은 두께 식을 따로 적어, 상부·하부 두께를 넣어도 **그림만 옛 두께**였음.
"""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from B08_Quantity.B08_Quantity_Engine_StructureFigure import ( # noqa: E402
attach_figures,
build_figure,
)
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import ( # noqa: E402
back_length_default_note,
stone_masonry,
)
def _sheet(**options) -> dict:
return {
"title": "돌쌓기(메)",
"type_id": "masonry_dry",
"height_m": 2.0,
"options": {"height_m": 2.0, **options},
}
def _paths(shapes: list[dict]) -> list[dict]:
return [shape for shape in shapes if shape["kind"] == "path"]
def _area(points: list[list[float]]) -> float:
return abs(sum(x0 * y1 - x1 * y0 for (x0, y0), (x1, y1) in zip(points, points[1:]))) / 2
def test_벽_두께는_사용자가_넣은_값을_따른다() -> None:
wall = _paths(build_figure(_sheet(back_len_cm=35, face_slope_ratio=0.3)))[0]["points"]
# 식: 상부 0.35+0.30=0.65 · 하부 0.65+0.30×(21)=0.95 · 기울기 0.3 → 앞면 위 끝 0.6
assert wall[:4] == [[0.0, 0.0], [0.6, 2.0], [1.25, 2.0], [0.95, 0.0]]
given = _paths(
build_figure(
_sheet(
back_len_cm=35, face_slope_ratio=0.3, thickness_top_m=0.5, thickness_bottom_m=1.2
)
)
)[0]["points"]
assert given[2] == [1.1, 2.0] and given[3] == [1.2, 0.0]
def test_터파기_넓이는_수량식과_같다() -> None:
dig = _paths(build_figure(_sheet(back_len_cm=35, face_slope_ratio=0.3)))[1]
assert dig["dash"]
assert abs(_area(dig["points"]) - 2.0 * ((0.65 + 0.95) / 2 + 0.2)) < 1e-9
def test_못_그리는_장은_그림_대신_까닭이_실린다() -> None:
payload = {
"sheets": [
_sheet(),
{**_sheet(stone_cm="60~80"), "type_id": "boulder_masonry"},
_sheet(back_len_cm=45),
]
}
attach_figures(payload)
no_back, boulder, drawn = payload["sheets"]
# 뒷길이 미정은 기본값이 있어 **그림이 섬**(2026-09-14 브레인 판정) — 까닭은 직경 축만.
assert no_back["figure_reason"] is None and no_back["figure"]
assert boulder["figure"] is None and "직경" in boulder["figure_reason"]
assert drawn["figure_reason"] is None and drawn["figure"]
def _texts(shapes: list[dict]) -> list[str]:
return [shape["text"] for shape in shapes if shape["kind"] == "text"]
def test_기본값으로_그린_장은_표_사유와_같은_말을_적는다() -> None:
options = {"height_m": 2.0}
_rows, table_notes = stone_masonry(2.0, 1.0, options, wet=False)
table_default = [note for note in table_notes if "뒷길이를 안 골라" in note]
assert table_default == [back_length_default_note(options, 45)]
texts = _texts(build_figure(_sheet()))
assert table_default[0] in texts
assert "뒷길이 ℓ₃ = 45㎝ (기본)" in texts
# 두께도 기본 45 로 — 상부 0.45+0.30
assert "상부 0.75 m" in texts
chosen = _texts(build_figure(_sheet(back_len_cm=45)))
assert "뒷길이 ℓ₃ = 45㎝" in chosen and not any("안 골라" in text for text in chosen)
assert back_length_default_note({"back_len_cm": 45}, 45) is None
def test_양식_장은_양식이_푼_뒷길이로_그린다() -> None:
sheet = {**_sheet(), "formula_sheet": {"vars": {"L3": 55}}}
texts = _texts(build_figure(sheet))
assert "뒷길이 ℓ₃ = 55㎝ (기본)" in texts and "상부 0.85 m" in texts