import { EMISSION_FACTORS } from '#shared/emissions' import type { Coord } from '#shared/types' const TRAIN_AVG_KMH = 90 /** * Distance a vol d oiseau entre deux points geographiques en km. * Formule de Haversine, rayon terrestre moyen 6371 km. */ function haversineKm(a: { lat: number, lon: number }, b: { lat: number, lon: number }): number { const toRad = (d: number) => (d * Math.PI) / 180 const R = 6371 const dLat = toRad(b.lat - a.lat) const dLon = toRad(b.lon - a.lon) const s = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(a.lat)) * Math.cos(toRad(b.lat)) * Math.sin(dLon / 2) ** 2 return 2 * R * Math.asin(Math.sqrt(s)) } /** * Fabrique une estimation train quand Transitous ne couvre pas le trajet. * Distance vol d oiseau x 1.2 pour approximer le detour ferroviaire, * vitesse pratique moyenne 90 km/h (compromis TGV/TER), facteur ADEME train * generique. C est un ordre de grandeur, pas un horaire. */ export function estimateTrainTrip( from: { lat: number, lon: number }, to: { lat: number, lon: number }, ) { const straightKm = haversineKm(from, to) // Facteur 1.2 : les voies ferrees suivent rarement une ligne droite. const distanceKm = Math.round(straightKm * 1.2 * 10) / 10 const durationMin = Math.round((distanceKm / TRAIN_AVG_KMH) * 60) const co2Grams = Math.round(distanceKm * EMISSION_FACTORS.train) // Geometrie ligne droite [depart, arrivee] pour que la carte affiche // quelque chose de coherent avec l estimation textuelle. const geometry: Coord[] = [[from.lon, from.lat], [to.lon, to.lat]] return { mode: 'train' as const, distanceKm, durationMin, co2Grams, geometry, estimated: true, } }