feat(D03 겹): 노선분석 지도 새 겹 일곱 — 음영기복 · 물 면 · 기존 임도 짐작 · 보호 · 규제 구역 · 계류 · 도로 띠 · 건물 · 지명 (PLAN 581-1 · 요구 440-8 · 442)
- 겹 단추 = 공용 지도 도구줄(createMapTools) 한 줄 · 묶음 셋(바탕 · 물 · 길 · 구역) · 넘치면 가로 밀기 · 오른쪽 도구줄 자리 = 겹 줄 폭(--d03-layers-w) - 새 겹 처음 값 = 끔 · 켬끔 기억(aislo:pref:d03.layers) · 받기 실패 = 그 겹만 꺼짐 + 알림 - 범례 = 켠 겹마다 한 줄(급경사 비율 · 보호구역 종류별 곳 · ha · 띠 ha · % · 물 면 · 건물 · 임도 짐작 수) - 면 겹 채움 · 겹 정의 = D03_PlanAnalysis_UI_LayerDefs.ts(700줄 한도로 나눔) - 부품 상자: 아이콘 shield · borderOuter · 그림 색 --draw-map-* 열넷 - 음영기복 빈 칸 투명(HILLSHADE_VERSION 2) - 시험 test_553_4_de_parts 의 D03 겹 단추 대조 고침 — 겹 단추가 createToolbar 에서 공용 지도 도구줄로 · 겹 열셋으로 바뀌어 옛 대조가 낡음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
/* =============================================================================
|
||||
* D03_PlanAnalysis_UI_LayerDefs.ts
|
||||
* D03 바탕 겹 정의(PLAN 569-2 · 581-1) — 겹 단추 묶음 · 처음 값 · 보호구역 색 · 면 겹 채우기.
|
||||
* 부르는 곳 = `D03_PlanAnalysis_UI_Layers.ts`(받기 · 그리기 차례 · 범례).
|
||||
* ========================================================================== */
|
||||
|
||||
import type { IconName } from "@ui/ui_template_icons";
|
||||
import {
|
||||
normalizedToScreen,
|
||||
type PreparedLayer,
|
||||
type ViewState,
|
||||
} from "../B04_PreProcess/B04_PreProcess_UI_MapRender";
|
||||
|
||||
export type PlanLayerKey =
|
||||
| "satellite"
|
||||
| "hillshade"
|
||||
| "contour"
|
||||
| "slope"
|
||||
| "stream"
|
||||
| "water"
|
||||
| "road"
|
||||
| "forestRoad"
|
||||
| "cadastral"
|
||||
| "zones"
|
||||
| "bands"
|
||||
| "building"
|
||||
| "place";
|
||||
|
||||
export interface LayerDef {
|
||||
key: PlanLayerKey;
|
||||
icon: IconName;
|
||||
title: string;
|
||||
on: boolean;
|
||||
}
|
||||
|
||||
/** 단추 묶음(사이 나눔선) — 바탕 · 물 · 길 · 구역. 「지금」 겹 처음 값 = 끔(`_분석_440-C` 1-4). */
|
||||
export const GROUPS: readonly (readonly LayerDef[])[] = [
|
||||
[
|
||||
{ key: "satellite", icon: "satellite", title: "위성사진", on: true },
|
||||
{ key: "hillshade", icon: "sun", title: "음영기복(2 m 지형 · 산줄기 · 골)", on: false },
|
||||
{ key: "contour", icon: "mountain", title: "도엽 등고선(굵은 선 = 계곡선 25 m)", on: true },
|
||||
{ key: "slope", icon: "angle", title: "급경사 색(15° · 35° · 40° 이상)", on: false },
|
||||
],
|
||||
[
|
||||
{ key: "stream", icon: "droplet", title: "세류선(가는 파랑) · 하천(굵은 파랑)", on: true },
|
||||
{ key: "water", icon: "ripple", title: "물 면(도엽 실폭하천 · 저수지 등)", on: false },
|
||||
{ key: "road", icon: "road", title: "기존 도로(도엽 도로중심선)", on: false },
|
||||
{
|
||||
key: "forestRoad",
|
||||
icon: "route",
|
||||
title: "기존 임도 짐작(도엽 도로 소로 · 미분류 = 주황 점선 · 정식 임도망도 아님)",
|
||||
on: false,
|
||||
},
|
||||
],
|
||||
[
|
||||
{ key: "cadastral", icon: "borderAll", title: "지적도(참고용 · 법적 효력 없음)", on: false },
|
||||
{
|
||||
key: "zones",
|
||||
icon: "shield",
|
||||
title: "보호 · 규제 구역(브이월드 여덟 종 · 참고용)",
|
||||
on: false,
|
||||
},
|
||||
{
|
||||
key: "bands",
|
||||
icon: "borderOuter",
|
||||
title: "계류 100 m · 도로 300 m 띠(타당성평가)",
|
||||
on: false,
|
||||
},
|
||||
{ key: "building", icon: "building", title: "건물(도엽 · 하류 민가 · 인가)", on: false },
|
||||
{ key: "place", icon: "mapPin", title: "지명(도엽 계곡 · 령 · 부락)", on: false },
|
||||
],
|
||||
];
|
||||
export const LAYERS: readonly LayerDef[] = GROUPS.flat();
|
||||
/** 보호구역 종류 → 그림 색 값(서버 `ZONE_KINDS` 열쇠). */
|
||||
export const ZONE_COLORS: Record<string, string> = {
|
||||
forest: "--draw-map-zone-forest",
|
||||
baekdu: "--draw-map-zone-baekdu",
|
||||
water: "--draw-map-zone-water",
|
||||
park: "--draw-map-zone-park",
|
||||
heritage: "--draw-map-zone-heritage",
|
||||
wetland: "--draw-map-zone-wetland",
|
||||
wildlife: "--draw-map-zone-wildlife",
|
||||
greenbelt: "--draw-map-zone-greenbelt",
|
||||
};
|
||||
/** 도로 중 기존 임도로 짐작하는 구분. */
|
||||
export const FOREST_ROAD_KINDS = new Set(["소로", "미분류"]);
|
||||
/** 물 면 = 도엽 수계(E) 면 셋. */
|
||||
export const WATER_KEYS = ["실폭하천", "수계면E003", "수계면E005"];
|
||||
|
||||
export const hectare = (m2: number): string => `${(m2 / 10000).toFixed(1)} ha`;
|
||||
|
||||
/** 면 겹 채움 — 지물마다 한 길(evenodd = 구멍) · 화면 밖 지물 거름(돌린 지도 귀퉁이까지 여유). */
|
||||
export function fillLayer(
|
||||
context: CanvasRenderingContext2D,
|
||||
layer: PreparedLayer,
|
||||
view: ViewState,
|
||||
fill: string,
|
||||
alpha: number,
|
||||
edge?: { color: string; width: number; dash?: number[] },
|
||||
): void {
|
||||
const [ox, oy] = normalizedToScreen(view, 0, 0);
|
||||
const [ex, ey] = normalizedToScreen(view, 1, 1);
|
||||
const ax = ex - ox;
|
||||
const ay = ey - oy;
|
||||
const pad = Math.max(view.width, view.height) / 2;
|
||||
context.fillStyle = fill;
|
||||
if (edge) {
|
||||
context.strokeStyle = edge.color;
|
||||
context.lineWidth = edge.width;
|
||||
context.setLineDash(edge.dash ?? []);
|
||||
}
|
||||
for (const feature of layer.features) {
|
||||
if (
|
||||
feature.maxX * ax + ox < -pad ||
|
||||
feature.minX * ax + ox > view.width + pad ||
|
||||
feature.maxY * ay + oy < -pad ||
|
||||
feature.minY * ay + oy > view.height + pad
|
||||
)
|
||||
continue;
|
||||
context.beginPath();
|
||||
for (const { coords } of feature.parts) {
|
||||
context.moveTo(coords[0] * ax + ox, coords[1] * ay + oy);
|
||||
for (let i = 2; i < coords.length; i += 2)
|
||||
context.lineTo(coords[i] * ax + ox, coords[i + 1] * ay + oy);
|
||||
context.closePath();
|
||||
}
|
||||
context.globalAlpha = alpha;
|
||||
context.fill("evenodd");
|
||||
if (edge) {
|
||||
context.globalAlpha = 0.9;
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
context.setLineDash([]);
|
||||
}
|
||||
Reference in New Issue
Block a user