fix: use Nominatim reverse geocoding for accurate country detection in atlas
Bounding boxes overlap for neighboring countries (e.g. Munich matched Austria instead of Germany). Now uses Nominatim reverse geocoding with in-memory cache as primary fallback, bounding boxes only as last resort.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import express, { Request, Response } from 'express';
|
||||
import fetch from 'node-fetch';
|
||||
import { db } from '../db/database';
|
||||
import { authenticate } from '../middleware/auth';
|
||||
import { AuthRequest, Trip, Place } from '../types';
|
||||
@@ -6,6 +7,30 @@ import { AuthRequest, Trip, Place } from '../types';
|
||||
const router = express.Router();
|
||||
router.use(authenticate);
|
||||
|
||||
// Geocode cache: rounded coords -> country code
|
||||
const geocodeCache = new Map<string, string | null>();
|
||||
|
||||
function roundKey(lat: number, lng: number): string {
|
||||
return `${lat.toFixed(3)},${lng.toFixed(3)}`;
|
||||
}
|
||||
|
||||
async function reverseGeocodeCountry(lat: number, lng: number): Promise<string | null> {
|
||||
const key = roundKey(lat, lng);
|
||||
if (geocodeCache.has(key)) return geocodeCache.get(key)!;
|
||||
try {
|
||||
const res = await fetch(`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&zoom=3&accept-language=en`, {
|
||||
headers: { 'User-Agent': 'TREK Travel Planner' },
|
||||
});
|
||||
if (!res.ok) return null;
|
||||
const data = await res.json() as { address?: { country_code?: string } };
|
||||
const code = data.address?.country_code?.toUpperCase() || null;
|
||||
geocodeCache.set(key, code);
|
||||
return code;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const COUNTRY_BOXES: Record<string, [number, number, number, number]> = {
|
||||
AF:[60.5,29.4,75,38.5],AL:[19,39.6,21.1,42.7],DZ:[-8.7,19,12,37.1],AD:[1.4,42.4,1.8,42.7],AO:[11.7,-18.1,24.1,-4.4],
|
||||
AR:[-73.6,-55.1,-53.6,-21.8],AM:[43.4,38.8,46.6,41.3],AU:[112.9,-43.6,153.6,-10.7],AT:[9.5,46.4,17.2,49],AZ:[44.8,38.4,50.4,41.9],
|
||||
@@ -83,7 +108,7 @@ const CONTINENT_MAP: Record<string, string> = {
|
||||
SE:'Europe',CH:'Europe',TH:'Asia',TR:'Europe',UA:'Europe',AE:'Asia',GB:'Europe',US:'North America',VN:'Asia',NG:'Africa',
|
||||
};
|
||||
|
||||
router.get('/stats', (req: Request, res: Response) => {
|
||||
router.get('/stats', async (req: Request, res: Response) => {
|
||||
const authReq = req as AuthRequest;
|
||||
const userId = authReq.user.id;
|
||||
|
||||
@@ -109,6 +134,9 @@ router.get('/stats', (req: Request, res: Response) => {
|
||||
const countrySet = new Map<string, CountryEntry>();
|
||||
for (const place of places) {
|
||||
let code = getCountryFromAddress(place.address);
|
||||
if (!code && place.lat && place.lng) {
|
||||
code = await reverseGeocodeCountry(place.lat, place.lng);
|
||||
}
|
||||
if (!code && place.lat && place.lng) {
|
||||
code = getCountryFromCoords(place.lat, place.lng);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user