code wiki / _hdl_build / nx_contour_print.nx
nx_contour_print.nx source
↩ module page · 121 lines · 5565 B
1// nx_contour_print.nx -- LIB: the UNIFIED multi-material contour emitter (3D-printing R1b). Generalises from a
2// hardcoded rectangle to ANY closed polygon contour, so arbitrary geometry (not just a wall) prints in any
3// material through ONE function. (Production contours come from the mature nx_slice_* pipeline; this proves the
4// emitter accepts arbitrary polygons + makes the R-ECO cistern ROUND.) Material family selects the deltas:
5// FILAMENT = hot hotend (M104/M109), METAL = arc (M3/M5) + inter-layer cooling dwell (G4), PASTE = cold; the
6// contour-tracing + layering is shared. No float: a 12-point integer circle table + Newton integer sqrt for
7// path length. CARDINAL 26: motion + extrusion/arc/hotend-temp only; no firmware/EEPROM. license_tier: ORIGINAL
8import "nx_print_material.nx"
9import "nx_food_science.nx"
10import "nx_seg_store.nx"
11import "nx_syscalls.nx"
12
13// integer microns -> "D.DDD" mm (valid Z for every firmware; whole-mm shows as e.g. 10.000)
14func cp_um_to_mm(dst: *u8, off: i64, um: i64) -> i64 {
15 var o: i64 = off
16 o = fd_apnum(dst, o, um / 1000)
17 dst[o] = 46 as u8; o = o + 1
18 let frac: i64 = um % 1000
19 dst[o] = (48 + (frac / 100)) as u8; o = o + 1
20 dst[o] = (48 + ((frac / 10) % 10)) as u8; o = o + 1
21 dst[o] = (48 + (frac % 10)) as u8; o = o + 1
22 return o
23}
24// Newton integer sqrt
25func cp_isqrt(nn: i64) -> i64 {
26 if nn <= 0 { return 0 }
27 var x: i64 = nn
28 var y: i64 = (x + 1) / 2
29 while y < x { x = y; y = (x + nn / x) / 2 }
30 return x
31}
32func cp_seglen(x0: i64, y0: i64, x1: i64, y1: i64) -> i64 {
33 let dx: i64 = x1 - x0
34 let dy: i64 = y1 - y0
35 return cp_isqrt(dx * dx + dy * dy)
36}
37func cp_move(out: *u8, off: i64, x: i64, y: i64, e: i64) -> i64 {
38 var o: i64 = off
39 o = as_append(out, o, "G1 X" as *u8); o = fd_apnum(out, o, x)
40 o = as_append(out, o, " Y" as *u8); o = fd_apnum(out, o, y)
41 o = as_append(out, o, " E" as *u8); o = fd_apnum(out, o, e)
42 o = as_append(out, o, " F1200\n" as *u8)
43 return o
44}
45
46// ---- geometry generators (contours; any polygon works) ----
47func cg_rect(xs: *i64, ys: *i64, w: i64, d: i64) -> i64 {
48 xs[0] = 0; ys[0] = 0
49 xs[1] = w; ys[1] = 0
50 xs[2] = w; ys[2] = d
51 xs[3] = 0; ys[3] = d
52 return 4
53}
54// 12-gon approximating a circle (no trig): unit cos/sin x1000, scaled by r about (cx,cy)
55func cg_circle(xs: *i64, ys: *i64, cx: i64, cy: i64, r: i64) -> i64 {
56 let co: *i64 = sys_mmap(8 * 16) as *i64
57 let si: *i64 = sys_mmap(8 * 16) as *i64
58 co[0] = 1000; si[0] = 0
59 co[1] = 866; si[1] = 500
60 co[2] = 500; si[2] = 866
61 co[3] = 0; si[3] = 1000
62 co[4] = 0 - 500; si[4] = 866
63 co[5] = 0 - 866; si[5] = 500
64 co[6] = 0 - 1000; si[6] = 0
65 co[7] = 0 - 866; si[7] = 0 - 500
66 co[8] = 0 - 500; si[8] = 0 - 866
67 co[9] = 0; si[9] = 0 - 1000
68 co[10] = 500; si[10] = 0 - 866
69 co[11] = 866; si[11] = 0 - 500
70 var i: i64 = 0
71 while i < 12 { xs[i] = cx + r * co[i] / 1000; ys[i] = cy + r * si[i] / 1000; i = i + 1 }
72 return 12
73}
74
75// emit `h`-tall prism of an arbitrary polygon (xs/ys, npts) in `mat_id`. Returns byte length.
76func cp_emit_prism(prefix: *u8, mat_id: *u8, xs: *i64, ys: *i64, npts: i64, h: i64, out: *u8) -> i64 {
77 let fam: *u8 = sys_mmap(24); pm_field_str(prefix, mat_id, 1, fam)
78 var hot: i64 = 0; var arc: i64 = 0
79 if pm_streq(fam, "FILAMENT" as *u8) == 1 { hot = 1 }
80 if pm_streq(fam, "METAL" as *u8) == 1 { arc = 1 }
81 let temp: i64 = pm_field_int(prefix, mat_id, 5)
82 var layer_um: i64 = pm_field_int(prefix, mat_id, 4); if layer_um <= 0 { layer_um = 200 }
83 let nm: *u8 = sys_mmap(48); pm_field_str(prefix, mat_id, 0, nm)
84
85 var o: i64 = 0
86 o = as_append(out, o, "; Nishi multi-material contour G-code -- " as *u8); o = as_append(out, o, nm); out[o] = 10 as u8; o = o + 1
87 o = as_append(out, o, "; NEVER-BRICK (Cardinal 26): motion + extrusion/arc/hotend-temp only; no firmware/EEPROM\n" as *u8)
88 if hot == 1 {
89 o = as_append(out, o, "M104 S" as *u8); o = fd_apnum(out, o, temp); out[o] = 10 as u8; o = o + 1
90 o = as_append(out, o, "M140 S60\nM190 S60\n" as *u8)
91 o = as_append(out, o, "M109 S" as *u8); o = fd_apnum(out, o, temp); out[o] = 10 as u8; o = o + 1
92 }
93 o = as_append(out, o, "G21\nG90\nG28\nG92 E0\n" as *u8)
94
95 let nlayers: i64 = h * 1000 / layer_um
96 var e: i64 = 0
97 var li: i64 = 0
98 while li < nlayers {
99 let zum: i64 = (li + 1) * layer_um
100 o = as_append(out, o, ";LAYER:" as *u8); o = fd_apnum(out, o, li); out[o] = 10 as u8; o = o + 1
101 o = as_append(out, o, "G1 Z" as *u8); o = cp_um_to_mm(out, o, zum); o = as_append(out, o, " F600\n" as *u8)
102 if arc == 1 { o = as_append(out, o, "M3 S150\n" as *u8) }
103 o = as_append(out, o, "G0 X" as *u8); o = fd_apnum(out, o, xs[0]); o = as_append(out, o, " Y" as *u8); o = fd_apnum(out, o, ys[0]); out[o] = 10 as u8; o = o + 1
104 var k: i64 = 1
105 while k < npts {
106 e = e + cp_seglen(xs[k - 1], ys[k - 1], xs[k], ys[k])
107 o = cp_move(out, o, xs[k], ys[k], e)
108 k = k + 1
109 }
110 e = e + cp_seglen(xs[npts - 1], ys[npts - 1], xs[0], ys[0])
111 o = cp_move(out, o, xs[0], ys[0], e)
112 if arc == 1 { o = as_append(out, o, "M5\nG4 P2000\n" as *u8) }
113 li = li + 1
114 }
115 o = as_append(out, o, "; end\n" as *u8)
116 if hot == 1 { o = as_append(out, o, "M104 S0\nM140 S0\n" as *u8) }
117 if arc == 1 { o = as_append(out, o, "M5\n" as *u8) }
118 o = as_append(out, o, "M84\n" as *u8)
119 out[o] = 0 as u8
120 return o
121}