code wiki / (root) / nx_mechparts.nx

nx_mechparts.nx source

↩ module page · 176 lines · 9689 B

1// nx_mechparts.nx -- proper procedural MECHANICAL PRIMITIVES for the CAD car-twin viewer (cadtwin R1b-lite): 2// real tessellated cylinders (24-gon), hex nuts WITH a real through-hole, bolts (shaft + hex head), washers, 3// L-brackets, plates -- so /explodelab parts read as actual HARDWARE instead of the crude octagon-prism 4// stand-ins. Emits straight into the nx_explode3d part buffers (ex3_vert/ex3_tri), all <=16 args, wasm-safe 5// (no mmap in loops -- uses the e[13] scratch), deterministic integer. NOT a STEP B-rep tessellation (that 6// needs a fixed-point B-spline evaluator = the deeper R1b rung); these are parametric primitives, the way CAD 7// part catalogs themselves generate standard hardware. license_tier: ORIGINAL 8import "nx_explode3d.nx" 9const K_MAGIC_16384: i64 = 16384 10const K_MAGIC_15827: i64 = 15827 11const K_MAGIC_4240: i64 = 4240 12const K_MAGIC_14189: i64 = 14189 13const K_MAGIC_8192: i64 = 8192 14const K_MAGIC_11585: i64 = 11585 15const K_MAGIC_1183: i64 = 1183 16const K_MAGIC_1024: i64 = 1024 17 18// 24-gon unit ring (Q14, 16384=1.0) at 15deg steps. nseg must divide 24 (6/8/12/24). out2[0]=cos out2[1]=sin. 19func mp_ring(k: i64, nseg: i64, out2: *i64) -> i64 { 20 let step: i64 = 24 / nseg 21 let i: i64 = (k % nseg) * step 22 if i == 0 { out2[0] = K_MAGIC_16384; out2[1] = 0; return 0 } 23 if i == 1 { out2[0] = K_MAGIC_15827; out2[1] = K_MAGIC_4240; return 0 } 24 if i == 2 { out2[0] = K_MAGIC_14189; out2[1] = K_MAGIC_8192; return 0 } 25 if i == 3 { out2[0] = K_MAGIC_11585; out2[1] = K_MAGIC_11585; return 0 } 26 if i == 4 { out2[0] = K_MAGIC_8192; out2[1] = K_MAGIC_14189; return 0 } 27 if i == 5 { out2[0] = K_MAGIC_4240; out2[1] = K_MAGIC_15827; return 0 } 28 if i == 6 { out2[0] = 0; out2[1] = K_MAGIC_16384; return 0 } 29 if i == 7 { out2[0] = 0 - K_MAGIC_4240; out2[1] = K_MAGIC_15827; return 0 } 30 if i == 8 { out2[0] = 0 - K_MAGIC_8192; out2[1] = K_MAGIC_14189; return 0 } 31 if i == 9 { out2[0] = 0 - K_MAGIC_11585; out2[1] = K_MAGIC_11585; return 0 } 32 if i == 10 { out2[0] = 0 - K_MAGIC_14189; out2[1] = K_MAGIC_8192; return 0 } 33 if i == 11 { out2[0] = 0 - K_MAGIC_15827; out2[1] = K_MAGIC_4240; return 0 } 34 if i == 12 { out2[0] = 0 - K_MAGIC_16384; out2[1] = 0; return 0 } 35 if i == 13 { out2[0] = 0 - K_MAGIC_15827; out2[1] = 0 - K_MAGIC_4240; return 0 } 36 if i == 14 { out2[0] = 0 - K_MAGIC_14189; out2[1] = 0 - K_MAGIC_8192; return 0 } 37 if i == 15 { out2[0] = 0 - K_MAGIC_11585; out2[1] = 0 - K_MAGIC_11585; return 0 } 38 if i == 16 { out2[0] = 0 - K_MAGIC_8192; out2[1] = 0 - K_MAGIC_14189; return 0 } 39 if i == 17 { out2[0] = 0 - K_MAGIC_4240; out2[1] = 0 - K_MAGIC_15827; return 0 } 40 if i == 18 { out2[0] = 0; out2[1] = 0 - K_MAGIC_16384; return 0 } 41 if i == 19 { out2[0] = K_MAGIC_4240; out2[1] = 0 - K_MAGIC_15827; return 0 } 42 if i == 20 { out2[0] = K_MAGIC_8192; out2[1] = 0 - K_MAGIC_14189; return 0 } 43 if i == 21 { out2[0] = K_MAGIC_11585; out2[1] = 0 - K_MAGIC_11585; return 0 } 44 if i == 22 { out2[0] = K_MAGIC_14189; out2[1] = 0 - K_MAGIC_8192; return 0 } 45 out2[0] = K_MAGIC_15827; out2[1] = 0 - K_MAGIC_4240 46 return 0 47} 48 49// 3D point of ring angle (rc,rs = r*cos, r*sin already scaled) at cap offset 'along' on 'axis' (0=y 1=x 2=z) 50func mp_pt(e: *i64, cx: i64, cy: i64, cz: i64, rc: i64, rs: i64, along: i64, axis: i64, color: i64) -> i64 { 51 if axis == 0 { return ex3_vert(e, cx + rc, cy + along, cz + rs, color) } 52 if axis == 1 { return ex3_vert(e, cx + along, cy + rc, cz + rs, color) } 53 return ex3_vert(e, cx + rc, cy + rs, cz + along, color) 54} 55 56// tessellated prism/cylinder: nseg-gon of radius r, half-height hh, centered at c, along axis. Emits side 57// quads + 2 fan caps. Set nseg=24 -> cylinder; nseg=6 -> hex bar; nseg=8 -> octagon. 58func mp_prism(e: *i64, cx: i64, cy: i64, cz: i64, r: i64, hh: i64, axis: i64, nseg: i64, color: i64) -> i64 { 59 let out2: *i64 = e[13] as *i64 60 // top + bottom center verts 61 var tc: i64 = 0 62 var bc: i64 = 0 63 if axis == 0 { tc = ex3_vert(e, cx, cy + hh, cz, color); bc = ex3_vert(e, cx, cy - hh, cz, color) } 64 if axis == 1 { tc = ex3_vert(e, cx + hh, cy, cz, color); bc = ex3_vert(e, cx - hh, cy, cz, color) } 65 if axis == 2 { tc = ex3_vert(e, cx, cy, cz + hh, color); bc = ex3_vert(e, cx, cy, cz - hh, color) } 66 // rim verts: for each k, a top and bottom vert. first = index of k=0 top. 67 var first: i64 = 0 - 1 68 var k: i64 = 0 69 while k < nseg { 70 mp_ring(k, nseg, out2) 71 let rc: i64 = (out2[0] * r) / K_MAGIC_16384 72 let rs: i64 = (out2[1] * r) / K_MAGIC_16384 73 let t: i64 = mp_pt(e, cx, cy, cz, rc, rs, hh, axis, color) 74 let b: i64 = mp_pt(e, cx, cy, cz, rc, rs, 0 - hh, axis, color) 75 if k == 0 { first = t } 76 k = k + 1 77 } 78 // faces: rim vert of k -> top=first+2k, bottom=first+2k+1 79 k = 0 80 while k < nseg { 81 let k1: i64 = (k + 1) % nseg 82 let tk: i64 = first + 2 * k 83 let bk: i64 = first + 2 * k + 1 84 let tk1: i64 = first + 2 * k1 85 let bk1: i64 = first + 2 * k1 + 1 86 let s1: i64 = ex3_tri(e, tk, bk, bk1) 87 let s2: i64 = ex3_tri(e, tk, bk1, tk1) 88 let c1: i64 = ex3_tri(e, tc, tk1, tk) // top cap fan 89 let c2: i64 = ex3_tri(e, bc, bk, bk1) // bottom cap fan 90 if c2 < 0 { return 0 - 1 } 91 k = k + 1 92 } 93 return 0 94} 95 96// ANNULAR prism (hex/round outer, round hole) = a NUT or WASHER. Outer nseg-gon radius or, inner 24-gon 97// hole radius ir, half-height hh, hole along 'axis'. Emits outer wall + inner wall (reversed) + 2 ring caps. 98func mp_annulus(e: *i64, cx: i64, cy: i64, cz: i64, or_: i64, ir: i64, hh: i64, axis: i64, nseg: i64, color: i64) -> i64 { 99 let out2: *i64 = e[13] as *i64 100 // emit 4 rings of verts: outer-top, outer-bot, inner-top, inner-bot -- interleaved per k on the OUTER nseg 101 // (inner sampled at the same nseg for matching cap quads). first = outer-top of k=0. 102 var first: i64 = 0 - 1 103 var k: i64 = 0 104 while k < nseg { 105 mp_ring(k, nseg, out2) 106 let oc: i64 = (out2[0] * or_) / K_MAGIC_16384 107 let os: i64 = (out2[1] * or_) / K_MAGIC_16384 108 let ic: i64 = (out2[0] * ir) / K_MAGIC_16384 109 let is: i64 = (out2[1] * ir) / K_MAGIC_16384 110 let ot: i64 = mp_pt(e, cx, cy, cz, oc, os, hh, axis, color) 111 let ob: i64 = mp_pt(e, cx, cy, cz, oc, os, 0 - hh, axis, color) 112 let it: i64 = mp_pt(e, cx, cy, cz, ic, is, hh, axis, color) 113 let ib: i64 = mp_pt(e, cx, cy, cz, ic, is, 0 - hh, axis, color) 114 if k == 0 { first = ot } 115 k = k + 1 116 } 117 // per k: ot=first+4k ob=+1 it=+2 ib=+3 118 k = 0 119 while k < nseg { 120 let k1: i64 = (k + 1) % nseg 121 let ot: i64 = first + 4 * k 122 let ob: i64 = first + 4 * k + 1 123 let it: i64 = first + 4 * k + 2 124 let ib: i64 = first + 4 * k + 3 125 let ot1: i64 = first + 4 * k1 126 let ob1: i64 = first + 4 * k1 + 1 127 let it1: i64 = first + 4 * k1 + 2 128 let ib1: i64 = first + 4 * k1 + 3 129 let w1: i64 = ex3_tri(e, ot, ob, ob1) // outer wall 130 let w2: i64 = ex3_tri(e, ot, ob1, ot1) 131 let n1: i64 = ex3_tri(e, it, ib1, ib) // inner wall (reversed) 132 let n2: i64 = ex3_tri(e, it, it1, ib1) 133 let t1: i64 = ex3_tri(e, ot, ot1, it1) // top ring cap 134 let t2: i64 = ex3_tri(e, ot, it1, it) 135 let b1: i64 = ex3_tri(e, ob, ib1, ob1) // bottom ring cap 136 let b2: i64 = ex3_tri(e, ob, ib, ib1) 137 if b2 < 0 { return 0 - 1 } 138 k = k + 1 139 } 140 return 0 141} 142 143// HEX NUT: hex outer (nseg=6) + round through-hole. axis = hole axis. 144func mp_hexnut(e: *i64, cx: i64, cy: i64, cz: i64, across: i64, hh: i64, axis: i64, color: i64) -> i64 { 145 // 'across' = half across-flats; hex circumradius ~ across*2/sqrt3 ~ across*1183/1024; hole ~ 0.6*across 146 let orad: i64 = (across * K_MAGIC_1183) / K_MAGIC_1024 147 let ir: i64 = (across * 600) / K_MAGIC_1024 148 return mp_annulus(e, cx, cy, cz, orad, ir, hh, axis, 6, color) 149} 150 151// BOLT: cylindrical shaft (radius sr, half-len sl) along axis + a hex head (radius hr, half-height hd) on the 152// +axis end. head_end = +1 -> head at +axis, shaft extends -axis. 153func mp_bolt(e: *i64, cx: i64, cy: i64, cz: i64, sr: i64, sl: i64, hr: i64, hd: i64, axis: i64, color: i64) -> i64 { 154 // shaft centered so its +axis top meets the head bottom. head sits just beyond +sl. 155 var shx: i64 = cx 156 var shy: i64 = cy 157 var shz: i64 = cz 158 var hcx: i64 = cx 159 var hcy: i64 = cy 160 var hcz: i64 = cz 161 if axis == 0 { shy = cy - hd; hcy = cy + sl } 162 if axis == 1 { shx = cx - hd; hcx = cx + sl } 163 if axis == 2 { shz = cz - hd; hcz = cz + sl } 164 let a: i64 = mp_prism(e, shx, shy, shz, sr, sl, axis, 24, color) // shaft (round) 165 let b: i64 = mp_prism(e, hcx, hcy, hcz, hr, hd, axis, 6, color) // hex head 166 return b 167} 168 169// L-BRACKET: an L cross-section extruded. Two boxes sharing a corner: a base slab + an upright slab. 170// leg = arm half-length, th = wall half-thickness, w = half-width (extrusion depth in z). 171func mp_lbracket(e: *i64, cx: i64, cy: i64, cz: i64, leg: i64, th: i64, w: i64, color: i64) -> i64 { 172 // base slab: sits along +x, thin in y (bottom). upright slab: along +y, thin in x (back). 173 let a: i64 = ex3_add_box(e, cx - leg + th, cy - leg + th, cz, leg, th, w, color) // horizontal arm 174 let b: i64 = ex3_add_box(e, cx - leg + th, cy - leg + th, cz, th, leg, w, color) // vertical arm 175 return b 176}