diff --git a/A00_Common/map/map_forest_layers.ts b/A00_Common/map/map_forest_layers.ts index 271194d9a..8e0e00206 100644 --- a/A00_Common/map/map_forest_layers.ts +++ b/A00_Common/map/map_forest_layers.ts @@ -1,7 +1,7 @@ /* ============================================================================= * map_forest_layers.ts * 공용 지도 — 받은 산림 · 환경 자료 겹(PLAN 622-2 · 624-2 · 요구 529 · 530) — 서버 줌별 조각(622-1)을 GL 고정 소스로(위성 · 등고선 615 꼴). - * 벡터 = 국유림 임도(forest_road · 간선 · 작업 · 산불 색 · 줌 따라 굵기) · 산림입지도(forest_soil · 토양 무리 색 · + * 벡터 = 임도망도(forest_road · 전국 국가임도 · 간선 · 작업 · 산불 색 · 줌 따라 굵기 · 줌 14 부터 연도 · 종류 글) · 산림입지도(forest_soil · 토양 무리 색 · * 반투명 · z10 아래 숨김) · 경제림(eco_forest · 국유 · 사유 테두리) / * 그림 = 생태자연도(ecology) · 산사태위험지도(landslide · 옛 캔버스는 받은 범위 한 장 그대로). * 조각만 쓰는 겹(`TILE_ONLY`) = 받기 없음 · 옛 캔버스(그래픽 카드 끔)엔 안 보임. @@ -11,7 +11,7 @@ import type { ExpressionSpecification, SourceSpecification } from "maplibre-gl"; import type { LegendItem } from "@ui/ui_template_flow_legend"; -import { tileSource, type GlSpec } from "@ui/ui_template_gl_map"; +import { GL_FONT, tileSource, type GlSpec } from "@ui/ui_template_gl_map"; import { themeColor } from "@ui/ui_template_palette"; import type { MapLayerKey } from "./map_layer_list"; @@ -147,7 +147,7 @@ export function forestAreaSpecs(): Spec[] { ]; } -/** 국유림 임도 선 — 검은 테 + 사업 구분 색(올린 임도망도 위). */ +/** 임도망도(전국 국가임도) 선 — 검은 테 + 사업 구분 색(도로 위 · 임도(업로드) 아래). */ export function forestRoadSpecs(): Spec[] { const color = [ "match", @@ -171,6 +171,42 @@ export function forestRoadSpecs(): Spec[] { ]; } +/** 임도망도 글(요구 534) — 줌 14 부터 선 따라 「개설 연도 · 종류」(연도 0 = 종류만) · 겹치면 뺌 · 꼴 = 지명 글. */ +export function forestRoadLabelSpec(): Spec { + const kind = [ + "match", + ["get", "kind"], + ...ROAD_KINDS.flatMap(({ kind, label }) => [kind, label]), + "", + ] as unknown as ExpressionSpecification; + return { + key: "nationalRoad", + id: "nationalRoad-label", + type: "symbol", + source: "forest_road", + "source-layer": "forest_road", + minzoom: 14, + layout: { + "symbol-placement": "line", + "symbol-spacing": 300, + "text-field": [ + "concat", + ["case", [">", ["get", "year"], 0], ["concat", ["to-string", ["get", "year"]], " · "], ""], + kind, + ], + "text-font": [GL_FONT], + "text-size": 11, + "text-max-angle": 30, + "text-padding": 2, + }, + paint: { + "text-color": themeColor("--draw-map-place", "#f8fafc"), + "text-halo-color": "rgba(0, 0, 0, 0.7)", + "text-halo-width": 1.5, + }, + } as unknown as Spec; +} + /** 범례 — 켠 조각 겹(산사태위험 = 범례 자리 `LANDSLIDE_LEGEND` 따로). */ export function forestLegendRows(on: Record): LegendItem[][] { const item = (label: string, color: string, kind?: LegendItem["kind"]): LegendItem => ({ @@ -180,7 +216,7 @@ export function forestLegendRows(on: Record): LegendItem[] }); const rows: LegendItem[][] = []; if (on.nationalRoad) - rows.push(ROAD_KINDS.map(({ label, color }) => item(`국유림 임도 ${label}`, color, "line"))); + rows.push(ROAD_KINDS.map(({ label, color }) => item(`임도망도 ${label}`, color, "line"))); if (on.ecoForest) rows.push(ECO_KINDS.map(({ own, color }) => item(`경제림 ${own}`, color, "line"))); if (on.ecology) diff --git a/A00_Common/map/map_layer_data.ts b/A00_Common/map/map_layer_data.ts index 5d82fb0c7..1b100fd93 100644 --- a/A00_Common/map/map_layer_data.ts +++ b/A00_Common/map/map_layer_data.ts @@ -1,13 +1,13 @@ /* ============================================================================= * map_layer_data.ts * 공용 지도 겹 자료 도움(PLAN 569-2 · 581 · 586-2 · 624-3) — D03 예정노선 · B05 평면이 같이 씀(D03 `UI_LayerDefs` 에서 옮김). - * 임도 짐작 구분 · 물 면 도엽 이름 · 넓이 글 · 그림 읽기 · GL 자료(지물 색 붙이기 · 그림 귀퉁이 · 음영 그늘 그림). + * 도로 소로 · 미분류 구분 · 물 면 도엽 이름 · 넓이 글 · 그림 읽기 · GL 자료(지물 색 붙이기 · 그림 귀퉁이 · 음영 그늘 그림). * ========================================================================== */ import type { GlImage } from "@ui/ui_template_gl_map"; import type { GeoJsonCollection, PlanRaster } from "./map_layer_api"; -/** 도로 중 기존 임도로 짐작하는 구분. */ +/** 도로 중 소로 · 미분류 구분(옛 임도 짐작 · 겹 걷음 · 페이지 자료 셈만 씀). */ export const FOREST_ROAD_KINDS = new Set(["소로", "미분류"]); /** 물 면 = 도엽 수계(E) 면 셋. */ export const WATER_KEYS = ["실폭하천", "수계면E003", "수계면E005"]; diff --git a/A00_Common/map/map_layer_list.ts b/A00_Common/map/map_layer_list.ts index a2e24f9e0..81654fa3c 100644 --- a/A00_Common/map/map_layer_list.ts +++ b/A00_Common/map/map_layer_list.ts @@ -19,7 +19,7 @@ export type MapLayerKey = | "stream" | "water" | "road" - | "forestRoad" + | "forestRoad" // 걷은 겹(임도 짐작 · 요구 532) — 목록 · 꼴 없음 · 페이지 자료 셈 이음만 남음 | "forestRoadFile" | "nationalRoad" | "ecoForest" @@ -36,7 +36,7 @@ export type MapLayerKey = | "building" | "place"; -/** 올린 임도망 고름(605-2) — 묶음 하나 또는 그 안의 선 하나(지도 강조). */ +/** 임도(업로드) 고름(605-2) — 묶음 하나 또는 그 안의 선 하나(지도 강조). */ export interface RoadPick { bundle: string; line?: number; @@ -63,23 +63,17 @@ export const GROUPS: readonly (readonly LayerDef[])[] = [ { key: "water", icon: "ripple", title: "물 면(도엽 실폭하천 · 저수지 등)", on: false }, { key: "road", icon: "road", title: "기존 도로(도엽 도로중심선)", on: false }, { - key: "forestRoad", + key: "nationalRoad", icon: "route", - title: "기존 임도 짐작(도엽 도로 소로 · 미분류 = 주황 점선 · 정식 임도망도 아님)", + title: + "임도망도(산림청 전국 국가임도 · 간선 · 작업 · 산불 색 · 지방 · 민간임도는 「임도(업로드)」로)", on: false, }, { key: "forestRoadFile", icon: "map", title: - "올린 임도망도(산림청 시군구 SHP = 밝은 분홍 실선 · 왼쪽 「위치」 칸에서 올리고 묶음 고름 · 지움)", - on: false, - }, - { - key: "nationalRoad", - icon: "flag", - title: - "국유림 임도(산림청 전국 국가임도 · 간선 · 작업 · 산불 색 · 지방 · 민간임도 없음 · 참고용)", + "임도(업로드)(산림청 시군구 SHP 등 사용자가 올린 지방 · 민간임도 = 밝은 분홍 실선 · 왼쪽 「위치」 칸에서 올리고 묶음 고름 · 지움)", on: false, }, ], @@ -155,7 +149,7 @@ export const MAP_LAYER_PAGES: Record< { hide: readonly MapLayerKey[]; on?: readonly MapLayerKey[]; pref: string } > = { d03: { hide: [], pref: "aislo:pref:d03.layers" }, - // A② 처음 = 지금 그대로(등고선 · 하천) · A⑨ 띠(타당성) · 올린 임도망도 숨김 + // A② 처음 = 지금 그대로(등고선 · 하천) · A⑨ 띠(타당성) · 임도(업로드) 숨김 b05: { hide: ["bands", "forestRoadFile"], on: ["contour", "stream"], diff --git a/A00_Common/map/map_layer_specs.ts b/A00_Common/map/map_layer_specs.ts index de0589b5e..6b433c29d 100644 --- a/A00_Common/map/map_layer_specs.ts +++ b/A00_Common/map/map_layer_specs.ts @@ -2,8 +2,8 @@ * map_layer_specs.ts * 공용 지도 GL 겹 꼴(PLAN 586-2 · 624-2 · 요구 530) — 바탕 겹 스물의 MapLibre 꼴 · 차례(아래 → 위): * 위성 · 그림 겹(음영 · 급경사 · 산사태위험 · 생태자연도) · 면 겹(산림입지 · 경제림 · 보호구역 · 띠 · 물 면 · 건물) · - * 선 겹(지적 · 등고선 · 도로 · 임도 짐작 · 올린 임도망도 · 국유림 임도 · 세류 · 단층 · 지질구조선 · 0차곡 · 산사태취약 필지) · - * 점 · 글(산사태취약 · 지명 · 등고 수치). + * 선 겹(지적 · 등고선 · 도로 · 임도망도 · 임도(업로드) · 세류 · 단층 · 지질구조선 · 0차곡 · 산사태취약 필지) · + * 점 · 글(산사태취약 · 임도망도 연도 · 종류 · 지명 · 등고 수치). * 자료 = 받는 쪽이 지물에 붙인 `_color` · 고정 소스(위성 · 등고 · 산림 조각) 이름 = `map_forest_layers` · `ui_template_gl_map`. * 카메라 · 지도 세우기는 페이지 몫(D03 `UI_MapGl.createGlBase` · B05 `createTmGl`) — 여기는 꼴만. * ========================================================================== */ @@ -11,7 +11,12 @@ import type { ExpressionSpecification, FilterSpecification } from "maplibre-gl"; import { GL_FONT, type GlSpec as GlMapSpec } from "@ui/ui_template_gl_map"; import { themeColor } from "@ui/ui_template_palette"; -import { forestAreaSpecs, forestRasterSpecs, forestRoadSpecs } from "./map_forest_layers"; +import { + forestAreaSpecs, + forestRasterSpecs, + forestRoadLabelSpec, + forestRoadSpecs, +} from "./map_forest_layers"; import { LINE_KEYS, LINE_LAYERS, @@ -20,7 +25,7 @@ import { type RoadPick, } from "./map_layer_list"; -/** 자료 소스(임도 짐작 = 도로 소스를 거름 · 위성 = 조각). */ +/** 자료 소스(위성 = 조각 · 걷은 임도 짐작 = 소스 없음). */ export type GlSource = Exclude; const GL_FONT_BOLD = [`${GL_FONT} SemiBold`, GL_FONT]; @@ -196,19 +201,7 @@ export function mapLayerSpecs(light: number, pick: RoadPick | null): GlSpec[] { color: HALO, width: 3.2, }), - ...haloLine( - "forestRoad", - "road", - themeColor("--draw-map-forest-road", "#f59e0b"), - 2, - [7, 4], - { color: HALO, width: 3.6 }, - [ - "in", - ["get", "도로구분"], - ["literal", ["소로", "미분류"]], - ] as unknown as FilterSpecification, - ), + ...forestRoadSpecs(), // 임도망도(전국 국가임도) = 벡터 조각 · 임도(업로드) 아래 ...haloLine( "forestRoadFile", "forestRoadFile", @@ -217,7 +210,6 @@ export function mapLayerSpecs(light: number, pick: RoadPick | null): GlSpec[] { [], { color: HALO, width: 4 }, ), - ...forestRoadSpecs(), // 국유림 임도 = 벡터 조각 // 고른 묶음 · 선 강조(605-2) — 같은 자료에서 걸러 한 겹 더 굵게 ...["-pick-halo", "-pick"].map( (tail, i) => @@ -269,6 +261,7 @@ export function mapLayerSpecs(light: number, pick: RoadPick | null): GlSpec[] { "circle-stroke-width": 1.5, }, } as GlSpec, + forestRoadLabelSpec(), // 임도망도 글 — 지명 아래(겹치면 지명이 앞섬) { key: "place", id: "place-dot", diff --git a/A00_Common/map/map_legend.ts b/A00_Common/map/map_legend.ts index 96a3aafb7..4ba5fd6cb 100644 --- a/A00_Common/map/map_legend.ts +++ b/A00_Common/map/map_legend.ts @@ -1,7 +1,7 @@ /* ============================================================================= * map_legend.ts * 공용 지도 범례(PLAN 569-2 · 622-2 · 624-2 · 요구 530) — 켠 겹 범례 칸 하나(줄마다 `createLegend`) + 페이지가 붙이는 덧 줄. - * 조각 겹 범례(산사태위험 · 국유림 임도 · 경제림 · 생태자연도) = 받을 자료 없음 → 켬끔만 보고 여기서 만듦(`tileLegendRows`). + * 조각 겹 범례(산사태위험 · 임도망도 · 경제림 · 생태자연도) = 받을 자료 없음 → 켬끔만 보고 여기서 만듦(`tileLegendRows`). * 받은 자료 범례 줄(수 · 넓이 · 급경사 범위 · 624-3 D03 에서 옮김) = `legendRows(on, data)` — 받은 자료 꼴은 `LegendData` * (D03 옛 캔버스 자료 · B05 GL 자료 둘 다 맞음 · 받는 일은 페이지 몫). * 쓰는 법 = `const legend = createMapLegend("d03-plan__legend")` → `legend.show(rows, [덧 줄])` · 줄 · 덧 없으면 숨김. @@ -189,15 +189,9 @@ export function legendRows( label: `건물 ${(data.building.features?.length ?? 0).toLocaleString()}동`, color: "var(--draw-map-building)", }); - if (on.forestRoad && data.road) - tail.push({ - label: `임도 짐작 ${data.road.small.features?.length ?? 0}가닥`, - color: "var(--draw-map-forest-road)", - kind: "dash", - }); if (on.forestRoadFile && data.forestRoadFile) tail.push({ - label: `올린 임도망도 ${data.forestRoadFile.info.count}가닥 ${km(data.forestRoadFile.info.length_m)}`, + label: `임도(업로드) ${data.forestRoadFile.info.count}가닥 ${km(data.forestRoadFile.info.length_m)}`, color: "var(--draw-map-forest-road-file)", kind: "line", }); diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_ForestRoad.py b/D03_PlanAnalysis/D03_PlanAnalysis_ForestRoad.py index 24d8440a4..ba990f737 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_ForestRoad.py +++ b/D03_PlanAnalysis/D03_PlanAnalysis_ForestRoad.py @@ -217,7 +217,7 @@ def bundle_layer( path, meta = _paths(project_root, bundle) stamp = file_stamp(path) if stamp is None: - raise FileNotFoundError(f"올린 임도망도 묶음 {bundle} 이(가) 없습니다.") + raise FileNotFoundError(f"임도(업로드) 묶음 {bundle} 이(가) 없습니다.") at = [round(v, 1) for v in origin] if origin else None key = derived_key( ROAD_KIND, ROAD_VERSION, bundle, stamp, int(epsg), [round(v, 1) for v in box], at @@ -238,7 +238,7 @@ def road_layer(project_root: Path, box: Box, epsg: int, origin: XY | None = None ids = bundle_ids(project_root) if not ids: raise FileNotFoundError( - "올린 임도망도가 없습니다 — [임도망 올리기]로 시군구 SHP 를 올리세요." + "임도(업로드)가 없습니다 — 「위치」 칸 [임도(업로드)]로 시군구 SHP 를 올리세요." ) rows, features, crs, edges, gaps = [], [], set(), [], [] for bundle in ids: @@ -335,9 +335,9 @@ def save_roads( def delete_bundle(project_root: Path, bundle: str) -> None: """묶음 하나 지움(저장본은 열쇠가 달라져 저절로 안 쓰임) — 없으면 `FileNotFoundError`.""" if bundle != LEGACY and not re.fullmatch(r"[0-9a-f]{12}", bundle): - raise FileNotFoundError(f"올린 임도망도 묶음 {bundle} 이(가) 없습니다.") + raise FileNotFoundError(f"임도(업로드) 묶음 {bundle} 이(가) 없습니다.") zip_path, meta_path = _paths(project_root, bundle) if not zip_path.is_file(): - raise FileNotFoundError(f"올린 임도망도 묶음 {bundle} 이(가) 없습니다.") + raise FileNotFoundError(f"임도(업로드) 묶음 {bundle} 이(가) 없습니다.") zip_path.unlink() meta_path.unlink(missing_ok=True) diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_LayerLegend.ts b/D03_PlanAnalysis/D03_PlanAnalysis_UI_LayerLegend.ts index 71aa3a5d9..823fb34de 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_LayerLegend.ts +++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_LayerLegend.ts @@ -34,9 +34,9 @@ export type Prepared = Record & { /** 세류 · 하천(소하천 · 지방하천 · 연결선). */ stream: [PreparedLayer, PreparedLayer]; cadastral: PreparedLayer; - /** 전체 · 그중 임도 짐작(소로 · 미분류) — `road` · `forestRoad` 가 함께 씀. */ + /** 전체 · 그중 소로 · 미분류(옛 임도 짐작 · 겹 걷음 · 수만 셈). */ road: { all: PreparedLayer; small: PreparedLayer }; - /** 올린 임도망도(584-3). */ + /** 임도(업로드)(584-3). */ forestRoadFile: { layer: PreparedLayer; info: PlanForestRoads }; /** 급경사(603) — 값 그림 칸 · 고른 범위 · 칠한 그림(blob 주소) · 칠하기 ms. */ slope: { diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts index 4cbf62757..6069d09f0 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts +++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts @@ -4,8 +4,8 @@ * (공용 겹 줄 `A00_Common/map/map_layer_bar` · 넘치면 가로 밀기 571-1 · 오른쪽 평면 도구줄과 따로). * * 겹 = 바탕(위성 · 음영기복 · 도엽 등고선(계곡선 25 m 굵게 · 수치) · 급경사 색) · - * 물 · 길(세류선 · 하천 · 물 면(실폭하천 · 저수지) · 기존 도로 · 기존 임도 짐작(소로 · 미분류) · - * 올린 임도망도(시군구 SHP · 올리기 = 왼쪽 「위치」 칸 `uploadRoads`)) · + * 물 · 길(세류선 · 하천 · 물 면(실폭하천 · 저수지) · 기존 도로 · 임도망도(전국 국가임도 · 조각) · + * 임도(업로드)(시군구 SHP · 올리기 = 왼쪽 「위치」 칸 `uploadRoads`)) · * 구역(지적도 · 보호 · 규제 구역 여덟 종 · 산림입지도(토양형) · 산사태위험지도 · 산사태취약지역(시도 표 점 · 지번 필지 테두리) · * 선 겹(단층 · 지질구조선 · 0차곡) · * 계류 100 m · 도로 300 m 띠 · 건물 · 지명). @@ -14,14 +14,14 @@ * 옛 차례 답은 버림(475) · 도엽 선 겹(등고 · 세류 · 물 면 · 도로 · 건물 · 지명) = 보이는 도엽 조각(606 · `UI_SheetTiles`) · 지형을 안 받았으면 단추를 막음 · * 받기 실패 = 그 겹만 꺼짐 + 알림 · 받는 일은 페이지 서클에 셈(`track`). * 그리기 차례(아래 → 위) = 위성(GL 조각만 · 옛 캔버스 = 위성 없음 · 590-2) → 음영기복 → 급경사 → 산사태위험지도 → 산림입지도 → 보호구역 → 띠 → 지적 → 물 면 → - * 건물 → 등고선 → 도로 → 임도 짐작 → 올린 임도망도 → 세류 → 선 겹 → 산사태취약지역 → 지명 → 그은 선. + * 건물 → 등고선 → 도로 → 임도(업로드) → 세류 → 선 겹 → 산사태취약지역 → 지명 → 그은 선. * 겹 모두 = 바탕 캔버스(`base` · 582) · 등고선 = 줌 단계 색인 · 글 폭 기억. * 범례 = 켠 겹의 받은 범위 안 수 · 넓이(왼쪽 아래 · 칸 = 공용 `map_legend` · 줄 = `D03_PlanAnalysis_UI_LayerLegend`). * 급경사 = 서버 값 그림을 고른 범위대로 칠함 · 범례 ⚙ → 범위 모달(603 · `D03_PlanAnalysis_UI_SlopeBands`). * GL 바탕(586-2 · 처음 = 켬 · 끝 단추 끔 = 옛 캔버스 · `aislo:pref:d03.canvas`) — 겹 스물 · 등고 글 · 지명을 * MapLibre 가 그림(`D03_PlanAnalysis_UI_MapGl`) · 캔버스 바탕 겹은 쉼(등고 간격 셈만) · 받기 · 범례는 같음 · * WebGL 못 씀 · 잃음 = 저절로 옛 캔버스 + 알림(취향은 안 바꿈). - * 받은 산림 · 환경 자료(622-2) = 국유림 임도 · 경제림 · 생태자연도(조각만 · 받기 없음) · 산림입지도 · 산사태위험(GL = 조각 · + * 받은 산림 · 환경 자료(622-2) = 임도망도 · 경제림 · 생태자연도(조각만 · 받기 없음) · 산림입지도 · 산사태위험(GL = 조각 · * 옛 캔버스 = 지금 받기 그대로) — 꼴 · 범례 = 공용 `A00_Common/map/map_forest_layers`. * ========================================================================== */ @@ -102,7 +102,7 @@ export interface PlanLayers { layers: PlanMapLayer[]; /** 지형(위성 틀)을 다시 읽음 — 처음 · 지형 받은 뒤 · 받은 범위(`have` · 지형면을 다 읽은 뒤 값)가 바뀌면 켠 겹 모두 새로. */ load: (have: [number, number, number, number] | null) => Promise; - /** 임도망도 올리기(왼쪽 「위치」 칸) — 받으면 그 겹을 켬 · 못 받으면 알림 + null. */ + /** 임도(업로드) 올리기(왼쪽 「위치」 칸) — 받으면 그 겹을 켬 · 못 받으면 알림 + null. */ uploadRoads: (files: File[]) => Promise; /** 올린 묶음 하나 지움(605-1) — 지도에서 바로 빠짐 · 못 지우면 알림 + 거짓. */ deleteRoad: (bundle: string) => Promise; @@ -285,7 +285,7 @@ export function createPlanLayers(opts: { if (meta !== at) return info; applyRoads(info); showToast( - `임도망도 받음 — 범위 안 ${info.count}가닥 ${(info.length_m / 1000).toFixed(2)} km (파일 ${info.total}가닥)`, + `임도(업로드) 받음 — 범위 안 ${info.count}가닥 ${(info.length_m / 1000).toFixed(2)} km (파일 ${info.total}가닥)`, "success", ); return info; @@ -302,7 +302,7 @@ export function createPlanLayers(opts: { return await job; } catch (error) { showToast( - `임도망도 올리지 못함 — ${error instanceof Error ? error.message : String(error)}`, + `임도(업로드) 올리지 못함 — ${error instanceof Error ? error.message : String(error)}`, "error", ); return null; @@ -339,14 +339,14 @@ export function createPlanLayers(opts: { applyRoads(info); showToast( info - ? `임도망도 묶음 지움 — 남은 ${info.bundles.length}묶음` - : "임도망도 묶음 지움 — 남은 것 없음", + ? `임도(업로드) 묶음 지움 — 남은 ${info.bundles.length}묶음` + : "임도(업로드) 묶음 지움 — 남은 것 없음", "success", ); return true; } catch (error) { showToast( - `임도망도 묶음을 지우지 못함 — ${error instanceof Error ? error.message : String(error)}`, + `임도(업로드) 묶음을 지우지 못함 — ${error instanceof Error ? error.message : String(error)}`, "error", ); return false; diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Page.ts b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Page.ts index acd639634..48689d050 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Page.ts +++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Page.ts @@ -463,7 +463,7 @@ export async function renderD03PlanAnalysis(root: HTMLElement): Promise { fitTo(around(site)); } - /** 임도망 올리기 — 지도 맞춤 = 주소지 둘레 ∪ 잘린 임도 상자(없으면 주소지). */ + /** 임도(업로드) 올리기 — 지도 맞춤 = 주소지 둘레 ∪ 잘린 임도 상자(없으면 주소지). */ async function uploadRoads(files: File[]): Promise { const info = await backdrop.uploadRoads(files); if (info) fitTo([...around(site), ...boxOfLonLat(epsg, info.bounds)]); diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_RoadList.ts b/D03_PlanAnalysis/D03_PlanAnalysis_UI_RoadList.ts index 15cb6b183..8ffb01c92 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_RoadList.ts +++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_RoadList.ts @@ -1,6 +1,6 @@ /* ============================================================================= * D03_PlanAnalysis_UI_RoadList.ts - * D03 「위치」 칸 올린 임도망 목록(PLAN 605-2 · 요구 476-1) — 묶음 줄(파일 이름 · 가닥 수 · 길이 · 지움) · + * D03 「위치」 칸 임도(업로드) 묶음 목록(PLAN 605-2 · 요구 476-1) — 묶음 줄(파일 이름 · 가닥 수 · 길이 · 지움) · * 펼치면 선 줄 · 줄 고름 = 지도 강조 + 맞춤(페이지가 함) · 지움 = 물음 뒤 그 묶음만 · 자료는 서버 한 번 읽음. * 부르는 곳 = `D03_PlanAnalysis_UI_Site.ts`. * ========================================================================== */ @@ -111,7 +111,7 @@ export function createRoadList(params: RoadListParams): RoadList { const bundles = info?.bundles ?? []; root.hidden = !bundles.length; if (!bundles.length) return void root.replaceChildren(); - const rows: HTMLElement[] = [createText(`올린 임도망 ${bundles.length}묶음`, "muted", 12)]; + const rows: HTMLElement[] = [createText(`임도(업로드) ${bundles.length}묶음`, "muted", 12)]; for (const bundle of bundles) { const shown = open.has(bundle.id); const fold = createIconButton({ @@ -130,7 +130,7 @@ export function createRoadList(params: RoadListParams): RoadList { size: 24, onClick: async () => { const ok = await askConfirm({ - message: `올린 임도망 「${bundle.name}」 묶음을 지울까요? 지도에서도 빠집니다.`, + message: `임도(업로드) 「${bundle.name}」 묶음을 지울까요? 지도에서도 빠집니다.`, okLabel: "지움", danger: true, }); diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Site.ts b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Site.ts index cc48c9dbe..2228854a8 100644 --- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Site.ts +++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Site.ts @@ -2,7 +2,7 @@ * D03_PlanAnalysis_UI_Site.ts * D03 「위치」 칸(PLAN 596-2 · 요구 463-3~6 · 19) — 지금 기준점 주소 한 줄 · 주소 · 장소 찾기 * (서버 VWorld `searchPlaces` · 부품 `createFindList` · Enter = 찾기 · ↑ ↓ Enter = 고름) · - * 알림 한 줄(받기 실패 · 끊김 · 기준점 없음 · 못 불러옴만) + [다시 받기] · [임도망 올리기] + 올린 임도망 목록 + * 알림 한 줄(받기 실패 · 끊김 · 기준점 없음 · 못 불러옴만) + [다시 받기] · [임도(업로드)] + 올린 묶음 목록 * (`D03_PlanAnalysis_UI_RoadList.ts` · 605-2). * 고름 = 페이지가 받기 물음(멂 · 다른 TM 띠) → 기준점 캐시 → 지도 이동 → 둘레 받기 · [저장] 때 정본(등록과 한 칸). * ========================================================================== */ @@ -24,7 +24,7 @@ export interface PlanSiteParams { onRetry: () => void; /** 올림(끝나면 목록을 다시 읽음). */ onUpload: (files: File[]) => Promise | void; - /** 올린 임도망 목록(605-2) — 고름 · 지움은 페이지. */ + /** 임도(업로드) 묶음 목록(605-2) — 고름 · 지움은 페이지. */ roads: RoadListParams; } @@ -111,7 +111,7 @@ export function createPlanSite(params: PlanSiteParams): PlanSite { }); const roads = createRoadList(params.roads); const upload = createButton({ - label: "임도망 올리기", + label: "임도(업로드)", variant: "ghost", size: 28, onClick: () => @@ -119,7 +119,8 @@ export function createPlanSite(params: PlanSiteParams): PlanSite { Promise.resolve(params.onUpload(files)).then(() => roads.reload()), ), }); - upload.title = "임도망도 SHP(시군구 zip 하나 · 또는 shp · shx · dbf · prj 함께 · 100 MB 까지)"; + upload.title = + "임도(업로드) — 산림청 시군구 SHP 등 지방 · 민간임도(zip 하나 · 또는 shp · shx · dbf · prj 함께 · 100 MB 까지)"; return { parts: [address, find.root, note, retry, upload, roads.root], render(state) { diff --git a/resources/tester/test_553_4_de_parts.py b/resources/tester/test_553_4_de_parts.py index 92f3777ee..187b782da 100644 --- a/resources/tester/test_553_4_de_parts.py +++ b/resources/tester/test_553_4_de_parts.py @@ -79,9 +79,8 @@ def test_d03_parts(): ("stream", "true"), ("water", "false"), ("road", "false"), - ("forestRoad", "false"), - ("forestRoadFile", "false"), ("nationalRoad", "false"), + ("forestRoadFile", "false"), ("cadastral", "false"), ("zones", "false"), ("soils", "false"), @@ -103,7 +102,10 @@ def test_d03_parts(): kind_css = _src("A00_Common/map/map_draw_kind.css") assert "createSegment({" in kind and kind.count("createInputField(") == 2 assert "columns: 2" in kind and "export function createDrawKindFields(" in kind - assert "createDrawKindFields," in draw_panel and 'from "../A00_Common/map/map_draw_kind"' in draw_panel + assert ( + "createDrawKindFields," in draw_panel + and 'from "../A00_Common/map/map_draw_kind"' in draw_panel + ) assert ".map-draw-kind__fields" in kind_css and "createDrawKindFields(" in draw assert '"길이·기울기 고정"' in kind and '"둘 다"' not in kind assert "d03-plan__hint" not in draw # 칸 설명 글 걷음(요구 463-6) diff --git a/resources/tester/test_584_3_plan_forest_road_zones.py b/resources/tester/test_584_3_plan_forest_road_zones.py index 94cd55249..db841d06d 100644 --- a/resources/tester/test_584_3_plan_forest_road_zones.py +++ b/resources/tester/test_584_3_plan_forest_road_zones.py @@ -360,7 +360,8 @@ def test_screen_defs() -> None: ) assert "createRoadList(" in site and "roads.reload()" in site assert len((folder / "D03_PlanAnalysis_UI_RoadList.ts").read_text("utf-8").splitlines()) <= 700 - assert "임도 짐작" in legend and "올린 임도망도" in legend # 범례 구분 + shared = (folder.parent / "A00_Common" / "map" / "map_legend.ts").read_text("utf-8") + assert "임도 짐작" not in shared and "임도(업로드) ${" in shared # 짐작 걷음(요구 532) assert "이 시도 자료 없음" in legend for name in ( "D03_PlanAnalysis_UI_Layers.ts", diff --git a/resources/tester/test_622_2_forest_layers.py b/resources/tester/test_622_2_forest_layers.py index d758fa61b..c8d074f2c 100644 --- a/resources/tester/test_622_2_forest_layers.py +++ b/resources/tester/test_622_2_forest_layers.py @@ -40,6 +40,14 @@ def test_layer_list_five_off_by_default() -> None: entry = re.search(rf'key: "{key}",\s*icon: "(\w+)",[^}}]*on: (\w+)', defs) assert entry and entry.group(2) == "false", key assert re.search(rf"^\s+{entry.group(1)}:", icons, re.M), entry.group(1) + # 630 — 임도망도 = 짐작 자리 · route 아이콘 · 짐작 겹 걷음 + assert re.search(r'key: "nationalRoad",\s*icon: "route",\s*title:\s*"임도망도\(', defs) + assert 'key: "forestRoad",' not in defs + assert "item(`임도망도 ${label}`" in _read(MAP / "map_forest_layers.ts") + forest = _read(MAP / "map_forest_layers.ts") + assert '"nationalRoad-label"' in forest and "minzoom: 14" in forest # 534 줌인 글 + assert '["get", "year"]' in forest and '"symbol-placement": "line"' in forest + assert "forestRoadLabelSpec()," in _read(MAP / "map_layer_specs.ts") def test_colors_are_draw_map_tokens() -> None: