import type { Point } from '../types'; export function pointInPolygon(p: Point, poly: Point[]): boolean { if (poly.length < 3) return true; let inside = false; for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) { const a = poly[i]; const b = poly[j]; if (onSegment(a, b, p)) return true; const intersect = a.y > p.y !== b.y > p.y && p.x < ((b.x - a.x) * (p.y - a.y)) / (b.y - a.y) + a.x; if (intersect) inside = !inside; } return inside; } function onSegment(a: Point, b: Point, p: Point): boolean { const cross = (b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x); if (Math.abs(cross) > 1e-9) return false; const dot = (p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y); if (dot < 0) return false; const len2 = (b.x - a.x) ** 2 + (b.y - a.y) ** 2; return dot <= len2; } function closestOnSegment(a: Point, b: Point, p: Point): Point { const dx = b.x - a.x; const dy = b.y - a.y; const len2 = dx * dx + dy * dy; if (len2 === 0) return { ...a }; let t = ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2; t = Math.max(0, Math.min(1, t)); return { x: a.x + t * dx, y: a.y + t * dy }; } export function nearestPointInPolygon(p: Point, poly: Point[]): Point { if (poly.length < 3) return { ...p }; if (pointInPolygon(p, poly)) return { ...p }; let best = poly[0]; let bestD = Infinity; for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) { const q = closestOnSegment(poly[j], poly[i], p); const d = (q.x - p.x) ** 2 + (q.y - p.y) ** 2; if (d < bestD) { bestD = d; best = q; } } return best; } export function rectanglePoints(width: number, height: number): Point[] { return [ { x: 0, y: 0 }, { x: width, y: 0 }, { x: width, y: height }, { x: 0, y: height }, ]; }