feat(outlines): voice outlines without Overpass — bundled US places and neighborhoods, guarded Nominatim, OpenFreeMap streets and buildings

This commit is contained in:
Bilawal Sidhu committed 2026-09-28 22:49:23 -05:00
1 parent e7707d9a0f
commit 9559e7a282
333 files changed
+13203 -271

No files matched your search

+24 -1
View File
@@ -57,6 +57,20 @@ const NAME_ALIASES = new Map([
['downtown', 'financial district south beach'],
]);
const FILLER_WORDS = new Set([
'the',
'district',
'neighborhood',
'neighbourhood',
]);
/** Whether a feature's words are all of the query's, ignoring filler words. */
function sameWords(featureWords, queryWords) {
const f = new Set(featureWords.filter((w) => !FILLER_WORDS.has(w)));
const q = [...queryWords].filter((w) => !FILLER_WORDS.has(w));
return q.length === f.size && q.every((w) => f.has(w));
}
/** Ray-casting point-in-ring. ring = [[lon,lat], …]. */
function pointInRing(lon, lat, ring) {
let inside = false;
@@ -139,10 +153,18 @@ async function loadCity(city) {
* @param {number} lat
* @param {number} lon
* @param {string} matchName - the geocoder's canonical place name (e.g. "Marina District")
* @param {{exact?: boolean}} [options] - `exact`: the name must be the whole ask
* (ignoring "the", "district", "neighborhood"), for asks no geocoder has typed
* ("the Mission District" matches Mission; "Mission Dolores Park" does not).
* @returns {Promise<{ring:[number,number][], name:string}|null>} the outer ring + matched
* neighborhood name, or null when the point isn't in a covered city / no match.
*/
export async function lookupNeighborhoodRing(lat, lon, matchName) {
export async function lookupNeighborhoodRing(
lat,
lon,
matchName,
{ exact = false } = {},
) {
const city = CITY_FILES.find(
(c) =>
lon >= c.bbox[0] &&
@@ -177,6 +199,7 @@ export async function lookupNeighborhoodRing(lat, lon, matchName) {
if (!fname) continue;
const fWords = fname.split(' ').filter(Boolean);
if (!fWords.length || !fWords.every((w) => qWords.has(w))) continue; // require name match
if (exact && !sameWords(fWords, qWords)) continue;
const containRing = containingOuterRing(f, lon, lat);
const ring = containRing || largestOuterRing(f.geometry);
if (!ring) continue;