code wiki / (root) / nx_uv_quality_candidate_t282.nx

nx_uv_quality_candidate_t282.nx source

↩ module page · 77 lines · 6130 B

1// nx_uv_quality_candidate_t282.nx -- Evaluates UV quality metrics for triangles in a mesh, tracking orientation, area, and anisotropy. 2import "nx_uv_gram_solver_candidate_t280.nx" 3// Additive candidate for nx_uvunwrap_lib's distortion referee. Source 4// identity validation belongs to the input adapter, numerical coverage here. 5struct UvQuality{ 6 stage:i64,triangles:i64,positive:i64,negative:i64,collapsed:i64,unknown:i64, 7 maxAnisotropy:f64,worstTriangle:i64,minPositiveArea:f64 8} 9struct UvQualityPolicy{ 10 expectedTriangles:i64,expectedOrientation:i64,maxCollapsed:i64,maxReversed:i64,maxAnisotropy:f64 11} 12const UVQ_PASS:i64=0 13const UVQ_FAIL:i64=1 14const UVQ_UNKNOWN:i64=2 15const UVQ_INVALID:i64=3 16// IEEE754 binary64 unit roundoff. This is the format, not a quality policy. 17const UVQ_ROUNDOFF:f64=0.00000000000000011102230246251565404236316680908203125 18// 2*(2^31-1)^2 fits signed i64, certifying integer determinant arithmetic. 19const UVQ_DET_EDGE:i64=2147483647 20func uvq_abs(x:f64)->f64{if x<0.0{return 0.0-x};return x} 21func uvq_subnormal(x:f64)->i64{let bits:*i64=(&x) as *i64;if x==0.0{return 0};if (bits[0]&0x7ff0000000000000)==0{return 1};return 0} 22func uvq_reset(q:*UvQuality,stage:i64)->i64{ 23 if q==(0 as *UvQuality){return UVQ_INVALID};q.stage=stage;q.triangles=0;q.positive=0;q.negative=0;q.collapsed=0;q.unknown=0;q.maxAnisotropy=0.0;q.worstTriangle=0-1;q.minPositiveArea=0.0;return UVQ_PASS 24} 25// uv contains [u0,v0,u1,v1,u2,v2], xyz three source vertices. 26// Integer mode is allowed only for exact integer-valued doubles supplied 27// by a validated i64 adapter. Ambiguous floating orientation stays unknown. 28func uvq_triangle(q:*UvQuality,xyz:*f64,uv:*f64,integerMode:i64,sourceTriangle:i64)->i64{ 29 if q==(0 as *UvQuality){return UVQ_INVALID};if xyz==(0 as *f64){return UVQ_INVALID};if uv==(0 as *f64){return UVQ_INVALID} 30 if integerMode!=0{if integerMode!=1{return UVQ_INVALID}} 31 q.triangles=q.triangles+1;var k:i64=0;while k<9{if uls_finite(xyz[k])==0{q.unknown=q.unknown+1;return UVQ_UNKNOWN};k=k+1};k=0;while k<6{if uls_finite(uv[k])==0{q.unknown=q.unknown+1;return UVQ_UNKNOWN};k=k+1} 32 let du:f64=uv[2]-uv[0];let dv:f64=uv[3]-uv[1];let eu:f64=uv[4]-uv[0];let ev:f64=uv[5]-uv[1] 33 var area:f64=du*ev-dv*eu;var orientation:i64=0 34 if integerMode==1{ 35 k=0;while k<6{if uvq_abs(uv[k])>9007199254740992.0{q.unknown=q.unknown+1;return UVQ_UNKNOWN};if __f64_from_i64(__f64_to_i64(uv[k]))!=uv[k]{q.unknown=q.unknown+1;return UVQ_UNKNOWN};k=k+1} 36 let bound:f64=__f64_from_i64(UVQ_DET_EDGE) 37 if uvq_abs(du)>bound{q.unknown=q.unknown+1;return UVQ_UNKNOWN};if uvq_abs(dv)>bound{q.unknown=q.unknown+1;return UVQ_UNKNOWN};if uvq_abs(eu)>bound{q.unknown=q.unknown+1;return UVQ_UNKNOWN};if uvq_abs(ev)>bound{q.unknown=q.unknown+1;return UVQ_UNKNOWN} 38 let d:i64=__f64_to_i64(du)*__f64_to_i64(ev)-__f64_to_i64(dv)*__f64_to_i64(eu);area=__f64_from_i64(d);if d>0{orientation=1};if d<0{orientation=0-1} 39 }else{ 40 let product0:f64=du*ev;let product1:f64=dv*eu 41 if product0==0.0{if du!=0.0{if ev!=0.0{q.unknown=q.unknown+1;return UVQ_UNKNOWN}}} 42 if product1==0.0{if dv!=0.0{if eu!=0.0{q.unknown=q.unknown+1;return UVQ_UNKNOWN}}} 43 if uvq_subnormal(product0)==1{q.unknown=q.unknown+1;return UVQ_UNKNOWN};if uvq_subnormal(product1)==1{q.unknown=q.unknown+1;return UVQ_UNKNOWN} 44 let err:f64=(3.0+16.0*UVQ_ROUNDOFF)*UVQ_ROUNDOFF*(uvq_abs(du*ev)+uvq_abs(dv*eu)) 45 if err==0.0{if product0!=0.0{q.unknown=q.unknown+1;return UVQ_UNKNOWN};if product1!=0.0{q.unknown=q.unknown+1;return UVQ_UNKNOWN}} 46 if uls_finite(area)==0{q.unknown=q.unknown+1;return UVQ_UNKNOWN} 47 if uvq_abs(area)<=err{ 48 if area==0.0{q.collapsed=q.collapsed+1};q.unknown=q.unknown+1;return UVQ_UNKNOWN 49 };if area>0.0{orientation=1}else{orientation=0-1} 50 } 51 if orientation==0{q.collapsed=q.collapsed+1;return UVQ_PASS} 52 if orientation>0{q.positive=q.positive+1}else{q.negative=q.negative+1} 53 let ax:f64=xyz[3]-xyz[0];let ay:f64=xyz[4]-xyz[1];let az:f64=xyz[5]-xyz[2] 54 let bx:f64=xyz[6]-xyz[0];let by:f64=xyz[7]-xyz[1];let bz:f64=xyz[8]-xyz[2] 55 let l:f64=uls_sqrt(ax*ax+ay*ay+az*az);let cx:f64=ay*bz-az*by;let cy:f64=az*bx-ax*bz;let cz:f64=ax*by-ay*bx;let a3:f64=uls_sqrt(cx*cx+cy*cy+cz*cz) 56 if l<=0.0{q.unknown=q.unknown+1;return UVQ_UNKNOWN};if a3<=0.0{q.unknown=q.unknown+1;return UVQ_UNKNOWN};if uls_finite(a3)==0{q.unknown=q.unknown+1;return UVQ_UNKNOWN} 57 let px:f64=(ax*bx+ay*by+az*bz)/l;let py:f64=a3/l 58 var j00:f64=du/l;var j10:f64=dv/l;var j01:f64=(eu-j00*px)/py;var j11:f64=(ev-j10*px)/py 59 var scale:f64=uvq_abs(j00);if uvq_abs(j10)>scale{scale=uvq_abs(j10)};if uvq_abs(j01)>scale{scale=uvq_abs(j01)};if uvq_abs(j11)>scale{scale=uvq_abs(j11)} 60 if scale<=0.0{q.unknown=q.unknown+1;return UVQ_UNKNOWN};if uls_finite(scale)==0{q.unknown=q.unknown+1;return UVQ_UNKNOWN} 61 j00=j00/scale;j10=j10/scale;j01=j01/scale;j11=j11/scale 62 let det:f64=uvq_abs(j00*j11-j01*j10);let trace:f64=j00*j00+j01*j01+j10*j10+j11*j11 63 if det<=0.0{q.unknown=q.unknown+1;return UVQ_UNKNOWN} 64 var disc:f64=trace*trace-4.0*det*det;if disc<0.0{disc=0.0} 65 var ratio:f64=(trace+uls_sqrt(disc))/(2.0*det);if ratio<1.0{ratio=1.0};if uls_finite(ratio)==0{q.unknown=q.unknown+1;return UVQ_UNKNOWN} 66 if ratio>q.maxAnisotropy{q.maxAnisotropy=ratio;q.worstTriangle=sourceTriangle} 67 if area>0.0{if q.minPositiveArea==0.0{q.minPositiveArea=area};if area<q.minPositiveArea{q.minPositiveArea=area}} 68 return UVQ_PASS 69} 70func uvq_qualify(q:*UvQuality,p:*UvQualityPolicy)->i64{ 71 if q==(0 as *UvQuality){return UVQ_INVALID};if p==(0 as *UvQualityPolicy){return UVQ_INVALID} 72 if p.expectedTriangles<1{return UVQ_INVALID};if p.expectedOrientation!=1{if p.expectedOrientation!=(0-1){return UVQ_INVALID}} 73 if p.maxCollapsed<0{return UVQ_INVALID};if p.maxReversed<0{return UVQ_INVALID};if p.maxAnisotropy<1.0{return UVQ_INVALID};if uls_finite(p.maxAnisotropy)==0{return UVQ_INVALID} 74 if q.triangles!=p.expectedTriangles{return UVQ_UNKNOWN};if q.unknown>0{return UVQ_UNKNOWN} 75 if q.collapsed>p.maxCollapsed{return UVQ_FAIL};var reversed:i64=q.negative;if p.expectedOrientation<0{reversed=q.positive} 76 if reversed>p.maxReversed{return UVQ_FAIL};if q.maxAnisotropy>p.maxAnisotropy{return UVQ_FAIL};return UVQ_PASS 77}