- 새 logic/B05_Profile_RouteEdit_Fit(unionArea · fitAreaToView) — 옛 _Visible 자리 - _RouteEdit_Cover 지움 · View · CurveBar · CSS 의 덮인 높이 따라가기 걷음(345-5 덧 · 덧 2) - 글판 · 도움말 접기(덧 3)는 그대로 - 시험: test_345_5b_plan_visible_area 3 고쳐 씀 · test_345_5c 자리 줄 고침 · 관련 86 통과 · typecheck 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Se7ytqbohmBQnfYpwYFnYf
69 lines
2.6 KiB
TypeScript
69 lines
2.6 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile_RouteEdit_Fit.ts
|
|
* 노선 편집 평면의 **처음 그림 · [맞춤]**(349-0) — 등고 영역(등고선 범위 ∪ 노선)을 칸 가운데에
|
|
* 알맞게(꽉 차지 않게 · 둘레 여유) 넣는 배율 · 이동량.
|
|
*
|
|
* 뜬 종단 판은 없다고 보고 칸 전체 기준 — 판은 위에 덮이기만 한다(다시 맞추지 않음).
|
|
* 영역은 도엽 정규화 좌표(0~1 · y 는 위가 0 · `PreparedFeature` 와 같은 꼴).
|
|
* ========================================================================== */
|
|
|
|
/** 칸에서 등고 영역이 차지하는 몫 — 나머지가 둘레 여유. */
|
|
export const AREA_FILL = 0.85;
|
|
|
|
export interface NormalizedArea {
|
|
minX: number;
|
|
minY: number;
|
|
maxX: number;
|
|
maxY: number;
|
|
}
|
|
|
|
export interface FitInput {
|
|
/** 배율 1 일 때 도엽이 놓이는 칸 안 사각형(`computeMapRect`). */
|
|
mapRect: { x: number; y: number; width: number; height: number };
|
|
/** 칸 크기(px). */
|
|
width: number;
|
|
height: number;
|
|
area: NormalizedArea;
|
|
/** 배율 하한 · 상한(지도 조작과 같은 값). */
|
|
minScale: number;
|
|
maxScale: number;
|
|
}
|
|
|
|
/** 영역들을 하나로 — 빈 목록이면 null. */
|
|
export function unionArea(areas: ReadonlyArray<NormalizedArea | null>): NormalizedArea | null {
|
|
let union: NormalizedArea | null = null;
|
|
// 등고선 가닥이 수만 개일 수 있음 — 펼쳐 넘기지 않고 하나씩.
|
|
for (const area of areas) {
|
|
if (!area) continue;
|
|
union = union
|
|
? {
|
|
minX: Math.min(union.minX, area.minX),
|
|
minY: Math.min(union.minY, area.minY),
|
|
maxX: Math.max(union.maxX, area.maxX),
|
|
maxY: Math.max(union.maxY, area.maxY),
|
|
}
|
|
: { minX: area.minX, minY: area.minY, maxX: area.maxX, maxY: area.maxY };
|
|
}
|
|
return union;
|
|
}
|
|
|
|
/** 영역이 칸 가운데 `AREA_FILL` 몫으로 들도록 배율 · 이동량. */
|
|
export function fitAreaToView(input: FitInput): {
|
|
scale: number;
|
|
offsetX: number;
|
|
offsetY: number;
|
|
} {
|
|
const { mapRect, width, height, area } = input;
|
|
const areaWidth = Math.max((area.maxX - area.minX) * mapRect.width, 1e-6);
|
|
const areaHeight = Math.max((area.maxY - area.minY) * mapRect.height, 1e-6);
|
|
const fit = AREA_FILL * Math.min(width / areaWidth, height / areaHeight);
|
|
const scale = Math.min(input.maxScale, Math.max(input.minScale, fit));
|
|
const baseX = mapRect.x + ((area.minX + area.maxX) / 2) * mapRect.width;
|
|
const baseY = mapRect.y + ((area.minY + area.maxY) / 2) * mapRect.height;
|
|
return {
|
|
scale,
|
|
offsetX: -(baseX - width / 2) * scale,
|
|
offsetY: -(baseY - height / 2) * scale,
|
|
};
|
|
}
|