Files
Aislo/resources/tester/helper_509_3_offscreen_skip.cjs
T

204 lines
5.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 509-3 공용 선 그리기 화면 밖 구간 건너뛰기 헬퍼 — `B04_PreProcess_UI_MapRender.ts` 의
* `drawPreparedLayer` 를 가짜 캔버스로 돌려 그린 구간 · 호출 수를 JSON 으로 낸다.
* 판정 = 화면(+ 여백)에 걸치는 원래 구간이 모두 그려졌나 · 화면 밖 구간은 줄었나.
*/
const path = require("path");
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const ROOT = path.join(__dirname, "..", "..");
const { load } = makeLoader({ root: ROOT, ui: () => ({ themeColor: () => "" }) });
const render = load("B04_PreProcess", "B04_PreProcess_UI_MapRender.ts");
const W = 800;
const H = 600;
const VIEW = {
width: W,
height: H,
scale: 1,
offsetX: 0,
offsetY: 0,
mapRect: { x: 0, y: 0, width: W, height: H },
};
/** 그린 선분을 모으는 가짜 캔버스. */
function fakeContext() {
const calls = { moveTo: 0, lineTo: 0, stroke: 0, closePath: 0 };
const segments = [];
let start = null;
let pen = null;
return {
calls,
segments,
beginPath() {
start = pen = null;
},
moveTo(x, y) {
calls.moveTo += 1;
start = pen = [x, y];
},
lineTo(x, y) {
calls.lineTo += 1;
segments.push([pen, [x, y]]);
pen = [x, y];
},
closePath() {
calls.closePath += 1;
segments.push([pen, start]);
pen = start;
},
stroke() {
calls.stroke += 1;
},
};
}
/** 화면 px 점렬 → 한 피처 레이어(정규 좌표 = px / 화면 크기 · weights 없음 = 다 그림). */
function layerOf(points, closed = false) {
const coords = [];
points.forEach(([x, y]) => coords.push(x / W, y / H));
const xs = points.map((p) => p[0] / W);
const ys = points.map((p) => p[1] / H);
return {
features: [
{
kind: "line",
parts: [{ coords: Float64Array.from(coords), closed, weights: null }],
minX: Math.min(...xs),
maxX: Math.max(...xs),
minY: Math.min(...ys),
maxY: Math.max(...ys),
labelAnchorX: 0,
labelAnchorY: 0,
labelText: null,
labelValue: null,
},
],
};
}
/** 선분이 사각형(여백 32)에 걸치나 — Liang–Barsky. */
function touches([a, b], m = 32) {
let t0 = 0;
let t1 = 1;
const dx = b[0] - a[0];
const dy = b[1] - a[1];
const edges = [
[-dx, a[0] + m],
[dx, W + m - a[0]],
[-dy, a[1] + m],
[dy, H + m - a[1]],
];
for (const [p, q] of edges) {
if (p === 0) {
if (q < 0) return false;
continue;
}
const t = q / p;
if (p < 0) t0 = Math.max(t0, t);
else t1 = Math.min(t1, t);
if (t0 > t1) return false;
}
return true;
}
const key = ([a, b]) => [a, b].map((p) => p.map((v) => v.toFixed(6)).join(",")).join(">");
function run(points, closed = false, pad = 0) {
const context = fakeContext();
render.drawPreparedLayer(context, layerOf(points, closed), VIEW, "dot", undefined, pad);
const drawn = new Set(context.segments.map(key));
const rev = new Set(context.segments.map(([a, b]) => key([b, a])));
const original = [];
for (let i = 1; i < points.length; i += 1) original.push([points[i - 1], points[i]]);
if (closed) original.push([points[points.length - 1], points[0]]);
const visible = original.filter((segment) => touches(segment));
const missing = visible.filter((s) => !drawn.has(key(s)) && !rev.has(key(s))).length;
return { calls: context.calls, drawn: context.segments.length, visible: visible.length, missing };
}
// 1) 다 화면 안 — 예전과 같음(moveTo 1 · lineTo n-1 · stroke 1).
const inside = run([
[100, 100],
[200, 150],
[300, 120],
[400, 300],
]);
// 2) 화면 밖 왼쪽으로 길게 돌다 돌아옴 — 밖 구간은 안 그림 · 보이는 구간 다 그림.
const wander = [[400, 300]];
for (let i = 0; i < 200; i += 1) wander.push([-100 - (i % 7) * 10, 300 + i]);
wander.push([400, 500]);
const leftLoop = run(wander);
// 3) 왼쪽 밖 → 아래 밖(모서리를 질러 감) — 쪽이 다르면 그대로 그림.
const corner = run([
[-50, 300],
[300, 700],
]);
// 4) 닫힌 고리 다 안 = closePath · 일부 밖 = 닫는 구간 따로.
const ringIn = run(
[
[100, 100],
[300, 100],
[300, 300],
[100, 300],
],
true,
);
const ringOut = run(
[
[100, 100],
[-200, 100],
[-200, 300],
[100, 300],
],
true,
);
// 5) 다 밖(한쪽) = 안 그림(stroke 0).
const allOut = run([
[-200, 10],
[-300, 200],
[-250, 500],
]);
// 6) 넓힘(pad) = 무한이면 하나도 안 거름(고른 등고선 덧그리기).
const padded = run(wander, false, Infinity);
// 7) 무작위 선 500 가닥 — 보이는 구간 빠짐 0.
let seed = 7;
const rand = () => ((seed = (seed * 16807) % 2147483647) / 2147483647) * 2 - 0.5;
let randomMissing = 0;
let randomDrawn = 0;
let randomTotal = 0;
for (let n = 0; n < 500; n += 1) {
const points = [];
let x = rand() * W * 2;
let y = rand() * H * 2;
for (let i = 0; i < 40; i += 1) {
x += (rand() - 0.25) * 200;
y += (rand() - 0.25) * 200;
points.push([x, y]);
}
const result = run(points, n % 5 === 0);
randomMissing += result.missing;
randomDrawn += result.drawn;
randomTotal += points.length - (n % 5 === 0 ? 0 : 1);
}
console.log(
JSON.stringify({
inside,
leftLoop,
corner,
ringIn,
ringOut,
allOut,
padded,
randomMissing,
randomDrawn,
randomTotal,
}),
);