nx_cad.nx source
↩ module page · 140 lines · 5106 B
1// nx_cad.nx -- parametric solid modeling (AutoCAD / Fusion / Siemens-class), the
2// "sketch -> extrude" core, sovereign. Takes a 2D profile (a sketch) in the XY
3// plane and extrudes it +Z into a closed solid: two end caps (fan-triangulated)
4// plus a ring of side quads. Convex profiles only in v1 (fan triangulation);
5// concave/holed profiles need ear-clipping + CSG (the next CAD rungs). Output is
6// a pipeline-native Q14-mm NxMesh -> flows straight to nx_stl_write_mesh -> slicer,
7// exactly like the DCC tools. Reuses nx_mesh + nx_trig (for round profiles). No
8// dup: grepped, no nx_cad/extrude/revolve existed. license_tier: ORIGINAL.
9
10import "nx_syscalls.nx"
11import "nx_mesh.nx"
12import "nx_trig.nx"
13
14// ===== extrude a convex 2D profile into a solid prism ============
15//
16// px[i], py[i] (Q14), i in [0,n), wound CCW. Extrudes by height_q14 along +Z.
17// Verts: 2n (bottom ring z=0 at [0,n), top ring z=h at [n,2n)).
18// Tris: 2*(n-2) caps + 2*n sides = 4n - 4.
19
20func nx_cad_extrude(px: *i64, py: *i64, n: i64, height_q14: i64, color: i64) -> *NxMesh {
21 if n < 3 { return 0 as *NxMesh }
22 let nv: i64 = 2 * n
23 let nt: i64 = 4 * n - 4
24 let m: *NxMesh = nx_mesh_alloc(nv, nt, 0)
25 if (m as i64) == 0 { return m }
26
27 var i: i64 = 0
28 while i < n {
29 nx_mesh_set_vertex(m, i, px[i], py[i], 0, color)
30 nx_mesh_set_vertex(m, n + i, px[i], py[i], height_q14, color)
31 i = i + 1
32 }
33
34 var t: i64 = 0
35 // bottom cap fan (faces -Z): (0, f+1, f)
36 var f: i64 = 1
37 while f < n - 1 {
38 nx_mesh_set_triangle(m, t, 0, f + 1, f)
39 t = t + 1
40 f = f + 1
41 }
42 // top cap fan (faces +Z): (n, n+f, n+f+1)
43 f = 1
44 while f < n - 1 {
45 nx_mesh_set_triangle(m, t, n, n + f, n + f + 1)
46 t = t + 1
47 f = f + 1
48 }
49 // side quads: edge i -> (i+1)%n, each split into 2 outward tris
50 i = 0
51 while i < n {
52 let j: i64 = (i + 1) % n
53 let ti: i64 = n + i
54 let tj: i64 = n + j
55 nx_mesh_set_triangle(m, t, i, j, tj)
56 t = t + 1
57 nx_mesh_set_triangle(m, t, i, tj, ti)
58 t = t + 1
59 i = i + 1
60 }
61 return m
62}
63
64// ===== parametric box ============================================
65// Rectangular prism wx*wy footprint (centred on origin in XY), height wz,
66// base on the z=0 plane. A rectangle sketch extruded.
67
68func nx_cad_make_box(wx_q14: i64, wy_q14: i64, wz_q14: i64, color: i64) -> *NxMesh {
69 let px: *i64 = (sys_mmap(4 * 8)) as *i64
70 let py: *i64 = (sys_mmap(4 * 8)) as *i64
71 let hx: i64 = wx_q14 / 2
72 let hy: i64 = wy_q14 / 2
73 px[0] = 0 - hx; py[0] = 0 - hy
74 px[1] = hx; py[1] = 0 - hy
75 px[2] = hx; py[2] = hy
76 px[3] = 0 - hx; py[3] = hy
77 return nx_cad_extrude(px, py, 4, wz_q14, color)
78}
79
80// ===== parametric cylinder =======================================
81// A regular `segments`-gon sketch (approximating a circle of radius_q14 via
82// nx_trig) extruded to height_q14. Faceted, like every mesh-CAD cylinder.
83
84func nx_cad_make_cylinder(radius_q14: i64, height_q14: i64,
85 segments: i64, color: i64) -> *NxMesh {
86 if segments < 3 { return 0 as *NxMesh }
87 let px: *i64 = (sys_mmap(segments * 8)) as *i64
88 let py: *i64 = (sys_mmap(segments * 8)) as *i64
89 var k: i64 = 0
90 while k < segments {
91 let turn: i64 = k * 1024 / segments // turn in Q10 (1024 = full circle)
92 let cv: i64 = nx_cos_turn_q10(turn) // Q10 cos
93 let sv: i64 = nx_sin_turn_q10(turn) // Q10 sin
94 px[k] = radius_q14 * cv / 1024
95 py[k] = radius_q14 * sv / 1024
96 k = k + 1
97 }
98 return nx_cad_extrude(px, py, segments, height_q14, color)
99}
100
101// ===== parametric cone ===========================================
102// A `segments`-gon base circle (radius_q14, z=0) tapering to an apex at
103// (0,0,height_q14). Direct factory (light): segments+1 verts, 2*segments-2 tris
104// (base cap fan + side triangles). A closed, printable solid.
105
106func nx_cad_make_cone(radius_q14: i64, height_q14: i64,
107 segments: i64, color: i64) -> *NxMesh {
108 if segments < 3 { return 0 as *NxMesh }
109 let nv: i64 = segments + 1
110 let nt: i64 = 2 * segments - 2
111 let m: *NxMesh = nx_mesh_alloc(nv, nt, 0)
112 if (m as i64) == 0 { return m }
113 var k: i64 = 0
114 while k < segments {
115 let turn: i64 = k * 1024 / segments
116 let cv: i64 = nx_cos_turn_q10(turn)
117 let sv: i64 = nx_sin_turn_q10(turn)
118 nx_mesh_set_vertex(m, k, radius_q14 * cv / 1024, radius_q14 * sv / 1024, 0, color)
119 k = k + 1
120 }
121 let apex: i64 = segments
122 nx_mesh_set_vertex(m, apex, 0, 0, height_q14, color)
123 var t: i64 = 0
124 // base cap fan (faces -Z)
125 var f: i64 = 1
126 while f < segments - 1 {
127 nx_mesh_set_triangle(m, t, 0, f + 1, f)
128 t = t + 1
129 f = f + 1
130 }
131 // side triangles to the apex
132 var i: i64 = 0
133 while i < segments {
134 let j: i64 = (i + 1) % segments
135 nx_mesh_set_triangle(m, t, i, j, apex)
136 t = t + 1
137 i = i + 1
138 }
139 return m
140}