export type LatLng = { lat: number; lng: number } /** * Storsirkel-avstand mellom to koordinater, i meter. Ren klient-side * beregning -- ingen Mapbox-kall (ADR-048 kostnadskontroll-invariant B). */ export function haversineMeters(a: LatLng, b: LatLng): number { const R = 6371000 const toRad = (d: number) => (d * Math.PI) / 180 const dLat = toRad(b.lat - a.lat) const dLng = toRad(b.lng - a.lng) const h = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(a.lat)) * Math.cos(toRad(b.lat)) * Math.sin(dLng / 2) ** 2 return 2 * R * Math.asin(Math.sqrt(h)) } /** * Retningsvinkel (kompassgrader, 0-360, 0 = nord) fra a til b. Brukes til å * rotere slagmålings-kartet slik at "opp på skjermen" følger spillerens * egen gangretning på hullet, uten å trenge lagrede green-koordinater -- * se bearingForShotMap() i shot-measurement-sheet.tsx. */ export function bearingDegrees(a: LatLng, b: LatLng): number { const toRad = (d: number) => (d * Math.PI) / 180 const toDeg = (r: number) => (r * 180) / Math.PI const lat1 = toRad(a.lat) const lat2 = toRad(b.lat) const dLng = toRad(b.lng - a.lng) const y = Math.sin(dLng) * Math.cos(lat2) const x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLng) return (toDeg(Math.atan2(y, x)) + 360) % 360 }