code wiki / (root) / nx_nxa_surface_support_candidate_t207.nx

nx_nxa_surface_support_candidate_t207.nx source

↩ module page · 144 lines · 13879 B

1// nx_nxa_surface_support_candidate_t207.nx -- Computes surface intersection parameters for garment attachment validation using exact rational arithmetic. 2import "nx_quicksort.nx" 3// Private candidate: generic surface query composed from canonical NXA attachment validation. 4// Returns existing face,bary0,bary1,bary2,denominator tuple; no new disk section or material kind. 5import "nx_nxa_garment_bind_lib.nx" 6const NSA_E_INPUT:i64=-50 7const NSA_E_RANGE:i64=-51 8const NSA_E_MISS:i64=-52 9const NSA_E_AMBIGUOUS:i64=-53 10// Exact fraction comparison without cross-products. Inputs nonnegative, denominators positive. 11func nsa_unsigned_ratio_cmp(a:i64,b:i64,c:i64,d:i64)->i64{ 12 var x:i64=a;var y:i64=b;var z:i64=c;var w:i64=d;var sign:i64=1 13 while true{let p:i64=x/y;let q:i64=z/w;if p<q{return 0-sign};if p>q{return sign} 14 let r:i64=x%y;let s:i64=z%w;if r==0{if s==0{return 0};return 0-sign};if s==0{return sign} 15 x=y;y=r;z=w;w=s;sign=0-sign 16 };return 0 17} 18func nsa_ratio_cmp(a:i64,b:i64,c:i64,d:i64)->i64{ 19 if a<0{if c>=0{return -1};return 0-nsa_unsigned_ratio_cmp(0-a,b,0-c,d)} 20 if c<0{return 1};return nsa_unsigned_ratio_cmp(a,b,c,d) 21} 22// Coordinate bounds inherited from canonical source validation make 2D determinants exact i64. 23// y numerator is checked independently, since determinant times depth can exceed i64. 24func nsa_triangle_y_v1(p:*i64,idx:*i64,face:i64,qx:i64,qz:i64,result:*i64)->i64{ 25 let a:i64=idx[face*3]*3;let b:i64=idx[face*3+1]*3;let c:i64=idx[face*3+2]*3 26 let x:i64=p[b]-p[a];let z:i64=p[b+2]-p[a+2];let u:i64=p[c]-p[a];let v:i64=p[c+2]-p[a+2] 27 let dx:i64=qx-p[a];let dz:i64=qz-p[a+2];var den:i64=x*v-z*u 28 if den==0{return NSA_E_MISS};var w1:i64=dx*v-dz*u;var w2:i64=x*dz-z*dx 29 if den<0{den=0-den;w1=0-w1;w2=0-w2};if w1<0||w2<0||w1>den||w2>den-w1{return NSA_E_MISS} 30 var w0:i64=den-w1-w2;let gcd:i64=ngb_clip_gcd(ngb_clip_gcd(w0,w1),ngb_clip_gcd(w2,den));w0=w0/gcd;w1=w1/gcd;w2=w2/gcd;den=den/gcd 31 result[0]=w0;result[1]=w1;result[2]=w2;result[3]=den;var depth:i64=0;var k:i64=0 32 while k<3{let y:i64=p[idx[face*3+k]*3+1];let mag:i64=ngb_clip_product(ngb_abs(y),result[k]);if mag<0{return NSA_E_RANGE} 33 if y<0{if depth<0-NGB_CLIP_I64_MAX+mag{return NSA_E_RANGE};depth=depth-mag} 34 else{if depth>NGB_CLIP_I64_MAX-mag{return NSA_E_RANGE};depth=depth+mag};k=k+1 35 };result[4]=depth;return 0 36} 37// direction=-1 chooses smallest Y, +1 greatest Y. Integer query coordinates are caller data. 38// Caller output: five i64 words; scratch: twelve disjoint i64 words. Output unchanged on refusal. 39// Equal-depth overlapping hits refuse instead of guessing an attachment seam. 40func nsa_landmark_y_v1(b:*u8,n:i64,qx:i64,qz:i64,direction:i64,out:*i64,cap:i64,work:*i64,words:i64)->i64{ 41 if direction!=-1&&direction!=1{return NSA_E_INPUT} 42 if qx<0-NGB_ATTACH_COORD_MAX||qx>NGB_ATTACH_COORD_MAX||qz<0-NGB_ATTACH_COORD_MAX||qz>NGB_ATTACH_COORD_MAX{return NSA_E_RANGE} 43 if cap<5||words<12{return NSA_E_INPUT};let valid:i64=ngb_attach_source_v1(b,n);if valid<0{return valid} 44 let ow:i64=ngp_output(b,n,out as *u8,40,40);if ow<0{return ow} 45 let sw:i64=ngp_output(b,n,work as *u8,96,96);if sw<0{return sw} 46 let overlap:i64=ngp_output(work as *u8,96,out as *u8,40,40);if overlap<0{return overlap} 47 let va:i64=nxa_counted_section(b,n,nxa_tag4("VERT"),3);let ta:i64=nxa_counted_section(b,n,nxa_tag4("TRIS"),3);let h:*i64=b as *i64 48 let p:*i64=((b as i64)+(va+1)*8) as *i64;let idx:*i64=((b as i64)+(ta+1)*8) as *i64 49 return nsa_landmark_mesh_y_v1(p,idx,h[ta],qx,qz,direction,out,work) 50} 51// Internal mesh view: source and disjoint storage already validated by boundary. 52func nsa_landmark_mesh_y_v1(p:*i64,idx:*i64,nt:i64,qx:i64,qz:i64,direction:i64,out:*i64,work:*i64)->i64{ 53 let trial:*i64=work;let best:*i64=((work as i64)+48) as *i64;var face:i64=0;var selected:i64=-1;var ambiguous:i64=0 54 while face<nt{let rc:i64=nsa_triangle_y_v1(p,idx,face,qx,qz,trial);if rc==NSA_E_RANGE{return rc} 55 if rc==0{var comparison:i64=0;if selected>=0{comparison=nsa_ratio_cmp(trial[4],trial[3],best[4],best[3])} 56 if selected<0||comparison==direction{selected=face;ambiguous=0;var k:i64=0;while k<5{best[k]=trial[k];k=k+1}} 57 else{if comparison==0{ambiguous=1}} 58 };face=face+1 59 };if selected<0{return NSA_E_MISS};if ambiguous!=0{return NSA_E_AMBIGUOUS} 60 out[0]=selected;var k:i64=0;while k<4{out[k+1]=best[k];k=k+1};return 0 61} 62 63// Topological correspondence only: labels identify connected source vertices, never anatomy. 64// Stable label is the minimum source vertex index, independent of triangle order. 65func nsa_component_root_v1(labels:*i64,v:i64)->i64{ 66 var root:i64=v;while labels[root]!=root{root=labels[root]} 67 var q:i64=v;while labels[q]!=q{let next:i64=labels[q];labels[q]=root;q=next};return root 68} 69func nsa_component_join_v1(labels:*i64,a:i64,b:i64)->i64{ 70 let x:i64=nsa_component_root_v1(labels,a);let y:i64=nsa_component_root_v1(labels,b) 71 if x<y{labels[y]=x}else{if y<x{labels[x]=y}};return 0 72} 73// Boundary validation completes before output writes. Capacity is measured in i64 labels. 74// Required capacity derives from the validated VERT count; isolated vertices remain components. 75func nsa_component_labels_v1(b:*u8,n:i64,labels:*i64,capacity:i64)->i64{ 76 let valid:i64=ngb_attach_source_v1(b,n);if valid<0{return valid} 77 let va:i64=nxa_counted_section(b,n,nxa_tag4("VERT"),3);let ta:i64=nxa_counted_section(b,n,nxa_tag4("TRIS"),3);let h:*i64=b as *i64 78 let nv:i64=h[va];let nt:i64=h[ta];if capacity<nv{return NSA_E_INPUT} 79 if nv>NGB_CLIP_I64_MAX/8{return NSA_E_RANGE} 80 let space:i64=ngp_output(b,n,labels as *u8,nv*8,nv*8);if space<0{return space} 81 let idx:*i64=((b as i64)+(ta+1)*8) as *i64 82 var i:i64=0;while i<nv{labels[i]=i;i=i+1} 83 i=0;while i<nt{let a:i64=idx[i*3];nsa_component_join_v1(labels,a,idx[i*3+1]);nsa_component_join_v1(labels,a,idx[i*3+2]);i=i+1} 84 var count:i64=0;i=0;while i<nv{labels[i]=nsa_component_root_v1(labels,i);if labels[i]==i{count=count+1};i=i+1};return count 85} 86 87const NSA_E_MIXED_SUPPORT:i64=-54 88// Derive rigid attachment support from the actual connected component and skin weights. 89// A mixed-joint component requires shared deformation, never an inferred replacement joint. 90func nsa_rigid_component_joint_v1(b:*u8,n:i64,seed:i64,labels:*i64,capacity:i64)->i64{ 91 let rc:i64=nsa_component_labels_v1(b,n,labels,capacity);if rc<0{return rc} 92 let va:i64=nxa_counted_section(b,n,nxa_tag4("VERT"),3);let sk:i64=nxa_counted_section(b,n,nxa_tag4("SKIN"),8);let sj:i64=nxa_counted_section(b,n,nxa_tag4("SKEL"),8);if va<0||sk<0||sj<0{return NSA_E_INPUT} 93 let h:*i64=b as *i64;let nv:i64=h[va];let nj:i64=h[sj];if seed<0||seed>=nv||h[sk]!=nv||nj<1{return NSA_E_INPUT} 94 let component:i64=labels[seed];var selected:i64=-1;var v:i64=0 95 while v<nv{if labels[v]==component{var sum:i64=0;var k:i64=0;while k<4{let j:i64=h[sk+1+v*8+k];let w:i64=h[sk+1+v*8+4+k];if j<0||j>=nj||w<0||w>4096{return NSA_E_INPUT};sum=sum+w;if w>0{if selected<0{selected=j}else{if selected!=j{return NSA_E_MIXED_SUPPORT}}};k=k+1};if sum!=4096{return NSA_E_INPUT}};v=v+1};return selected 96} 97 98// Exact source component boundary edges, not anatomical landmarks. 99// A measure call uses out=null,out_words=0 and still requires labels/sort workspace. 100// Labels need nv words; sort workspace needs 3*nt words. Output is [a,b] per edge. 101// All storage is caller owned. Output remains unchanged on refusal. 102const NSA_E_NONMANIFOLD:i64=-55 103func nsa_component_boundary_v1(b:*u8,n:i64,seed:i64,labels:*i64,label_words:i64,work:*i64,work_words:i64,out:*i64,out_words:i64)->i64{ 104 let valid:i64=ngb_attach_source_v1(b,n);if valid<0{return valid} 105 let va:i64=nxa_counted_section(b,n,nxa_tag4("VERT"),3);let ta:i64=nxa_counted_section(b,n,nxa_tag4("TRIS"),3);let h:*i64=b as *i64;let nv:i64=h[va];let nt:i64=h[ta] 106 if seed<0||seed>=nv||label_words<nv||nt>NGB_CLIP_I64_MAX/24||nv>NGB_CLIP_I64_MAX/8||work_words<nt*3||out_words<0||out_words>NGB_CLIP_I64_MAX/8{return NSA_E_INPUT} 107 if ngb_clip_product(nv,nv)<0{return NSA_E_RANGE} 108 let lb:i64=nv*8;let wb:i64=nt*24;let ob:i64=out_words*8 109 if ngp_output(b,n,labels as *u8,lb,lb)<0||ngp_output(b,n,work as *u8,wb,wb)<0||ngp_output(labels as *u8,lb,work as *u8,wb,wb)<0{return NSA_E_INPUT} 110 if ob>0{if ngp_output(b,n,out as *u8,ob,ob)<0||ngp_output(labels as *u8,lb,out as *u8,ob,ob)<0||ngp_output(work as *u8,wb,out as *u8,ob,ob)<0{return NSA_E_INPUT}} 111 if ob==0&&(out as i64)!=0{return NSA_E_INPUT} 112 let rc:i64=nsa_component_labels_v1(b,n,labels,label_words);if rc<0{return rc};let root:i64=labels[seed];let idx:*i64=((b as i64)+(ta+1)*8) as *i64 113 var count:i64=0;var t:i64=0;while t<nt{if labels[idx[t*3]]==root{var k:i64=0;while k<3{let a:i64=idx[t*3+k];let c:i64=idx[t*3+(k+1)%3];if a<c{work[count]=a*nv+c}else{work[count]=c*nv+a};count=count+1;k=k+1}};t=t+1} 114 nx_quicksort(work as *nx_int,count);var at:i64=0;var boundary:i64=0 115 while at<count{var end:i64=at+1;while end<count&&work[end]==work[at]{end=end+1};if end-at>2{return NSA_E_NONMANIFOLD};if end-at==1{boundary=boundary+1};at=end} 116 if ob==0{return boundary};if boundary>out_words/2{return NSA_E_INPUT} 117 at=0;var written:i64=0;while at<count{var end:i64=at+1;while end<count&&work[end]==work[at]{end=end+1};if end-at==1{out[written*2]=work[at]/nv;out[written*2+1]=work[at]%nv;written=written+1};at=end} 118 return written 119} 120 121import "nx_fs_create_lib.nx" 122import "nx_sha256.nx" 123// Count/write serializer: null data pointer measures exact output bytes. 124func nsa_text(r:*i64,s:*u8)->i64{var n:i64=0;while s[n]!=0{n=n+1};if n>NGB_CLIP_I64_MAX-r[2]{r[3]=1;return -1};if r[0]!=0{if r[2]>r[1]||n>r[1]-r[2]{r[3]=1;return -1};let b:*u8=r[0] as *u8;var i:i64=0;while i<n{b[r[2]+i]=s[i];i=i+1}};r[2]=r[2]+n;return n} 125func nsa_number(r:*i64,x:i64)->i64{let b:*u8=r[4] as *u8;var v:i64=x;var p:i64=30;b[31]=0 as u8;if v<0{nsa_text(r,"-");v=0-v};if v==0{b[p]=48 as u8;p=p-1};while v>0{b[p]=(48+v%10) as u8;v=v/10;p=p-1};return nsa_text(r,((b as i64)+p+1) as *u8)} 126func nsa_seed_arg(s:*u8)->i64{var i:i64=0;var n:i64=0;if s[0]==0{return -1};while s[i]!=0{let v:i64=s[i] as i64;if v<48||v>57||n>(NGB_CLIP_I64_MAX-(v-48))/10{return -1};n=n*10+v-48;i=i+1};return n} 127func nsa_support_json(r:*i64,sha:*u8,n:i64,records:*i64,count:i64,edges:*i64)->i64{ 128 nsa_text(r,"{\"schema\":\"nishi.source.component-support.v1\",\"selection\":\"caller-provided seeds; anatomical identity unqualified\",\"sourceSha256\":\"");nsa_text(r,sha);nsa_text(r,"\",\"sourceBytes\":");nsa_number(r,n);nsa_text(r,",\"coordinateFrame\":\"source mesh bind coordinates\",\"components\":["); 129 var i:i64=0;while i<count{if i>0{nsa_text(r,",")};let a:i64=i*5;nsa_text(r,"{\"seed\":");nsa_number(r,records[a]);nsa_text(r,",\"component\":");nsa_number(r,records[a+1]);nsa_text(r,",\"rigidJoint\":");if records[a+2]<0{nsa_text(r,"null")}else{nsa_number(r,records[a+2])};nsa_text(r,",\"supportResult\":");nsa_number(r,records[a+2]);nsa_text(r,",\"boundaryEdges\":[");var e:i64=0;while e<records[a+3]{if e>0{nsa_text(r,",")};let k:i64=records[a+4]+e*2;nsa_text(r,"[");nsa_number(r,edges[k]);nsa_text(r,",");nsa_number(r,edges[k+1]);nsa_text(r,"]");e=e+1};nsa_text(r,"]}");i=i+1};nsa_text(r,"]}\n");return r[3] 130} 131func main(argc:i64,argv:*i64)->i64{ 132 if argc<4{fsx_puts("usage: asset.nxa output.json component_seed...\n");return 2} 133 let size:*i64=sys_mmap_try(16) as *i64;if (size as i64)<=0{return 3};let b:*u8=sys_map_file(argv[1] as *u8,size);if (b as i64)<=0{return 3};let n:i64=size[0];let valid:i64=ngb_attach_source_v1(b,n);if valid<0{return 4} 134 let h:*i64=b as *i64;let va:i64=nxa_counted_section(b,n,nxa_tag4("VERT"),3);let ta:i64=nxa_counted_section(b,n,nxa_tag4("TRIS"),3);let nv:i64=h[va];let nt:i64=h[ta];let count:i64=argc-3 135 if nv>NGB_CLIP_I64_MAX/8||nt>NGB_CLIP_I64_MAX/24||count>NGB_CLIP_I64_MAX/40{return 5} 136 let labels:*i64=sys_mmap_try(nv*8) as *i64;let work:*i64=sys_mmap_try(nt*24) as *i64;let records:*i64=sys_mmap_try(count*40) as *i64;if (labels as i64)<=0||(work as i64)<=0||(records as i64)<=0{return 3} 137 var total:i64=0;var i:i64=0;while i<count{let seed:i64=nsa_seed_arg(argv[i+3] as *u8);let need:i64=nsa_component_boundary_v1(b,n,seed,labels,nv,work,nt*3,0 as *i64,0);if need<0{return 6};if need>(NGB_CLIP_I64_MAX-total)/2{return 5} 138 let a:i64=i*5;records[a]=seed;records[a+1]=labels[seed];records[a+2]=nsa_rigid_component_joint_v1(b,n,seed,labels,nv);records[a+3]=need;records[a+4]=total;var j:i64=0;while j<i{if records[j*5+1]==records[a+1]{return 7};j=j+1};total=total+need*2;i=i+1} 139 if total>NGB_CLIP_I64_MAX/8{return 5};let edges:*i64=sys_mmap_try((total+1)*8) as *i64;if (edges as i64)<=0{return 3};i=0;while i<count{let a:i64=i*5;if records[a+3]>0{let dst:*i64=((edges as i64)+records[a+4]*8) as *i64;let written:i64=nsa_component_boundary_v1(b,n,records[a],labels,nv,work,nt*3,dst,records[a+3]*2);if written!=records[a+3]{return 8}};i=i+1} 140 let hs:*u8=sys_mmap_try(104);let r:*i64=sys_mmap_try(72) as *i64;if (hs as i64)<=0||(r as i64)<=0{return 3};let hex:*u8=((hs as i64)+32) as *u8;sha256_digest(b,n,hs);let digits:*u8="0123456789abcdef";i=0;while i<32{let v:i64=hs[i] as i64;hex[i*2]=digits[v/16];hex[i*2+1]=digits[v%16];i=i+1};hex[64]=0 as u8 141 r[0]=0;r[1]=0;r[2]=0;r[3]=0;r[4]=(r as i64)+40;if nsa_support_json(r,hex,n,records,count,edges)!=0{return 9};let bytes:i64=r[2];let output:*u8=sys_mmap_try(bytes);if (output as i64)<=0{return 3};r[0]=output as i64;r[1]=bytes;r[2]=0;if nsa_support_json(r,hex,n,records,count,edges)!=0||r[2]!=bytes{return 9} 142 var wrote:i64=fxc_create(argv[2] as *u8,output,bytes);if wrote==FXC_EXISTS{let oldn:*i64=sys_mmap_try(16) as *i64;if (oldn as i64)<=0{return 3};let old:*u8=sys_map_file(argv[2] as *u8,oldn);if (old as i64)<=0||oldn[0]!=bytes{return 10};i=0;while i<bytes{if old[i]!=output[i]{return 10};i=i+1};wrote=bytes} 143 if wrote!=bytes{return 11};fsx_puts("SOURCE-SUPPORT components=");fsx_putn(count);fsx_puts(" boundary_edges=");fsx_putn(total/2);fsx_puts(" bytes=");fsx_putn(bytes);fsx_puts(" source_sha256=");fsx_puts(hex);fsx_puts(" anatomical_qualification=0\n");return 0 144}