Files
Aislo/B07_DesignDetail/B07_DesignDetail_Engine_Cad_LongSheet.py
T
eomsangdonandClaude Opus 5.5 1398625d2d feat(B07): 종단도 장 = 일반측점 30 간격 600 m · Y축 여유 10 mm · 그림 자리 +50 mm (525-1 · 요구 343-3)
- 장 나눔 = 추가 · MC 측점 안 세고 일반측점 30 간격(20 m 면 600 m) · 경계 측점 나눠 가짐 · 넘치면 줄이는 규칙 그대로
- Y축 · 측점표 머리 = 첫 측점 왼쪽 10 mm
- 그림 = 작도 영역 좌하단에서 오른쪽 50 · 위 50 mm(도각 · 평면 칸 · 넘침 판정이 같은 장 bbox)
- 장 나눔 · 도각을 Engine_Cad_LongSheet.py 로 뗌(Engine_Cad_Long.py 700줄 한도)
- 옛 종단 확정본 풂 = 칸 층 찾기 → 매니페스트 long_sheet_rule(2) 비교 — 521-2 뒤 확정본도 자리가 바뀌어 한 번 더 풂 · 낡은 시험(칸 층 기준) 고침

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 14:25:57 +09:00

137 lines
5.5 KiB
Python

"""B07 종단도 장 — 일반측점 30 간격(600 m) 나눔 · 장 자리(그림 = 작도 영역 좌하단 + 50 mm) · 도각.
추가 · MC 측점은 세지 않고 구간 안이면 함께 그린다(525-1 · 요구 343-3). 그림 본체는
`Engine_Cad_Long._long_content`.
"""
from bisect import bisect_right
from typing import Any
from B07_DesignDetail.B07_DesignDetail_Engine_Cad import (
DESIGN_LAYER_ID,
DRAWING_FORMAT,
FRAME_LAYER_ID,
GROUND_LAYER_ID,
LONG_SPLIT_STATION_COUNT,
LONG_TABLE_LAYER_ID,
_layer,
_stations,
infer_station_interval,
)
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Long import LONG_GRID_LAYER_ID, _long_content
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_LongPlan import (
LONG_PLAN_LAYER_ID,
long_plan_entities,
plan_box_overlaps,
)
from B07_DesignDetail.B07_DesignDetail_Engine_Template import (
drawing_scale,
entities_bbox,
frame_entities,
scale_fields,
usable_area,
)
_SHEET_SHIFT = 50.0 # 그림 = 작도 영역 좌하단에서 오른쪽 · 위로(종이 mm · 525-1)
def _sheet_bbox(
bbox: tuple[float, float, float, float] | None,
) -> tuple[float, float, float, float] | None:
"""그림 bbox 를 좌 · 하로 넓힌 장 기준 — 도각 · 평면 칸 · 넘침 판정이 이 좌하단에 맞춤."""
if bbox is None:
return None
return (bbox[0] - _SHEET_SHIFT, bbox[1] - _SHEET_SHIFT, bbox[2], bbox[3])
def _span(stations: list[dict[str, Any]], index: int, take: int) -> dict[str, float]:
return {
"start_m": float(stations[index]["chainage_m"]),
"end_m": float(stations[index + take - 1]["chainage_m"]),
}
def _fits_sheet(longitudinal: dict[str, Any], span: dict[str, float]) -> bool:
"""이 구간을 고정 축척으로 그렸을 때 A1 작도 영역에 들고 평면 위치도 칸을 안 덮는가."""
content = _long_content(longitudinal, "probe", span)
bbox = _sheet_bbox(entities_bbox(content))
if bbox is None:
return True
usable_w, usable_h = usable_area()
fits = bbox[2] - bbox[0] <= usable_w + 1e-6 and bbox[3] - bbox[1] <= usable_h + 1e-6
return fits and not plan_box_overlaps(longitudinal, content, bbox)
def longitudinal_chunks(longitudinal: dict[str, Any]) -> list[dict[str, Any]]:
"""일반측점 30 간격(20 m 면 600 m) 단위 분할 목록. 각 항목: {id, label, start_m, end_m}.
추가 · MC 측점은 세지 않고 구간 안이면 함께 그린다(525-1 · 요구 343-3).
한 장이면 단일 도면(id="longitudinal", 기존 manifest 호환). 여러 장이면
경계 측점 1개를 중복시켜 도면 간 선이 이어지게 한다(납품 도면 관례).
축척(H 1/1,000 · V 1/200)은 모든 장이 같다 — 작도 영역을 넘으면 측점을 줄여
장을 더 나눌 뿐 줄이지 않는다.
"""
stations = sorted(_stations(longitudinal), key=lambda s: float(s["chainage_m"]))
if not stations:
return [{"id": "longitudinal", "label": "종단도", "start_m": None, "end_m": None}]
chainages = [float(s["chainage_m"]) for s in stations]
length_m = LONG_SPLIT_STATION_COUNT * infer_station_interval(stations)
spans: list[dict[str, float]] = []
index = 0
while True:
take = max(2, bisect_right(chainages, chainages[index] + length_m + 1e-6) - index)
take = min(take, len(stations) - index)
# ponytail: 한 측점씩 줄이며 다시 잰다 — 넘치는 장에서만 돎
while take > 2 and not _fits_sheet(longitudinal, _span(stations, index, take)):
take -= 1
spans.append(_span(stations, index, take))
if index + take >= len(stations):
break
index += take - 1 # 경계 1측점 중복
if len(spans) == 1:
return [{"id": "longitudinal", "label": "종단도", "number": 1, "total": 1, **spans[0]}]
return [
{"id": f"longitudinal_{number}", "label": f"종단도({number})", "number": number, **span}
| {"total": len(spans)}
for number, span in enumerate(spans, start=1)
]
def build_longitudinal_drawing(
longitudinal: dict[str, Any], drawing_id: str, chunk: dict[str, Any]
) -> dict[str, Any]:
"""종단도 청크 하나를 지반선+계획선+그래프 축·격자+측점 테이블로 만든다."""
entities = _long_content(longitudinal, drawing_id, chunk)
scale = drawing_scale("longitudinal")
# A1 도각: 콘텐츠가 이미 종이 mm라 도각도 실치수(1:1)로 두고 위치만 맞춘다.
# 그림 좌하단 = 작도영역 좌하단 + (50, 50) mm — 장마다 같은 자리에서 시작한다.
bbox = _sheet_bbox(entities_bbox(entities))
entities.extend(long_plan_entities(longitudinal, drawing_id, chunk, bbox)) # 521-2
if bbox:
entities.extend(
frame_entities(
drawing_id,
bbox,
fit=False,
bottom_left=True,
fields={
"도면명": "종단면도",
**scale_fields(("H", scale["x"]), ("V", scale["y"])),
},
)
)
return {
"format": DRAWING_FORMAT,
"entities": entities,
"layers": [
_layer(GROUND_LAYER_ID, "원지반", locked=True),
_layer(DESIGN_LAYER_ID, "계획선"),
_layer(LONG_GRID_LAYER_ID, "그래프 격자", locked=True),
_layer(LONG_TABLE_LAYER_ID, "측점표"),
_layer(LONG_PLAN_LAYER_ID, "평면 위치도"),
_layer(FRAME_LAYER_ID, "도각", locked=True),
],
}