import type { MeteoStationPosition, SynopStation } from "@/types/imgw"; import type { LocationSearchResult, SelectedLocation } from "@/types/location"; const stationAliases: Record = { gdansk: "gdanskrebiechowo", gorzow: "gorzowwielkopolski", katowice: "katowicemuchowiec", kielce: "kielcesukow", kolo: "koloradoszewice", kolobrzeg: "kolobrzegdzwirzyno", krakow: "krakowbalice", lublin: "lublinradawiec", lodz: "lodzlublinek", poznan: "poznanlawica", resko: "reskosmolsko", rzeszow: "rzeszowjasionka", warszawa: "warszawaokecie", }; function normalizeName(value: string) { return value .replace(/[Łł]/g, "l") .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") .replace(/[^a-zA-Z0-9]/g, "") .toLowerCase(); } function distanceKm(latitudeA: number, longitudeA: number, latitudeB: number, longitudeB: number) { const earthRadiusKm = 6371; const toRadians = (value: number) => value * Math.PI / 180; const latitudeDistance = toRadians(latitudeB - latitudeA); const longitudeDistance = toRadians(longitudeB - longitudeA); const a = Math.sin(latitudeDistance / 2) ** 2 + Math.cos(toRadians(latitudeA)) * Math.cos(toRadians(latitudeB)) * Math.sin(longitudeDistance / 2) ** 2; return earthRadiusKm * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); } export interface LocatedSynopStation extends SynopStation { latitude: number; longitude: number; } export function locateSynopStations(stations: SynopStation[], positions: MeteoStationPosition[]) { const positionsByName = new Map(positions.map((position) => [normalizeName(position.name), position])); return stations.flatMap((station) => { const normalizedStation = normalizeName(station.name); const position = positionsByName.get(stationAliases[normalizedStation] ?? normalizedStation); return position ? [{ ...station, latitude: position.latitude, longitude: position.longitude }] : []; }); } export function findNearestSynopStation(location: LocationSearchResult, stations: LocatedSynopStation[]): SelectedLocation | null { const nearest = stations.reduce<{ station: LocatedSynopStation; distanceKm: number } | null>((best, station) => { const distance = distanceKm(location.latitude, location.longitude, station.latitude, station.longitude); return !best || distance < best.distanceKm ? { station, distanceKm: distance } : best; }, null); if (!nearest) return null; return { name: location.name, province: location.province, stationId: nearest.station.id, stationName: nearest.station.name, distanceKm: Math.round(nearest.distanceKm), }; }