code wiki / (root) / nx_part_solver_lib.nx

nx_part_solver_lib.nx

buildroot/runtime/nx_part_solver_lib.nx

49528 B1095 linesdepth 2pulls 4 transitivereach 8 importersview sourcekind library
docsdependenciesstructsconstsfunctions

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

nx_syscalls.nx nx_vecmath.nx nx_part_solver_lib.nx nx_canon_solver.nx nx_canon_solver_gate.nx nx_indoorgen.nx nx_indoorgen_gate.nx nx_indoorgen_lib.nx nx_part_solver.nx nx_part_solver_gate.nx nx_scene_compose_gate.nx

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

49const PS_MAXP: i64 = 256
50const PS_MAXC: i64 = 512
51const PS_NAMEB: i64 = 32
52const PS_PASSES: i64 = 96
53const PS_TOL: i64 = 2
54const PS_ERRFD: i64 = 2
55const PS_K_ATTACH: i64 = 1
56const PS_K_MIRROR: i64 = 2
57const PS_K_STATION: i64 = 3
58const PS_K_CLEAR: i64 = 4
59const PS_K_INSIDE: i64 = 5
62const PS_K_RATIO: i64 = 6
63const PS_K_BAND: i64 = 7
65const PS_K_NOCLIP: i64 = 8
66const PS_K_ENVELOPE: i64 = 9
67const PS_K_FACE: i64 = 10
68const PS_RATIO_DEFTOL: i64 = 60
69const PS_E_PARSE: i64 = 3
70const PS_E_INCONSISTENT: i64 = 4
113const SC_MAXP: i64 = 64
114const SC_NAMEB: i64 = 24
115const SC_BUFB: i64 = 65536
116const SC_K_SITE: i64 = 1
117const SC_K_WATER: i64 = 2
118const SC_K_ROOM: i64 = 3
119const SC_K_TREE: i64 = 4
120const SC_K_BEING: i64 = 5
121const SC_GAP: i64 = 2 // the pavement between solids
122const SC_NEAR: i64 = 40 // how far from its house a being may wander (the band width)
123const SC_WATER_EZ: i64 = 1 // a water body is a ground slab one unit tall, so ground solids collide with it
124const SC_E_PARSE: i64 = 3
125const SC_E_CAP: i64 = 5
126const SC_LCG_A: i64 = 48271
127const SC_LCG_M: i64 = 2147483647
128const SC_MAXNEAR: i64 = 64
129const SC_ROWB: i64 = 96 // the longest row the composer can write; the buffer guard keeps this headroom

functions

