"use strict"; function round2(x) { return Math.round(x * 100) / 100; } const DEG2RAD = Math.PI / 180; const EARTH_RADIUS_KM = 6371.0088; // IUGG mean radius function haversineKm(lat1, lon1, lat2, lon2) { const dLat = (lat2 - lat1) * DEG2RAD; const dLon = (lon2 - lon1) * DEG2RAD; const la1 = lat1 * DEG2RAD; const la2 = lat2 * DEG2RAD; const a = Math.sin(dLat / 2) ** 2 + Math.cos(la1) * Math.cos(la2) * Math.sin(dLon / 2) ** 2; const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return EARTH_RADIUS_KM * c; } module.exports = { slug: "great-circle-distance-haversine", title: "Great-circle distance (haversine)", deck_category: "astronomy", description: "Computes the great-circle distance between two latitude/longitude points using the haversine formula.", inputs: [ { name: "lat1", type: "number", unit: "degrees", required: true, description: "Latitude of point 1.", min: -90, max: 90 }, { name: "lon1", type: "number", unit: "degrees", required: true, description: "Longitude of point 1.", min: -180, max: 180 }, { name: "lat2", type: "number", unit: "degrees", required: true, description: "Latitude of point 2.", min: -90, max: 90 }, { name: "lon2", type: "number", unit: "degrees", required: true, description: "Longitude of point 2.", min: -180, max: 180 } ], outputs: [ { name: "distance_km", unit: "km", description: "Great-circle distance between the two points." } ], steps: [ "Convert both points' latitudes and longitudes to radians.", "Haversine formula: a = sin^2(dLat/2) + cos(lat1)*cos(lat2)*sin^2(dLon/2), where dLat and dLon are the differences in latitude and longitude.", "c = 2 * atan2(sqrt(a), sqrt(1-a)).", "distance = R * c, where R is the mean Earth radius, 6371.0088 km (IUGG).", "Round to 2 decimals.", "This treats Earth as a sphere; true geodesic distance on the actual ellipsoid can differ by a small fraction of a percent." ], constants: [ { name: "mean_earth_radius_km", value: 6371.0088, unit: "km", source: 0 } ], sources: [ { kind: "doi", value: "Moritz, H. (2000). Geodetic Reference System 1980. Journal of Geodesy, 74(1), 128-133.", title: "Geodetic Reference System 1980 (IUGG mean Earth radius)", publisher: "International Union of Geodesy and Geophysics (IUGG)", retrieved_utc: "2026-09-30T19:44:00Z", note: "Source of the 6371.0088 km IUGG mean Earth radius." } ], disclaimer: null, questionText(inputs) { return `What is the great-circle distance between (${inputs.lat1}, ${inputs.lon1}) and (${inputs.lat2}, ${inputs.lon2})?`; }, run(inputs) { const { lat1, lon1, lat2, lon2 } = inputs || {}; for (const [name, v] of Object.entries({ lat1, lon1, lat2, lon2 })) { if (typeof v !== "number" || Number.isNaN(v)) throw new Error(`${name} must be a number`); } const d = round2(haversineKm(lat1, lon1, lat2, lon2)); return { answer: `${d.toFixed(2)} km`, values: { distance_km: d } }; }, examples: [ { name: "worked example", inputs: { lat1: 51.5074, lon1: -0.1278, lat2: 48.8566, lon2: 2.3522 }, expected: { answer: "343.56 km" }, check: "London to Paris is commonly cited as about 344 km great-circle distance; the computed 343.56 km matches that commonly cited figure to within a kilometer." }, { name: "test vector: quarter of the equator", inputs: { lat1: 0, lon1: 0, lat2: 0, lon2: 90 }, expected: { answer: "10007.56 km" }, check: "Two points on the equator 90 degrees of longitude apart are exactly a quarter of the equatorial great circle apart, so the distance must equal (pi/2) * R = 1.5707963268 * 6371.0088 = 10007.56 km, which the formula reproduces analytically." } ] };