feat(D03 겹): 노선분석 지도 단층 · 지질구조선 · 0차곡 겹 — 묶음 셋째 · 처음 끔 (PLAN 584-1 · 요구 443)
- 서버: 선 겹 = 브이월드 WFS lt_l_gimsfault · lt_l_gimslinea 받은 범위로 잘라 가닥 · 길이 · 덮으면 다시 안 받음 · 실패 = 502 · 새 선 겹은 LINE_KINDS 한 줄 - 서버: 0차곡 = 사업 DEM 2 m 솎음 D8 흐름누적(웅덩이 메움 · 평지 넘김 · numpy) · 위 집수 0.1~1 ha 칸 세선화 선 · 10 m 미만 토막 거름 · 파생 저장본(격자 지문 · 임계) · 임계 = 요청 min_m2 · max_m2 - 화면: 단추 셋(bolt · lineDashed · arrowsJoin 부품 상자에 더함) · 색 --draw-map-fault · lineament · zero-order · 범례 = 가닥 · km · 첫 셈 늦으면 알림 · 바탕 캔버스 - 선 긋기 · 그림 겹 놓기 · 그림 읽기를 LayerDefs 로 옮김(700줄 한도) - test_553_4: 겹 목록에 faults · lineaments · zeroOrder 더함(새 겹 · 기대 목록 갱신) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
/* =============================================================================
|
||||
* D03_PlanAnalysis_UI_Layers.ts
|
||||
* D03 평면 바탕 겹 켜고 끔(PLAN 569-2 · 581-1 · 581-2 · 요구 395-2 · 440-8 · 442) — 지도 왼쪽 위 아이콘 한 줄
|
||||
* D03 평면 바탕 겹 켜고 끔(PLAN 569-2 · 581-1 · 581-2 · 584-1 · 요구 395-2 · 440-8 · 442 · 443) — 지도 왼쪽 위 아이콘 한 줄
|
||||
* (공용 지도 도구줄 `createMapTools` · 넘치면 가로 밀기 571-1 · 오른쪽 평면 도구줄과 따로).
|
||||
*
|
||||
* 겹 = 바탕(위성 · 음영기복 · 도엽 등고선(계곡선 25 m 굵게 · 수치) · 급경사 색) ·
|
||||
* 물 · 길(세류선 · 하천 · 물 면(실폭하천 · 저수지) · 기존 도로 · 기존 임도 짐작(소로 · 미분류)) ·
|
||||
* 구역(지적도 · 보호 · 규제 구역 여덟 종 · 산림입지도(토양형) · 계류 100 m · 도로 300 m 띠 · 건물 · 지명).
|
||||
* 구역(지적도 · 보호 · 규제 구역 여덟 종 · 산림입지도(토양형) · 선 겹(단층 · 지질구조선 · 0차곡) ·
|
||||
* 계류 100 m · 도로 300 m 띠 · 건물 · 지명).
|
||||
* 처음 켬 = 위성 · 등고선 · 세류 · 고른 값 = 화면 취향(`aislo:pref:d03.layers`) 기억.
|
||||
* 받기 = 켤 때만(한 번 받으면 다시 안 받음) · 지형을 안 받았으면 단추를 막음 · 받기 실패 = 그 겹만 꺼짐 + 알림.
|
||||
* 그리기 차례(아래 → 위) = 위성(`scene.image`) → 음영기복 → 급경사 → 산림입지도 → 보호구역 → 띠 → 지적 → 물 면 →
|
||||
* 건물 → 등고선 → 도로 → 임도 짐작 → 세류 → 지명 → 그은 선.
|
||||
* 건물 → 등고선 → 도로 → 임도 짐작 → 세류 → 선 겹 → 지명 → 그은 선.
|
||||
* 겹 모두 = 바탕 캔버스(`base` · 582) · 등고선 = 줌 단계 색인 · 글 폭 기억.
|
||||
* 범례 = 켠 겹의 받은 범위 안 수 · 넓이(왼쪽 아래).
|
||||
* ========================================================================== */
|
||||
@@ -29,7 +30,6 @@ import {
|
||||
import {
|
||||
createNormalizer,
|
||||
drawPreparedLabels,
|
||||
drawPreparedLayer,
|
||||
lonLatToScreen,
|
||||
pickLevelStep,
|
||||
type GeoJsonCollection,
|
||||
@@ -42,9 +42,11 @@ import {
|
||||
import {
|
||||
fetchPlanBands,
|
||||
fetchPlanCadastral,
|
||||
fetchPlanLines,
|
||||
fetchPlanRaster,
|
||||
fetchPlanSheetLayer,
|
||||
fetchPlanSoils,
|
||||
fetchPlanZeroOrder,
|
||||
fetchPlanZones,
|
||||
type PlanBand,
|
||||
type PlanRaster,
|
||||
@@ -55,20 +57,32 @@ import {
|
||||
FOREST_ROAD_KINDS,
|
||||
GROUPS,
|
||||
LAYERS,
|
||||
LINE_KEYS,
|
||||
LINE_LAYERS,
|
||||
SOIL_COLORS,
|
||||
WATER_KEYS,
|
||||
ZONE_COLORS,
|
||||
drawRaster,
|
||||
fillLayer,
|
||||
hectare,
|
||||
loadImage,
|
||||
stroke,
|
||||
type LineLayerKey,
|
||||
type PlanLayerKey,
|
||||
} from "./D03_PlanAnalysis_UI_LayerDefs";
|
||||
import type { PlanMap, PlanMapLayer, ScreenMap } from "./D03_PlanAnalysis_UI_Map";
|
||||
import type { PlanMap, PlanMapLayer } from "./D03_PlanAnalysis_UI_Map";
|
||||
import type { Vertex } from "./logic/D03_PlanAnalysis_Plan";
|
||||
|
||||
const PREF_KEY = "aislo:pref:d03.layers";
|
||||
/** 등고선을 받아 올 그은 선 둘레(m). */
|
||||
const CONTOUR_PAD_M = 600;
|
||||
interface Prepared {
|
||||
/** 선 겹 — 그릴 선 · 받은 범위 안 가닥 · 길이 m. */
|
||||
interface PreparedLines {
|
||||
layer: PreparedLayer;
|
||||
count: number;
|
||||
length_m: number;
|
||||
}
|
||||
type Prepared = Record<LineLayerKey, PreparedLines> & {
|
||||
contour: PreparedLayer;
|
||||
/** 세류 · 하천(소하천 · 지방하천 · 연결선). */
|
||||
stream: [PreparedLayer, PreparedLayer];
|
||||
@@ -84,7 +98,7 @@ interface Prepared {
|
||||
bands: { stream: PreparedLayer; road: PreparedLayer; info: { stream: PlanBand; road: PlanBand } };
|
||||
building: PreparedLayer;
|
||||
place: Array<{ lon: number; lat: number; name: string }>;
|
||||
}
|
||||
};
|
||||
type DataKey = keyof Prepared;
|
||||
|
||||
/** 겹 → 받는 자료(임도 짐작 = 도로 자료). */
|
||||
@@ -121,14 +135,6 @@ function readPref(): Record<PlanLayerKey, boolean> {
|
||||
return on;
|
||||
}
|
||||
|
||||
const loadImage = (src: string): Promise<HTMLImageElement> =>
|
||||
new Promise((done, fail) => {
|
||||
const image = new Image();
|
||||
image.onload = () => done(image);
|
||||
image.onerror = () => fail(new Error("그림을 읽지 못했습니다"));
|
||||
image.src = src;
|
||||
});
|
||||
|
||||
export function createPlanLayers(opts: {
|
||||
projectId: string;
|
||||
map: PlanMap;
|
||||
@@ -220,6 +226,20 @@ export function createPlanLayers(opts: {
|
||||
},
|
||||
]);
|
||||
}
|
||||
const lines = LINE_KEYS.flatMap((key) => {
|
||||
const got = on[key] && data[key];
|
||||
if (!got) return [];
|
||||
const { label, color, dash } = LINE_LAYERS[key];
|
||||
return [
|
||||
{
|
||||
label: `${label} ${got.count}가닥 ${(got.length_m / 1000).toFixed(2)} km`,
|
||||
color: `var(${color})`,
|
||||
kind: dash.length ? ("dash" as const) : ("line" as const),
|
||||
off: !got.count,
|
||||
},
|
||||
];
|
||||
});
|
||||
if (lines.length) rows.push(lines);
|
||||
const tail: LegendItem[] = [];
|
||||
if (on.water && data.water)
|
||||
tail.push({ label: `물 면 ${data.water.features.length}곳`, color: "var(--draw-map-water)" });
|
||||
@@ -377,6 +397,28 @@ export function createPlanLayers(opts: {
|
||||
})),
|
||||
summary: soils.summary,
|
||||
};
|
||||
} else if (key === "faults" || key === "lineaments" || key === "zeroOrder") {
|
||||
const kind = LINE_LAYERS[key].kind;
|
||||
// 0차곡 첫 셈 = 몇 초 — 늦으면 알림
|
||||
const slow = window.setTimeout(
|
||||
() => showToast(`${LINE_LAYERS[key].label} 셈 중 — 처음 한 번만`, "info"),
|
||||
600,
|
||||
);
|
||||
try {
|
||||
const got = kind
|
||||
? await fetchPlanLines(projectId, kind).then((lines) => ({
|
||||
collection: lines,
|
||||
...lines.summary,
|
||||
}))
|
||||
: await fetchPlanZeroOrder(projectId);
|
||||
data[key] = {
|
||||
layer: prepare(got.collection),
|
||||
count: got.count,
|
||||
length_m: got.length_m,
|
||||
};
|
||||
} finally {
|
||||
window.clearTimeout(slow);
|
||||
}
|
||||
} else if (key === "bands") {
|
||||
const info = await fetchPlanBands(projectId);
|
||||
data.bands = {
|
||||
@@ -396,30 +438,6 @@ export function createPlanLayers(opts: {
|
||||
}
|
||||
}
|
||||
|
||||
const stroke = (
|
||||
context: CanvasRenderingContext2D,
|
||||
map: ScreenMap,
|
||||
layer: PreparedLayer,
|
||||
color: string,
|
||||
width: number,
|
||||
everyM?: number,
|
||||
): void => {
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = width;
|
||||
drawPreparedLayer(context, layer, map.view, "dot", everyM);
|
||||
};
|
||||
|
||||
const drawRaster = (
|
||||
context: CanvasRenderingContext2D,
|
||||
map: ScreenMap,
|
||||
raster: { raster: PlanRaster; image: HTMLImageElement },
|
||||
): void => {
|
||||
const [x0, y0, x1, y1] = raster.raster.box_m;
|
||||
const [left, top] = map.toScreen([x0, y1]);
|
||||
const [right, bottom] = map.toScreen([x1, y0]);
|
||||
context.drawImage(raster.image, left, top, right - left, bottom - top);
|
||||
};
|
||||
|
||||
/** 등고 글 폭 기억(글꼴 하나 · 582). */
|
||||
const labelWidths = new Map<string, number>();
|
||||
const layers: PlanMapLayer[] = [
|
||||
@@ -560,6 +578,18 @@ export function createPlanLayers(opts: {
|
||||
stroke(context, map, data.stream[1], color, 2.4);
|
||||
},
|
||||
},
|
||||
...LINE_KEYS.map((key): PlanMapLayer => ({
|
||||
base: true,
|
||||
draw: (context, map) => {
|
||||
const got = on[key] && data[key];
|
||||
if (!got) return;
|
||||
const { color, width, dash } = LINE_LAYERS[key];
|
||||
context.setLineDash(dash);
|
||||
stroke(context, map, got.layer, "rgba(0, 0, 0, 0.55)", width + 1.6);
|
||||
stroke(context, map, got.layer, themeColor(color, "#f43f5e"), width);
|
||||
context.setLineDash([]);
|
||||
},
|
||||
})),
|
||||
{
|
||||
base: true,
|
||||
draw: (context, map) => {
|
||||
@@ -629,6 +659,17 @@ export function createPlanLayers(opts: {
|
||||
band_road_m2: data.bands.info.road.area_m2,
|
||||
}),
|
||||
...(data.hillshade && { hillshade_px: data.hillshade.image.naturalWidth }),
|
||||
...Object.fromEntries(
|
||||
LINE_KEYS.flatMap((key) => {
|
||||
const got = data[key];
|
||||
return got
|
||||
? [
|
||||
[key, got.count],
|
||||
[`${key}_m`, got.length_m],
|
||||
]
|
||||
: [];
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user