perf(D03): 0차곡 무거운 셈 일꾼으로 · 급경사 값 그림 바이너리 · 칠하기 toDataURL (PLAN 616-3 · 616-4)
- 0차곡 길 = 창고 선으로 바로(스레드) · 셈 필요하면 서버 본체 밖 일꾼 · 응답 = json.dumps 바로(큰 선 묶음 jsonable_encoder 건넘) - 급경사 = PNG 바이트 + 머리 X-Plan-Raster(칸 수 · 범위) · Content-Encoding identity(PNG 다시 gzip 안 함) · 음영기복 · 산사태 = JSON 그대로 - Api fetchPlanRaster 급경사만 바이너리(blob 주소 · slopeValues 가 다 읽고 놓음) - 칠하기 = canvas.toDataURL(toBlob 한가 작업 기다림 최대 1 s 없앰) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -399,8 +399,9 @@ async def plan_layer_cadastral(project_id: UUID, request: Request) -> Response:
|
||||
|
||||
|
||||
@router.get("/{project_id}/plan/layers/raster", response_model=None)
|
||||
async def plan_layer_raster(project_id: UUID, kind: str = "slope") -> dict[str, Any]:
|
||||
"""급경사 기울기 % 값 그림 + 1 % 칸 수(603) · 음영기복(`hillshade`) — 격자 지문 같으면 저장본 ·
|
||||
async def plan_layer_raster(project_id: UUID, kind: str = "slope") -> dict[str, Any] | Response:
|
||||
"""급경사 기울기 % 값 그림 + 1 % 칸 수(603 · PNG 바이트 + 머리 `X-Plan-Raster` 616-4) ·
|
||||
음영기복(`hillshade`) — 격자 지문 같으면 저장본 ·
|
||||
산사태위험지도(`landslide` · 행안부 WMS) — 받은 범위를 덮으면 저장본."""
|
||||
if kind == "landslide":
|
||||
root, epsg, box = await _layer_root(project_id)
|
||||
@@ -422,6 +423,10 @@ async def plan_layer_raster(project_id: UUID, kind: str = "slope") -> dict[str,
|
||||
)
|
||||
except FileNotFoundError as error:
|
||||
raise HTTPException(status_code=404, detail=str(error)) from error
|
||||
if kind == "slope":
|
||||
png, meta = layers.raster_bytes(value)
|
||||
head = {"X-Plan-Raster": json.dumps({"kind": kind, **meta}), "Content-Encoding": "identity"}
|
||||
return Response(png, media_type="image/png", headers=head) # PNG = 다시 압축 안 함
|
||||
return {"status": "success", "kind": kind, **value}
|
||||
|
||||
|
||||
@@ -479,18 +484,23 @@ async def plan_layer_zero_order(
|
||||
project_id: UUID,
|
||||
min_m2: float = zero_order.ZERO_ORDER_MIN_M2,
|
||||
max_m2: float = zero_order.ZERO_ORDER_MAX_M2,
|
||||
) -> dict[str, Any]:
|
||||
"""0차곡 선(지형 추정 · 위 집수 `min_m2` ~ `max_m2`) — 격자 지문 · 임계 같으면 저장본."""
|
||||
) -> Response:
|
||||
"""0차곡 선(지형 추정 · 위 집수 `min_m2` ~ `max_m2`) — 창고 도엽 선 · 다른 임계는 저장본 ·
|
||||
창고에 없어 셈이 필요하면 서버 본체 밖 일꾼(616-3 · 다른 겹 요청을 안 막음)."""
|
||||
if not 0 < min_m2 < max_m2:
|
||||
raise HTTPException(status_code=400, detail="0 < min_m2 < max_m2 여야 합니다.")
|
||||
root, epsg, _ = await _layer_root(project_id)
|
||||
args = (root, terrain.models_dir_of(root), epsg, min_m2, max_m2)
|
||||
pool = zero_order.heavy_pool()
|
||||
try:
|
||||
value = await asyncio.to_thread(
|
||||
zero_order.zero_order_layer, root, terrain.models_dir_of(root), epsg, min_m2, max_m2
|
||||
)
|
||||
value = await asyncio.to_thread(zero_order.zero_order_layer, *args, False)
|
||||
if value is None:
|
||||
loop = asyncio.get_running_loop()
|
||||
value = await loop.run_in_executor(pool, zero_order.zero_order_layer, *args)
|
||||
except FileNotFoundError as error:
|
||||
raise HTTPException(status_code=404, detail=str(error)) from error
|
||||
return {"status": "success", **value}
|
||||
body = json.dumps({"status": "success", **value}, ensure_ascii=False) # 큰 선 묶음 = 바로 글로
|
||||
return Response(body, media_type="application/json")
|
||||
|
||||
|
||||
async def _road_frame(project_id: UUID) -> tuple[Path, int, terrain.Box, tuple[float, float]]:
|
||||
|
||||
Reference in New Issue
Block a user