feat(b07): 안 연 측점 횡단배수 미리 넣음 — 파이썬 짝 (260-4)
- 새 B07_DesignDetail_Engine_Cad_CulvertNote = TS culvertNoteEntities · stationNoLabel 짝(두 파일 머리 표시) - 횡단 장 만들 때 CAD 칸 없음 · 옛 글 없음 · 배수관 주인 측점 = 정본 pipe_points 로 미리 넣음 칸을 얹은 사본 - 지운 칸(빈 엔티티) · 옛 글 · 설계 없음 · 이웃 측점 = 그대로 - 시험 test_260_note_cad 거울 9쌍(같은 입력 → 같은 엔티티) · 정본 읽기 · B07 그림 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TNMXVCZXMpHpVvqmFkeChL
This commit is contained in:
@@ -7,6 +7,9 @@
|
||||
* (`_Engine_Cad_Table.cross_note_cad_entities`).
|
||||
* 처음 열 때 칸이 없으면 — 옛 글(`structure_note`)이 있으면 줄마다 Text 로 옮김 · 없고 횡단배수
|
||||
* 주인 측점이면 관 · 관보호공 · 관유출부보강 글을 미리 넣음 · 그 밖 = 빈 도면.
|
||||
* ⚠ 짝(①) = `B07_DesignDetail/B07_DesignDetail_Engine_Cad_CulvertNote.py` — `culvertNoteEntities` ·
|
||||
* `stationNoLabel` 와 같은 입력 → 같은 엔티티(id 만 다름) · 모달을 안 연 측점은 B07 이 그것으로 그림 ·
|
||||
* 거울 시험 `test_260_note_cad.py`.
|
||||
* 좌표 = 도면 mm(B07 표와 같은 자 · 글 2.0 · 줄 3.0) · 칸 왼쪽 위 = (0, 0) · 아래로 음수.
|
||||
* ========================================================================== */
|
||||
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
"""B07 횡단도 표 위 CAD 칸 — 횡단배수 미리 넣음(260-4 · 요구 162-21).
|
||||
|
||||
⚠ 짝(①) = `B06_Section/B06_Section_UI_Cross_Detail_Cad.ts` `culvertNoteEntities` ·
|
||||
`stationNoLabel` — 같은 입력 → 같은 엔티티(id 만 다름) · 거울 시험 `test_260_note_cad.py`.
|
||||
B06 [상세] 모달을 한 번도 안 연 측점(칸 = 없음)에 B07 이 같은 그림을 놓음 · 사용자가 지운 칸
|
||||
(빈 엔티티)은 덮지 않음 · 옛 글(`structure_note`)이 있으면 옛 글이 먼저
|
||||
(모달이 처음 열 때 옮기는 차례와 같음).
|
||||
좌표 = 도면 mm(글 2.0 · 줄 3.0) · 칸 왼쪽 위 = (0, 0) · 아래로 음수.
|
||||
"""
|
||||
|
||||
import json
|
||||
import math
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from B06_Section.B06_Section_Engine_Culvert import _culvert_set, pipe_points_file
|
||||
from common_util.common_util_drainage_pipes import PIPE_FACILITY_PIPE, parse_pipe_points
|
||||
|
||||
# TS `PIPE_MATCH_M`(`design_selection`) — 관 자리와 측점이 같은 자리로 보는 폭
|
||||
PIPE_MATCH_M = 0.51
|
||||
_LAYER_ID = "기본"
|
||||
_FONT = 2.0
|
||||
_LINE = 3.0
|
||||
_COLOR = "#ff7f7f"
|
||||
_BASIN_FORMS = {"I": "I형", "L": "L형", "U": "ㄷ형"}
|
||||
|
||||
|
||||
def _js_round(value: float) -> int:
|
||||
"""JS `Math.round` — .5 는 위로."""
|
||||
return math.floor(value + 0.5)
|
||||
|
||||
|
||||
def _one(value: Any) -> str:
|
||||
ok = isinstance(value, (int, float)) and not isinstance(value, bool) and math.isfinite(value)
|
||||
return f"{value:.1f}" if ok else ""
|
||||
|
||||
|
||||
def _metres(value: Any) -> str:
|
||||
return f"{_one(value)}m" if _one(value) else ""
|
||||
|
||||
|
||||
def _trim(value: float) -> str:
|
||||
rounded = _js_round(value * 100) / 100
|
||||
return str(int(rounded)) if rounded == int(rounded) else str(rounded)
|
||||
|
||||
|
||||
def _bond(form: Any) -> str:
|
||||
"""돌쌓기(찰) · 찰붙임 → 찰 · (메) · 메붙임 → 메 · 그 밖 = 그대로."""
|
||||
text = str(form) if form is not None else ""
|
||||
return "찰" if "찰" in text else "메" if "메" in text else text
|
||||
|
||||
|
||||
def _side_line(side: Any, title: str) -> str | None:
|
||||
if not isinstance(side, dict) or not side.get("structure"):
|
||||
return None
|
||||
basin = side["structure"] == "집수정"
|
||||
form = (
|
||||
_BASIN_FORMS.get(side.get("basin_form") or "", "")
|
||||
if basin
|
||||
else _bond(side.get("revet_form"))
|
||||
)
|
||||
height = side.get("basin_height_m" if basin else "revet_height_m")
|
||||
length = side.get("basin_length_m" if basin else "revet_length_m")
|
||||
spec = ",".join(part for part in (form, f"H={_one(height)}") if part)
|
||||
return f"관보호공({title}) {side['structure']}({spec}) L={_metres(length)}"
|
||||
|
||||
|
||||
def _area(value: Any) -> float:
|
||||
"""JS `Number()` 꼴 — 빈 글 = 0 · 못 읽음 = nan."""
|
||||
if value is None:
|
||||
return math.nan
|
||||
if isinstance(value, str) and not value.strip():
|
||||
return 0.0
|
||||
try:
|
||||
return float(value)
|
||||
except (TypeError, ValueError):
|
||||
return math.nan
|
||||
|
||||
|
||||
def _chute_line(options: dict[str, Any], fallback: str | None) -> str | None:
|
||||
picked = sorted(
|
||||
int(hit.group(1))
|
||||
for key, value in options.items()
|
||||
if (hit := re.match(r"^chute_add_(\d+)_structure$", key))
|
||||
and str(value if value is not None else "").strip()
|
||||
)
|
||||
head = f"chute_add_{picked[0]}_" if picked else None
|
||||
structure = str(options[f"{head}structure"]).strip() if head else fallback
|
||||
if not structure:
|
||||
return None
|
||||
bond_raw = options.get(f"{head}bond") if head else None
|
||||
bond = _bond(bond_raw if bond_raw is not None else "") if head else ""
|
||||
area = _area(options.get(f"{head}area")) if head else math.nan
|
||||
spec = ",".join(part for part in (structure, bond) if part)
|
||||
return f"관유출부보강({spec}) {_trim(area) if area > 0 else ''}m2"
|
||||
|
||||
|
||||
def station_no_label(chainage_m: float, interval_m: float) -> str:
|
||||
"""측점 이름(대문자 NO · 거리 정수) — TS `stationNoLabel` 짝."""
|
||||
safe = interval_m if interval_m > 0 else 1.0
|
||||
number = math.floor((chainage_m + 1e-6) / safe)
|
||||
rest = chainage_m - number * safe
|
||||
if rest >= safe - 0.05:
|
||||
number += 1
|
||||
rest = 0.0
|
||||
return f"NO.{number}" if abs(rest) < 0.05 else f"NO.{number}+{_js_round(rest)}"
|
||||
|
||||
|
||||
def _shape(index: int, kind: str, shape_data: dict[str, Any]) -> dict[str, Any]:
|
||||
return {
|
||||
"id": f"culvert-note:{index}",
|
||||
"type": kind,
|
||||
"lineColor": _COLOR,
|
||||
"lineWidth": 1,
|
||||
"layerId": _LAYER_ID,
|
||||
"shapeData": shape_data,
|
||||
}
|
||||
|
||||
|
||||
def _text(index: int, label: str, x: float, y: float, align: str = "left") -> dict[str, Any]:
|
||||
return _shape(
|
||||
index,
|
||||
"Text",
|
||||
{
|
||||
"label": label,
|
||||
"basePoint": {"x": x, "y": y},
|
||||
"options": {
|
||||
"textDirection": {"x": 1, "y": 0},
|
||||
"textAlign": align,
|
||||
"textColor": _COLOR,
|
||||
"fontSize": _FONT,
|
||||
"fontFamily": "sans-serif",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def culvert_note_entities(
|
||||
chainage_m: float,
|
||||
culvert: dict[str, Any] | None,
|
||||
design: dict[str, Any] | None,
|
||||
station: str,
|
||||
options: dict[str, Any] | None = None,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""횡단배수 미리 넣음 — 이 측점에 놓인(주인) 배수관만 · 상자형 · 숨은 관 · 이웃 = 빈 목록.
|
||||
|
||||
`culvert` = 측점에 얹힌 세트(`attach_culvert_sets` 꼴) · `options` = 그 관의 `pipe_points` 옵션.
|
||||
"""
|
||||
if not isinstance(culvert, dict) or culvert.get("type") != "pipe":
|
||||
return []
|
||||
if culvert.get("body") or culvert.get("hidden_pipe"):
|
||||
return []
|
||||
owner = culvert.get("chainage_m")
|
||||
if abs((owner if isinstance(owner, (int, float)) else chainage_m) - chainage_m) >= PIPE_MATCH_M:
|
||||
return []
|
||||
cx, cy, radius = 6.5, -9.0, 6.5
|
||||
length = design.get("pipe_length_m") if isinstance(design, dict) else None
|
||||
inside = [
|
||||
"배수관",
|
||||
f"Φ{_js_round(float(culvert.get('diameter_m') or 0.0) * 1000)}m/m",
|
||||
f"L={_metres(length)}",
|
||||
]
|
||||
chute = culvert.get("chute") if isinstance(culvert.get("chute"), dict) else {}
|
||||
right = [
|
||||
line
|
||||
for line in (
|
||||
station,
|
||||
_side_line(culvert.get("inlet"), "유입"),
|
||||
_side_line(culvert.get("outlet"), "유출"),
|
||||
_chute_line(options or {}, chute.get("structure")),
|
||||
)
|
||||
if line
|
||||
]
|
||||
entities = [
|
||||
_shape(0, "Circle", {"center": {"x": cx, "y": cy}, "radius": radius}),
|
||||
_shape(
|
||||
1,
|
||||
"Line",
|
||||
{
|
||||
"startPoint": {"x": cx, "y": cy - radius},
|
||||
"endPoint": {"x": cx, "y": cy - radius - _LINE},
|
||||
},
|
||||
),
|
||||
]
|
||||
entities += [
|
||||
_text(2 + i, line, cx, cy + _LINE * (1 - i), "center") for i, line in enumerate(inside)
|
||||
]
|
||||
entities += [_text(5 + i, line, 15, -_LINE * (i + 0.5)) for i, line in enumerate(right)]
|
||||
return entities
|
||||
|
||||
|
||||
def load_pipe_notes(project_root: Path) -> list[tuple[float, dict[str, Any], dict[str, Any]]]:
|
||||
"""정본 `pipe_points.json` 의 배수관 — (관 누가거리, 세트, 옵션) · 관경 안 고름 = 관 없음."""
|
||||
path = pipe_points_file(project_root)
|
||||
try:
|
||||
document = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return []
|
||||
pipes = []
|
||||
for point in parse_pipe_points(document.get("points")):
|
||||
options = dict(point.options or {})
|
||||
if point.facility != PIPE_FACILITY_PIPE or options.get("pipe_diameter_mm") in (None, ""):
|
||||
continue
|
||||
spec = {**_culvert_set(options), "chainage_m": float(point.chainage_m)}
|
||||
pipes.append((float(point.chainage_m), spec, options))
|
||||
return pipes
|
||||
|
||||
|
||||
def with_culvert_note(
|
||||
design: dict[str, Any] | None,
|
||||
chainage_m: float,
|
||||
pipes: list[tuple[float, dict[str, Any], dict[str, Any]]],
|
||||
station: str,
|
||||
) -> dict[str, Any] | None:
|
||||
"""CAD 칸이 없고 옛 글도 없는 주인 측점 — 미리 넣음을 칸으로 얹은 사본 · 그 밖 = 그대로.
|
||||
|
||||
설계가 없는 측점(dict 아님)은 그대로 — 표 · 계획선 셈이 설계 없음으로 가는 길을 안 바꿈.
|
||||
"""
|
||||
if not isinstance(design, dict) or design.get("structure_note_cad") is not None:
|
||||
return design
|
||||
if str(design.get("structure_note") or "").strip():
|
||||
return design
|
||||
near = [pipe for pipe in pipes if abs(pipe[0] - chainage_m) < PIPE_MATCH_M]
|
||||
if not near:
|
||||
return design
|
||||
_at, spec, options = min(near, key=lambda pipe: abs(pipe[0] - chainage_m))
|
||||
entities = culvert_note_entities(chainage_m, spec, design, station, options)
|
||||
if not entities:
|
||||
return design
|
||||
return {**design, "structure_note_cad": {"entities": entities}}
|
||||
@@ -25,6 +25,13 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Cad import (
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Basin import build_watershed_drawing
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Cover import build_cover_drawing
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_CulvertNote import (
|
||||
load_pipe_notes,
|
||||
with_culvert_note,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_CulvertNote import (
|
||||
station_no_label as station_no_label_upper,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Long import (
|
||||
build_longitudinal_drawing,
|
||||
longitudinal_chunks,
|
||||
@@ -383,17 +390,22 @@ def _cross_section_input(
|
||||
chainage: int | float,
|
||||
design: dict[str, Any] | None,
|
||||
overlay: tuple[float, float, float, float] | None = None,
|
||||
pipes: list[tuple[float, dict[str, Any], dict[str, Any]]] | None = None,
|
||||
) -> dict[str, Any] | None:
|
||||
"""한 측점의 장 배치 입력(원본·계획선·수량표·제목)을 만든다."""
|
||||
"""한 측점의 장 배치 입력(원본·계획선·수량표·제목)을 만든다.
|
||||
|
||||
`pipes` = 정본 배수관(`load_pipe_notes`) — CAD 칸 없는 주인 측점에 미리 넣음(260-4)."""
|
||||
path = find_cross_file(longitudinal_path.parent.parent / "cross_sections", chainage)
|
||||
if not path.is_file():
|
||||
return None
|
||||
source = _read_json(path)
|
||||
interval = infer_station_interval(longitudinal.get("stations") or [])
|
||||
at = float(source.get("chainage_m", chainage))
|
||||
return {
|
||||
"chainage": chainage,
|
||||
"source": source,
|
||||
"design": design,
|
||||
# 표 · 계획선은 저장 설계 그대로 · 그림만 미리 넣음 칸을 얹은 사본(260-4)
|
||||
"design": with_culvert_note(design, at, pipes or [], station_no_label_upper(at, interval)),
|
||||
"design_line": _cross_design_line(longitudinal_path, source, design),
|
||||
"quantity_table": _quantity_table(source, design),
|
||||
"title": station_no_label(float(source.get("chainage_m", chainage)), interval),
|
||||
@@ -416,6 +428,7 @@ def _read_cross_sheet(
|
||||
if sheet is None:
|
||||
raise FileNotFoundError("요청한 횡단 장을 찾을 수 없습니다.")
|
||||
longitudinal = _read_json(longitudinal_path)
|
||||
pipes = load_pipe_notes(project_root)
|
||||
sections = [
|
||||
section
|
||||
for section in (
|
||||
@@ -425,6 +438,7 @@ def _read_cross_sheet(
|
||||
chainage,
|
||||
designs.get(chainage),
|
||||
overlays.get(chainage),
|
||||
pipes,
|
||||
)
|
||||
for chainage in sheet["chainages"]
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* PLAN 260 단위검증 헬퍼 — [상세] 표 위 CAD 칸 · 옛 글 옮김 · 횡단배수 미리 넣음.
|
||||
* `B06_Section_UI_Cross_Detail_Cad.ts` 를 그 자리에서 트랜스파일해 Node 로 돌린다(CAD · 세션 · 서버 = 흉내).
|
||||
* 결과는 표준출력에 JSON 한 벌. 확장자 `.cjs` 까닭은 `helper_108_drag_box_hit.cjs` 머리와 같다.
|
||||
* 결과는 표준출력에 JSON 한 벌 · 인자 `mirror` = 표준입력 입력으로 거울 결과(260-4). 확장자 `.cjs` 까닭은 `helper_108_drag_box_hit.cjs` 머리와 같다.
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
@@ -108,4 +108,13 @@ const out = {
|
||||
cad.stationNoLabel(1439.97, 20),
|
||||
],
|
||||
};
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
// 거울(260-4) — 시험이 표준입력으로 준 같은 입력 [{section, station, options, chainage, interval}]
|
||||
// → TS 엔티티 · 측점 이름(파이썬 짝 `_Engine_Cad_CulvertNote` 와 대조)
|
||||
if (process.argv[2] === "mirror") {
|
||||
const cases = JSON.parse(fs.readFileSync(0, "utf8"));
|
||||
const mirrored = cases.map((item) => ({
|
||||
entities: cad.culvertNoteEntities(item.section, item.station, item.options),
|
||||
station: cad.stationNoLabel(item.chainage, item.interval),
|
||||
}));
|
||||
process.stdout.write(JSON.stringify(mirrored));
|
||||
} else process.stdout.write(JSON.stringify(out));
|
||||
|
||||
@@ -294,3 +294,160 @@ def test_CAD_칸이_없으면_옛_글_줄_그대로():
|
||||
noted = _draw({"structure_note": "L형 측구\n집수정 보강"})
|
||||
labels = [e["shapeData"]["label"] for e in noted["entities"] if e["type"] == "Text"]
|
||||
assert labels == ["L형 측구", "집수정 보강"]
|
||||
|
||||
|
||||
# ── 260-4 안 연 측점 = B07 이 파이썬 짝으로 넣음 ─────────────────────────
|
||||
|
||||
from B06_Section.B06_Section_Engine_Culvert import _culvert_set, pipe_points_file # noqa: E402
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_CulvertNote import ( # noqa: E402
|
||||
culvert_note_entities,
|
||||
load_pipe_notes,
|
||||
station_no_label,
|
||||
with_culvert_note,
|
||||
)
|
||||
|
||||
_OPTIONS = {
|
||||
"pipe_diameter_mm": 1200,
|
||||
"inlet_type": "기슭막이",
|
||||
"inlet_revet_form": "돌쌓기(찰)",
|
||||
"inlet_revet_height_m": 2,
|
||||
"inlet_revet_length_m": 10,
|
||||
"outlet_type": "기슭막이",
|
||||
"outlet_revet_form": "돌쌓기(메)",
|
||||
"outlet_revet_height_m": 2,
|
||||
"outlet_revet_length_m": 10,
|
||||
"chute_add_1_structure": "돌붙임",
|
||||
"chute_add_1_bond": "찰붙임",
|
||||
"chute_add_1_area": 10,
|
||||
}
|
||||
_NO_CHUTE = {k: v for k, v in _OPTIONS.items() if not k.startswith("chute")}
|
||||
|
||||
|
||||
def _case(options: dict, pipe_at: float, chainage: float, design: dict | None, **spec) -> dict:
|
||||
culvert = {**_culvert_set(options), "chainage_m": pipe_at, **spec}
|
||||
return {
|
||||
"section": {"chainage_m": chainage, "culvert": culvert, "design": design},
|
||||
"station": station_no_label(chainage, 20.0),
|
||||
"options": options,
|
||||
"chainage": chainage,
|
||||
"interval": 20.0,
|
||||
}
|
||||
|
||||
|
||||
_MIRROR_CASES = [
|
||||
_case(_OPTIONS, 1433.0, 1433.0, {"pipe_length_m": 22}),
|
||||
_case(_NO_CHUTE, 1433.0, 1433.0, {}),
|
||||
_case(
|
||||
{
|
||||
**_NO_CHUTE,
|
||||
"inlet_type": "집수정",
|
||||
"inlet_structure": "L",
|
||||
"inlet_basin_height_m": 1.7,
|
||||
"inlet_basin_length_m": 2,
|
||||
},
|
||||
1433.0,
|
||||
1433.0,
|
||||
{"pipe_length_m": 9.5},
|
||||
),
|
||||
_case({**_NO_CHUTE, "chute_add_2_structure": "도수로", "chute_add_2_area": ""}, 80, 80, None),
|
||||
_case({**_OPTIONS, "pipe_diameter_mm": 800, "chute_add_1_area": 12.345}, 12.5, 12.5, {}),
|
||||
_case({**_OPTIONS, "inlet_revet_form": "콘크리트"}, 440.241, 440.0, {"pipe_length_m": 7}),
|
||||
_case(_OPTIONS, 1433.0, 1440.0, {"pipe_length_m": 22}),
|
||||
_case(_OPTIONS, 1433.0, 1433.0, {}, body="ford"),
|
||||
_case(_OPTIONS, 1433.0, 1433.0, {}, hidden_pipe=True),
|
||||
]
|
||||
|
||||
|
||||
def _without_id(entities: list[dict]) -> list[dict]:
|
||||
return [{k: v for k, v in entity.items() if k != "id"} for entity in entities]
|
||||
|
||||
|
||||
def test_거울_TS_와_파이썬_짝은_같은_입력에_같은_엔티티():
|
||||
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||||
["node", str(HERE / "helper_260_note_cad.cjs"), "mirror"],
|
||||
input=json.dumps(_MIRROR_CASES, ensure_ascii=False),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
timeout=60,
|
||||
)
|
||||
assert proc.returncode == 0, proc.stderr
|
||||
mirrored = json.loads(proc.stdout)
|
||||
assert len(mirrored) == len(_MIRROR_CASES)
|
||||
for case, ts in zip(_MIRROR_CASES, mirrored, strict=True):
|
||||
section = case["section"]
|
||||
py = culvert_note_entities(
|
||||
section["chainage_m"],
|
||||
section["culvert"],
|
||||
section["design"],
|
||||
case["station"],
|
||||
case["options"],
|
||||
)
|
||||
assert _without_id(py) == _without_id(ts["entities"]), case["station"]
|
||||
assert station_no_label(case["chainage"], case["interval"]) == ts["station"]
|
||||
# 대조가 빈 목록끼리만이 아님 — 주인 측점 여섯은 그림이 있음 · 이웃 · 세월교 · 숨은 관 = 빈값
|
||||
assert [bool(item["entities"]) for item in mirrored] == [True] * 6 + [False] * 3
|
||||
labels = [e["shapeData"].get("label") for e in mirrored[4]["entities"]]
|
||||
assert "Φ800m/m" in labels and "관유출부보강(돌붙임,찰) 12.35m2" in labels
|
||||
|
||||
|
||||
def _write_pipes(root: Path, points: list[dict]) -> None:
|
||||
path = pipe_points_file(root)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps({"points": points}, ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
|
||||
def test_정본_배수관만_읽음(tmp_path):
|
||||
_write_pipes(
|
||||
tmp_path,
|
||||
[
|
||||
{"chainage_m": 1433.0, "lonlat": [0, 0], "facility": "pipe", "options": _OPTIONS},
|
||||
{"chainage_m": 80.0, "lonlat": [0, 0], "facility": "pipe", "options": {}},
|
||||
{"chainage_m": 90.0, "lonlat": [0, 0], "facility": "ford_bridge", "options": {}},
|
||||
],
|
||||
)
|
||||
pipes = load_pipe_notes(tmp_path)
|
||||
assert [pipe[0] for pipe in pipes] == [1433.0] # 관경 안 고름 · 세월교 = 빼
|
||||
assert pipes[0][1]["chainage_m"] == 1433.0 and pipes[0][2] == _OPTIONS
|
||||
assert load_pipe_notes(tmp_path / "없음") == []
|
||||
|
||||
|
||||
def test_칸_없음_만_미리_넣음_지운_칸_옛_글_설계없음_이웃은_그대로(tmp_path):
|
||||
_write_pipes(
|
||||
tmp_path,
|
||||
[{"chainage_m": 1433.0, "lonlat": [0, 0], "facility": "pipe", "options": _OPTIONS}],
|
||||
)
|
||||
pipes = load_pipe_notes(tmp_path)
|
||||
design = {"pipe_length_m": 22, "paved": False}
|
||||
seeded = with_culvert_note(design, 1433.0, pipes, "NO.71+13")
|
||||
assert seeded is not design and "structure_note_cad" not in design # 저장 설계는 안 바뀜
|
||||
labels = [e["shapeData"].get("label") for e in seeded["structure_note_cad"]["entities"]]
|
||||
assert labels[2:] == [
|
||||
"배수관",
|
||||
"Φ1200m/m",
|
||||
"L=22.0m",
|
||||
"NO.71+13",
|
||||
"관보호공(유입) 기슭막이(찰,H=2.0) L=10.0m",
|
||||
"관보호공(유출) 기슭막이(메,H=2.0) L=10.0m",
|
||||
"관유출부보강(돌붙임,찰) 10m2",
|
||||
]
|
||||
cleared = {**design, "structure_note_cad": {"entities": []}}
|
||||
assert with_culvert_note(cleared, 1433.0, pipes, "x") is cleared
|
||||
old = {**design, "structure_note": "옛 글"}
|
||||
assert with_culvert_note(old, 1433.0, pipes, "x") is old
|
||||
assert with_culvert_note(None, 1433.0, pipes, "x") is None
|
||||
assert with_culvert_note(design, 1440.0, pipes, "x") is design
|
||||
|
||||
|
||||
def test_B07_은_안_연_측점에_미리_넣음을_표_위에_그림(tmp_path):
|
||||
_write_pipes(
|
||||
tmp_path,
|
||||
[{"chainage_m": 20.2, "lonlat": [0, 0], "facility": "pipe", "options": _OPTIONS}],
|
||||
)
|
||||
design = with_culvert_note({"pipe_length_m": 22}, 20.0, load_pipe_notes(tmp_path), "NO.1")
|
||||
drawn = _draw(design)
|
||||
labels = [e["shapeData"]["label"] for e in drawn["entities"] if e["type"] == "Text"]
|
||||
assert "NO.1" in labels and "관유출부보강(돌붙임,찰) 10m2" in labels
|
||||
plain_top = _table(_draw({"pipe_length_m": 22}))["shapeData"]["origin"]["y"]
|
||||
drop = plain_top - _table(drawn)["shapeData"]["origin"]["y"]
|
||||
assert drop == pytest.approx(cross_note_block_height(design)) and drop > 15
|
||||
|
||||
Reference in New Issue
Block a user