nx_part_solver_lib.nx
buildroot/runtime/nx_part_solver_lib.nx
about
nx_part_solver_lib.nx -- ★CONSTRAINT-BASED PART PLACEMENT (operator method pointer 2026-08-12:
arXiv 2406.11824 Infinigen Indoors organizes ROOMS with a constraint DSL + maximal-satisfaction solver;
operator transfer: "use similar logic ... to organizing the generated elements of a human").
This is rung 1 of that transfer: parts are POINTS with radii; constraints are DECLARATIVE ROWS in a
data file (rule 11 -- the anatomy lives in data, never typed coordinates in an emitter); the solver is
deterministic integer constraint PROJECTION (fixed pass count, fixed order). The SAME engine is meant
to assemble face/organ parts AND, later, furnish rooms and city blocks (one engine, bodies AND worlds).
★RUNG 2 (2026-08-14): EXTENT + ORIENTATION + ENVELOPE AS FIRST-CLASS PARTS -- the rung named from two
directions on /world/procgen ("orientation + extent (parts are points today)" and W4 R1 "orientation +
extents + envelope as first-class parts"). A part may now carry a BOX and a FACING, and three new
constraints consume them, so orientation is SOLVED geometry, not decoration: turning a part swaps its
footprint, which changes what it collides with and whether it still fits its envelope.
Constraint rows (whitespace-separated, # comments):
part <name> <x> <y> <z> <r> declare a part with an INITIAL (possibly garbage) placement
extent <a> <ex> <ey> <ez> give a declared part HALF-EXTENTS (a box). Default 0 = a point.
facing <a> <fx> <fy> orientation as an integer direction vector in the ground plane,
snapped to the nearest cardinal. Default (1,0) = +x.
attach <a> <b> <dx> <dy> <dz> hard: pos[a] = pos[b] + (dx,dy,dz)
mirror <a> <b> bilateral symmetry about the x=0 plane: ax=-bx, ay=by, az=bz
station <a> <lo> <hi> a.z clamped into [lo,hi] (the anatomical station band)
clear <a> <b> <mind> centre distance >= mind (no-intersection of POINTS)
inside <a> <b> <maxd> centre distance <= maxd (containment; a moves toward b)
band <a> <b> <lo> <hi> centre distance inside [lo,hi]
ratio <a> <b> <c> <d> <num> <den> [tol_permil] dist(a,b) : dist(c,d) = num:den
noclip <a> <b> [gap] BOX no-intersection: the two oriented footprints must be
separated by >= gap on some ground axis. Parts whose z-intervals
do not overlap are exempt (different storeys never collide).
envelope <a> <b> box a lies ENTIRELY INSIDE box b -- the room shell / city block /
skull cavity. Only a moves: an envelope is GIVEN, not solved.
face <a> <b> a's facing is the cardinal direction toward b (chairs face the
table, buildings face the street). Orientation solved from
geometry, never typed.
ORIENTATION IS EXACT BY CONSTRUCTION, AND THE BOUND IS DECLARED: facing snaps to the four cardinal
directions, so a rotated footprint is an exact swap of ex/ey -- no trig, no fixed-point error, and the
measured violation is the true violation. Arbitrary-angle boxes need an exact-enough integer rotation
contract (the fleet's rc_sin_q14 is a Bhaskara approximation, ~2 permil -- fine for a camera, NOT for a
predicate whose whole contract is an exact refusal). That is the NEXT rung, and it is named, not claimed.
dependencies 2 imports · 8 importers
imports: nx_syscalls.nxnx_vecmath.nx
imported by: nx_canon_solver.nxnx_canon_solver_gate.nxnx_indoorgen.nxnx_indoorgen_gate.nxnx_indoorgen_lib.nxnx_part_solver.nxnx_part_solver_gate.nxnx_scene_compose_gate.nx
structs
| none |
consts
| 49 | const PS_MAXP: i64 = 256 |
| 50 | const PS_MAXC: i64 = 512 |
| 51 | const PS_NAMEB: i64 = 32 |
| 52 | const PS_PASSES: i64 = 96 |
| 53 | const PS_TOL: i64 = 2 |
| 54 | const PS_ERRFD: i64 = 2 |
| 55 | const PS_K_ATTACH: i64 = 1 |
| 56 | const PS_K_MIRROR: i64 = 2 |
| 57 | const PS_K_STATION: i64 = 3 |
| 58 | const PS_K_CLEAR: i64 = 4 |
| 59 | const PS_K_INSIDE: i64 = 5 |
| 62 | const PS_K_RATIO: i64 = 6 |
| 63 | const PS_K_BAND: i64 = 7 |
| 65 | const PS_K_NOCLIP: i64 = 8 |
| 66 | const PS_K_ENVELOPE: i64 = 9 |
| 67 | const PS_K_FACE: i64 = 10 |
| 68 | const PS_RATIO_DEFTOL: i64 = 60 |
| 69 | const PS_E_PARSE: i64 = 3 |
| 70 | const PS_E_INCONSISTENT: i64 = 4 |
| 113 | const SC_MAXP: i64 = 64 |
| 114 | const SC_NAMEB: i64 = 24 |
| 115 | const SC_BUFB: i64 = 65536 |
| 116 | const SC_K_SITE: i64 = 1 |
| 117 | const SC_K_WATER: i64 = 2 |
| 118 | const SC_K_ROOM: i64 = 3 |
| 119 | const SC_K_TREE: i64 = 4 |
| 120 | const SC_K_BEING: i64 = 5 |
| 121 | const SC_GAP: i64 = 2 // the pavement between solids |
| 122 | const SC_NEAR: i64 = 40 // how far from its house a being may wander (the band width) |
| 123 | const SC_WATER_EZ: i64 = 1 // a water body is a ground slab one unit tall, so ground solids collide with it |
| 124 | const SC_E_PARSE: i64 = 3 |
| 125 | const SC_E_CAP: i64 = 5 |
| 126 | const SC_LCG_A: i64 = 48271 |
| 127 | const SC_LCG_M: i64 = 2147483647 |
| 128 | const SC_MAXNEAR: i64 = 64 |
| 129 | const SC_ROWB: i64 = 96 // the longest row the composer can write; the buffer guard keeps this headroom |
functions
| 147 | func sc_reset() -> i64 |
| 172 | func sc_name(i: i64) -> *u8 { return ((SC_NAMES as i64) + i*SC_NAMEB) as *u8 } |
| 173 | func sc_find(b: *u8, ts: i64, tl: i64) -> i64 |
| 188 | func sc_add(b: *u8, ts: i64, tl: i64, kind: i64, a: i64, bb: i64, c: i64, d: i64, e: i64) -> i64 |
| 207 | func sc_rand() -> i64 called by 1: ps_scene_compose |
| 213 | func sc_w(s: *u8) -> i64 |
| 222 | func sc_wn(v: i64) -> i64 |
| 236 | func sc_sp() -> i64 { return sc_w(" " as *u8) } |
| 237 | func sc_nl() -> i64 { return sc_w("\n" as *u8) } |
| 238 | func sc_kind(i: i64) -> i64 { let k: *i64 = SC_KIND as *i64; return k[i] } |
| 239 | func sc_a(i: i64) -> i64 { let a: *i64 = SC_A as *i64; return a[i] } called by 1: ps_scene_compose |
| 240 | func sc_b(i: i64) -> i64 { let a: *i64 = SC_B as *i64; return a[i] } called by 1: ps_scene_compose |
| 241 | func sc_c(i: i64) -> i64 { let a: *i64 = SC_C as *i64; return a[i] } called by 1: ps_scene_compose |
| 242 | func sc_d(i: i64) -> i64 { let a: *i64 = SC_D as *i64; return a[i] } called by 1: ps_scene_compose |
| 243 | func sc_e(i: i64) -> i64 { let a: *i64 = SC_E as *i64; return a[i] } called by 1: ps_scene_compose |
| 244 | func sc_first_of(kind: i64) -> i64 |
| 249 | func ps_scene_rows() -> *u8 { return SC_BUF as *u8 } |
| 250 | func ps_scene_len() -> i64 { return SC_LEN } called by 1: main |
| 251 | func ps_scene_np() -> i64 { return SC_NP } |
| 252 | func ps_scene_nc() -> i64 { return PS_NC } called by 1: main |
| 253 | func ps_scene_compose(b: *u8, n: i64) -> i64 |
| 405 | func ps_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 406 | func ps_err(s: *u8) -> i64 { sys_write(PS_ERRFD, s, ps_slen(s)); return 0 } |
| 407 | func ps_out(s: *u8) -> i64 { sys_write(1, s, ps_slen(s)); return 0 } |
| 408 | func ps_outn(v: i64) -> i64 |
| 423 | func ps_isqrt(v: i64) -> i64 { return vm_isqrt(v) } |
| 424 | func ps_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } |
| 427 | func ps_cardx(rx: i64, ry: i64) -> i64 |
| 431 | func ps_cardy(rx: i64, ry: i64) -> i64 |
| 437 | func ps_reset() -> i64 |
| 468 | func ps_np() -> i64 { return PS_NP } |
| 469 | func ps_x(i: i64) -> i64 { let a: *i64 = PS_PX as *i64; return a[i] } |
| 470 | func ps_y(i: i64) -> i64 { let a: *i64 = PS_PY as *i64; return a[i] } |
| 471 | func ps_z(i: i64) -> i64 { let a: *i64 = PS_PZ as *i64; return a[i] } |
| 472 | func ps_r(i: i64) -> i64 { let a: *i64 = PS_PR as *i64; return a[i] } called by 1: main |
| 473 | func ps_ex(i: i64) -> i64 { let a: *i64 = PS_EX as *i64; return a[i] } |
| 474 | func ps_ey(i: i64) -> i64 { let a: *i64 = PS_EY as *i64; return a[i] } |
| 475 | func ps_ez(i: i64) -> i64 { let a: *i64 = PS_EZ as *i64; return a[i] } |
| 476 | func ps_fx(i: i64) -> i64 { let a: *i64 = PS_FX as *i64; return a[i] } |
| 477 | func ps_fy(i: i64) -> i64 { let a: *i64 = PS_FY as *i64; return a[i] } |
| 478 | func ps_name(i: i64) -> *u8 { return ((PS_PN as i64) + i*PS_NAMEB) as *u8 } |
| 481 | func ps_exx(i: i64) -> i64 { let f: *i64 = PS_FY as *i64; if f[i] != 0 { return ps_ey(i) } return ps_ex(i) } |
| 482 | func ps_eyy(i: i64) -> i64 { let f: *i64 = PS_FY as *i64; if f[i] != 0 { return ps_ex(i) } return ps_ey(i) } |
| 483 | func ps_worst() -> i64 { return PS_WORST } |
| 484 | func ps_worstv() -> i64 { return PS_WORSTV } |
| 485 | func ps_resid() -> i64 { return PS_RESID } |
| 486 | func ps_kindname(k: i64) -> *u8 |
| 499 | func ps_find(name: *u8) -> i64 |
| 517 | func ps_ntok(b: *u8, s: i64, e: i64, out: *i64) -> i64 |
| 544 | func ps_tokeq(b: *u8, ts: i64, tl: i64, kw: *u8) -> i64 |
| 550 | func ps_toknum(b: *u8, ts: i64, tl: i64) -> i64 |
| 563 | func ps_tokpart(b: *u8, ts: i64, tl: i64) -> i64 |
| 579 | func ps_load(b: *u8, n: i64) -> i64 |
| 745 | func ps_zoverlap(a: i64, b2: i64) -> i64 |
| 751 | func ps_apply(ci: i64) -> i64 |
| 949 | func ps_violation(ci: i64) -> i64 |
| 1038 | func ps_solve() -> i64 |
| 1059 | func ps_ckind(ci: i64) -> i64 { let ck: *i64 = PS_CK as *i64; return ck[ci] } |
| 1061 | func ps_dump() -> i64 |