code wiki / _hdl_build / nx_contour_print.nx
nx_contour_print.nx source
↩ module page · 116 lines · 5470 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"
12import "nx_vecmath.nx"
13
14// integer microns -> "D.DDD" mm (valid Z for every firmware; whole-mm shows as e.g. 10.000)
15func cp_um_to_mm(dst: *u8, off: i64, um: i64) -> i64 {
16 var o: i64 = off
17 o = fd_apnum(dst, o, um / 1000)
18 dst[o] = 46 as u8; o = o + 1
19 let frac: i64 = um % 1000
20 dst[o] = (48 + (frac / 100)) as u8; o = o + 1
21 dst[o] = (48 + ((frac / 10) % 10)) as u8; o = o + 1
22 dst[o] = (48 + (frac % 10)) as u8; o = o + 1
23 return o
24}
25// Newton integer sqrt
26func cp_isqrt(nn: i64) -> i64 { return vm_isqrt(nn) }
27func cp_seglen(x0: i64, y0: i64, x1: i64, y1: i64) -> i64 {
28 let dx: i64 = x1 - x0
29 let dy: i64 = y1 - y0
30 return cp_isqrt(dx * dx + dy * dy)
31}
32func cp_move(out: *u8, off: i64, x: i64, y: i64, e: i64) -> i64 {
33 var o: i64 = off
34 o = as_append(out, o, "G1 X" as *u8); o = fd_apnum(out, o, x)
35 o = as_append(out, o, " Y" as *u8); o = fd_apnum(out, o, y)
36 o = as_append(out, o, " E" as *u8); o = fd_apnum(out, o, e)
37 o = as_append(out, o, " F1200\n" as *u8)
38 return o
39}
40
41// ---- geometry generators (contours; any polygon works) ----
42func cg_rect(xs: *i64, ys: *i64, w: i64, d: i64) -> i64 {
43 xs[0] = 0; ys[0] = 0
44 xs[1] = w; ys[1] = 0
45 xs[2] = w; ys[2] = d
46 xs[3] = 0; ys[3] = d
47 return 4
48}
49// 12-gon approximating a circle (no trig): unit cos/sin x1000, scaled by r about (cx,cy)
50func cg_circle(xs: *i64, ys: *i64, cx: i64, cy: i64, r: i64) -> i64 {
51 let co: *i64 = sys_mmap(8 * 16) as *i64
52 let si: *i64 = sys_mmap(8 * 16) as *i64
53 co[0] = 1000; si[0] = 0
54 co[1] = 866; si[1] = 500
55 co[2] = 500; si[2] = 866
56 co[3] = 0; si[3] = 1000
57 co[4] = 0 - 500; si[4] = 866
58 co[5] = 0 - 866; si[5] = 500
59 co[6] = 0 - 1000; si[6] = 0
60 co[7] = 0 - 866; si[7] = 0 - 500
61 co[8] = 0 - 500; si[8] = 0 - 866
62 co[9] = 0; si[9] = 0 - 1000
63 co[10] = 500; si[10] = 0 - 866
64 co[11] = 866; si[11] = 0 - 500
65 var i: i64 = 0
66 while i < 12 { xs[i] = cx + r * co[i] / 1000; ys[i] = cy + r * si[i] / 1000; i = i + 1 }
67 return 12
68}
69
70// emit `h`-tall prism of an arbitrary polygon (xs/ys, npts) in `mat_id`. Returns byte length.
71func cp_emit_prism(prefix: *u8, mat_id: *u8, xs: *i64, ys: *i64, npts: i64, h: i64, out: *u8) -> i64 {
72 let fam: *u8 = sys_mmap(24); pm_field_str(prefix, mat_id, 1, fam)
73 var hot: i64 = 0; var arc: i64 = 0
74 if pm_streq(fam, "FILAMENT" as *u8) == 1 { hot = 1 }
75 if pm_streq(fam, "METAL" as *u8) == 1 { arc = 1 }
76 let temp: i64 = pm_field_int(prefix, mat_id, 5)
77 var layer_um: i64 = pm_field_int(prefix, mat_id, 4); if layer_um <= 0 { layer_um = 200 }
78 let nm: *u8 = sys_mmap(48); pm_field_str(prefix, mat_id, 0, nm)
79
80 var o: i64 = 0
81 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
82 o = as_append(out, o, "; NEVER-BRICK (Cardinal 26): motion + extrusion/arc/hotend-temp only; no firmware/EEPROM\n" as *u8)
83 if hot == 1 {
84 o = as_append(out, o, "M104 S" as *u8); o = fd_apnum(out, o, temp); out[o] = 10 as u8; o = o + 1
85 o = as_append(out, o, "M140 S60\nM190 S60\n" as *u8)
86 o = as_append(out, o, "M109 S" as *u8); o = fd_apnum(out, o, temp); out[o] = 10 as u8; o = o + 1
87 }
88 o = as_append(out, o, "G21\nG90\nG28\nG92 E0\n" as *u8)
89
90 let nlayers: i64 = h * 1000 / layer_um
91 var e: i64 = 0
92 var li: i64 = 0
93 while li < nlayers {
94 let zum: i64 = (li + 1) * layer_um
95 o = as_append(out, o, ";LAYER:" as *u8); o = fd_apnum(out, o, li); out[o] = 10 as u8; o = o + 1
96 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)
97 if arc == 1 { o = as_append(out, o, "M3 S150\n" as *u8) }
98 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
99 var k: i64 = 1
100 while k < npts {
101 e = e + cp_seglen(xs[k - 1], ys[k - 1], xs[k], ys[k])
102 o = cp_move(out, o, xs[k], ys[k], e)
103 k = k + 1
104 }
105 e = e + cp_seglen(xs[npts - 1], ys[npts - 1], xs[0], ys[0])
106 o = cp_move(out, o, xs[0], ys[0], e)
107 if arc == 1 { o = as_append(out, o, "M5\nG4 P2000\n" as *u8) }
108 li = li + 1
109 }
110 o = as_append(out, o, "; end\n" as *u8)
111 if hot == 1 { o = as_append(out, o, "M104 S0\nM140 S0\n" as *u8) }
112 if arc == 1 { o = as_append(out, o, "M5\n" as *u8) }
113 o = as_append(out, o, "M84\n" as *u8)
114 out[o] = 0 as u8
115 return o
116}