147func sc_reset() -> i64
called by 1: ps_scene_compose calls 1: sys_mmap
172func sc_name(i: i64) -> *u8 { return ((SC_NAMES as i64) + i*SC_NAMEB) as *u8 }
173func sc_find(b: *u8, ts: i64, tl: i64) -> i64
188func sc_add(b: *u8, ts: i64, tl: i64, kind: i64, a: i64, bb: i64, c: i64, d: i64, e: i64) -> i64
207func sc_rand() -> i64
called by 1: ps_scene_compose
213func sc_w(s: *u8) -> i64
called by 3: sc_spsc_nlps_scene_compose calls 1: ps_slen
222func sc_wn(v: i64) -> i64
called by 1: ps_scene_compose calls 1: sys_mmap
236func sc_sp() -> i64 { return sc_w(" " as *u8) }
called by 1: ps_scene_compose calls 1: sc_w
237func sc_nl() -> i64 { return sc_w("\n" as *u8) }
called by 1: ps_scene_compose calls 1: sc_w
238func sc_kind(i: i64) -> i64 { let k: *i64 = SC_KIND as *i64; return k[i] }
239func sc_a(i: i64) -> i64 { let a: *i64 = SC_A as *i64; return a[i] }
called by 1: ps_scene_compose
240func sc_b(i: i64) -> i64 { let a: *i64 = SC_B as *i64; return a[i] }
called by 1: ps_scene_compose
241func sc_c(i: i64) -> i64 { let a: *i64 = SC_C as *i64; return a[i] }
called by 1: ps_scene_compose
242func sc_d(i: i64) -> i64 { let a: *i64 = SC_D as *i64; return a[i] }
called by 1: ps_scene_compose
243func sc_e(i: i64) -> i64 { let a: *i64 = SC_E as *i64; return a[i] }
called by 1: ps_scene_compose
244func sc_first_of(kind: i64) -> i64
called by 1: ps_scene_compose calls 1: sc_kind
249func ps_scene_rows() -> *u8 { return SC_BUF as *u8 }
250func ps_scene_len() -> i64 { return SC_LEN }
called by 1: main
251func ps_scene_np() -> i64 { return SC_NP }
252func ps_scene_nc() -> i64 { return PS_NC }
called by 1: main
253func ps_scene_compose(b: *u8, n: i64) -> i64
405func ps_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
406func ps_err(s: *u8) -> i64 { sys_write(PS_ERRFD, s, ps_slen(s)); return 0 }
407func ps_out(s: *u8) -> i64 { sys_write(1, s, ps_slen(s)); return 0 }
called by 3: mainmainps_dump calls 2: sys_writeps_slen
408func ps_outn(v: i64) -> i64
called by 3: mainmainps_dump calls 2: sys_writesys_mmap
423func ps_isqrt(v: i64) -> i64 { return vm_isqrt(v) }
424func ps_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
427func ps_cardx(rx: i64, ry: i64) -> i64
431func ps_cardy(rx: i64, ry: i64) -> i64
437func ps_reset() -> i64
called by 1: ps_load calls 1: sys_mmap
468func ps_np() -> i64 { return PS_NP }
called by 3: mainmainmain
469func ps_x(i: i64) -> i64 { let a: *i64 = PS_PX as *i64; return a[i] }
470func ps_y(i: i64) -> i64 { let a: *i64 = PS_PY as *i64; return a[i] }
471func ps_z(i: i64) -> i64 { let a: *i64 = PS_PZ as *i64; return a[i] }
called by 4: mainmainmainps_dump
472func ps_r(i: i64) -> i64 { let a: *i64 = PS_PR as *i64; return a[i] }
called by 1: main
473func ps_ex(i: i64) -> i64 { let a: *i64 = PS_EX as *i64; return a[i] }
474func ps_ey(i: i64) -> i64 { let a: *i64 = PS_EY as *i64; return a[i] }
475func ps_ez(i: i64) -> i64 { let a: *i64 = PS_EZ as *i64; return a[i] }
476func ps_fx(i: i64) -> i64 { let a: *i64 = PS_FX as *i64; return a[i] }
477func ps_fy(i: i64) -> i64 { let a: *i64 = PS_FY as *i64; return a[i] }
478func ps_name(i: i64) -> *u8 { return ((PS_PN as i64) + i*PS_NAMEB) as *u8 }
481func ps_exx(i: i64) -> i64 { let f: *i64 = PS_FY as *i64; if f[i] != 0 { return ps_ey(i) } return ps_ex(i) }
482func ps_eyy(i: i64) -> i64 { let f: *i64 = PS_FY as *i64; if f[i] != 0 { return ps_ex(i) } return ps_ey(i) }
483func ps_worst() -> i64 { return PS_WORST }
484func ps_worstv() -> i64 { return PS_WORSTV }
485func ps_resid() -> i64 { return PS_RESID }
called by 3: mainmainmain
486func ps_kindname(k: i64) -> *u8
499func ps_find(name: *u8) -> i64
called by 3: ig_room_solvemainmain calls 1: ps_name
517func ps_ntok(b: *u8, s: i64, e: i64, out: *i64) -> i64
544func ps_tokeq(b: *u8, ts: i64, tl: i64, kw: *u8) -> i64
called by 2: ps_scene_composeps_load calls 1: ps_slen
550func ps_toknum(b: *u8, ts: i64, tl: i64) -> i64
563func ps_tokpart(b: *u8, ts: i64, tl: i64) -> i64
called by 1: ps_load calls 2: ps_nameps_slen
579func ps_load(b: *u8, n: i64) -> i64
745func ps_zoverlap(a: i64, b2: i64) -> i64
751func ps_apply(ci: i64) -> i64
949func ps_violation(ci: i64) -> i64
1038func ps_solve() -> i64
1059func ps_ckind(ci: i64) -> i64 { let ck: *i64 = PS_CK as *i64; return ck[ci] }
1061func ps_dump() -> i64