계획서 4-12. **빈 자리를 그냥 두면 사용자가 「고장인가」로 읽음** — 장마다 왜 그림이 없는지와 **무엇을 받아야 서는지**를 표 위에 한 줄 적음. - 돌쌓기(찰) — 「뒷길이를 고르면 그림이 섭니다」 · 옹벽 — 「단면이 달라 아직 안 그림」 ⚠ **큰돌쌓기를 `FIGURE_TYPE_IDS` 에서 뺌** — 그림은 두께를 뒷길이에서 내는데 큰돌쌓기는 규격이 **직경**이라 목록에만 있고 결과는 늘 빈 그림이었음(품셈 13-6 직경 ↔ 13-4 뒷길이, 수량 쪽에서 이미 갈라 둔 자리). **식은 만들지 않음** — 「직경에서 두께를 내는 법」은 도메인 판단이라 사용자 몫이고, 지금은 사유만 띄움. ⚠ 곁가지 하나를 화면에서 잡아 함께 고침 — 그림 대상 목록을 **기울기 판정**에도 쓰고 있어 큰돌쌓기를 빼자 **장 제목의 「1:0.3」까지 사라졌음**. `SLOPE_TYPE_IDS` 로 갈라 되살림. 화면 실측 — 표준도 1장에 「그림 없음 — 큰돌쌓기는 규격이 직경이라 …」 한 줄이 표 위에 뜸. 시험 다섯 추가, 전체 1225 통과·실패 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
82 lines
3.1 KiB
Python
82 lines
3.1 KiB
Python
"""표준도 — 그림이 **안 서는 까닭을 화면에 드러낸다** (2026-09-09 사용자 지시).
|
|
|
|
빈 자리를 그냥 두면 사용자가 「고장인가」로 읽는다. 장마다 **왜 그림이 없는지와 무엇을
|
|
받아야 서는지**를 표 위에 한 줄 적는다.
|
|
|
|
⚠ **큰돌쌓기를 그림 대상에서 뺐다** — 그림은 두께를 **뒷길이**에서 내는데 큰돌쌓기는 규격이
|
|
**직경**이라 영영 못 그렸다(품셈 13-6 직경 ↔ 13-4 뒷길이). 식은 만들지 않는다 —
|
|
「직경에서 두께를 내는 법」은 도메인 판단이라 사용자 몫이다.
|
|
⚠ 그림 대상과 **기울기 판정 대상은 다른 목록**이다 — 한 벌로 묶었더니 큰돌쌓기를 그림에서
|
|
뺄 때 **장 제목의 「1:0.3」까지 사라졌다**(화면 실측에서 잡음).
|
|
"""
|
|
|
|
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 B07_DesignDetail.B07_DesignDetail_Engine_Cad_StandardFigure import ( # noqa: E402
|
|
FIGURE_TYPE_IDS,
|
|
SLOPE_TYPE_IDS,
|
|
figure_reason,
|
|
)
|
|
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_StandardSheet import ( # noqa: E402
|
|
build_standard_drawing,
|
|
)
|
|
from B07_DesignDetail.B07_DesignDetail_Engine_Standard_Sheet import sheet_title # noqa: E402
|
|
|
|
|
|
def _sheet(type_id: str, **options) -> dict:
|
|
return {
|
|
"key": type_id,
|
|
"title": type_id,
|
|
"type_id": type_id,
|
|
"height_m": 2.5,
|
|
"options": {"height_m": 2.5, **options},
|
|
"rows": [{"name": "콘크리트", "unit": "㎥", "amount": 1.0, "basis": "시험"}],
|
|
"member_count": 1,
|
|
"unit_label": "m당",
|
|
}
|
|
|
|
|
|
def test_뒷길이가_없으면_무엇을_고르면_되는지_적는다() -> None:
|
|
reason = figure_reason(_sheet("masonry_wet"))
|
|
assert reason is not None and "뒷길이" in reason and "섭니다" in reason
|
|
|
|
|
|
def test_뒷길이가_있으면_까닭이_없다() -> None:
|
|
assert figure_reason(_sheet("masonry_dry", back_len_cm=35)) is None
|
|
|
|
|
|
def test_큰돌쌓기는_그림_대상에서_빠지고_까닭이_적힌다() -> None:
|
|
assert "boulder_masonry" not in FIGURE_TYPE_IDS
|
|
reason = figure_reason(_sheet("boulder_masonry", stone_cm="60~80"))
|
|
assert reason is not None and "직경" in reason
|
|
|
|
|
|
def test_기울기_판정은_큰돌쌓기에도_남는다() -> None:
|
|
"""그림 대상 목록으로 판정하면 장 제목에서 「1:0.3」이 사라진다 — 목록을 갈라 둔 자리."""
|
|
assert "boulder_masonry" in SLOPE_TYPE_IDS
|
|
title = sheet_title(
|
|
{"name": "큰돌쌓기", "type_id": "boulder_masonry", "height_m": 2.5, "options": {}}
|
|
)
|
|
assert "1:0.3" in title
|
|
|
|
|
|
def test_까닭이_도면에_한_줄로_실린다() -> None:
|
|
drawing = build_standard_drawing(
|
|
"standard_sheet_1",
|
|
"표준도 1장",
|
|
{"sheets": [_sheet("retaining_wall")], "structure_count": 1},
|
|
)
|
|
texts = [
|
|
(entity.get("shapeData") or {}).get("label", "")
|
|
for entity in drawing["entities"]
|
|
if entity.get("type") == "Text"
|
|
]
|
|
assert any("그림 없음" in text for text in texts), texts
|