nx_solid_grid_candidate_t365.nx source
↩ module page · 58 lines · 6962 B
1// Part-aware union grid, using counted YZ buckets and one reusable workspace.
2// Field scalars are signed X-column boundary distances; NOT Euclidean SDF.
3// Unmerged (part ID, crossing) events are retained for every column as provenance.
4import "nx_solid_mesh_column_candidate_t365.nx"
5struct SfgRecipe { ox:i64,oy:i64,oz:i64,step:i64,nx:i64,ny:i64,nz:i64,units:i64,max_bytes:i64,max_tests:i64, }
6struct SfgStats { field_words:i64,columns:i64,event_offset:i64,event_count:i64,peak_bytes:i64,tests:i64,insertions:i64,max_bucket:i64,failed_y:i64,failed_z:i64, }
7func sfg_add(a:i64,b:i64)->i64{if a<0||b<0||b>NX_BO_I64_MAX-a{return -1};return a+b}
8func sfg_mul(a:i64,b:i64)->i64{if a<0||b<0{return -1};if a==0||b==0{return 0};if b>NX_BO_I64_MAX/a{return -1};return a*b}
9func sfg_axis(o:i64,n:i64,step:i64)->i64{if o<0-SFC_COORD||o>SFC_COORD||n<1||step<1||step>2*SFC_COORD{return 0};if n-1>(SFC_COORD-o)/step{return 0};return 1}
10func sfg_lo(t:*i64,axis:i64,o:i64,step:i64,n:i64)->i64{var v:i64=t[axis];if t[axis+3]<v{v=t[axis+3]};if t[axis+6]<v{v=t[axis+6]};if v<=o{return 0};let j:i64=(v-o+step-1)/step;if j>n{return n};return j}
11func sfg_hi(t:*i64,axis:i64,o:i64,step:i64,n:i64)->i64{var v:i64=t[axis];if t[axis+3]>v{v=t[axis+3]};if t[axis+6]>v{v=t[axis+6]};if v<o{return -1};let j:i64=(v-o)/step;if j>=n{return n-1};return j}
12func sfg_grid_v1(tri:*i64,nt:i64,part_tris:*i64,np:i64,r:*SfgRecipe,out:*NxBufOwned,stats:*SfgStats,e:*SfuFailure)->i64{
13 if (r as i64)<=0||(stats as i64)<=0||(e as i64)<=0{return SFU_INVALID}
14 stats.field_words=0;stats.columns=0;stats.event_offset=0;stats.event_count=0;stats.peak_bytes=0;stats.tests=0;stats.insertions=0;stats.max_bucket=0;stats.failed_y=-1;stats.failed_z=-1;e.code=0;e.part=-1;e.crossing=-1
15 if nx_bo_state(out)!=0{return sfu_fail(e,SFU_INVALID,-1,-1)};if out.cap!=0{return sfu_fail(e,SFU_INVALID,-1,-1)}
16 if nt<0||nt>NX_BO_I64_MAX/72||np<0||np>NX_BO_I64_MAX/8{return sfu_fail(e,SFU_RESOURCE,-1,-1)}
17 if nt>0&&(tri as i64)<=0{return sfu_fail(e,SFU_INVALID,-1,-1)};if np>0&&(part_tris as i64)<=0{return sfu_fail(e,SFU_INVALID,-1,-1)}
18 if r.units<=0||r.max_bytes<=0||r.max_tests<=0{return sfu_fail(e,SFU_RESOURCE,-1,-1)}
19 if sfg_axis(r.ox,r.nx,r.step)==0||sfg_axis(r.oy,r.ny,r.step)==0||sfg_axis(r.oz,r.nz,r.step)==0{return sfu_fail(e,SFC_DOMAIN,-1,-1)}
20 var p:i64=0;var sum:i64=0;while p<np{if part_tris[p]<0||part_tris[p]>nt-sum{return sfu_fail(e,SFU_INVALID,p,part_tris[p])};sum=sum+part_tris[p];p=p+1};if sum!=nt{return sfu_fail(e,SFU_INVALID,np,sum)}
21 let columns:i64=sfg_mul(r.ny,r.nz);let nodes:i64=sfg_mul(r.nx,columns);if columns<0||nodes<0{return sfu_fail(e,SFU_RESOURCE,-1,-1)}
22 var ti:i64=0;var inserts:i64=0
23 while ti<nt{let t:*i64=(tri as *u8+ti*72) as *i64;var j:i64=0;while j<9{if t[j]<0-SFC_COORD||t[j]>SFC_COORD{return sfu_fail(e,SFC_DOMAIN,-1,ti)};j=j+1}
24 let yl:i64=sfg_lo(t,1,r.oy,r.step,r.ny);let yh:i64=sfg_hi(t,1,r.oy,r.step,r.ny);let zl:i64=sfg_lo(t,2,r.oz,r.step,r.nz);let zh:i64=sfg_hi(t,2,r.oz,r.step,r.nz)
25 if yh>=yl&&zh>=zl{inserts=sfg_add(inserts,sfg_mul(yh-yl+1,zh-zl+1));if inserts<0||inserts>r.max_tests{return sfu_fail(e,SFU_RESOURCE,-1,inserts)}};ti=ti+1}
26 // Worst-case provenance is two words per tested triangle. No event truncation.
27 let output_words:i64=sfg_add(sfg_add(nodes,sfg_mul(columns,2)),sfg_mul(inserts,2))
28 let work_words:i64=sfg_add(sfg_add(sfg_add(columns,sfg_mul(inserts,2)),sfg_mul(nt,3)),sfg_add(np,1))
29 let out_bytes:i64=sfg_mul(output_words,8);let work_bytes:i64=sfg_mul(work_words,8);let peak:i64=sfg_add(out_bytes,work_bytes)
30 if peak<0||peak>r.max_bytes{return sfu_fail(e,SFU_RESOURCE,-1,peak)}
31 let raw:*u8=sys_mmap_try(out_bytes);if (raw as i64)<=0{return sfu_fail(e,SFU_ALLOCATION,-1,out_bytes)}
32 let work:*u8=sys_mmap_try(work_bytes);if (work as i64)<=0{sys_munmap_direct(raw,out_bytes);return sfu_fail(e,SFU_ALLOCATION,-1,work_bytes)}
33 let field:*i64=raw as *i64;let colmeta:*i64=(raw+nodes*8) as *i64;let history:*i64=(raw+(nodes+columns*2)*8) as *i64
34 let heads:*i64=work as *i64;let next:*i64=(work+columns*8) as *i64;let refs:*i64=(work+(columns+inserts)*8) as *i64
35 let owner:*i64=(work+(columns+inserts*2)*8) as *i64;let counts:*i64=(work+(columns+inserts*2+nt)*8) as *i64
36 let events:*i64=(work+(columns+inserts*2+nt+np)*8) as *i64;let scratch:*i64=(work+(work_words-1)*8) as *i64
37 var i:i64=0;while i<columns{heads[i]=-1;i=i+1};p=0;ti=0;while p<np{var j:i64=0;while j<part_tris[p]{owner[ti]=p;ti=ti+1;j=j+1};p=p+1}
38 var filled:i64=0;ti=0;while ti<nt{let t:*i64=(tri as *u8+ti*72) as *i64
39 let yl:i64=sfg_lo(t,1,r.oy,r.step,r.ny);let yh:i64=sfg_hi(t,1,r.oy,r.step,r.ny);let zl:i64=sfg_lo(t,2,r.oz,r.step,r.nz);let zh:i64=sfg_hi(t,2,r.oz,r.step,r.nz)
40 var y:i64=yl;while y<=yh{var z:i64=zl;while z<=zh{let col:i64=y*r.nz+z;if filled>=inserts{sys_munmap_direct(work,work_bytes);sys_munmap_direct(raw,out_bytes);return sfu_fail(e,SFU_INVALID,-1,filled)};next[filled]=heads[col];refs[filled]=ti;heads[col]=filled;filled=filled+1;z=z+1};y=y+1};ti=ti+1}
41 if filled!=inserts{sys_munmap_direct(work,work_bytes);sys_munmap_direct(raw,out_bytes);return sfu_fail(e,SFU_INVALID,-1,filled)}
42 stats.field_words=nodes;stats.columns=columns;stats.event_offset=(nodes+columns*2)*8;stats.peak_bytes=peak;stats.insertions=inserts
43 var rc:i64=0;var column:i64=0;var saved:i64=0
44 while column<columns&&rc==0{let iy:i64=column/r.nz;let iz:i64=column%r.nz;let y:i64=r.oy+iy*r.step;let z:i64=r.oz+iz*r.step
45 p=0;while p<np{counts[p]=0;p=p+1};var nh:i64=0;var bucket:i64=0;var at:i64=heads[column]
46 while at>=0&&rc==0{let tid:i64=refs[at];let hit:i64=sfc_cross_v1((tri as *u8+tid*72) as *i64,y,z,scratch);stats.tests=stats.tests+1;bucket=bucket+1
47 if hit<0{rc=sfu_fail(e,hit,owner[tid],tid)}else{if hit==1{events[nh*2]=owner[tid];events[nh*2+1]=scratch[0];nh=nh+1}};at=next[at]}
48 if bucket>stats.max_bucket{stats.max_bucket=bucket}
49 if rc==0{rc=nx_sort_pairs_first(events,nh)}
50 colmeta[column*2]=saved;colmeta[column*2+1]=nh
51 i=0;while i<nh&&rc==0{let part:i64=events[i*2];let crossing:i64=events[i*2+1];history[saved*2]=part;history[saved*2+1]=crossing;saved=saved+1;counts[part]=counts[part]+1;events[i]=crossing;i=i+1}
52 var offset:i64=0;p=0;while p<np&&rc==0{let count:i64=counts[p];if (count&1)!=0{rc=sfu_fail(e,SFU_ODD,p,count)}else{nx_sort_insertion((events as *u8+offset*8) as *i64,count);i=1;while i<count&&rc==0{if events[offset+i]==events[offset+i-1]{rc=sfu_fail(e,SFC_PRECISION,p,i)};i=i+1}};offset=offset+count;p=p+1}
53 if rc==0{let used:i64=sfu_merge_workspace_v1(events,nh);if used<0{rc=sfu_fail(e,used,-1,nh)}else{var x:i64=0;while x<r.nx&&rc==0{let v:i64=sfu_column_value(events,used,r.ox+x*r.step,2*SFC_COORD,scratch);if v<0{rc=sfu_fail(e,v,-1,x)}else{field[(x*r.ny+iy)*r.nz+iz]=scratch[0]};x=x+1}}}
54 if rc<0{stats.failed_y=iy;stats.failed_z=iz};column=column+1}
55 sys_munmap_direct(work,work_bytes);stats.event_count=saved
56 if rc<0{sys_munmap_direct(raw,out_bytes);return rc}
57 out.buf=raw;out.cap=out_bytes;out.len=(nodes+columns*2+saved*2)*8;return 0
58}