export function knotsToMs(knots: number): number {
return Math.round(knots * 0.5144 * 10) / 10;
}
export function kmhToMs(kmh: number): number {
return Math.round((kmh / 3.6) * 10) / 10;
}
export function mphToMs(mph: number): number {
return Math.round(mph * 0.4470 * 10) / 10;
}
export function inHgToHpa(inHg: number): number {
return Math.round(inHg * 33.8639 * 10) / 10;
}
export function fToC(f: number): number {
return Math.round(((f - 32) * 5) / 9 * 10) / 10;
}
export function milesToKm(miles: number): number {
return Math.round(miles * 1.60934 * 10) / 10;
}
export function degreesToCardinal(deg: number): string {
const directions = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'];
const index = Math.round(deg / 22.5) % 16;
return directions[index];
}
// WMO Weather interpretation codes (WW)
const wmoDescriptions: Record<number, string> = {
0: 'Clear sky',
1: 'Mainly clear',
2: 'Partly cloudy',
3: 'Overcast',
45: 'Fog',
48: 'Depositing rime fog',
51: 'Light drizzle',
53: 'Moderate drizzle',
55: 'Dense drizzle',
56: 'Light freezing drizzle',
57: 'Dense freezing drizzle',
61: 'Slight rain',
63: 'Moderate rain',
65: 'Heavy rain',
66: 'Light freezing rain',
67: 'Heavy freezing rain',
71: 'Slight snowfall',
73: 'Moderate snowfall',
75: 'Heavy snowfall',
77: 'Snow grains',
80: 'Slight rain showers',
81: 'Moderate rain showers',
82: 'Violent rain showers',
85: 'Slight snow showers',
86: 'Heavy snow showers',
95: 'Thunderstorm',
96: 'Thunderstorm with slight hail',
99: 'Thunderstorm with heavy hail',
};
export function wmoCodeToDescription(code: number): string {
return wmoDescriptions[code] ?? `Unknown (code ${code})`;
}
export function aqiToCategory(aqi: number): string {
if (aqi <= 50) return 'Good';
if (aqi <= 100) return 'Moderate';
if (aqi <= 150) return 'Unhealthy for Sensitive Groups';
if (aqi <= 200) return 'Unhealthy';
if (aqi <= 300) return 'Very Unhealthy';
return 'Hazardous';
}