nx_uvunwrap_gate.nx
buildroot/runtime/nx_uvunwrap_gate.nx
about
nx_uvunwrap_gate.nx -- the gate for nx_uvunwrap_lib (/compare/dcc DC5).
THE HAZARD THIS GATE IS SHAPED AGAINST. A parameteriser is unusually easy to fake, because the two
obvious ways to fail both score well on the obvious metrics:
* MAP EVERY VERTEX TO ONE POINT and every triangle is a perfect similarity of nothing. Angle and area
distortion computed over non-degenerate triangles are zero because there are no non-degenerate
triangles left to average. The tooth that kills it is chart AREA, and it is planted and bitten here.
* FOLD THE CHART OVER ITSELF and the per-triangle metrics stay small while the atlas is unusable. The
tooth that kills that one is the flipped-triangle count, and the unseamed cylinder below is a real
mesh that actually produces it rather than a synthetic case.
So the load-bearing structure is: a POSITIVE CONTROL that must come back at essentially zero, a
DISCRIMINATION pair that must come back different, and a planted defect for every refusal class.
WHY A DEVELOPABLE SURFACE IS THE RIGHT POSITIVE CONTROL, AND WHY THIS IS A HARD CLAIM RATHER THAN A
SOFT ONE. A surface with zero Gaussian curvature is EXACTLY parameterisable -- an isometry into the
plane exists, so the true minimum of the conformal energy is zero and any distortion measured on one is
a bug in the solver, not a property of the input. Three of the fixtures below are developable for three
different reasons (a plane, six planes cut apart, a piecewise-flat prism wall with no interior vertex)
and all three must read at or under the tolerance.
WHY THE CURVED FIXTURE IS A PYRAMID AND NOT THE CYLINDER THE BRIEF SUGGESTED. A cylinder WALL is
developable -- it unrolls with no distortion at all -- so a cylinder reading non-zero would be reporting
its own TOPOLOGY (an uncut annulus cannot embed in the plane) rather than curvature, and reading that as
a curvature measurement would be measuring a different subject than the one being named. The pyramid's
apex is a genuine cone point: four faces meet there with a total angle of 282 degrees against the 360 a
plane would need, a deficit of 78 degrees that no cutting can remove. It CANNOT be flattened, so its
distortion must be non-zero, and this gate prints the number rather than asserting a bound it invented.
The cylinder still appears -- in both states -- because it is the only fixture that proves a seam does
anything: the same 16 triangles refuse as a fold uncut, and unwrap cleanly with one edge cut.
COMPOSES nx_meshvalid_lib rather than carrying a second validity checker, per the brief and per the
duplicate-ruler law. 100% sovereign. No hardware writes (Rule 26). license_tier: ORIGINAL expect_exit: 0
dependencies 4 imports · 0 importers
imports: nx_syscalls.nxnx_gate_verdict.nxnx_meshvalid_lib.nxnx_uvunwrap_lib.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 40 | const UG_S: i64 = 1000 // flat quad side |
| 41 | const UG_CS: i64 = 400 // cube side |
| 42 | const UG_PA: i64 = 100 // pyramid base half-width |
| 43 | const UG_PH: i64 = 100 // pyramid height |
| 44 | const UG_R1: i64 = 100 // octagon short radius component |
| 45 | const UG_R2: i64 = 241 // octagon long radius component, round(100 * (1 + sqrt(2))) |
| 46 | const UG_CH: i64 = 200 // cylinder height |
| 47 | const UG_NSEG: i64 = 8 // cylinder segments |
| 48 | const UG_QUAD_VERTS: i64 = 4 // the flat quad's four corners |
| 49 | const UG_QUAD_TRIS: i64 = 2 // and the two triangles they split into |
| 50 | const UG_PYR_VERTS: i64 = 5 // the pyramid's apex plus its four base corners |
| 51 | const UG_PYR_TRIS: i64 = 4 // and its four side faces |
| 52 | const UG_CUBE_FACES: i64 = 6 |
| 53 | const UG_CUBE_TRIS_PER_FACE: i64 = 2 |
| 54 | const UG_CUBE_CORNERS_PER_FACE: i64 = 4 |
| 65 | const UG_FLAT_TOL_PERMIL: i64 = 5 |
| 68 | const UG_CURVED_FLOOR: i64 = 50 |
functions
| 70 | func ug_eq(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 } called by 1: main |
| 71 | func ug_ne(a: i64, b: i64) -> i64 { if a != b { return 1 } return 0 } called by 1: main |
| 72 | func ug_gt(a: i64, b: i64) -> i64 { if a > b { return 1 } return 0 } called by 1: main |
| 73 | func ug_le(a: i64, b: i64) -> i64 { if a <= b { return 1 } return 0 } called by 1: main |
| 74 | func ug_pn(label: *u8, v: i64) -> i64 { gv_puts(label); gv_num(v); gv_puts("\n" as *u8); return 0 } |
| 81 | func ug_class_collisions(m: *i64, nt: i64) -> i64 |
| 101 | func ug_quad() -> *i64 |
| 116 | func ug_cube(seams: i64) -> *i64 |
| 159 | func ug_pyramid() -> *i64 |
| 174 | func ug_oct_x(i: i64) -> i64 called by 1: ug_cyl |
| 184 | func ug_oct_y(i: i64) -> i64 called by 1: ug_cyl |
| 200 | func ug_cyl(seam: i64) -> *i64 |
| 223 | func ug_nonmanifold() -> *i64 |
| 237 | func main(argc: i64, argv: *i64) -> i64 |