code wiki / _hdl_build / nx_geo_geocode.nx

nx_geo_geocode.nx source

↩ module page · 85 lines · 3105 B

1// nx_geo_geocode.nx -- LIB: GEO-006 geocoding (address/place <-> coordinate). Sovereign: the place 2// gazetteer is DATA in the store (open data / OSM as last-mile DATA, never substrate); FORWARD = 3// name -> coords (case-insensitive match), REVERSE = coords -> nearest place (REUSES GEO-009 4// geo_nearest -- no new geometry). Pure-integer microdegree coords -> deterministic. The seeded 5// gazetteer is small + extensible; swap in a larger open-data set without code change. ORIGINAL 6import "nx_syscalls.nx" 7 8func gz_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 9 10// parse a signed integer from buf[s..e) (handles a leading '-'). 11func gz_signed(buf: *u8, s: i64, e: i64) -> i64 { 12 var neg: i64 = 0 13 var p: i64 = s 14 if p < e { if buf[p] == (45 as u8) { neg = 1; p = p + 1 } } 15 var v: i64 = 0 16 while p < e { 17 let c: i64 = buf[p] as i64 18 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } 19 p = p + 1 20 } 21 if neg == 1 { return 0 - v } 22 return v 23} 24 25// lowercase a byte (ASCII A-Z -> a-z). 26func gz_lc(c: i64) -> i64 { 27 if c >= 65 { if c <= 90 { return c + 32 } } 28 return c 29} 30 31// case-insensitive compare: a[0..n) vs b[0..n). 32func gz_ci_eq(a: *u8, b: *u8, n: i64) -> i64 { 33 var i: i64 = 0 34 while i < n { 35 if gz_lc(a[i] as i64) != gz_lc(b[i] as i64) { return 0 } 36 i = i + 1 37 } 38 return 1 39} 40 41// parse the gazetteer (lines: name<tab>lat<tab>lon) into a flat points array [lat,lon,...] plus 42// per-place name offset/length (into gaz). Returns the place count (capped at maxp). 43func geo_gaz_parse(gaz: *u8, gn: i64, pts: *i64, noff: *i64, nlen: *i64, maxp: i64) -> i64 { 44 var cnt: i64 = 0 45 var i: i64 = 0 46 while i < gn { 47 var le: i64 = i 48 var go: i64 = 1 49 while go == 1 { if le >= gn { go = 0 } else { if gaz[le] == (10 as u8) { go = 0 } else { le = le + 1 } } } 50 if le > i { 51 // first tab 52 var t1: i64 = i 53 var f1: i64 = 0 54 var p: i64 = i 55 while p < le { if gaz[p] == (9 as u8) { t1 = p; f1 = 1; p = le } else { p = p + 1 } } 56 // second tab (after t1) 57 var t2: i64 = t1 58 var f2: i64 = 0 59 p = t1 + 1 60 while p < le { if gaz[p] == (9 as u8) { t2 = p; f2 = 1; p = le } else { p = p + 1 } } 61 if f1 == 1 { if f2 == 1 { if cnt < maxp { 62 noff[cnt] = i 63 nlen[cnt] = t1 - i 64 pts[cnt * 2] = gz_signed(gaz, t1 + 1, t2) 65 pts[cnt * 2 + 1] = gz_signed(gaz, t2 + 1, le) 66 cnt = cnt + 1 67 } } } 68 } 69 i = le + 1 70 } 71 return cnt 72} 73 74// FORWARD geocode: index of the place whose name == query (case-insensitive, full match), else -1. 75func geocode_forward(gaz: *u8, noff: *i64, nlen: *i64, count: i64, query: *u8) -> i64 { 76 let qn: i64 = gz_len(query) 77 var c: i64 = 0 78 while c < count { 79 if nlen[c] == qn { 80 if gz_ci_eq((gaz as i64 + noff[c]) as *u8, query, qn) == 1 { return c } 81 } 82 c = c + 1 83 } 84 return 0 - 1 85}