feat(B07): 계획평면도 종류 · 정보 조각 서버 (PLAN 60-1 · 60-2)

- 정보 조각(등고선 · 계류 · 중심선 · 성토사면 외곽선 · 비탈 눈금 · IP · R · 측점 NO · 시종점 · 대피소/사토장 · 라이다 배경)마다 장별 파일(plan_pieces/{장}/{조각}.json)
- 외곽선 = 노견 끝 + 설계선이 지반에 닿는 자리(B06 횡단 설계 결과) · 측점 자리는 횡단 파일 중심 · 좌축
- 종류 = 조각 고르기 목록(plan_kinds/{id}.json) · 기본 넷(지형 · 노선배치도 · 대피소 · 라이다) · 더하기 · 지우기 API
- 대피소 · 사토장 = 구조물 정본 refuge · spoil_bank + 사용자 지정 자리(plan_marks.json)
- 도면 목록 · 단건 조회를 종류 × 장으로 · 옛 plan_* id 그대로 이어짐

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPJGtfXo6GMbcpiboQC4uK
This commit is contained in:
2026-10-06 17:51:40 +09:00
co-authored by Claude Opus 5.5
parent 2fc95c51c9
commit 138e80c79f
8 changed files with 1168 additions and 86 deletions
+7 -14
View File
@@ -39,9 +39,7 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Template import (
from B07_DesignDetail.B07_DesignDetail_Router_Support import (
CROSS_STANDARD_ID,
LANDUSE_ID,
LIDAR_ID,
MASS_HAUL_ID,
PLAN_ID,
WATERSHED_ID,
_cross_sheet_plan,
_drawing_list,
@@ -50,10 +48,9 @@ from B07_DesignDetail.B07_DesignDetail_Router_Support import (
_read_json,
_store_confirmed_drawing,
landuse_source,
lidar_source,
plan_source,
watershed_source,
)
from B07_DesignDetail.B07_DesignDetail_Router_Support_Plan import PLAN_KIND_ID, plan_kind_source
from B07_DesignDetail.B07_DesignDetail_Schema import (
DesignDrawingConfirmRequest,
DesignDrawingConfirmResponse,
@@ -342,13 +339,16 @@ async def get_design_drawing(
if row
else None
)
elif LIDAR_ID.fullmatch(drawing_id):
# 라이다 계획평면도는 확정 DTM 격자로 음영기복 그림을 만들어 넘긴다.
elif PLAN_KIND_ID.fullmatch(drawing_id):
# 계획평면도 — 정보 조각을 서버가 계산 · 파일로 두고 그 종류가 고른 것만 얹는다.
context, reason = await load_drainage_context(project_id)
if context is None:
return JSONResponse(status_code=404, content={"status": "error", "message": reason})
longitudinal = await asyncio.to_thread(_read_json, longitudinal_path)
source_design = await asyncio.to_thread(lidar_source, context, longitudinal, drawing_id)
designs = await _designs_by_chainage(route_id)
source_design = await asyncio.to_thread(
plan_kind_source, context, longitudinal, longitudinal_path, designs, drawing_id
)
elif LANDUSE_ID.fullmatch(drawing_id):
# 용지도도 같은 배경 창구를 쓴다 — 지적·행정 경계만 따로 읽는다.
context, reason = await load_drainage_context(project_id)
@@ -358,13 +358,6 @@ async def get_design_drawing(
source_design = await asyncio.to_thread(
landuse_source, context, longitudinal, drawing_id
)
elif PLAN_ID.fullmatch(drawing_id):
# 계획평면도는 유역도와 **같은 배경 창구**를 쓴다 — 자료 읽기·환산이 캐시된다.
context, reason = await load_drainage_context(project_id)
if context is None:
return JSONResponse(status_code=404, content={"status": "error", "message": reason})
longitudinal = await asyncio.to_thread(_read_json, longitudinal_path)
source_design = await asyncio.to_thread(plan_source, context, longitudinal, drawing_id)
kind, label, drawing, confirmed, quantity_table = await asyncio.to_thread(
_read_drawing,
project_root,