keep bent streets, enclosed landmarks and same-name outlines honest

A street ribbon that holds neither its ring mean nor the anchor is centred
on the street's nearest point when the street runs within 100 m.

Nominatim outline selection ranks an exact name, then one holding every
asked word, then an overlap, and refuses an overlap whose name lacks the
ask's last word unless that word is in the result's address or type, so
"Central Park Zoo" is no longer Central Park. The server caches every
accepted outline and answers each ask with the one holding its resolved
anchor (sent as alat/alon), read across the antimeridian.

A duplicate mark that fails to clean up no longer tears down the new
outline it duplicates.
This commit is contained in:
Sameh Khamis committed 2026-11-02 08:37:45 -08:00
1 parent d9a460658d
commit a38a065c5c
16 files changed
+516 -133

No files matched your search

+16 -2
View File
@@ -11,6 +11,7 @@ import {
approximateAreaM2,
approximateDistanceM,
pointInPolygon,
nearestPointOnLines,
} from '../sources/featureGeometry.js';
import { defaultGeospatial } from '../search/defaults.js';
import * as Cesium from 'cesium';
@@ -79,6 +80,9 @@ function localOutlineFrame(fp) {
/** Ms the analyst region lookup waits on geocode + admin boundary. */
const REGION_FALLBACK_BUDGET_MS = 3_000;
/** How far a street may run from its anchor when the ribbon holds neither. */
const STREET_SNAP_MAX_M = 100;
/**
* Names that end like a landmark rather than a district: "Central Park",
* "Lake Merritt"-style suffixes are checked on the last word only, so "Park
@@ -830,8 +834,18 @@ export function createAnnotationResolver({
frame.reference === null
? lon
: lon - 360 * Math.round((lon - frame.reference) / 360);
if (!polygonsContainPoint(frame.polygons, lat, anchorLon)) return null;
centroid = { lat, lon };
if (polygonsContainPoint(frame.polygons, lat, anchorLon)) {
centroid = { lat, lon };
} else if (Array.isArray(fp.lines)) {
// A bent street's ribbon rarely holds its ring mean, and a geocoded
// anchor can sit beside the centreline: centre on the street itself,
// only when it runs beside the anchor.
const onStreet = nearestPointOnLines(fp.lines, lat, lon);
if (!onStreet || onStreet.distanceM > STREET_SNAP_MAX_M) return null;
centroid = { lat: onStreet.lat, lon: onStreet.lon };
} else {
return null;
}
}
if (
frame.reference !== null &&