/* ============================================================================= * 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 { 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, }; }