Files
Aislo/resources/tester/helper_281_1_drainage_zoom_range.cjs
T
eomsangdonandClaude Sonnet 5.5 156ce1cf52 test(508-1b 옛 헬퍼 공용 불러오기 3/7): 헬퍼 28 곳 loadTs 베낌 걷고 makeLoader 로
- 헬퍼 동작 그대로(풀이 함수 본문은 옮겨 담음) · 제품 코드 안 고침
- 확인: 이 묶음 헬퍼를 쓰는 시험 218 개 전 218 통과 → 후 218 통과 (시험별 junit 대조 · 어긋남 0)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 17:08:08 +09:00

121 lines
3.8 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.
/* 281-1 배수유역 지도 줌아웃 한계 헬퍼 — `B05_Profile_UI_Drainage_ZoomRange.ts` 를
* 그 자리에서 트랜스파일해 Node 로 돌리고 값을 JSON 으로 낸다.
* `.cjs` 까닭은 `helper_b05_curve_radius_floor.cjs` 와 같다.
*/
const fs = require("fs");
const path = require("path");
const { makeLoader } = require("./helper_ts_stub_loader.cjs");
const ROOT = path.join(__dirname, "..", "..");
/** TS 한 장을 CommonJS 로 옮겨 실행한다. `@ui/` 는 색 함수만 쓰므로 빈 값으로 갈음한다. */
const { loadTs } = makeLoader({
root: ROOT,
requireFor: (full) => (request) => {
if (request.startsWith(".")) return loadTs(path.join(path.dirname(full), `${request}.ts`));
if (request.startsWith("@ui/")) return { themeColor: () => "" };
return require(request);
},
});
const zoom = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_Drainage_ZoomRange.ts"));
const render = loadTs(path.join(ROOT, "B04_PreProcess", "B04_PreProcess_UI_MapRender.ts"));
const { computeZoomOutLimit, clampWheelScale, ZOOM_OUT_ROUTE_FACTOR, ZOOM_OUT_FALLBACK_SCALE } =
zoom;
// 도엽 4000 × 3000 m — 경위도는 1 도 = 1000 m 로 단순하게 둔다.
const META = {
x_min: 0,
x_max: 4000,
y_min: 0,
y_max: 3000,
width_meters: 4000,
height_meters: 3000,
lon_min: 127,
lon_max: 131,
lat_min: 36,
lat_max: 39,
};
const W = 800;
const H = 600; // 도엽과 같은 비율 — 배율 1 = 화면 폭 4000 m
const toLonLat = (x, y) => [127 + x / 1000, 36 + y / 1000];
/** 배율 s 에서 화면 폭에 드는 실폭(m). */
const viewWidthM = (s) => 4000 / s;
// 노선 1000 × 500 m (가운데 2000, 1500) — 2 배 = 2000 × 1000 m.
const ROUTE = [
{ x: 1500, y: 1250 },
{ x: 2500, y: 1750 },
];
const routeOnly = computeZoomOutLimit(META, ROUTE, [], W, H);
// 유역이 노선 2 배 범위 밖(서쪽 400 m 까지)으로 나감 → 폭 2600 m.
const basinOut = computeZoomOutLimit(
META,
ROUTE,
[{ polygon_lonlat: [toLonLat(400, 1500), toLonLat(1500, 1400), toLonLat(1500, 1600)] }],
W,
H,
);
// 유역이 2 배 범위 안 → 한계 그대로.
const basinIn = computeZoomOutLimit(
META,
ROUTE,
[{ polygon_lonlat: [toLonLat(1800, 1400), toLonLat(2200, 1400), toLonLat(2000, 1600)] }],
W,
H,
);
// 노선이 도엽만큼 길면 2 배가 도엽보다 큼 → 도엽 전체(배율 1)에서 멈춤.
const wide = computeZoomOutLimit(
META,
[
{ x: 100, y: 100 },
{ x: 3900, y: 2900 },
],
[],
W,
H,
);
// 짧은 노선(100 m) — 2 배(200 m)가 처음 보기(노선 + 200 m 여유 양쪽)보다 좁음 → 처음 보기에 맞춤.
const SHORT = [
{ x: 1950, y: 1500 },
{ x: 2050, y: 1500 },
];
const short = computeZoomOutLimit(META, SHORT, [], W, H);
const shortInitial = render.computeRouteView(
META,
{ x_min: 1950, x_max: 2050, y_min: 1500, y_max: 1500 },
W,
H,
).scale;
// 휠 — 밀기(×0.87)를 계속하면 한계에서 멈춤 · 당기기(×1.15)는 상한에서 멈춤.
let scale = 3;
for (let i = 0; i < 40; i += 1) scale = clampWheelScale(scale * 0.87, scale, routeOnly, 200);
const wheelOutStop = scale;
for (let i = 0; i < 80; i += 1) scale = clampWheelScale(scale * 1.15, scale, routeOnly, 200);
const wheelInStop = scale;
// 이미 한계 밖(더 멀리)에 있으면 밀어도 더 안 빠지고 튀지도 않음.
const outside = clampWheelScale(1.2 * 0.87, 1.2, routeOnly, 200);
process.stdout.write(
JSON.stringify({
factor: ZOOM_OUT_ROUTE_FACTOR,
fallbackConst: ZOOM_OUT_FALLBACK_SCALE,
routeOnly,
routeOnlyViewM: viewWidthM(routeOnly),
basinOutViewM: viewWidthM(basinOut),
basinIn,
noRoute: computeZoomOutLimit(META, [], [], W, H),
noMeta: computeZoomOutLimit(null, ROUTE, [], W, H),
wide,
short,
shortInitial,
wheelOutStop,
wheelInStop,
outside,
}),
);