code wiki / _hdl_build / nx_geo_osmrender.nx

nx_geo_osmrender.nx source

↩ module page · 254 lines · 14124 B

1// nx_geo_osmrender.nx -- GEO-007 the REAL map engine: renders ACTUAL OpenStreetMap geography 2// (knowledge/geo/osm/lowman.tsv = real ways of lower Manhattan, ODbL) to a styled vector map. 3// Each line: "<class>\t<lon_microdeg>,<lat_microdeg> <lon>,<lat> ...". Computes the bbox, projects 4// every vertex (equirectangular, cos-lat aspect), classifies by OSM road type, and draws LAYERED 5// cartographic strokes (water/park fills, then footways, minor, secondary, major roads on top). 6// Pure-integer projection. NO third-party map library. Writes sites/nishifamily/maps/index.html. 7import "nx_syscalls.nx" 8import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 9const K_MAGIC_4194304: i64 = 4194304 10const K_MAGIC_999000000: i64 = 999000000 11 12func r_w(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 } 13// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 14// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 15// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 16// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 17func r_n(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 } 18func r_read(path: *u8, buf: *u8, cap: i64) -> i64 { 19 let fd: i64 = sys_openat_rd(path) 20 if fd < 0 { return 0 - 1 } 21 var tot: i64 = 0; var go: i64 = 1 22 while go == 1 { let r: i64 = sys_read(fd, (buf as i64 + tot) as *u8, cap - tot); if r <= 0 { go = 0 } else { tot = tot + r; if tot >= cap { go = 0 } } } 23 sys_close(fd); return tot 24} 25func r_int(buf: *u8, s: i64, e: i64) -> i64 { 26 var neg: i64 = 0; var i: i64 = s 27 if s < e { if buf[s] == (45 as u8) { neg = 1; i = s + 1 } } 28 var v: i64 = 0 29 while i < e { if buf[i] >= (48 as u8) { if buf[i] <= (57 as u8) { v = v * 10 + (buf[i] as i64 - 48) } } i = i + 1 } 30 if neg == 1 { return 0 - v } 31 return v 32} 33// scan from i within [i,lim) to the next byte == d; returns that index (or lim). Clean, no recovery. 34func r_to(buf: *u8, i: i64, lim: i64, d: i64) -> i64 { 35 var e: i64 = i; var go: i64 = 1 36 while go == 1 { if e >= lim { go = 0 } else { if buf[e] == (d as u8) { go = 0 } else { e = e + 1 } } } 37 return e 38} 39func r_starts(buf: *u8, s: i64, e: i64, lit: *u8) -> i64 { 40 var i: i64 = 0 41 while lit[i] != (0 as u8) { if s + i >= e { return 0 } if buf[s + i] != lit[i] { return 0 } i = i + 1 } 42 return 1 43} 44// OSM class -> code: 0 major, 1 secondary, 2 minor, 3 foot/path, 4 water, 5 park, 6 other. 45func r_code(buf: *u8, s: i64, e: i64) -> i64 { 46 if r_starts(buf, s, e, "building" as *u8) == 1 { return 7 } 47 if r_starts(buf, s, e, "motorway" as *u8) == 1 { return 0 } 48 if r_starts(buf, s, e, "trunk" as *u8) == 1 { return 0 } 49 if r_starts(buf, s, e, "primary" as *u8) == 1 { return 0 } 50 if r_starts(buf, s, e, "secondary" as *u8) == 1 { return 1 } 51 if r_starts(buf, s, e, "tertiary" as *u8) == 1 { return 1 } 52 if r_starts(buf, s, e, "residential" as *u8) == 1 { return 2 } 53 if r_starts(buf, s, e, "unclassified" as *u8) == 1 { return 2 } 54 if r_starts(buf, s, e, "living" as *u8) == 1 { return 2 } 55 if r_starts(buf, s, e, "service" as *u8) == 1 { return 2 } 56 if r_starts(buf, s, e, "foot" as *u8) == 1 { return 3 } 57 if r_starts(buf, s, e, "pedestrian" as *u8) == 1 { return 3 } 58 if r_starts(buf, s, e, "path" as *u8) == 1 { return 3 } 59 if r_starts(buf, s, e, "steps" as *u8) == 1 { return 3 } 60 if r_starts(buf, s, e, "cycle" as *u8) == 1 { return 3 } 61 if r_starts(buf, s, e, "track" as *u8) == 1 { return 3 } 62 if r_starts(buf, s, e, "water" as *u8) == 1 { return 4 } 63 if r_starts(buf, s, e, "park" as *u8) == 1 { return 5 } 64 return 6 65} 66// update bbox box4=[lonmin,lonmax,latmin,latmax] over coords region [cs,ce). 67func r_bbox(buf: *u8, cs: i64, ce: i64, box: *i64) -> i64 { 68 var j: i64 = cs 69 while j < ce { 70 var sp: i64 = 1 71 while sp == 1 { if j < ce { if buf[j] == (32 as u8) { j = j + 1 } else { sp = 0 } } else { sp = 0 } } 72 if j < ce { 73 let te: i64 = r_to(buf, j, ce, 32) 74 let cm: i64 = r_to(buf, j, te, 44) 75 if cm < te { 76 let lon: i64 = r_int(buf, j, cm) 77 let lat: i64 = r_int(buf, cm + 1, te) 78 if lon < box[0] { box[0] = lon } 79 if lon > box[1] { box[1] = lon } 80 if lat < box[2] { box[2] = lat } 81 if lat > box[3] { box[3] = lat } 82 } 83 j = te 84 } 85 } 86 return 0 87} 88// emit projected SVG for coords [cs,ce) with style for code. pj=[lonmin,latmax,lonrange,latrange,W,H]. 89func r_emit(fd: i64, buf: *u8, cs: i64, ce: i64, pj: *i64, code: i64) -> i64 { 90 if code == 4 { r_w(fd, "<polygon fill=\"#14304d\" stroke=\"#2b5681\" stroke-width=\"0.8\" points=\"" as *u8) } 91 else { if code == 5 { r_w(fd, "<polygon fill=\"#163020\" stroke=\"none\" points=\"" as *u8) } 92 else { if code == 7 { r_w(fd, "<polygon fill=\"#171e35\" stroke=\"#27314f\" stroke-width=\"0.4\" points=\"" as *u8) } 93 else { 94 var col: *u8 = "#5a6a8f" as *u8; var wd: *u8 = "0.7" as *u8 95 if code == 0 { col = "#ffd166" as *u8; wd = "2.6" as *u8 } 96 if code == 1 { col = "#eef2fb" as *u8; wd = "1.7" as *u8 } 97 if code == 2 { col = "#9aa7c7" as *u8; wd = "1.0" as *u8 } 98 if code == 3 { col = "#41506f" as *u8; wd = "0.5" as *u8 } 99 r_w(fd, "<polyline fill=\"none\" stroke=\"" as *u8); r_w(fd, col) 100 r_w(fd, "\" stroke-width=\"" as *u8); r_w(fd, wd); r_w(fd, "\" stroke-linecap=\"round\" stroke-linejoin=\"round\" points=\"" as *u8) 101 } } } 102 var j: i64 = cs 103 while j < ce { 104 // skip leading spaces 105 var sp: i64 = 1 106 while sp == 1 { if j < ce { if buf[j] == (32 as u8) { j = j + 1 } else { sp = 0 } } else { sp = 0 } } 107 if j < ce { 108 let te: i64 = r_to(buf, j, ce, 32) 109 let cm: i64 = r_to(buf, j, te, 44) 110 if cm < te { 111 let lon: i64 = r_int(buf, j, cm) 112 let lat: i64 = r_int(buf, cm + 1, te) 113 let px: i64 = (lon - pj[0]) * pj[4] / pj[2] 114 let py: i64 = (pj[1] - lat) * pj[5] / pj[3] 115 r_n(fd, px); r_w(fd, "," as *u8); r_n(fd, py); r_w(fd, " " as *u8) 116 } 117 j = te 118 } 119 } 120 r_w(fd, "\"/>\n" as *u8) 121 return 0 122} 123// write [s,e) to fd with minimal HTML escaping (& < >). 124func r_esc(fd: i64, buf: *u8, s: i64, e: i64) -> i64 { 125 var i: i64 = s 126 while i < e { 127 if buf[i] == (38 as u8) { r_w(fd, "&amp;" as *u8) } 128 else { if buf[i] == (60 as u8) { r_w(fd, "&lt;" as *u8) } 129 else { if buf[i] == (62 as u8) { r_w(fd, "&gt;" as *u8) } 130 else { sys_write(fd, (buf as i64 + i) as *u8, 1) } } } 131 i = i + 1 132 } 133 return 0 134} 135// emit a street-name label at the MIDDLE vertex of coords [cs,ce). name=[ns,ne). 136func r_label(fd: i64, buf: *u8, ns: i64, ne: i64, cs: i64, ce: i64, pj: *i64) -> i64 { 137 if ne <= ns { return 0 } 138 var cnt: i64 = 0 139 var j: i64 = cs 140 while j < ce { 141 var sp: i64 = 1 142 while sp == 1 { if j < ce { if buf[j] == (32 as u8) { j = j + 1 } else { sp = 0 } } else { sp = 0 } } 143 if j < ce { let te: i64 = r_to(buf, j, ce, 32); cnt = cnt + 1; j = te } 144 } 145 if cnt == 0 { return 0 } 146 let mid: i64 = cnt / 2 147 var idx: i64 = 0; var mx: i64 = 0; var my: i64 = 0; var got: i64 = 0 148 j = cs 149 while j < ce { 150 var sp2: i64 = 1 151 while sp2 == 1 { if j < ce { if buf[j] == (32 as u8) { j = j + 1 } else { sp2 = 0 } } else { sp2 = 0 } } 152 if j < ce { 153 let te: i64 = r_to(buf, j, ce, 32) 154 let cm: i64 = r_to(buf, j, te, 44) 155 if cm < te { 156 if idx == mid { 157 let lon: i64 = r_int(buf, j, cm); let lat: i64 = r_int(buf, cm + 1, te) 158 mx = (lon - pj[0]) * pj[4] / pj[2]; my = (pj[1] - lat) * pj[5] / pj[3]; got = 1 159 } 160 idx = idx + 1 161 } 162 j = te 163 } 164 } 165 if got == 1 { 166 r_w(fd, "<text class=\"lbl\" x=\"" as *u8); r_n(fd, mx); r_w(fd, "\" y=\"" as *u8); r_n(fd, my) 167 r_w(fd, "\">" as *u8); r_esc(fd, buf, ns, ne); r_w(fd, "</text>\n" as *u8) 168 } 169 return 0 170} 171func main(argc: i64, argv: *i64) -> i64 { 172 let cap: i64 = K_MAGIC_4194304 173 let buf: *u8 = sys_mmap(cap) 174 let n: i64 = r_read("knowledge/geo/osm/lowman.tsv" as *u8, buf, cap - 4) 175 if n <= 0 { r_w(1, "OSMRENDER FATAL no data\n" as *u8); sys_exit(1); return 1 } 176 177 let box: *i64 = sys_mmap(4 * 8) as *i64 178 box[0] = K_MAGIC_999000000; box[1] = 0 - K_MAGIC_999000000; box[2] = K_MAGIC_999000000; box[3] = 0 - K_MAGIC_999000000 179 // line loop -> bbox 180 var p: i64 = 0 181 while p < n { 182 let le: i64 = r_to(buf, p, n, 10) 183 let t1: i64 = r_to(buf, p, le, 9) 184 let t2: i64 = r_to(buf, t1 + 1, le, 9) 185 if t2 < le { r_bbox(buf, t2 + 1, le, box) } 186 p = le + 1 187 } 188 let lonmin: i64 = box[0]; let latmax: i64 = box[3] 189 let lonrange: i64 = box[1] - box[0] 190 let latrange: i64 = box[3] - box[2] 191 let H: i64 = 1000 192 let W: i64 = H * lonrange * 758 / (latrange * 1000) // cos(40.7N)~=0.758, preserves aspect 193 let pj: *i64 = sys_mmap(6 * 8) as *i64 194 pj[0] = lonmin; pj[1] = latmax; pj[2] = lonrange; pj[3] = latrange; pj[4] = W; pj[5] = H 195 196 let fd: i64 = sys_openat_wr("sites/nishifamily/maps/index.html" as *u8, 420) 197 if fd < 0 { r_w(1, "OSMRENDER FATAL open out\n" as *u8); sys_exit(1); return 1 } 198 r_w(fd, "<!DOCTYPE html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>Nishi Maps - Lower Manhattan</title>\n" as *u8) 199 r_w(fd, "<style>body{font-family:-apple-system,Segoe UI,Roboto,sans-serif;margin:0;background:#0a0f1e;color:#dbe3f2}header{padding:16px 22px}h1{margin:0;font-size:1.35rem}.tag{color:#8190b5;font-size:.9rem;margin-top:3px}.wrap{padding:0 22px 22px;display:flex;justify-content:center}svg{height:90vh;width:auto;background:#0a0f1e;border:1px solid #1c2950;border-radius:8px}.foot{padding:0 22px 22px;font-size:.78rem;color:#5a6a93}code{color:#9fb0d6}.lbl{fill:#c7d3ef;font:9px -apple-system,Segoe UI,sans-serif;paint-order:stroke;stroke:#0a0f1e;stroke-width:2.4px;pointer-events:none}</style></head><body>\n" as *u8) 200 r_w(fd, "<header><h1>Nishi Maps &mdash; Lower Manhattan</h1><div class=\"tag\">Real OpenStreetMap geography rendered bits-up by <code>nx_geo_osmrender</code> &mdash; integer-exact projection, cartographic layering. No Leaflet, Mapbox, Google, or any third-party map library.</div></header>\n" as *u8) 201 r_w(fd, "<div class=\"wrap\"><svg viewBox=\"0 0 " as *u8); r_n(fd, W); r_w(fd, " " as *u8); r_n(fd, H) 202 r_w(fd, "\" xmlns=\"http://www.w3.org/2000/svg\">\n<rect x=\"0\" y=\"0\" width=\"" as *u8); r_n(fd, W) 203 r_w(fd, "\" height=\"" as *u8); r_n(fd, H); r_w(fd, "\" fill=\"#0a0f1e\"/>\n" as *u8) 204 205 let zorder: *i64 = sys_mmap(8 * 8) as *i64 206 zorder[0] = 7; zorder[1] = 4; zorder[2] = 5; zorder[3] = 6; zorder[4] = 3; zorder[5] = 2; zorder[6] = 1; zorder[7] = 0 207 var z: i64 = 0 208 while z < 8 { 209 let target: i64 = zorder[z] 210 p = 0 211 while p < n { 212 let le: i64 = r_to(buf, p, n, 10) 213 let t1: i64 = r_to(buf, p, le, 9) 214 let t2: i64 = r_to(buf, t1 + 1, le, 9) 215 if t2 < le { 216 let code: i64 = r_code(buf, p, t1) 217 if code == target { r_emit(fd, buf, t2 + 1, le, pj, code) } 218 } 219 p = le + 1 220 } 221 z = z + 1 222 } 223 // LABEL pass: name the major + secondary roads + parks (drawn last, on top). 224 p = 0 225 while p < n { 226 let le: i64 = r_to(buf, p, n, 10) 227 let t1: i64 = r_to(buf, p, le, 9) 228 let t2: i64 = r_to(buf, t1 + 1, le, 9) 229 if t2 < le { 230 if t2 > t1 + 1 { 231 let code: i64 = r_code(buf, p, t1) 232 var lab: i64 = 0 233 if code == 0 { lab = 1 } 234 if code == 1 { lab = 1 } 235 if code == 5 { lab = 1 } 236 if lab == 1 { r_label(fd, buf, t1 + 1, t2, t2 + 1, le, pj) } 237 } 238 } 239 p = le + 1 240 } 241 r_w(fd, "</svg></div>\n" as *u8) 242 r_w(fd, "<p class=\"foot\">Drag to pan &middot; scroll to zoom. Source: OpenStreetMap contributors (ODbL). Rendered sovereignly &mdash; bbox + equirectangular projection + cartographic layering, all integer-exact in <code>nx_geo_osmrender</code>; pan/zoom is our own SVG viewBox code, no map library. Served by the Nishi sites daemon. nishifamily.com/maps</p>\n" as *u8) 243 // SOVEREIGN pan/zoom: our own SVG viewBox driver (drag=pan, wheel=zoom-at-cursor). No map lib. 244 r_w(fd, "<script>(function(){var s=document.querySelector('svg');var vb={x:0,y:0,w:" as *u8) 245 r_n(fd, W); r_w(fd, ",h:" as *u8); r_n(fd, H) 246 r_w(fd, "};function ap(){s.setAttribute('viewBox',vb.x+' '+vb.y+' '+vb.w+' '+vb.h);}var d=null;s.style.cursor='grab';s.addEventListener('mousedown',function(e){d={x:e.clientX,y:e.clientY,vx:vb.x,vy:vb.y};s.style.cursor='grabbing';e.preventDefault();});window.addEventListener('mousemove',function(e){if(!d)return;var r=s.getBoundingClientRect();vb.x=d.vx-(e.clientX-d.x)*vb.w/r.width;vb.y=d.vy-(e.clientY-d.y)*vb.h/r.height;ap();});window.addEventListener('mouseup',function(){d=null;s.style.cursor='grab';});s.addEventListener('wheel',function(e){e.preventDefault();var r=s.getBoundingClientRect();var mx=vb.x+(e.clientX-r.left)/r.width*vb.w;var my=vb.y+(e.clientY-r.top)/r.height*vb.h;var f=e.deltaY<0?0.84:1.19;vb.w*=f;vb.h*=f;vb.x=mx-(e.clientX-r.left)/r.width*vb.w;vb.y=my-(e.clientY-r.top)/r.height*vb.h;ap();},{passive:false});})();</script>\n" as *u8) 247 r_w(fd, "</body></html>\n" as *u8) 248 sys_close(fd) 249 r_w(1, "OSMRENDER wrote map W=" as *u8); r_n(1, W); r_w(1, " H=" as *u8); r_n(1, H) 250 r_w(1, " lonrange=" as *u8); r_n(1, lonrange); r_w(1, " latrange=" as *u8); r_n(1, latrange) 251 r_w(1, " verdict=GREEN\n" as *u8) 252 sys_exit(0) 253 return 0 254}