- 장 나눔 = 추가 · 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>
137 lines
5.5 KiB
Python
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),
|
|
],
|
|
}
|