perf(509-1 · 509-3 · 509-6 도엽 등고선 범위 · 화면 밖 건너뜀): 노선 편집 = 노선 띠(저장 노선 bbox + 300 + 여유 300 m)로 자른 도엽 · 배수유역도 = 세부 유역 ∪ 줌아웃 한계 + 300 m 로 따로 자른 도엽(서버 _derived/sheet_<범위> · 사본 지문 + 범위 열쇠) · 띠가 범위 밖인 초안 = 통째 사본 · 미리 받기도 범위본 · 공용 선 그리기 = 같은 쪽 화면 밖 구간 끊음(돌린 화면 = 반 대각선 넓힘) — 요구 317
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -273,7 +273,7 @@ export function drawPreparedFeature(
|
||||
): void {
|
||||
const feature = layer.features[index];
|
||||
if (!feature || feature.kind !== "line") return;
|
||||
drawLineParts(context, feature, affineOf(view));
|
||||
drawLineParts(context, feature, affineOf(view), view, Infinity); // 몇 가닥뿐 — 안 거름
|
||||
}
|
||||
|
||||
/** 점과 선분 사이 거리(px). */
|
||||
@@ -358,9 +358,19 @@ function drawLineParts(
|
||||
context: CanvasRenderingContext2D,
|
||||
feature: PreparedFeature,
|
||||
affine: Affine,
|
||||
view: ViewState,
|
||||
pad: number,
|
||||
): void {
|
||||
// affine.ax = 정규화 1.0당 화면 px — 종횡비 보정 좌표계의 거리를 px로 바꾸는 계수.
|
||||
const tolerance = LOD_PX / affine.ax;
|
||||
// 화면 밖 구간 건너뛰기(509-3) — 두 끝이 **같은 쪽** 화면 밖이면 그 구간은 안 보임 → 선을 끊음.
|
||||
// 한쪽이라도 화면 쪽이거나 서로 다른 쪽(모서리를 질러 갈 수 있음)이면 그대로 그림.
|
||||
const left = -CULL_MARGIN - pad;
|
||||
const top = -CULL_MARGIN - pad;
|
||||
const right = view.width + CULL_MARGIN + pad;
|
||||
const bottom = view.height + CULL_MARGIN + pad;
|
||||
const sideOf = (x: number, y: number): number =>
|
||||
(x < left ? 1 : x > right ? 2 : 0) | (y < top ? 4 : y > bottom ? 8 : 0);
|
||||
for (const part of feature.parts) {
|
||||
const coords = part.coords;
|
||||
if (coords.length < 4) continue;
|
||||
@@ -368,19 +378,51 @@ function drawLineParts(
|
||||
// 현재 줌에서 화면 오차 LOD_PX 미만인 정점만 생략 (끝점은 weight=∞라 항상 유지).
|
||||
// 정점 사이 보간은 하지 않는다 — 원본 데이터의 형상 그대로 표시 (2026-07-28 사용자 지시).
|
||||
context.beginPath();
|
||||
let started = false;
|
||||
let kept = 0;
|
||||
let moves = 0;
|
||||
let fromFirst = false;
|
||||
let penDown = false;
|
||||
let firstX = 0;
|
||||
let firstY = 0;
|
||||
let firstSide = 0;
|
||||
let prevX = 0;
|
||||
let prevY = 0;
|
||||
let prevSide = 0;
|
||||
for (let i = 0; i < coords.length; i += 2) {
|
||||
if (weights && weights[i / 2] < tolerance) continue;
|
||||
const x = coords[i] * affine.ax + affine.bx;
|
||||
const y = coords[i + 1] * affine.ay + affine.by;
|
||||
if (started) context.lineTo(x, y);
|
||||
else {
|
||||
context.moveTo(x, y);
|
||||
started = true;
|
||||
const side = sideOf(x, y);
|
||||
if (kept === 0) {
|
||||
firstX = x;
|
||||
firstY = y;
|
||||
firstSide = side;
|
||||
} else if (side & prevSide) {
|
||||
penDown = false;
|
||||
} else {
|
||||
if (!penDown) {
|
||||
context.moveTo(prevX, prevY);
|
||||
if (moves === 0) fromFirst = kept === 1;
|
||||
moves += 1;
|
||||
}
|
||||
context.lineTo(x, y);
|
||||
penDown = true;
|
||||
}
|
||||
kept += 1;
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
prevSide = side;
|
||||
}
|
||||
if (part.closed && kept > 2) {
|
||||
// 한 줄로 이어졌으면 closePath(모서리 이음 그대로) · 끊겼으면 닫는 구간만 따로.
|
||||
if (moves === 1 && fromFirst && penDown) context.closePath();
|
||||
else if (!(prevSide & firstSide)) {
|
||||
if (!penDown) context.moveTo(prevX, prevY);
|
||||
context.lineTo(firstX, firstY);
|
||||
moves += 1;
|
||||
}
|
||||
}
|
||||
if (!started) continue;
|
||||
if (part.closed) context.closePath();
|
||||
if (moves === 0) continue;
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
@@ -424,8 +466,8 @@ const CULL_MARGIN = 32;
|
||||
const LABEL_GAP_PX = 10;
|
||||
const LABEL_ROW_PX = 14;
|
||||
|
||||
function isVisible(feature: PreparedFeature, affine: Affine, view: ViewState): boolean {
|
||||
const margin = CULL_MARGIN;
|
||||
function isVisible(feature: PreparedFeature, affine: Affine, view: ViewState, pad = 0): boolean {
|
||||
const margin = CULL_MARGIN + pad;
|
||||
const minX = feature.minX * affine.ax + affine.bx;
|
||||
const maxX = feature.maxX * affine.ax + affine.bx;
|
||||
const minY = feature.minY * affine.ay + affine.by;
|
||||
@@ -506,21 +548,25 @@ export function pickLevelStep(
|
||||
*
|
||||
* `everyM` 을 주면 **그 배수의 표고만** 그린다. 1m 간격 LAS 등고선을 멀리서 다 그리면 화면이
|
||||
* 선으로 뭉개져 지형이 안 읽힌다 — 확대에 따라 성긴 등고선부터 내보이려는 것이다. 안 주면
|
||||
* 전부 그리므로 기존 화면(B04 지도·배수유역도)의 표기는 그대로다. */
|
||||
* 전부 그리므로 기존 화면(B04 지도·배수유역도)의 표기는 그대로다.
|
||||
*
|
||||
* `padPx` = 화면 밖 판정을 이만큼 넓힘 — 그림을 돌린 화면(B05 노선 편집)은 모서리가 화면 사각형
|
||||
* 밖에서 들어오므로 반 대각선만큼 준다. */
|
||||
export function drawPreparedLayer(
|
||||
context: CanvasRenderingContext2D,
|
||||
layer: PreparedLayer,
|
||||
view: ViewState,
|
||||
marker: MarkerKind,
|
||||
everyM?: number,
|
||||
padPx = 0,
|
||||
): void {
|
||||
const affine = affineOf(view);
|
||||
const step = everyM !== undefined && everyM > 0 ? everyM : 0;
|
||||
for (const feature of layer.features) {
|
||||
if (step && feature.labelValue !== null && feature.labelValue % step !== 0) continue;
|
||||
if (!isVisible(feature, affine, view)) continue;
|
||||
if (!isVisible(feature, affine, view, padPx)) continue;
|
||||
if (feature.kind === "point") drawPointParts(context, feature, affine, marker);
|
||||
else drawLineParts(context, feature, affine);
|
||||
else drawLineParts(context, feature, affine, view, padPx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user