import type { Coord, Route } from './types';
const OSRM_URL = 'https://router.project-osrm.org/route/v1/driving/';
export async function fetchRoute(from: Coord, to: Coord, signal?: AbortSignal): Promise<Route> {
try {
const path = `${from.longitude},${from.latitude};${to.longitude},${to.latitude}`;
const res = await fetch(`${OSRM_URL}${path}?overview=full&geometries=geojson`, { signal });
if (!res.ok) throw new Error(`Routing failed (${res.status})`);
const data = await res.json();
const route = data.routes?.[0];
if (!route) throw new Error('No route found');
return {
coordinates: route.geometry.coordinates.map(([longitude, latitude]: [number, number]) => ({ latitude, longitude })),
distanceMeters: route.distance,
durationSeconds: route.duration,
approximate: false,
};
} catch (err) {
if (signal?.aborted) throw err;
return straightLineRoute(from, to);
}
}
function straightLineRoute(from: Coord, to: Coord): Route {
const distanceMeters = haversineMeters(from, to);
const averageSpeedMetersPerSecond = 30_000 / 3600;
return {
coordinates: [from, to],
distanceMeters,
durationSeconds: distanceMeters / averageSpeedMetersPerSecond,
approximate: true,
};
}
function haversineMeters(a: Coord, b: Coord): number {
const R = 6_371_000;
const toRad = (deg: number) => (deg * Math.PI) / 180;
const dLat = toRad(b.latitude - a.latitude);
const dLon = toRad(b.longitude - a.longitude);
const h = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(a.latitude)) * Math.cos(toRad(b.latitude)) * Math.sin(dLon / 2) ** 2;
return 2 * R * Math.asin(Math.sqrt(h));
}