feat(B07): 계획평면도 3종 — 수치등고선 배경 위 노선·측점·구조물
빈 도각이던 계획평면도(지형·노선배치도·배치도)를 실제 도면으로 만듦. - 배경 공용화: map_background() 한 창구로 도엽 등고선·세류선 읽기·좌표 환산· 도곽 절취를 모음. 유역도와 계획평면도가 같은 것을 부르고, 환산 결과는 파일 mtime 을 키로 캐시(_metric_lines_cached). - 축척 1/1,200 고정(DRAWING_SCALE_PLAN) — 지식DB 「설계제원_총괄」 측량·도면 기준. 횡단면도와 같은 원칙으로 줄이지 않고 안 들어가면 장을 나눔(plan_chunks, 종단 측점 기준·경계 측점 1개 중복). - 세 장이 같은 배경·같은 도곽 배치를 쓰고 주제만 다름. 측점 눈금은 종단 측점 좌표로 찍고, 구조물은 pipe_points.json 정본을 읽어 마름모+이름으로 표기. - 도면 목록·단건 조회에 kind="plan" 추가. 화면 목록은 id 접두어로 묶어 장이 나뉘어도 한 그룹으로 보임. 검증(용화_LAS): 콘텐츠 734.3x489.2 mm ≤ A1 작도영역 739.2x499.2, 노선 실거리 630.1x214.2 m → 종이 525.12x178.46 mm(실측 0.83333 mm/m = 1/1,200 일치), 배경 등고선 180줄이 세 장 동일, 유역도 8.5초 → 계획평면도 1.3초(캐시 적중, 파일 재읽기 없음). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,13 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Long import (
|
||||
longitudinal_chunks,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_MassHaul import build_mass_haul_drawing
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Plan import (
|
||||
PLAN_KINDS,
|
||||
build_plan_drawing,
|
||||
plan_chunks,
|
||||
plan_drawing_id,
|
||||
plan_drawing_label,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import (
|
||||
CROSS_SHEET_ID,
|
||||
build_cross_sheet,
|
||||
@@ -45,6 +52,9 @@ from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
||||
CONTOUR_FILE as CONTOUR_FILE,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
||||
PLAN_ID as PLAN_ID,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
||||
STREAM_FILE as STREAM_FILE,
|
||||
)
|
||||
@@ -69,6 +79,12 @@ from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
||||
clip_line_to_box as clip_line_to_box,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
||||
plan_source as plan_source,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
||||
plan_stations as plan_stations,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
||||
watershed_source as watershed_source,
|
||||
)
|
||||
@@ -100,9 +116,6 @@ COVER_ID = "cover"
|
||||
# 아직 내용을 만들지 않은 도면 — 도각만 실어 연다(2026-09-01 사용자 지시).
|
||||
# 화면 순서(DRAWING_GROUPS)와 같은 이름을 쓴다.
|
||||
BLANK_DRAWINGS: tuple[tuple[str, str], ...] = (
|
||||
("blank_plan_terrain", "계획평면도(지형)"),
|
||||
("blank_plan_route", "계획평면도(노선배치도)"),
|
||||
("blank_plan_layout", "계획평면도(배치도)"),
|
||||
("blank_plan_lidar", "계획평면도(라이다)"),
|
||||
("blank_cross_standard", "표준 횡단면도"),
|
||||
("blank_standard", "표준도"),
|
||||
@@ -151,6 +164,19 @@ def _drawing_list(
|
||||
confirmed=bool(manifest_drawings.get(sheet["id"], {}).get("confirmed")),
|
||||
)
|
||||
)
|
||||
# 계획평면도 3종 — 축척 1/1,200 고정이라 노선이 길면 장이 나뉜다(장수는 노선이 정한다).
|
||||
plan_sheets = plan_chunks(plan_stations(longitudinal))
|
||||
for kind, _label, *_rest in PLAN_KINDS:
|
||||
for chunk in plan_sheets:
|
||||
drawing_id = plan_drawing_id(kind, chunk, len(plan_sheets))
|
||||
drawings.append(
|
||||
DesignDrawingItem(
|
||||
id=drawing_id,
|
||||
kind="plan",
|
||||
label=plan_drawing_label(kind, chunk, len(plan_sheets)),
|
||||
confirmed=bool(manifest_drawings.get(drawing_id, {}).get("confirmed")),
|
||||
)
|
||||
)
|
||||
# 노선 전장 1장짜리 도면 — 자료가 없으면 여는 시점에 404로 알린다(목록에는 항상 둔다).
|
||||
for drawing_id, kind, label in (
|
||||
(COVER_ID, "cover", "표지"),
|
||||
@@ -381,6 +407,8 @@ def _read_drawing(
|
||||
if saved.get("format") == DRAWING_FORMAT:
|
||||
if drawing_id in (COVER_ID, MASS_HAUL_ID, WATERSHED_ID):
|
||||
kind = drawing_id # id와 kind가 같은 단장 도면
|
||||
elif PLAN_ID.fullmatch(drawing_id):
|
||||
kind = "plan"
|
||||
else:
|
||||
kind = "longitudinal" if _LONG_ID.fullmatch(drawing_id) else "cross"
|
||||
label = str(manifest_entry.get("label") or drawing_id)
|
||||
@@ -409,6 +437,31 @@ def _read_drawing(
|
||||
None,
|
||||
)
|
||||
|
||||
if PLAN_ID.fullmatch(drawing_id):
|
||||
# stored_design = plan_source()가 모아 준 노선·측점·배경·구조물 좌표(사업지 CRS).
|
||||
if not isinstance(stored_design, dict):
|
||||
raise FileNotFoundError("계획평면도 자료가 없습니다.")
|
||||
longitudinal = _read_json(longitudinal_path)
|
||||
interval = infer_station_interval(longitudinal.get("stations") or [])
|
||||
label = str(stored_design.get("label") or drawing_id)
|
||||
return (
|
||||
"plan",
|
||||
label,
|
||||
build_plan_drawing(
|
||||
str(stored_design.get("kind") or "plan_terrain"),
|
||||
drawing_id,
|
||||
label,
|
||||
stored_design.get("route_xy") or [],
|
||||
stored_design.get("stations") or [],
|
||||
stored_design.get("contours") or [],
|
||||
stored_design.get("streams") or [],
|
||||
stored_design.get("structures") or [],
|
||||
interval,
|
||||
),
|
||||
False,
|
||||
None,
|
||||
)
|
||||
|
||||
if drawing_id == WATERSHED_ID:
|
||||
# stored_design = watershed_source()가 모아 준 노선·유역·배경 좌표(사업지 CRS).
|
||||
if not isinstance(stored_design, dict):
|
||||
|
||||
Reference in New Issue
Block a user