/** Great-circle interpolation for Pressure Front arcs (spherical linear interpolation, N points). */ export function greatCircle(from: [number, number], to: [number, number], n = 64): [number, number][] { const toRad = Math.PI / 180; const toDeg = 180 / Math.PI; const [lon1, lat1] = [from[0] * toRad, from[1] * toRad]; const [lon2, lat2] = [to[0] * toRad, to[1] * toRad]; const d = 2 * Math.asin(Math.sqrt(Math.sin((lat2 - lat1) / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin((lon2 - lon1) / 2) ** 2)); if (d === 0) return [from, to]; const pts: [number, number][] = []; for (let i = 0; i <= n; i++) { const f = i / n; const A = Math.sin((1 - f) * d) / Math.sin(d); const B = Math.sin(f * d) / Math.sin(d); const x = A * Math.cos(lat1) * Math.cos(lon1) + B * Math.cos(lat2) * Math.cos(lon2); const y = A * Math.cos(lat1) * Math.sin(lon1) + B * Math.cos(lat2) * Math.sin(lon2); const z = A * Math.sin(lat1) + B * Math.sin(lat2); const lat = Math.atan2(z, Math.sqrt(x * x + y * y)) * toDeg; let lon = Math.atan2(y, x) * toDeg; // keep the line continuous when it would cross the antimeridian if (pts.length) { const prev = pts[pts.length - 1]![0]; if (lon - prev > 180) lon -= 360; else if (prev - lon > 180) lon += 360; } pts.push([lon, lat]); } return pts; }