code wiki / _hdl_build / nx_curve_smoothness_census.nx

nx_curve_smoothness_census.nx source

↩ module page · 226 lines · 12306 B

1// nx_curve_smoothness_census.nx -- a WEIGHT-INVARIANT smoothness metric that actually isolates FACETING 2// (the thing edge-complexity confounded). Insight: faceting is about the CONTOUR'S TURNING, not its 3// thickness. A smooth curve turns UNIFORMLY (a circle's curvature is constant); a faceted polygon 4// concentrates all its turning into a few sharp vertices. So along the traced outer contour: 5// facet_index = n * Sum(T_i^2) / (Sum|T_i|)^2 where T_i = per-step turning of the tangent 6// For a perfectly-uniform (smooth) contour this = 1.0; for turning concentrated at k corners it -> ~n/k. 7// Scale-free, weight-free, trig-free (turning via integer cross-product of normalized tangent vectors). 8// SELF-VALIDATING LIAR-KILL: a synthetic CIRCLE must read near 1 (smooth) and a HEXAGON must read MUCH 9// higher (6 corners) -- if the metric can't tell a circle from a hexagon it declares ITSELF broken. Only 10// then does it report our "O" vs Chrome's "O". license_tier: ORIGINAL expect_exit: 0 11import "nx_img_bytes_to_rgb.nx" 12const K_MAGIC_2126: i64 = 2126 13const K_MAGIC_7152: i64 = 7152 14const K_MAGIC_10000: i64 = 10000 15const K_MAGIC_1024: i64 = 1024 16const K_MAGIC_40000: i64 = 40000 17 18func cs_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 19func cs_num(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 20func cs_lum(rgb: *u8, o: i64) -> i64 { return (K_MAGIC_2126*(rgb[o] as i64)+K_MAGIC_7152*(rgb[o+1] as i64)+722*(rgb[o+2] as i64))/K_MAGIC_10000 } 21func cs_ink(rgb: *u8, w: i64, h: i64, x: i64, y: i64) -> i64 { 22 if x<0 { return 0 } ; if y<0 { return 0 } ; if x>=w { return 0 } ; if y>=h { return 0 } 23 if cs_lum(rgb,(y*w+x)*3) < 128 { return 1 } 24 return 0 25} 26func cs_isqrt(n: i64) -> i64 { if n<=0 { return 0 } var x: i64=n; var y: i64=(x+1)/2; while y<x { x=y; y=(x+n/x)/2 } return x } 27 28// synthetic shapes rasterized into an RGB buffer (white bg, dark shape) -- same path as a decoded PNG. 29func cs_fill_white(rgb: *u8, w: i64, h: i64) -> i64 { var i: i64=0; while i<w*h*3 { rgb[i]=255 as u8; i=i+1 } return 0 } 30func cs_dot(rgb: *u8, w: i64, x: i64, y: i64) -> i64 { let o: i64=(y*w+x)*3; rgb[o]=20 as u8; rgb[o+1]=20 as u8; rgb[o+2]=43 as u8; return 0 } 31func cs_make_circle(rgb: *u8, w: i64, h: i64, cx: i64, cy: i64, r: i64) -> i64 { 32 cs_fill_white(rgb,w,h) 33 var y: i64=0 34 while y<h { var x: i64=0; while x<w { let dx: i64=x-cx; let dy: i64=y-cy; if dx*dx+dy*dy <= r*r { cs_dot(rgb,w,x,y) } x=x+1 } y=y+1 } 35 return 0 36} 37// regular hexagon via 6 half-plane tests (point inside iff inside all 6 edges) 38func cs_make_hexagon(rgb: *u8, w: i64, h: i64, cx: i64, cy: i64, r: i64, vx: *i64, vy: *i64) -> i64 { 39 cs_fill_white(rgb,w,h) 40 // 6 vertices (cos/sin at 0,60,...300 deg, x1000): (1000,0)(500,866)(-500,866)(-1000,0)(-500,-866)(500,-866) 41 let cxx: *i64 = sys_mmap(8*8) as *i64 42 let cyy: *i64 = sys_mmap(8*8) as *i64 43 cxx[0]=1000; cyy[0]=0 ; cxx[1]=500; cyy[1]=866 ; cxx[2]=0-500; cyy[2]=866 44 cxx[3]=0-1000; cyy[3]=0 ; cxx[4]=0-500; cyy[4]=0-866 ; cxx[5]=500; cyy[5]=0-866 45 var k: i64=0 46 while k<6 { vx[k]=cx+(r*cxx[k])/1000; vy[k]=cy+(r*cyy[k])/1000; k=k+1 } 47 var y: i64=0 48 while y<h { 49 var x: i64=0 50 while x<w { 51 var inside: i64=1 52 var e: i64=0 53 while e<6 { 54 let a: i64=e; let bb: i64=(e+1)%6 55 let cr: i64=(vx[bb]-vx[a])*(y-vy[a]) - (vy[bb]-vy[a])*(x-vx[a]) // cross: sign tells side 56 if cr < 0 { inside=0; e=6 } else { e=e+1 } 57 } 58 if inside==1 { cs_dot(rgb,w,x,y) } 59 x=x+1 60 } 61 y=y+1 62 } 63 return 0 64} 65 66// Moore-neighbour boundary trace (clockwise) of the outer contour containing the first ink pixel. 67// Fills px[],py[]; returns point count n (or 0 if none / overflow). 68func cs_trace(rgb: *u8, w: i64, h: i64, px: *i64, py: *i64, maxn: i64) -> i64 { 69 // find start = first ink pixel in raster order 70 var sx: i64=0 - 1 71 var sy: i64=0 72 var yy: i64=0 73 while yy<h { var xx: i64=0; while xx<w { if cs_ink(rgb,w,h,xx,yy)==1 { sx=xx; sy=yy; xx=w; yy=h } else { xx=xx+1 } } if sx<0 { yy=yy+1 } } 74 if sx<0 { return 0 } 75 // 8-neighbour offsets, clockwise starting from E 76 let ox: *i64 = sys_mmap(8*8) as *i64 77 let oy: *i64 = sys_mmap(8*8) as *i64 78 ox[0]=1;oy[0]=0 ; ox[1]=1;oy[1]=1 ; ox[2]=0;oy[2]=1 ; ox[3]=0-1;oy[3]=1 79 ox[4]=0-1;oy[4]=0 ; ox[5]=0-1;oy[5]=0-1 ; ox[6]=0;oy[6]=0-1 ; ox[7]=1;oy[7]=0-1 80 var cx: i64=sx 81 var cy: i64=sy 82 var n: i64=0 83 var backdir: i64=4 // came from the west of the start 84 var guard: i64=0 85 var run: i64=1 86 while run==1 { 87 px[n]=cx; py[n]=cy; n=n+1 88 if n>=maxn { return n } 89 // search neighbours clockwise starting just after the back-direction 90 var found: i64=0 91 var s: i64=0 92 while s<8 { 93 let d: i64=(backdir+1+s)%8 94 let nx: i64=cx+ox[d]; let ny: i64=cy+oy[d] 95 if cs_ink(rgb,w,h,nx,ny)==1 { 96 backdir=(d+4)%8 // we entered new pixel from opposite side 97 cx=nx; cy=ny; found=1; s=8 98 } else { s=s+1 } 99 } 100 if found==0 { run=0 } // isolated pixel 101 else { if cx==sx { if cy==sy { run=0 } } } // returned to start 102 guard=guard+1 103 if guard > maxn { run=0 } 104 } 105 return n 106} 107 108// facet_index x1000 : n * Sum(T^2) / (Sum|T|)^2, times 1000. window w = tangent half-span (px). 109func cs_facet(px: *i64, py: *i64, n: i64, w: i64) -> i64 { 110 if n < 4*w+4 { return 0 } 111 let ndx: *i64 = sys_mmap(8*(n+8)) as *i64 112 let ndy: *i64 = sys_mmap(8*(n+8)) as *i64 113 let MAG: i64 = K_MAGIC_1024 114 var i: i64=0 115 while i<n { 116 let ia: i64=(i+w)%n 117 let ib: i64=(i-w+n)%n 118 let dx: i64=px[ia]-px[ib] 119 let dy: i64=py[ia]-py[ib] 120 let mag: i64=cs_isqrt(dx*dx+dy*dy) 121 if mag>0 { ndx[i]=(dx*MAG)/mag; ndy[i]=(dy*MAG)/mag } else { ndx[i]=0; ndy[i]=0 } 122 i=i+1 123 } 124 var sumAbs: i64=0 125 var sumSq: i64=0 126 i=0 127 while i<n { 128 let j: i64=(i+1)%n 129 var t: i64=(ndx[i]*ndy[j] - ndy[i]*ndx[j])/MAG // ~ MAG*sin(turn) 130 var ta: i64=t 131 if ta<0 { ta=0-ta } 132 sumAbs=sumAbs+ta 133 sumSq=sumSq+ta*ta // T^2 (abs^2 == t^2) 134 i=i+1 135 } 136 if sumAbs<=0 { return 0 } 137 return (n * sumSq * 1000) / (sumAbs * sumAbs) 138} 139 140func cs_load(path: *u8, wh: *i64) -> *u8 { 141 let lp: *i64 = sys_mmap(16) as *i64 142 lp[0]=0-1 143 let raw: *u8 = sys_read_file(path, lp) 144 if lp[0]<=0 { return 0 as *u8 } 145 return nx_img_bytes_to_rgb(raw, lp[0], wh) 146} 147func cs_measure_png(path: *u8) -> i64 { 148 let wh: *i64 = sys_mmap(16) as *i64 149 let rgb: *u8 = cs_load(path, wh) 150 if rgb==(0 as *u8) { return 0 - 1 } 151 let px: *i64 = sys_mmap(8*K_MAGIC_40000) as *i64 152 let py: *i64 = sys_mmap(8*K_MAGIC_40000) as *i64 153 let n: i64 = cs_trace(rgb, wh[0], wh[1], px, py, K_MAGIC_40000) 154 if n<40 { return 0 - 2 } 155 return cs_facet(px, py, n, 6) 156} 157 158func main() -> i64 { 159 cs_puts("=== nx_curve_smoothness_census -- weight-invariant FACETING metric (contour turning) ===\n" as *u8) 160 let W: i64=400 161 let H: i64=400 162 let rgb: *u8 = sys_mmap(W*H*3+64) 163 let px: *i64 = sys_mmap(8*K_MAGIC_40000) as *i64 164 let py: *i64 = sys_mmap(8*K_MAGIC_40000) as *i64 165 let vx: *i64 = sys_mmap(8*8) as *i64 166 let vy: *i64 = sys_mmap(8*8) as *i64 167 168 // ---- LIAR-KILL: circle (smooth floor) vs hexagon (6 corners) ---- 169 cs_make_circle(rgb, W, H, 200, 200, 150) 170 let nc: i64 = cs_trace(rgb, W, H, px, py, K_MAGIC_40000) 171 let circ: i64 = cs_facet(px, py, nc, 6) 172 cs_make_hexagon(rgb, W, H, 200, 200, 160, vx, vy) 173 let nh: i64 = cs_trace(rgb, W, H, px, py, K_MAGIC_40000) 174 let hexf: i64 = cs_facet(px, py, nh, 6) 175 cs_puts(" synthetic CIRCLE facet_index(x1000)=" as *u8); cs_num(circ); cs_puts(" (smooth floor) contour pts=" as *u8); cs_num(nc); cs_puts("\n" as *u8) 176 cs_puts(" synthetic HEXAGON facet_index(x1000)=" as *u8); cs_num(hexf); cs_puts(" (6 corners) contour pts=" as *u8); cs_num(nh); cs_puts("\n" as *u8) 177 var metric_ok: i64=0 178 if hexf > circ*2 { metric_ok=1 } // hexagon MUST read at least 2x rougher than a circle 179 if metric_ok==0 { 180 cs_puts(" LIAR-KILL FIRED: the metric cannot tell a circle from a hexagon -> INVALID\n" as *u8) 181 cs_puts("NX-CURVE-SMOOTHNESS: BROKEN\n" as *u8); sys_exit(1); return 1 182 } 183 cs_puts(" metric liar-kill: PASS (hexagon reads >2x rougher than circle -> the metric isolates faceting)\n" as *u8) 184 185 // ---- the real question: our "O" vs Chrome's "O" (vs the circle floor) ---- 186 let oursO: i64 = cs_measure_png("knowledge/status/typeq_O_ours.png\x00" as *u8) 187 let chrO: i64 = cs_measure_png("knowledge/status/typeq_O_chrome.png\x00" as *u8) 188 cs_puts(" our 'O' facet_index(x1000)=" as *u8); cs_num(oursO); cs_puts("\n" as *u8) 189 cs_puts(" chrome 'O' facet_index(x1000)=" as *u8); cs_num(chrO); cs_puts("\n" as *u8) 190 var pass: i64=0 191 var ttl: i64=0 192 ttl=ttl+1; if metric_ok==1 { pass=pass+1 } 193 ttl=ttl+1; cs_puts(" C2 both O's measured: " as *u8); if oursO>0 { if chrO>0 { pass=pass+1; cs_puts("PASS\n" as *u8) } else { cs_puts("FAIL\n" as *u8) } } else { cs_puts("FAIL\n" as *u8) } 194 // The RIGHT reference for "is it faceted" is the CIRCLE FLOOR (+ HEXAGON ceiling), NOT Chrome -- because a 195 // professional font is intentionally MODULATED (Arial's O isn't a pure circle), so scoring nearer the circle 196 // than Chrome means "more circular / blander", NOT "better". So we ground ONLY the faceting claim here. 197 if oursO>0 { 198 let above_floor: i64 = ((oursO - circ) * 1000) / circ // how far our O sits above the smooth floor 199 let span: i64 = hexf - circ 200 let toward_hex: i64 = ((oursO - circ) * 1000) / span // 0 = at circle floor, 1000 = at hexagon 201 cs_puts(" >>> FACETING: our O sits " as *u8); cs_num(above_floor); cs_puts(" permille above the CIRCLE floor, " as *u8); cs_num(toward_hex); cs_puts(" permille of the way to the HEXAGON ceiling\n" as *u8) 202 if toward_hex < 100 { cs_puts(" GROUNDED: our O is at the smooth-circle floor (<10% toward faceted) -> FACETING ELIMINATED (Chaikin worked), MEASURED weight-invariantly.\n" as *u8) } 203 else { cs_puts(" HONEST: our O is measurably faceted (well above the circle floor) -> curves NOT yet smooth.\n" as *u8) } 204 } 205 if oursO>0 { if chrO>0 { 206 var rr: i64=0 207 rr=(oursO*1000)/chrO 208 cs_puts(" ~ vs Chrome's O = " as *u8); cs_num(rr); cs_puts(" permille -- ★NOT a quality verdict: Chrome's Arial O is intentionally MODULATED (design), so 'more circular than Chrome' != 'better'. Eyeball: Chrome's O is the better-drawn letter (bolder, modulated); this metric ONLY proves faceting.\n" as *u8) 209 } } 210 // benchmark log line (composed by nx_font_pioneer_benchmark): faceting = permille toward the hexagon 211 if oursO>0 { 212 let span2: i64 = hexf - circ 213 var th: i64 = 0 214 if span2>0 { th = ((oursO - circ) * 1000) / span2 } 215 if th<0 { th=0 } 216 let lg: *u8 = sys_mmap(96); var lo: i64=0 217 let pfx: *u8 = "FONT-FACET toward_hex=\x00" as *u8; while pfx[lo]!=(0 as u8) { lg[lo]=pfx[lo]; lo=lo+1 } 218 let t: *u8=sys_mmap(24); var k: i64=0; var m: i64=th; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var z: i64=0; while z<k{lg[lo]=t[k-1-z];lo=lo+1;z=z+1} 219 lg[lo]=10 as u8; lo=lo+1 220 let fd: i64=sys_openat_wr("knowledge/status/font_facet.log\x00" as *u8, 0x1a4) 221 if fd>0 { sys_write(fd, lg, lo); sys_close(fd) } 222 } 223 cs_puts("CURVE-SMOOTHNESS-CENSUS-GATE passed " as *u8); cs_num(pass); cs_puts("/" as *u8); cs_num(ttl) 224 if pass==ttl { cs_puts(" verdict=GREEN (faceting MEASURED weight-invariantly, liar-killed)\n" as *u8); sys_exit(0); return 0 } 225 cs_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1 226}