From bbfe7ce27ed6d382cfff5a1e01a7627fae08bf1a Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 17 Oct 2026 15:20:34 +0900 Subject: [PATCH] =?UTF-8?q?fix(377=20B07=20=EC=A0=84=EA=B0=9C=EB=8F=84):?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=EA=B2=80=EC=A6=9D=20=EC=86=90=EC=A7=88?= =?UTF-8?q?=20=E2=80=94=20=EB=8F=8C=20=EB=AC=B4=EB=8A=AC=EA=B0=80=20?= =?UTF-8?q?=EB=B0=95=EC=8A=A4=20=EC=99=BC=EC=AA=BD=EC=9D=84=20=EB=84=98?= =?UTF-8?q?=EB=8D=98=20=ED=9D=94=EB=93=A4=EB=A6=BC=20=ED=95=9C=EB=8F=84=20?= =?UTF-8?q?=C2=B7=20=EC=BD=98=ED=81=AC=EB=A6=AC=ED=8A=B8=20=C2=B7=20?= =?UTF-8?q?=EC=87=84=EC=84=9D=20=EC=A0=90=20=ED=81=AC=EA=B8=B0(=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=EB=B0=B0=EC=9C=A8=EC=97=90=EC=84=9C=20=EC=95=88=20?= =?UTF-8?q?=EB=B3=B4=EC=9E=84)=20=C2=B7=20=ED=91=9C=20=ED=81=AC=EA=B2=8C(?= =?UTF-8?q?=EA=B7=B8=EB=A6=BC=20241=20=EA=BC=B4)=20=C2=B7=20=EB=86=92?= =?UTF-8?q?=EC=9D=B4=20=C2=B7=20=ED=8F=AD=20=EC=86=8C=EC=88=98=20=EB=91=98?= =?UTF-8?q?=EC=A7=B8=20=EC=9E=90=EB=A6=AC=20=ED=91=9C=EA=B8=B0(=EB=A9=B4?= =?UTF-8?q?=EC=A0=81=EC=9D=B4=20=EC=93=B4=20=EA=B0=92=20=EA=B7=B8=EB=8C=80?= =?UTF-8?q?=EB=A1=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 시험: 무늬는 박스 안(형태 다섯 · 견본 서른) · 확정본 kind development · 3.55 폭 표기 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Se7ytqbohmBQnfYpwYFnYf --- ...esignDetail_Engine_Cad_Development_Draw.py | 28 +++++++++---- resources/tester/test_241_development.py | 42 +++++++++++++++++++ 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/B07_DesignDetail/B07_DesignDetail_Engine_Cad_Development_Draw.py b/B07_DesignDetail/B07_DesignDetail_Engine_Cad_Development_Draw.py index 4b0984400..e1000df42 100644 --- a/B07_DesignDetail/B07_DesignDetail_Engine_Cad_Development_Draw.py +++ b/B07_DesignDetail/B07_DesignDetail_Engine_Cad_Development_Draw.py @@ -51,9 +51,10 @@ _BELOW = 9.0 # 박스 아래 L= 자리 _GAP = 16.0 # 박스 사이(오른 끝 기울인 글 자리) _MIN_H, _MAX_H = 12.0, 40.0 # 가장 높은 박스 세로 mm _EMPTY_H = 0.6 # 높이 빈칸 박스 = 가장 높은 박스의 몫 -_FONT, _TITLE_FONT = 2.2, 7.0 -_ROW_H = 6.0 -_COLUMNS = (44.0, 18.0, 18.0, 22.0) +_FONT, _TITLE_FONT = 2.5, 7.0 +_TABLE_FONT = 3.2 # 표는 그림 241 처럼 크게(작도 영역 폭의 약 1/4) +_ROW_H = 9.0 +_COLUMNS = (80.0, 32.0, 32.0, 40.0) _SLANT = (0.5, math.sqrt(3) / 2) # 60° @@ -61,6 +62,14 @@ def _fmt(value: float | None) -> str: return "" if value is None else f"{value:,.1f}" +def _size(value: float | None) -> str: + """높이 · 폭 — 소수 둘째 자리까지(3.55 · 3.5 · 2.0) · 면적이 쓴 값 그대로 보이게.""" + if value is None: + return "" + text = f"{value:.2f}".rstrip("0") + return f"{text}0" if text.endswith(".") else text + + # ── 무늬 ──────────────────────────────────────────────── @@ -89,7 +98,8 @@ def _stones(seed, rng, box, rows, cap=500): while y <= y1 - 0.3 - r + 1e-9 and len(out) < cap: x = x0 + 0.3 + r + (step / 2 if row % 2 else 0.0) while x <= x1 - 0.3 - r + 1e-9 and len(out) < cap: - jx = min(rng.uniform(-0.15, 0.15) * step, x1 - 0.3 - r - x, x - x0 - 0.3 - r) + room = (x - x0 - 0.3 - r, x1 - 0.3 - r - x) # 왼 · 오 여유 — 돌이 박스를 안 넘게 + jx = max(-room[0], min(rng.uniform(-0.15, 0.15) * step, room[1])) line = polyline_entity( seed, _stone(rng, x + jx, y, r), FILL_LAYER_ID, FILL_COLOR, f":s{len(out)}" ) @@ -170,9 +180,9 @@ def fill_entities(seed: str, form: str, group: str, box: tuple[float, float, flo """형태 → 무늬(찰 작은 돌 · 메 큰 돌 · 콘크리트 · 쇄석 점 · 돌망태 격자+돌 · 통나무 원).""" rng = random.Random(seed) if group == "gravel": - return _dots(seed, rng, box, 0.12, 0.35, 900) + return _dots(seed, rng, box, 0.025, 0.9, 900) if group == "concrete" or form == "콘크리트": - return _dots(seed, rng, box, 0.2, 0.15, 1200) + return _dots(seed, rng, box, 0.045, 0.6, 1200) if form == "돌쌓기(찰)": return _stones(seed, rng, box, 5) if form == "돌쌓기(메)": @@ -254,7 +264,7 @@ def _box_entities(drawing_id, index, row, box, label, station): ) ] out += fill_entities(f"{seed}:{row['key']}", row["form"], row["group"], (x0, y0, x1, y1)) - height = "미입력" if row["height_m"] is None else f"{row['height_m']:.1f}" + height = "미입력" if row["height_m"] is None else _size(row["height_m"]) for end, x, chainage in (("s", x0, row["start_m"]), ("e", x1, row["end_m"])): out.append( _line_entity( @@ -318,7 +328,7 @@ def _table(drawing_id, lines, label, origin): [ cell(item["station"]), cell(_fmt(item["distance"]), "right", TABLE_VALUE_COLOR), - cell(_fmt(item["height"]), "right", TABLE_VALUE_COLOR), + cell(_size(item["height"]), "right", TABLE_VALUE_COLOR), cell(_fmt(item["area"]), "right", TABLE_VALUE_COLOR), ] ) @@ -339,7 +349,7 @@ def _table(drawing_id, lines, label, origin): cells, TABLE_LAYER_ID, TABLE_COLOR, - _FONT, + _TABLE_FONT, TABLE_LABEL_COLOR, ) diff --git a/resources/tester/test_241_development.py b/resources/tester/test_241_development.py index 19a568b25..61f11ffaa 100644 --- a/resources/tester/test_241_development.py +++ b/resources/tester/test_241_development.py @@ -16,6 +16,7 @@ from B07_DesignDetail import B07_DesignDetail_Engine_Cad_Development as dev from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Development_Draw import ( FILL_LAYER_ID, build_development_drawing, + fill_entities, ) from B07_DesignDetail.B07_DesignDetail_Engine_Frame_Export import drawing_to_dxf @@ -197,6 +198,13 @@ def test_묶음_거리_높이(root): pave = _sheet(sheets, "development_concrete") assert pave["title"] == "콘크리트포장 전개도" assert [r["height_m"] for r in pave["rows"]] == [3.5, 4.5] # 빈 폭 = (4 + 5 + 4.5) / 3 + # 표 · 끝 글 = 면적이 쓴 폭 그대로(3.55 를 3.5 로 줄여 보이지 않음) + odd = {**pave, "rows": [{**pave["rows"][0], "height_m": 3.55}]} + drawing = build_development_drawing(odd["id"], odd, 20.0) + cells = next(e for e in drawing["entities"] if e["type"] == "Table")["shapeData"]["cells"] + assert [c["text"] for c in cells[2]] == ["No.22+00~No.26+05", "85.0", "3.55", "301.8"] + labels = [e["shapeData"]["label"] for e in drawing["entities"] if e["type"] == "Text"] + assert "B=3.55" in labels def test_설계_없으면_단수_안_거름_목록(root): @@ -239,6 +247,24 @@ def test_높이_빈칸_박스와_미입력_글_무늬_DXF(root): assert text.count("LINE\r\n") > 50 # 돌 무늬 = 선(DXF 에도 남음) +@pytest.mark.parametrize( + "form", ["돌쌓기(찰)", "돌쌓기(메)", "돌망태", "통나무·목재틀", "콘크리트"] +) +def test_무늬는_박스_안(form): + for seed in range(30): + width, height = 10 + seed * 9.7, 8 + seed % 7 * 5.0 + for entity in fill_entities(f"s{seed}", form, "soil", (0.0, 0.0, width, height)): + for one in entity.get("children") or [entity]: + shape = one["shapeData"] + if "center" in shape: + r, (x, y) = shape["radius"], (shape["center"]["x"], shape["center"]["y"]) + points = [(x - r, y - r), (x + r, y + r)] + else: + points = [(p["x"], p["y"]) for p in (shape["startPoint"], shape["endPoint"])] + for x, y in points: + assert -1e-6 <= x <= width + 1e-6 and -1e-6 <= y <= height + 1e-6, (seed, x, y) + + def test_목록_전_장_없으면_빈_장(root, tmp_path): long_path = tmp_path / "long.json" long_path.write_text(json.dumps({"stations": []}), encoding="utf-8") @@ -248,3 +274,19 @@ def test_목록_전_장_없으면_빈_장(root, tmp_path): assert kind == "development" and label == "관보호공 돌쌓기(메) 전개도" and not confirmed with pytest.raises(ValueError): dev.read_development(root, long_path, "development_x-1", DESIGNS) + + +def test_확정본은_전개도_kind_로_읽음(root, tmp_path): + from B07_DesignDetail.B07_DesignDetail_Engine_Cad import DRAWING_FORMAT + from B07_DesignDetail.B07_DesignDetail_Router_Support import _design_root, _read_drawing + + stage = _design_root(root) + (stage / "drawings").mkdir(parents=True) + saved = {"format": DRAWING_FORMAT, "entities": [], "layers": []} + (stage / "drawings" / "development_pipe0.json").write_text(json.dumps(saved), "utf-8") + manifest = {"drawings": {"development_pipe0": {"confirmed": True, "label": "관보호공"}}} + (stage / "manifest.json").write_text(json.dumps(manifest, ensure_ascii=False), "utf-8") + kind, label, drawing, confirmed, table = _read_drawing( + root, tmp_path / "long.json", "development_pipe0" + ) + assert (kind, label, confirmed, table) == ("development", "관보호공", True, None)