import type { ScreenRect } from "./types"; export type ScreenPoint = { x: number; y: number }; /** Returns corners in northwest, northeast, southwest, southeast order. */ export function rotatedRectCorners(rect: ScreenRect, rotation: number): [ScreenPoint, ScreenPoint, ScreenPoint, ScreenPoint] { if (!Number.isFinite(rotation)) rotation = 0; const center = { x: rect.x + rect.w / 2, y: rect.y + rect.h / 2 }; const cosine = Math.cos(rotation); const sine = Math.sin(rotation); const rotate = (point: ScreenPoint): ScreenPoint => { const x = point.x - center.x; const y = point.y - center.y; return { x: center.x + x * cosine - y * sine, y: center.y + x * sine + y * cosine }; }; return [ rotate({ x: rect.x, y: rect.y }), rotate({ x: rect.x + rect.w, y: rect.y }), rotate({ x: rect.x, y: rect.y + rect.h }), rotate({ x: rect.x + rect.w, y: rect.y + rect.h }), ]; } /** Axis-aligned screen bounds used to constrain WebGL scissoring around a rotated quad. */ export function rotatedRectBounds(rect: ScreenRect, rotation: number): ScreenRect { if (rotation === 0) return rect; const points = rotatedRectCorners(rect, rotation); const xs = points.map((point) => point.x); const ys = points.map((point) => point.y); const x = Math.min(...xs); const y = Math.min(...ys); return { x, y, w: Math.max(...xs) - x, h: Math.max(...ys) - y }; }