/** * Static geographic hierarchy lookup — no API calls, works offline. * * Provides continent/country bounding-box lookups and breadcrumb generation * for semantic zoom on the map and calendar views. */ // ── Continent definitions ── interface BoundingBox { name: string; latMin: number; latMax: number; lngMin: number; lngMax: number; } interface CountryDef extends BoundingBox { continent: string; area: number; // approx sq degrees for specificity sorting } export const CONTINENTS: BoundingBox[] = [ { name: "Europe", latMin: 35, latMax: 72, lngMin: -25, lngMax: 45 }, { name: "Asia", latMin: -10, latMax: 75, lngMin: 45, lngMax: 180 }, { name: "Africa", latMin: -35, latMax: 37, lngMin: -20, lngMax: 55 }, { name: "North America", latMin: 15, latMax: 84, lngMin: -170, lngMax: -50 }, { name: "South America", latMin: -56, latMax: 15, lngMin: -82, lngMax: -34 }, { name: "Oceania", latMin: -48, latMax: 0, lngMin: 110, lngMax: 180 }, { name: "Antarctica", latMin: -90, latMax: -60, lngMin: -180, lngMax: 180 }, ]; export const CONTINENT_CENTROIDS: Record = { "Europe": [50.0, 10.0], "Asia": [35.0, 90.0], "Africa": [5.0, 25.0], "North America": [45.0, -100.0], "South America": [-15.0, -60.0], "Oceania": [-25.0, 140.0], "Antarctica": [-82.0, 0.0], }; // ~50 major countries sorted by area (ascending) for specificity-first matching const COUNTRIES: CountryDef[] = [ // Europe { name: "Luxembourg", continent: "Europe", latMin: 49.4, latMax: 50.2, lngMin: 5.7, lngMax: 6.5, area: 1 }, { name: "Slovenia", continent: "Europe", latMin: 45.4, latMax: 46.9, lngMin: 13.4, lngMax: 16.6, area: 5 }, { name: "Belgium", continent: "Europe", latMin: 49.5, latMax: 51.5, lngMin: 2.5, lngMax: 6.4, area: 8 }, { name: "Netherlands", continent: "Europe", latMin: 50.7, latMax: 53.6, lngMin: 3.4, lngMax: 7.2, area: 11 }, { name: "Switzerland", continent: "Europe", latMin: 45.8, latMax: 47.8, lngMin: 5.9, lngMax: 10.5, area: 9 }, { name: "Denmark", continent: "Europe", latMin: 54.5, latMax: 57.8, lngMin: 8.0, lngMax: 15.2, area: 24 }, { name: "Austria", continent: "Europe", latMin: 46.4, latMax: 49.0, lngMin: 9.5, lngMax: 17.2, area: 20 }, { name: "Czech Republic",continent: "Europe", latMin: 48.5, latMax: 51.1, lngMin: 12.1, lngMax: 18.9, area: 18 }, { name: "Ireland", continent: "Europe", latMin: 51.4, latMax: 55.4, lngMin: -10.5, lngMax: -5.5, area: 20 }, { name: "Portugal", continent: "Europe", latMin: 36.9, latMax: 42.2, lngMin: -9.5, lngMax: -6.2, area: 18 }, { name: "Hungary", continent: "Europe", latMin: 45.7, latMax: 48.6, lngMin: 16.1, lngMax: 22.9, area: 20 }, { name: "Croatia", continent: "Europe", latMin: 42.4, latMax: 46.6, lngMin: 13.5, lngMax: 19.4, area: 25 }, { name: "Greece", continent: "Europe", latMin: 34.8, latMax: 41.8, lngMin: 19.3, lngMax: 29.6, area: 72 }, { name: "Italy", continent: "Europe", latMin: 36.6, latMax: 47.1, lngMin: 6.6, lngMax: 18.5, area: 125 }, { name: "United Kingdom",continent: "Europe", latMin: 49.9, latMax: 58.7, lngMin: -8.2, lngMax: 1.8, area: 88 }, { name: "Romania", continent: "Europe", latMin: 43.6, latMax: 48.3, lngMin: 20.3, lngMax: 29.7, area: 44 }, { name: "Poland", continent: "Europe", latMin: 49.0, latMax: 54.8, lngMin: 14.1, lngMax: 24.2, area: 59 }, { name: "Germany", continent: "Europe", latMin: 47.3, latMax: 55.1, lngMin: 5.9, lngMax: 15.0, area: 71 }, { name: "Finland", continent: "Europe", latMin: 59.8, latMax: 70.1, lngMin: 20.6, lngMax: 31.6, area: 113 }, { name: "Norway", continent: "Europe", latMin: 57.9, latMax: 71.2, lngMin: 4.6, lngMax: 31.1, area: 353 }, { name: "Sweden", continent: "Europe", latMin: 55.3, latMax: 69.1, lngMin: 11.1, lngMax: 24.2, area: 181 }, { name: "France", continent: "Europe", latMin: 41.3, latMax: 51.1, lngMin: -5.1, lngMax: 9.6, area: 144 }, { name: "Spain", continent: "Europe", latMin: 36.0, latMax: 43.8, lngMin: -9.3, lngMax: 4.3, area: 106 }, { name: "Ukraine", continent: "Europe", latMin: 44.4, latMax: 52.4, lngMin: 22.1, lngMax: 40.2, area: 145 }, { name: "Turkey", continent: "Europe", latMin: 36.0, latMax: 42.1, lngMin: 26.0, lngMax: 44.8, area: 115 }, // Asia { name: "Israel", continent: "Asia", latMin: 29.5, latMax: 33.3, lngMin: 34.2, lngMax: 35.9, area: 6 }, { name: "South Korea", continent: "Asia", latMin: 33.1, latMax: 38.6, lngMin: 124.6, lngMax: 131.9, area: 40 }, { name: "Japan", continent: "Asia", latMin: 24.0, latMax: 45.5, lngMin: 123.0, lngMax: 146.0, area: 495 }, { name: "Thailand", continent: "Asia", latMin: 5.6, latMax: 20.5, lngMin: 97.3, lngMax: 105.6, area: 124 }, { name: "Vietnam", continent: "Asia", latMin: 8.4, latMax: 23.4, lngMin: 102.1, lngMax: 109.5, area: 111 }, { name: "Indonesia", continent: "Asia", latMin: -11.0, latMax: 6.0, lngMin: 95.0, lngMax: 141.0, area: 782 }, { name: "India", continent: "Asia", latMin: 6.7, latMax: 35.5, lngMin: 68.2, lngMax: 97.4, area: 841 }, { name: "China", continent: "Asia", latMin: 18.2, latMax: 53.6, lngMin: 73.5, lngMax: 134.8, area: 2172 }, // Africa { name: "Tunisia", continent: "Africa", latMin: 30.2, latMax: 37.3, lngMin: 7.5, lngMax: 11.6, area: 29 }, { name: "Morocco", continent: "Africa", latMin: 27.7, latMax: 35.9, lngMin: -13.2, lngMax: -1.0, area: 100 }, { name: "Kenya", continent: "Africa", latMin: -4.7, latMax: 5.0, lngMin: 33.9, lngMax: 41.9, area: 78 }, { name: "South Africa", continent: "Africa", latMin: -34.8, latMax: -22.1, lngMin: 16.5, lngMax: 32.9, area: 209 }, { name: "Nigeria", continent: "Africa", latMin: 4.3, latMax: 13.9, lngMin: 2.7, lngMax: 14.7, area: 115 }, { name: "Egypt", continent: "Africa", latMin: 22.0, latMax: 31.7, lngMin: 24.7, lngMax: 36.9, area: 118 }, { name: "Ethiopia", continent: "Africa", latMin: 3.4, latMax: 14.9, lngMin: 33.0, lngMax: 48.0, area: 173 }, // North America { name: "Costa Rica", continent: "North America", latMin: 8.0, latMax: 11.2, lngMin: -85.9, lngMax: -82.6, area: 11 }, { name: "Mexico", continent: "North America", latMin: 14.5, latMax: 32.7, lngMin: -118.4, lngMax: -86.7, area: 577 }, { name: "United States", continent: "North America", latMin: 24.5, latMax: 49.4, lngMin: -125.0, lngMax: -66.9, area: 1449 }, { name: "Canada", continent: "North America", latMin: 41.7, latMax: 83.1, lngMin: -141.0, lngMax: -52.6, area: 3652 }, // South America { name: "Colombia", continent: "South America", latMin: -4.2, latMax: 12.5, lngMin: -79.0, lngMax: -66.9, area: 202 }, { name: "Argentina", continent: "South America", latMin: -55.1, latMax: -21.8, lngMin: -73.6, lngMax: -53.6, area: 666 }, { name: "Brazil", continent: "South America", latMin: -33.8, latMax: 5.3, lngMin: -73.9, lngMax: -34.8, area: 1528 }, // Oceania { name: "New Zealand", continent: "Oceania", latMin: -47.3, latMax: -34.4, lngMin: 166.4, lngMax: 178.6, area: 157 }, { name: "Australia", continent: "Oceania", latMin: -43.6, latMax: -10.7, lngMin: 113.2, lngMax: 153.6, area: 1331 }, ].sort((a, b) => a.area - b.area); // smallest first for specificity // ── Lookup functions ── function inBox(lat: number, lng: number, box: BoundingBox): boolean { return lat >= box.latMin && lat <= box.latMax && lng >= box.lngMin && lng <= box.lngMax; } export function lookupContinent(lat: number, lng: number): string | null { for (const c of CONTINENTS) { if (inBox(lat, lng, c)) return c.name; } return null; } export function lookupCountry(lat: number, lng: number): string | null { // Countries sorted by area ascending → smallest match first (most specific) for (const c of COUNTRIES) { if (inBox(lat, lng, c)) return c.name; } return null; } /** * Generate a geographic breadcrumb string from coordinates. * Returns e.g. "Earth > Europe > Germany > Berlin" * * @param lat Latitude * @param lng Longitude * @param locationName Optional city/venue name to append as most specific level */ export function generateBreadcrumb(lat: number, lng: number, locationName?: string | null): string { const parts = ["Earth"]; const continent = lookupContinent(lat, lng); if (continent) parts.push(continent); const country = lookupCountry(lat, lng); if (country) parts.push(country); if (locationName) { // Strip common venue prefixes to get just the city/place // e.g. "Factory Berlin" → "Berlin", "KICC, Nairobi" → "Nairobi" const city = locationName.includes(",") ? locationName.split(",").pop()!.trim() : locationName; // Avoid duplicating country in breadcrumb if (city && city !== country) { parts.push(city); } } return parts.join(" > "); }