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, "&" as *u8) }
128 else { if buf[i] == (60 as u8) { r_w(fd, "<" as *u8) }
129 else { if buf[i] == (62 as u8) { r_w(fd, ">" 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 — Lower Manhattan</h1><div class=\"tag\">Real OpenStreetMap geography rendered bits-up by <code>nx_geo_osmrender</code> — 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 · scroll to zoom. Source: OpenStreetMap contributors (ODbL). Rendered sovereignly — 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}