feat(B07): 계획평면도(라이다) — 지표면 음영기복 배경 1차 배치

빈 도각이던 라이다 계획평면도에 지표면 탑뷰 그림을 얹음.

- 확정 DTM 격자를 도곽 범위로 잘라 음영기복 PNG 를 만들고 Image 엔티티로 실음
  (북서 315도·고도 45도, 한 변 최대 1,600 px). 점구름 4,900만 점을 그대로
  그리지 않음.
- 어느 지표면을 쓸지는 1단계 확정값을 따름 — DrainageContext 에 surface_params
  를 실어 전달.
- 축척·도곽·장 나눔은 계획평면도와 같음(1/1,200) — 노선이 같은 자리에 섬.
- entities_bbox 가 꼭짓점 배열(points)을 세도록 고침. 세지 않으면 그림이 도곽
  계산에서 통째로 빠짐.

검증(용화_LAS): 콘텐츠 726.1x487.2 mm ≤ A1 작도영역, 그림 범위 안에 노선이
완전히 들어감, 음영기복 준비 0.4초·자료 214 KB. 능선·계곡이 눈으로 구분됨.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-04 19:00:38 +09:00
co-authored by Claude Opus 5
parent d662b0725d
commit 18c174036b
9 changed files with 402 additions and 2 deletions
@@ -58,6 +58,9 @@ class DrainageContext:
crs: str = "EPSG:5186"
route_id: int | None = None
to_lonlat: Callable[[float, float], tuple[float, float]] = lambda x, y: (x, y)
# 1단계에서 확정한 지표면 선택(source_filter·method·smooth). B07 라이다 계획평면도가
# 어느 DTM 격자로 음영기복을 만들지 고르는 데 쓴다(2026-09-04).
surface_params: dict[str, Any] = field(default_factory=dict)
async def load_drainage_context(project_id: UUID) -> tuple[DrainageContext | None, str]:
@@ -112,6 +115,7 @@ async def load_drainage_context(project_id: UUID) -> tuple[DrainageContext | Non
crs=crs,
route_id=int(route["id"]) if route else None,
to_lonlat=lambda x, y: transformer.transform(x, y),
surface_params=dict(surface_params),
),
"",
)