feat(위성): 위성 조각 프로젝트당 150 MB 한도 · 오래 안 본 것부터 지움 · 한 장짜리 위성 걷음 · B 저장 복사에서 조각 뺌 (PLAN 590-2 · 요구 452 · 453)
- 조각 저장본 한 벌(_derived/plan_tile) — 처음 열 때 한 번 셈 · 받을 때 더함 · 넘치면 묵은 것부터 80 % 까지 · 하루 넘게 묵은 것만 본 때 찍음 - 한 장짜리 위성 그림 안 만듦(메타 = 지도 틀만) · vworld-map 위성 404 · 미리 받기 줄 걷음 - 옛 캔버스(D03 · B04 · B05 배수유역) = 위성 바탕 없이 + 알림 - 저장 떠 두기에서 조각 폴더 뺌 - 시험 590_2 새로 · 283 한 본문 손 고침 실패는 고치기 전부터(이 고침과 무관) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -74,7 +74,11 @@ def download_vworld_satellite_map(
|
||||
) -> Path | None:
|
||||
"""PRJ 좌표 정보와 지형 범위(bounds)를 바탕으로,
|
||||
해당 임도 산림 지역을 감싸는 VWorld 지도 타일을 다운로드하여 하나의 PNG 텍스처로 병합합니다.
|
||||
|
||||
위성(`Satellite`)은 그림 없이 메타(지도 틀)만 씀 → 메타 경로를 돌려줌(590-2 · 위성 바탕 =
|
||||
GL 조각 `plan/tile`).
|
||||
"""
|
||||
meta_only = layer_name.lower() == "satellite"
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
file_name = f"vworld_{layer_name.lower()}.png"
|
||||
map_png_path = output_dir / file_name
|
||||
@@ -118,11 +122,11 @@ def download_vworld_satellite_map(
|
||||
break
|
||||
zoom -= 1
|
||||
|
||||
# 4. 개별 타일 다운로드 및 이미지 병합
|
||||
map_img = Image.new("RGBA", (tile_w * 256, tile_h * 256))
|
||||
# 4. 개별 타일 다운로드 및 이미지 병합(위성 = 건너뜀)
|
||||
map_img = Image.new("RGBA", (1, 1) if meta_only else (tile_w * 256, tile_h * 256))
|
||||
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
|
||||
|
||||
for ty in range(y_start, y_end + 1):
|
||||
for ty in range(y_start, y_end + 1) if not meta_only else ():
|
||||
for tx in range(x_start, x_end + 1):
|
||||
try:
|
||||
normalized_layer = layer_name.lower()
|
||||
@@ -176,7 +180,8 @@ def download_vworld_satellite_map(
|
||||
img_x_max, img_y_min = rev_transformer.transform(lon_right, lat_bottom)
|
||||
|
||||
# 6. 이미지 저장 및 메타데이터 작성
|
||||
map_img.save(map_png_path, "PNG")
|
||||
if not meta_only:
|
||||
map_img.save(map_png_path, "PNG")
|
||||
|
||||
meta = {
|
||||
"x_min": img_x_min,
|
||||
@@ -194,7 +199,7 @@ def download_vworld_satellite_map(
|
||||
}
|
||||
meta_json_path.write_text(json.dumps(meta, indent=2), encoding="utf-8")
|
||||
|
||||
return map_png_path
|
||||
return meta_json_path if meta_only else map_png_path
|
||||
|
||||
|
||||
# 경위도 격자 — 그림 상자와 둘레 한 폭씩(도엽이 상자 밖 0.8 폭까지 · 3 × 3 폭) · 한 변 25 마디
|
||||
|
||||
@@ -78,7 +78,14 @@ async def get_vworld_meta(
|
||||
async def get_vworld_map(
|
||||
project_id: UUID, request: Request, layer_name: str = "satellite"
|
||||
) -> Response | JSONResponse:
|
||||
"""배경 지도 레이어 PNG 이미지를 반환합니다(ETag — 바뀌지 않았으면 304)."""
|
||||
"""배경 지도 레이어 PNG 이미지를 반환합니다(ETag — 바뀌지 않았으면 304).
|
||||
|
||||
위성은 한 장 그림을 안 씀(590-2 · GL 조각 `plan/tile`) → 404."""
|
||||
if layer_name.lower() == "satellite":
|
||||
return JSONResponse(
|
||||
status_code=404,
|
||||
content={"status": "error", "message": "위성 한 장 그림은 쓰지 않습니다."},
|
||||
)
|
||||
pool = get_db_pool()
|
||||
try:
|
||||
async with pool.acquire() as connection:
|
||||
@@ -93,9 +100,6 @@ async def get_vworld_map(
|
||||
map_name = f"vworld_{target_layer}.png"
|
||||
map_path = target_dir / map_name
|
||||
|
||||
if not map_path.exists() and target_layer == "satellite":
|
||||
map_path = target_dir / "vworld_map.png"
|
||||
|
||||
if not map_path.exists():
|
||||
return JSONResponse(
|
||||
status_code=404,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* 따라감 — 카메라 = 화면 가운데 1차 맞춤(`logic/…_MapGl_Frame` · 닮음꼴) + 남는 늘림 = 지도 칸 CSS 행렬 · 위 그림(노선 · 관 · 측점 · 고르기)은
|
||||
* 위 캔버스 그대로 · 누름 · 끌기 판정 그대로.
|
||||
* 처음 = 켬 · 끔 = 옛 캔버스(취향 `aislo:pref:map.canvas` = "1" · 세 화면 하나) · WebGL 못 씀 · 잃음 =
|
||||
* 저절로 옛 캔버스 + 알림(취향은 안 바꿈).
|
||||
* 저절로 옛 캔버스 + 알림(취향은 안 바꿈) · 옛 캔버스 = 위성 바탕 없음(590-2 · 위성 = 조각만).
|
||||
* ========================================================================== */
|
||||
|
||||
import type { ExpressionSpecification, FilterSpecification } from "maplibre-gl";
|
||||
@@ -25,7 +25,10 @@ import { glCameraOf } from "./logic/B04_PreProcess_UI_MapGl_Frame";
|
||||
|
||||
/** 옛 캔버스로 그림("1") — 처음 = GL. */
|
||||
const CANVAS_PREF_KEY = "aislo:pref:map.canvas";
|
||||
export const GL_TOGGLE_TITLE = "그래픽 카드 그림(바탕 겹을 GPU 로 · 끔 = 옛 캔버스 그림)";
|
||||
export const GL_TOGGLE_TITLE =
|
||||
"그래픽 카드 그림(바탕 겹을 GPU 로 · 끔 = 옛 캔버스 그림 · 위성 바탕 없음)";
|
||||
/** 옛 캔버스 알림 — 위성 = GL 조각만(590-2). */
|
||||
const NO_SATELLITE_NOTE = "옛 그림은 위성 바탕 없이 그림";
|
||||
|
||||
export interface TmGl<K extends string> {
|
||||
gl: GlMap<K>;
|
||||
@@ -68,7 +71,7 @@ export function createTmGl<K extends string>(opts: {
|
||||
themeNames: opts.themeNames,
|
||||
onFail: (why) => {
|
||||
if (!wanted) return;
|
||||
showToast(`그래픽 카드 그림을 못 써 옛 그림으로 — ${why}`, "info");
|
||||
showToast(`그래픽 카드 그림을 못 써 옛 그림으로 — ${why} · ${NO_SATELLITE_NOTE}`, "info");
|
||||
use(false);
|
||||
},
|
||||
});
|
||||
@@ -87,6 +90,7 @@ export function createTmGl<K extends string>(opts: {
|
||||
toggle() {
|
||||
writeByKey(CANVAS_PREF_KEY, active ? "1" : "0");
|
||||
use(!active);
|
||||
if (!active) showToast(NO_SATELLITE_NOTE, "info");
|
||||
},
|
||||
follow(meta, normalizer, toScreen, width, height) {
|
||||
if (!active || !meta || !normalizer || width <= 0 || height <= 0) return;
|
||||
|
||||
@@ -502,6 +502,8 @@ export function createSurfaceMapViewer(): SurfaceMapViewer {
|
||||
surfaceGl.setLayer(layer, data);
|
||||
});
|
||||
BACKGROUND_LAYERS.forEach((layer) => {
|
||||
// 위성 = GL 조각만(옛 캔버스 = 위성 바탕 없음 · 590-2)
|
||||
if (layer === "satellite") return;
|
||||
// 주소에 시각을 붙이면 브라우저가 매번 다시 받는다. 서버가 ETag를 주므로 그대로 쓴다.
|
||||
backgroundImages.get(layer)!.src = getVWorldMapUrl(projectId, layer);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user