| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| export interface PriorityCountryInfo { |
| name: string; |
| pop: number; |
| area: number; |
| } |
|
|
| export interface ExposureEstimate { |
| exposedPopulation: number; |
| exposureRadiusKm: number; |
| nearestCountry: string; |
| densityPerKm2: number; |
| } |
|
|
| export interface CountryPopulation { |
| code: string; |
| name: string; |
| population: number; |
| densityPerKm2: number; |
| } |
|
|
| export const PRIORITY_COUNTRIES: Record<string, PriorityCountryInfo> = { |
| UKR: { name: 'Ukraine', pop: 37000000, area: 603550 }, |
| RUS: { name: 'Russia', pop: 144100000, area: 17098242 }, |
| ISR: { name: 'Israel', pop: 9800000, area: 22072 }, |
| PSE: { name: 'Palestine', pop: 5400000, area: 6020 }, |
| SYR: { name: 'Syria', pop: 22100000, area: 185180 }, |
| IRN: { name: 'Iran', pop: 88600000, area: 1648195 }, |
| TWN: { name: 'Taiwan', pop: 23600000, area: 36193 }, |
| ETH: { name: 'Ethiopia', pop: 126500000, area: 1104300 }, |
| SDN: { name: 'Sudan', pop: 48100000, area: 1861484 }, |
| SSD: { name: 'South Sudan', pop: 11400000, area: 619745 }, |
| SOM: { name: 'Somalia', pop: 18100000, area: 637657 }, |
| YEM: { name: 'Yemen', pop: 34400000, area: 527968 }, |
| AFG: { name: 'Afghanistan', pop: 42200000, area: 652230 }, |
| PAK: { name: 'Pakistan', pop: 240500000, area: 881913 }, |
| IND: { name: 'India', pop: 1428600000, area: 3287263 }, |
| MMR: { name: 'Myanmar', pop: 54200000, area: 676578 }, |
| COD: { name: 'DR Congo', pop: 102300000, area: 2344858 }, |
| NGA: { name: 'Nigeria', pop: 223800000, area: 923768 }, |
| MLI: { name: 'Mali', pop: 22600000, area: 1240192 }, |
| BFA: { name: 'Burkina Faso', pop: 22700000, area: 274200 }, |
| }; |
|
|
| export const EXPOSURE_CENTROIDS: Record<string, [number, number]> = { |
| UKR: [48.4, 31.2], RUS: [61.5, 105.3], ISR: [31.0, 34.8], PSE: [31.9, 35.2], |
| SYR: [35.0, 38.0], IRN: [32.4, 53.7], TWN: [23.7, 121.0], ETH: [9.1, 40.5], |
| SDN: [15.5, 32.5], SSD: [6.9, 31.3], SOM: [5.2, 46.2], YEM: [15.6, 48.5], |
| AFG: [33.9, 67.7], PAK: [30.4, 69.3], IND: [20.6, 79.0], MMR: [19.8, 96.7], |
| COD: [-4.0, 21.8], NGA: [9.1, 7.5], MLI: [17.6, -4.0], BFA: [12.3, -1.6], |
| }; |
|
|
| const FALLBACK_INFO: PriorityCountryInfo = { name: '', pop: 50_000_000, area: 500_000 }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export const MAX_EXPOSURE_RADIUS_KM = 1000; |
|
|
| export function computeExposure(lat: number, lon: number, radiusKm: number): ExposureEstimate { |
| const effectiveRadiusKm = Math.max(0, Number.isFinite(radiusKm) ? radiusKm : 0); |
| let bestMatch: string | null = null; |
| let bestDist = Infinity; |
|
|
| for (const [code, [cLat, cLon]] of Object.entries(EXPOSURE_CENTROIDS)) { |
| const dist = Math.sqrt((lat - cLat) ** 2 + (lon - cLon) ** 2); |
| if (dist < bestDist) { |
| bestDist = dist; |
| bestMatch = code; |
| } |
| } |
|
|
| const info = bestMatch ? PRIORITY_COUNTRIES[bestMatch] ?? FALLBACK_INFO : FALLBACK_INFO; |
| const density = info.pop / info.area; |
| const areaKm2 = Math.PI * effectiveRadiusKm * effectiveRadiusKm; |
|
|
| return { |
| exposedPopulation: Math.round(density * areaKm2), |
| exposureRadiusKm: effectiveRadiusKm, |
| nearestCountry: bestMatch || '', |
| densityPerKm2: Math.round(density), |
| }; |
| } |
|
|
| export function computeBoundedExposure( |
| lat: number, |
| lon: number, |
| radiusKm: number, |
| ): ExposureEstimate { |
| const boundedRadiusKm = Number.isFinite(radiusKm) |
| ? Math.min(MAX_EXPOSURE_RADIUS_KM, Math.max(0, radiusKm)) |
| : 0; |
| return computeExposure(lat, lon, boundedRadiusKm); |
| } |
|
|
| export function getRadiusForEventType(type: string): number { |
| switch (type) { |
| case 'conflict': |
| case 'battle': |
| case 'state-based': |
| case 'non-state': |
| case 'one-sided': |
| return 50; |
| case 'earthquake': |
| return 100; |
| case 'flood': |
| return 100; |
| case 'fire': |
| case 'wildfire': |
| return 30; |
| default: |
| return 50; |
| } |
| } |
|
|
| export function listCountryPopulations(): CountryPopulation[] { |
| return Object.entries(PRIORITY_COUNTRIES).map(([code, info]) => ({ |
| code, |
| name: info.name, |
| population: info.pop, |
| densityPerKm2: Math.round(info.pop / info.area), |
| })); |
| } |
|
|