three-slicer 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +342 -24
- package/components/README.md +1 -1
- package/components/dist/SettingsPanel.js +111 -112
- package/components/styles.css +9 -9
- package/data/invalidation-map.json +1 -1
- package/engine/examples/headless.mjs +2 -2
- package/engine/index.d.ts +3 -1
- package/engine/index.js +2 -2
- package/engine/src/data.js +12 -0
- package/engine/src/settings.js +35 -35
- package/engine/src/slicer.worker.js +25 -22
- package/engine/src/slicer_core.js +0 -0
- package/engine/src/slicer_core.mt.js +0 -0
- package/engine/src/toggle_eval.js +12 -13
- package/package.json +54 -26
- package/types/components.d.ts +19 -0
- package/types/data/config-schema.json.d.ts +55 -0
- package/types/data/invalidation-map.json.d.ts +15 -0
- package/types/data/toggle-rules.json.d.ts +20 -0
- package/types/data/ui-tree.json.d.ts +19 -0
- package/types/data.d.ts +17 -0
- package/types/gen_settings_types.mjs +70 -0
- package/types/settings-keys.d.ts +1704 -0
- package/types/settings.d.ts +19 -0
- package/types/toggle.d.ts +22 -0
- package/types/viewer-loaders.d.ts +33 -0
- package/types/viewer-toolpath.d.ts +105 -0
- package/types/viewer.d.ts +15 -0
- package/types/wasm.d.ts +5 -0
- package/types/worker.d.ts +3 -0
- package/viewer/README.md +1 -1
- package/viewer/dist/Viewport.js +1774 -923
- package/viewer/dist/make_worker.js +6 -6
- package/viewer/dist/model_loaders.js +221 -109
- package/viewer/dist/toolpath_gpu.js +146 -147
- package/viewer/styles.css +27 -25
- package/data/config-schema-builddump.json +0 -12921
- package/viewer/src/Viewport.jsx +0 -1353
- package/viewer/src/assets/add.svg +0 -1
- package/viewer/src/assets/arrange.svg +0 -1
- package/viewer/src/assets/boolean.svg +0 -1
- package/viewer/src/assets/cut.svg +0 -1
- package/viewer/src/assets/delete.svg +0 -1
- package/viewer/src/assets/deleteall.svg +0 -1
- package/viewer/src/assets/duplicate.svg +0 -1
- package/viewer/src/assets/measure.svg +0 -1
- package/viewer/src/assets/mmu.svg +0 -1
- package/viewer/src/assets/move.svg +0 -1
- package/viewer/src/assets/negative.svg +0 -1
- package/viewer/src/assets/onbed.svg +0 -1
- package/viewer/src/assets/open.svg +0 -1
- package/viewer/src/assets/orient.svg +0 -1
- package/viewer/src/assets/paint.svg +0 -1
- package/viewer/src/assets/rotate.svg +0 -1
- package/viewer/src/assets/scale.svg +0 -1
- package/viewer/src/assets/seam.svg +0 -1
- package/viewer/src/assets/split.svg +0 -1
- package/viewer/src/assets/textmark.svg +0 -1
- package/viewer/src/assets/varlayer.svg +0 -1
- package/viewer/src/icons.js +0 -23
- package/viewer/src/make_worker.js +0 -9
- package/viewer/src/model_loaders.js +0 -178
- package/viewer/src/shadow_host.jsx +0 -30
- package/viewer/src/toolpath_gpu.js +0 -430
|
@@ -1,33 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
0,
|
|
3
|
-
1,
|
|
4
|
-
2,
|
|
5
|
-
0,
|
|
6
|
-
2,
|
|
7
|
-
3,
|
|
8
|
-
// front spike
|
|
9
|
-
0,
|
|
10
|
-
3,
|
|
11
|
-
4,
|
|
12
|
-
0,
|
|
13
|
-
4,
|
|
14
|
-
5,
|
|
15
|
-
// right/bottom body
|
|
16
|
-
0,
|
|
17
|
-
5,
|
|
18
|
-
6,
|
|
19
|
-
0,
|
|
20
|
-
6,
|
|
21
|
-
1,
|
|
22
|
-
// left/top body
|
|
23
|
-
5,
|
|
24
|
-
4,
|
|
25
|
-
7,
|
|
26
|
-
5,
|
|
27
|
-
7,
|
|
28
|
-
6
|
|
29
|
-
// back spike
|
|
30
|
-
], U = {
|
|
1
|
+
const U = {
|
|
31
2
|
0: [0.42, 0.45, 0.5],
|
|
32
3
|
1: [0.85, 0.51, 0.17],
|
|
33
4
|
2: [0.21, 0.45, 0.76],
|
|
@@ -45,42 +16,61 @@ function ie(t) {
|
|
|
45
16
|
const i = Math.round(t[0] * 255), s = Math.round(t[1] * 255), n = Math.round(t[2] * 255);
|
|
46
17
|
return i << 16 | s << 8 | n;
|
|
47
18
|
}
|
|
48
|
-
|
|
19
|
+
const le = { 1: "Wall", 2: "Sparse", 3: "Solid", 4: "Skirt", 5: "Support", 6: "Raft", 7: "Gap fill", 8: "Thin wall", 9: "Bridge", 10: "Ironing", 11: "Prime" }, _e = [
|
|
20
|
+
[11, 44, 122],
|
|
21
|
+
[19, 89, 133],
|
|
22
|
+
[28, 136, 145],
|
|
23
|
+
[4, 214, 15],
|
|
24
|
+
[170, 242, 0],
|
|
25
|
+
[252, 249, 3],
|
|
26
|
+
[245, 206, 10],
|
|
27
|
+
[227, 136, 32],
|
|
28
|
+
[209, 104, 48],
|
|
29
|
+
[194, 82, 60],
|
|
30
|
+
[148, 38, 22]
|
|
31
|
+
].map((t) => [t[0] / 255, t[1] / 255, t[2] / 255]);
|
|
32
|
+
function ce(t, i, s, n) {
|
|
33
|
+
const l = n.length;
|
|
34
|
+
if (!(s > i)) return n[0];
|
|
35
|
+
const a = (s - i) / (l - 1), h = (t - i) / a, _ = Math.max(0, Math.min(l - 1, Math.floor(h))), y = Math.max(0, Math.min(l - 1, _ + 1)), v = h - _, r = n[_], x = n[y];
|
|
36
|
+
return [r[0] + (x[0] - r[0]) * v, r[1] + (x[1] - r[1]) * v, r[2] + (x[2] - r[2]) * v];
|
|
37
|
+
}
|
|
38
|
+
function pe(t, i) {
|
|
49
39
|
const s = t.length, n = i > 0 ? i : 0.42, l = new Array(s);
|
|
50
40
|
for (let e = 0; e < s; e++) {
|
|
51
41
|
const o = t[e].z;
|
|
52
42
|
l[e] = Math.max(0.02, e === 0 ? o : o - t[e - 1].z);
|
|
53
43
|
}
|
|
54
|
-
const a = [], h = [], _ = [], y = [], v = [], r = [], x = [], b = [], A = [], M = [], L = new Float64Array(16), P = [],
|
|
44
|
+
const a = [], h = [], _ = [], y = [], v = [], r = [], x = [], b = [], A = [], M = [], L = new Float64Array(16), P = [], D = [];
|
|
55
45
|
let W = -1, $ = 0, R = 0, H = 0, E = -1, c = 0;
|
|
56
|
-
const d = 1e-4,
|
|
46
|
+
const d = 1e-4, p = (e, o, g, m, u, w) => (a.push(e), h.push(o), _.push(g), r.push(m), y.push(u), v.push(w), x.push(c), b.push(!1), a.length - 1);
|
|
57
47
|
for (let e = 0; e < s; e++) {
|
|
58
48
|
const o = t[e].paths, g = t[e].widths, m = l[e];
|
|
59
49
|
if (c = e, !!o)
|
|
60
|
-
for (let
|
|
61
|
-
const w = o[
|
|
50
|
+
for (let u = 0; u < o.length; u += 8) {
|
|
51
|
+
const w = o[u + 3], F = o[u], S = o[u + 1], G = o[u + 2], I = o[u + 4], V = o[u + 5], B = o[u + 6];
|
|
62
52
|
if (w === 0) {
|
|
63
|
-
P.push(F,
|
|
53
|
+
P.push(F, S, G, I, V, B), D.push(e);
|
|
64
54
|
continue;
|
|
65
55
|
}
|
|
66
|
-
const O = g && g[
|
|
67
|
-
w < 16 && (L[w] += Math.hypot(
|
|
68
|
-
let
|
|
69
|
-
W >= 0 && E === w && Math.abs($ - F) < d && Math.abs(R -
|
|
56
|
+
const O = g && g[u / 8] > 0 ? g[u / 8] : n;
|
|
57
|
+
w < 16 && (L[w] += Math.hypot(I - F, V - S));
|
|
58
|
+
let k;
|
|
59
|
+
W >= 0 && E === w && Math.abs($ - F) < d && Math.abs(R - S) < d && Math.abs(H - G) < d ? (k = W, p(I, V, B, w, m, O)) : (k = p(F, S, G, w, m, O), p(I, V, B, w, m, O)), b[k] = !0, W = k + 1, $ = I, R = V, H = B, E = w, A.push(k), M.push(e);
|
|
70
60
|
}
|
|
71
61
|
}
|
|
72
62
|
const f = a.length, C = A.length, z = new Float32Array(f * 4), Y = new Float32Array(f * 4);
|
|
73
|
-
let ee = 0, ne = !1,
|
|
63
|
+
let ee = 0, ne = !1, T = 1 / 0, j = 1 / 0, X = 1 / 0, Z = -1 / 0, q = -1 / 0, J = -1 / 0;
|
|
74
64
|
for (let e = 0; e < f; e++) {
|
|
75
|
-
const o = y[e], g = a[e], m = h[e],
|
|
76
|
-
z[e * 4] = g, z[e * 4 + 1] = m, z[e * 4 + 2] =
|
|
65
|
+
const o = y[e], g = a[e], m = h[e], u = _[e] - 0.5 * o;
|
|
66
|
+
z[e * 4] = g, z[e * 4 + 1] = m, z[e * 4 + 2] = u;
|
|
77
67
|
const w = e > 0 && b[e - 1], F = b[e];
|
|
78
|
-
let
|
|
68
|
+
let S = 0;
|
|
79
69
|
if (w || F) {
|
|
80
|
-
const G = w ? a[e] - a[e - 1] : 0,
|
|
81
|
-
|
|
70
|
+
const G = w ? a[e] - a[e - 1] : 0, I = w ? h[e] - h[e - 1] : 0, V = w ? _[e] - _[e - 1] : 0, B = F ? a[e + 1] - a[e] : 0, O = F ? h[e + 1] - h[e] : 0, k = F ? _[e + 1] - _[e] : 0;
|
|
71
|
+
S = Math.atan2(G * O - I * B, G * B + I * O + V * k);
|
|
82
72
|
}
|
|
83
|
-
Y[e * 4] = o, Y[e * 4 + 1] = v[e], Y[e * 4 + 2] =
|
|
73
|
+
Y[e * 4] = o, Y[e * 4 + 1] = v[e], Y[e * 4 + 2] = S, Y[e * 4 + 3] = ie(U[r[e]] || U[1]), (!Number.isFinite(g) || !Number.isFinite(m) || !Number.isFinite(u) || !Number.isFinite(S)) && (ne = !0), ee = Math.max(ee, Math.abs(g), Math.abs(m), Math.abs(u)), g < T && (T = g), g > Z && (Z = g), m < j && (j = m), m > q && (q = m), u < X && (X = u), u > J && (J = u);
|
|
84
74
|
}
|
|
85
75
|
const te = new Uint32Array(C * 4);
|
|
86
76
|
for (let e = 0; e < C; e++)
|
|
@@ -96,24 +86,23 @@ function ue(t, i) {
|
|
|
96
86
|
oe[o + 1] = e;
|
|
97
87
|
}
|
|
98
88
|
}
|
|
99
|
-
const Q =
|
|
89
|
+
const Q = D.length, N = new Float32Array(Q * 6);
|
|
100
90
|
for (let e = 0; e < N.length; e++) N[e] = P[e];
|
|
101
91
|
for (let e = 0; e < N.length; e += 3) {
|
|
102
92
|
const o = N[e], g = N[e + 1], m = N[e + 2];
|
|
103
|
-
o <
|
|
93
|
+
o < T && (T = o), o > Z && (Z = o), g < j && (j = g), g > q && (q = g), m < X && (X = m), m > J && (J = m);
|
|
104
94
|
}
|
|
105
95
|
const re = new Int32Array(s + 1);
|
|
106
96
|
{
|
|
107
97
|
let e = 0;
|
|
108
98
|
for (let o = 0; o < s; o++) {
|
|
109
|
-
for (; e < Q &&
|
|
99
|
+
for (; e < Q && D[e] === o; ) e++;
|
|
110
100
|
re[o + 1] = e;
|
|
111
101
|
}
|
|
112
102
|
}
|
|
113
|
-
const se = f + Q > 0 ? { min: [
|
|
103
|
+
const se = f + Q > 0 ? { min: [T, j, X], max: [Z, q, J] } : null;
|
|
114
104
|
return { position: z, hwa: Y, segIndex: te, nV: f, nSeg: C, layerSegPrefix: oe, travelPos: N, travelPrefix: re, nTrav: Q, layerCount: s, maxAbs: ee, hasNaN: ne, meta: K, typeLengths: L, bbox: se };
|
|
115
105
|
}
|
|
116
|
-
const _e = { 1: "벽", 2: "스파스", 3: "솔리드", 4: "스커트", 5: "서포트", 6: "래프트", 7: "갭필", 8: "씬월", 9: "브리지", 10: "아이어닝", 11: "프라임" };
|
|
117
106
|
function ve(t) {
|
|
118
107
|
let i = 0;
|
|
119
108
|
for (let n = 1; n < 16; n++) i += t[n] || 0;
|
|
@@ -121,74 +110,11 @@ function ve(t) {
|
|
|
121
110
|
if (i <= 0) return s;
|
|
122
111
|
for (let n = 1; n < 16; n++) {
|
|
123
112
|
const l = t[n] || 0;
|
|
124
|
-
l > 0 && s.push({ type: n, label:
|
|
113
|
+
l > 0 && s.push({ type: n, label: le[n] || "t" + n, pct: 100 * l / i, color: U[n] || U[1] });
|
|
125
114
|
}
|
|
126
115
|
return s.sort((n, l) => l.pct - n.pct);
|
|
127
116
|
}
|
|
128
|
-
const
|
|
129
|
-
[11, 44, 122],
|
|
130
|
-
[19, 89, 133],
|
|
131
|
-
[28, 136, 145],
|
|
132
|
-
[4, 214, 15],
|
|
133
|
-
[170, 242, 0],
|
|
134
|
-
[252, 249, 3],
|
|
135
|
-
[245, 206, 10],
|
|
136
|
-
[227, 136, 32],
|
|
137
|
-
[209, 104, 48],
|
|
138
|
-
[194, 82, 60],
|
|
139
|
-
[148, 38, 22]
|
|
140
|
-
].map((t) => [t[0] / 255, t[1] / 255, t[2] / 255]);
|
|
141
|
-
function he(t, i, s, n) {
|
|
142
|
-
const l = n.length;
|
|
143
|
-
if (!(s > i)) return n[0];
|
|
144
|
-
const a = (s - i) / (l - 1), h = (t - i) / a, _ = Math.max(0, Math.min(l - 1, Math.floor(h))), y = Math.max(0, Math.min(l - 1, _ + 1)), v = h - _, r = n[_], x = n[y];
|
|
145
|
-
return [r[0] + (x[0] - r[0]) * v, r[1] + (x[1] - r[1]) * v, r[2] + (x[2] - r[2]) * v];
|
|
146
|
-
}
|
|
147
|
-
const ae = [
|
|
148
|
-
{ key: "feature", label: "Feature type", cont: !1, unit: "" },
|
|
149
|
-
{ key: "speed", label: "Speed", cont: !0, unit: "mm/s" },
|
|
150
|
-
{ key: "height", label: "Layer Height", cont: !0, unit: "mm" },
|
|
151
|
-
{ key: "width", label: "Line Width", cont: !0, unit: "mm" },
|
|
152
|
-
{ key: "fan", label: "Fan Speed", cont: !0, unit: "%" },
|
|
153
|
-
{ key: "temp", label: "Temperature", cont: !0, unit: "°C" }
|
|
154
|
-
];
|
|
155
|
-
function de(t, i, s, n) {
|
|
156
|
-
const l = i.vType[s], a = i.vLayer[s], h = a === 0;
|
|
157
|
-
switch (t) {
|
|
158
|
-
case "height":
|
|
159
|
-
return i.vHeight[s];
|
|
160
|
-
case "width":
|
|
161
|
-
return i.vWidth[s];
|
|
162
|
-
case "speed":
|
|
163
|
-
return h ? n.firstLayerSpeed : n.speedByType[l] ?? n.speedByType[1];
|
|
164
|
-
case "fan":
|
|
165
|
-
return a < n.closeFanLayers ? 0 : l === 9 ? 100 : n.fanNormal;
|
|
166
|
-
case "temp":
|
|
167
|
-
return h ? n.tempFirst : n.tempNormal;
|
|
168
|
-
default:
|
|
169
|
-
return 0;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
function ge(t, i, s) {
|
|
173
|
-
const { meta: n, nV: l } = t, a = new Float32Array(l * 4), h = ae.find((r) => r.key === i) || ae[0];
|
|
174
|
-
if (!h.cont) {
|
|
175
|
-
for (let r = 0; r < l; r++) a[r * 4] = ie(U[n.vType[r]] || U[1]);
|
|
176
|
-
return { color: a, min: 0, max: 0, viewType: i, label: h.label, unit: h.unit, cont: !1 };
|
|
177
|
-
}
|
|
178
|
-
let _ = 1 / 0, y = -1 / 0;
|
|
179
|
-
const v = new Float32Array(l);
|
|
180
|
-
for (let r = 0; r < l; r++) {
|
|
181
|
-
const x = de(i, n, r, s);
|
|
182
|
-
v[r] = x, x < _ && (_ = x), x > y && (y = x);
|
|
183
|
-
}
|
|
184
|
-
Number.isFinite(_) || (_ = 0, y = 1);
|
|
185
|
-
for (let r = 0; r < l; r++) {
|
|
186
|
-
const x = he(v[r], _, y, ce);
|
|
187
|
-
a[r * 4] = ie(x);
|
|
188
|
-
}
|
|
189
|
-
return { color: a, min: _, max: y, viewType: i, label: h.label, unit: h.unit, cont: !0 };
|
|
190
|
-
}
|
|
191
|
-
const fe = `
|
|
117
|
+
const he = `
|
|
192
118
|
precision highp float;
|
|
193
119
|
precision highp int;
|
|
194
120
|
precision highp sampler2D;
|
|
@@ -209,11 +135,11 @@ uniform mat4 projection_matrix;
|
|
|
209
135
|
uniform vec3 camera_position;
|
|
210
136
|
uniform sampler2D position_tex;
|
|
211
137
|
uniform sampler2D height_width_angle_tex;
|
|
212
|
-
uniform int layer_lo; // 25
|
|
213
|
-
uniform int layer_hi; //
|
|
138
|
+
uniform int layer_lo; // stage 25: dual slider lower bound (layer). The shader clips out-of-range segments in O(1).
|
|
139
|
+
uniform int layer_hi; // the upper bound is cut via instanceCount (sorted by layer).
|
|
214
140
|
in float vertex_id_float;
|
|
215
|
-
in uint seg_id_a_u; //
|
|
216
|
-
in uint seg_layer_u; //
|
|
141
|
+
in uint seg_id_a_u; // instance attribute (formerly segment_index_tex.r) — attribute fetch is cheaper than texelFetch
|
|
142
|
+
in uint seg_layer_u; // instance attribute (formerly segment_index_tex.g)
|
|
217
143
|
out vec3 color;
|
|
218
144
|
vec3 decode_color(float col) {
|
|
219
145
|
int c = int(round(col));
|
|
@@ -236,7 +162,7 @@ ivec2 tex_coord(sampler2D sampler, int id) {
|
|
|
236
162
|
void main() {
|
|
237
163
|
int vertex_id = int(vertex_id_float);
|
|
238
164
|
int seg_layer = int(seg_layer_u);
|
|
239
|
-
if (seg_layer < layer_lo || seg_layer > layer_hi) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); return; } //
|
|
165
|
+
if (seg_layer < layer_lo || seg_layer > layer_hi) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); return; } // out of range -> clip
|
|
240
166
|
int id_a = int(seg_id_a_u);
|
|
241
167
|
int id_b = id_a + 1;
|
|
242
168
|
vec3 pos_a = texelFetch(position_tex, tex_coord(position_tex, id_a), 0).xyz;
|
|
@@ -308,22 +234,51 @@ void main() {
|
|
|
308
234
|
color = color_base * lighting(eye_position, eye_normal);
|
|
309
235
|
gl_Position = projection_matrix * vec4(eye_position, 1.0);
|
|
310
236
|
}
|
|
311
|
-
`,
|
|
237
|
+
`, de = `
|
|
312
238
|
precision highp float;
|
|
313
239
|
in vec3 color;
|
|
314
240
|
out vec4 fragment_color;
|
|
315
241
|
void main() {
|
|
316
242
|
fragment_color = vec4(color, 1.0);
|
|
317
243
|
}
|
|
318
|
-
|
|
319
|
-
|
|
244
|
+
`, fe = [
|
|
245
|
+
0,
|
|
246
|
+
1,
|
|
247
|
+
2,
|
|
248
|
+
0,
|
|
249
|
+
2,
|
|
250
|
+
3,
|
|
251
|
+
// front spike
|
|
252
|
+
0,
|
|
253
|
+
3,
|
|
254
|
+
4,
|
|
255
|
+
0,
|
|
256
|
+
4,
|
|
257
|
+
5,
|
|
258
|
+
// right/bottom body
|
|
259
|
+
0,
|
|
260
|
+
5,
|
|
261
|
+
6,
|
|
262
|
+
0,
|
|
263
|
+
6,
|
|
264
|
+
1,
|
|
265
|
+
// left/top body
|
|
266
|
+
5,
|
|
267
|
+
4,
|
|
268
|
+
7,
|
|
269
|
+
5,
|
|
270
|
+
7,
|
|
271
|
+
6
|
|
272
|
+
// back spike
|
|
273
|
+
];
|
|
274
|
+
function ge(t, i) {
|
|
320
275
|
const s = (c, d) => {
|
|
321
|
-
const
|
|
322
|
-
C.set(c.subarray(0, Math.min(c.length,
|
|
323
|
-
const z = new t.DataTexture(C,
|
|
276
|
+
const p = Math.min(2048, Math.max(1, d)), f = Math.max(1, Math.ceil(d / p)), C = new Float32Array(p * f * 4);
|
|
277
|
+
C.set(c.subarray(0, Math.min(c.length, p * f * 4)));
|
|
278
|
+
const z = new t.DataTexture(C, p, f, t.RGBAFormat, t.FloatType);
|
|
324
279
|
return z.minFilter = z.magFilter = t.NearestFilter, z.generateMipmaps = !1, z.needsUpdate = !0, z;
|
|
325
280
|
}, n = s(i.position, i.nV), l = s(i.hwa, i.nV), a = new t.InstancedBufferGeometry();
|
|
326
|
-
a.setIndex(
|
|
281
|
+
a.setIndex(fe), a.setAttribute("position", new t.BufferAttribute(new Float32Array(8 * 3), 3)), a.setAttribute("vertex_id_float", new t.BufferAttribute(new Float32Array([0, 1, 2, 3, 4, 5, 6, 7]), 1));
|
|
327
282
|
const h = new t.InstancedInterleavedBuffer(i.segIndex, 4);
|
|
328
283
|
a.setAttribute("seg_id_a_u", new t.InterleavedBufferAttribute(h, 1, 0)), a.setAttribute("seg_layer_u", new t.InterleavedBufferAttribute(h, 1, 1)), a.instanceCount = 0;
|
|
329
284
|
const _ = new t.RawShaderMaterial({
|
|
@@ -337,50 +292,94 @@ function me(t, i) {
|
|
|
337
292
|
layer_lo: { value: 0 },
|
|
338
293
|
layer_hi: { value: i.layerCount }
|
|
339
294
|
},
|
|
340
|
-
vertexShader:
|
|
341
|
-
fragmentShader:
|
|
295
|
+
vertexShader: he,
|
|
296
|
+
fragmentShader: de,
|
|
342
297
|
side: t.DoubleSide
|
|
343
298
|
}), y = new t.Mesh(a, _);
|
|
344
299
|
let v = null;
|
|
345
300
|
if (i.bbox) {
|
|
346
|
-
const { min: c, max: d } = i.bbox,
|
|
347
|
-
v = new t.Sphere(
|
|
301
|
+
const { min: c, max: d } = i.bbox, p = new t.Vector3((c[0] + d[0]) / 2, (c[1] + d[1]) / 2, (c[2] + d[2]) / 2), f = Math.hypot(d[0] - c[0], d[1] - c[1], d[2] - c[2]) / 2 + 2;
|
|
302
|
+
v = new t.Sphere(p, f);
|
|
348
303
|
}
|
|
349
304
|
y.frustumCulled = !!v, v && (a.boundingSphere = v);
|
|
350
305
|
const r = new t.Matrix4(), x = new t.Vector3();
|
|
351
|
-
y.onBeforeRender = (c, d,
|
|
352
|
-
_.uniforms.projection_matrix.value.copy(
|
|
306
|
+
y.onBeforeRender = (c, d, p) => {
|
|
307
|
+
_.uniforms.projection_matrix.value.copy(p.projectionMatrix), _.uniforms.view_matrix.value.multiplyMatrices(p.matrixWorldInverse, y.matrixWorld), r.copy(y.matrixWorld).invert(), p.getWorldPosition(x).applyMatrix4(r), _.uniforms.camera_position.value.copy(x);
|
|
353
308
|
};
|
|
354
309
|
const b = new t.BufferGeometry();
|
|
355
310
|
b.setAttribute("position", new t.BufferAttribute(i.travelPos, 3)), b.setDrawRange(0, 0);
|
|
356
311
|
const A = new t.LineSegments(b, new t.LineBasicMaterial({ color: 7041658 }));
|
|
357
312
|
A.frustumCulled = !!v, A.visible = !1, v && (b.boundingSphere = v);
|
|
358
313
|
let M = !1, L = 0, P = i.layerCount - 1;
|
|
359
|
-
const
|
|
314
|
+
const D = () => {
|
|
360
315
|
const c = i.travelPrefix[L], d = i.travelPrefix[P + 1];
|
|
361
316
|
b.setDrawRange(M ? c * 2 : 0, M ? (d - c) * 2 : 0);
|
|
362
317
|
}, W = (c, d) => {
|
|
363
|
-
const
|
|
364
|
-
L = Math.max(0, Math.min(
|
|
318
|
+
const p = i.layerCount;
|
|
319
|
+
L = Math.max(0, Math.min(p - 1, c | 0)), P = Math.max(L, Math.min(p - 1, d | 0)), _.uniforms.layer_lo.value = L, _.uniforms.layer_hi.value = P, a.instanceCount = i.layerSegPrefix[P + 1], D();
|
|
365
320
|
};
|
|
366
321
|
return { mesh: y, travLines: A, setVisibleLayers: (c) => W(0, (c | 0) - 1), setLayerRange: W, setTravelVisible: (c) => {
|
|
367
|
-
M = !!c, A.visible = M,
|
|
322
|
+
M = !!c, A.visible = M, D();
|
|
368
323
|
}, setColors: (c) => {
|
|
369
|
-
const d = l.image.data,
|
|
370
|
-
for (let f = 0; f <
|
|
324
|
+
const d = l.image.data, p = Math.min(c.length, d.length) / 4;
|
|
325
|
+
for (let f = 0; f < p; f++) d[f * 4 + 3] = c[f * 4];
|
|
371
326
|
l.needsUpdate = !0;
|
|
372
327
|
}, dispose: () => {
|
|
373
328
|
a.dispose(), _.dispose(), n.dispose(), l.dispose(), b.dispose(), A.material.dispose();
|
|
374
329
|
}, nSeg: i.nSeg, layerCount: i.layerCount };
|
|
375
330
|
}
|
|
331
|
+
const ae = [
|
|
332
|
+
{ key: "feature", label: "Feature type", cont: !1, unit: "" },
|
|
333
|
+
{ key: "speed", label: "Speed", cont: !0, unit: "mm/s" },
|
|
334
|
+
{ key: "height", label: "Layer Height", cont: !0, unit: "mm" },
|
|
335
|
+
{ key: "width", label: "Line Width", cont: !0, unit: "mm" },
|
|
336
|
+
{ key: "fan", label: "Fan Speed", cont: !0, unit: "%" },
|
|
337
|
+
{ key: "temp", label: "Temperature", cont: !0, unit: "°C" }
|
|
338
|
+
];
|
|
339
|
+
function ue(t, i, s, n) {
|
|
340
|
+
const l = i.vType[s], a = i.vLayer[s], h = a === 0;
|
|
341
|
+
switch (t) {
|
|
342
|
+
case "height":
|
|
343
|
+
return i.vHeight[s];
|
|
344
|
+
case "width":
|
|
345
|
+
return i.vWidth[s];
|
|
346
|
+
case "speed":
|
|
347
|
+
return h ? n.firstLayerSpeed : n.speedByType[l] ?? n.speedByType[1];
|
|
348
|
+
case "fan":
|
|
349
|
+
return a < n.closeFanLayers ? 0 : l === 9 ? 100 : n.fanNormal;
|
|
350
|
+
case "temp":
|
|
351
|
+
return h ? n.tempFirst : n.tempNormal;
|
|
352
|
+
default:
|
|
353
|
+
return 0;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function me(t, i, s) {
|
|
357
|
+
const { meta: n, nV: l } = t, a = new Float32Array(l * 4), h = ae.find((r) => r.key === i) || ae[0];
|
|
358
|
+
if (!h.cont) {
|
|
359
|
+
for (let r = 0; r < l; r++) a[r * 4] = ie(U[n.vType[r]] || U[1]);
|
|
360
|
+
return { color: a, min: 0, max: 0, viewType: i, label: h.label, unit: h.unit, cont: !1 };
|
|
361
|
+
}
|
|
362
|
+
let _ = 1 / 0, y = -1 / 0;
|
|
363
|
+
const v = new Float32Array(l);
|
|
364
|
+
for (let r = 0; r < l; r++) {
|
|
365
|
+
const x = ue(i, n, r, s);
|
|
366
|
+
v[r] = x, x < _ && (_ = x), x > y && (y = x);
|
|
367
|
+
}
|
|
368
|
+
Number.isFinite(_) || (_ = 0, y = 1);
|
|
369
|
+
for (let r = 0; r < l; r++) {
|
|
370
|
+
const x = ce(v[r], _, y, _e);
|
|
371
|
+
a[r * 4] = ie(x);
|
|
372
|
+
}
|
|
373
|
+
return { color: a, min: _, max: y, viewType: i, label: h.label, unit: h.unit, cont: !0 };
|
|
374
|
+
}
|
|
376
375
|
export {
|
|
377
|
-
|
|
376
|
+
_e as DEFAULT_RANGES_COLORS,
|
|
378
377
|
U as TYPE_COLOR,
|
|
379
|
-
|
|
380
|
-
|
|
378
|
+
le as TYPE_LABEL,
|
|
379
|
+
fe as VERTEX_DATA,
|
|
381
380
|
ae as VIEW_TYPES,
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
381
|
+
pe as buildSegmentData,
|
|
382
|
+
me as computeColors,
|
|
383
|
+
ge as makeToolpath,
|
|
385
384
|
ve as roleRatios
|
|
386
385
|
};
|
package/viewer/styles.css
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
/* Shadow DOM
|
|
2
|
-
shadow root
|
|
1
|
+
/* Shadow DOM isolation (shadow_host.jsx) — this file is inlined into the bundle as a string via ?inline
|
|
2
|
+
and injected into the shadow root. Outside resets (*{box-sizing}, …) cannot reach it, so they are spelled out here. */
|
|
3
3
|
:host { display: contents; }
|
|
4
4
|
* { box-sizing: border-box; }
|
|
5
5
|
|
|
6
|
-
/* ===== 27
|
|
6
|
+
/* ===== Stage 27: desktop-style shell (top bar · left rail · center viewport · right sidebar) ===== */
|
|
7
7
|
.app-shell { position: absolute; inset: 0; display: flex; flex-direction: column; background: #0e1216; color: #cdd6dd;
|
|
8
8
|
font: 14px/1.5 -apple-system, "Segoe UI", sans-serif; }
|
|
9
9
|
.app-body { flex: 1 1 auto; display: flex; min-height: 0; }
|
|
10
10
|
|
|
11
|
-
/* S1
|
|
11
|
+
/* S1 top bar */
|
|
12
12
|
.topbar { flex: 0 0 44px; height: 44px; display: flex; align-items: center; padding: 0 12px; gap: 10px;
|
|
13
13
|
background: #161b21; border-bottom: 1px solid #262d35; }
|
|
14
14
|
.topbar .tb-left, .topbar .tb-right { flex: 1 1 0; display: flex; align-items: center; gap: 8px; }
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
.tb-tabs button:disabled { color: #5a6570; cursor: not-allowed; }
|
|
26
26
|
.tb-icon { width: 28px; height: 28px; border: 1px solid #2c353d; background: #20272f; color: #7d8b96; border-radius: 6px; font-size: 15px; cursor: not-allowed; }
|
|
27
27
|
|
|
28
|
-
/* S3
|
|
28
|
+
/* S3 left gizmo rail */
|
|
29
29
|
.left-rail { flex: 0 0 48px; display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 9px 0;
|
|
30
30
|
background: #12171c; border-right: 1px solid #232a31; }
|
|
31
31
|
.left-rail button { width: 36px; height: 36px; border: 1px solid transparent; border-radius: 8px; background: transparent;
|
|
@@ -36,12 +36,12 @@
|
|
|
36
36
|
.left-rail button.on img { opacity: 1; filter: brightness(1.6); }
|
|
37
37
|
.rail-sep { width: 26px; height: 1px; background: #2a323a; margin: 3px 0; }
|
|
38
38
|
|
|
39
|
-
/*
|
|
39
|
+
/* Center viewport column */
|
|
40
40
|
.viewport-col { position: relative; flex: 1 1 auto; min-width: 0; background: #161a1e; }
|
|
41
41
|
.vp-top-toolbar { position: absolute; top: 12px; left: 50%; transform: translateX(-50%); display: flex; align-items: center;
|
|
42
42
|
gap: 3px; background: rgba(18,23,28,.85); padding: 4px; border-radius: 9px; border: 1px solid #2a323a; z-index: 3;
|
|
43
|
-
/* 33
|
|
44
|
-
|
|
43
|
+
/* Stage 33: more buttons. flex-wrap collapses the shrink-to-fit width of an absolutely positioned box (measured 848 -> 424px),
|
|
44
|
+
folding into two rows even when everything fits. Keep one row and let narrow viewports scroll horizontally instead. */
|
|
45
45
|
max-width: calc(100% - 24px); overflow-x: auto; scrollbar-width: none; }
|
|
46
46
|
.vp-top-toolbar::-webkit-scrollbar { display: none; }
|
|
47
47
|
.vp-top-toolbar > * { flex: 0 0 auto; }
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
.vp-top-toolbar button:disabled { opacity: .32; cursor: not-allowed; }
|
|
53
53
|
.vtt-sep { width: 1px; align-self: stretch; background: #333c45; margin: 3px 3px; }
|
|
54
54
|
|
|
55
|
-
/* 29
|
|
55
|
+
/* Stage 29-2: plate tab bar + slice dropdown */
|
|
56
56
|
.plate-bar { position: absolute; right: 14px; bottom: 30px; display: flex; align-items: center; gap: 4px; z-index: 3;
|
|
57
57
|
background: rgba(18,23,28,.85); border: 1px solid #2a323a; border-radius: 9px; padding: 4px; }
|
|
58
58
|
.plate-bar button { min-width: 26px; height: 26px; border: 1px solid #2c353d; background: #1a2027; color: #9fb3c0;
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
color: #24282e; cursor: pointer; font-size: 13px; }
|
|
69
69
|
.slice-menu button:hover { background: #eef7f1; }
|
|
70
70
|
|
|
71
|
-
/*
|
|
71
|
+
/* Floating painting panel */
|
|
72
72
|
.brush-panel { position: absolute; top: 58px; left: 14px; width: 214px; background: rgba(22,27,33,.95);
|
|
73
73
|
border: 1px solid #2c353d; border-radius: 10px; padding: 10px; z-index: 4; box-shadow: 0 3px 14px rgba(0,0,0,.45); }
|
|
74
74
|
.bp-title { font-weight: 600; margin-bottom: 6px; color: #cdd6dd; }
|
|
@@ -80,12 +80,12 @@
|
|
|
80
80
|
.bp-radius input { width: 100%; }
|
|
81
81
|
.bp-counts { margin-top: 6px; font-size: 11px; }
|
|
82
82
|
|
|
83
|
-
/* Preview
|
|
83
|
+
/* Preview stats card, bottom left */
|
|
84
84
|
.stats-card { position: absolute; left: 14px; bottom: 32px; background: rgba(22,27,33,.93); border: 1px solid #2c353d;
|
|
85
85
|
border-radius: 10px; padding: 10px 14px; font-size: 13px; line-height: 1.7; z-index: 2; color: #cdd6dd; }
|
|
86
86
|
.stats-card b { color: #9fe3bd; }
|
|
87
87
|
|
|
88
|
-
/* S4
|
|
88
|
+
/* S4 right sidebar (light) */
|
|
89
89
|
.sidebar { flex: 0 0 384px; width: 384px; display: flex; flex-direction: column; background: #eef0f2; color: #24282e;
|
|
90
90
|
border-left: 1px solid #d5d8dd; min-height: 0; }
|
|
91
91
|
.sidebar-scroll { flex: 1 1 auto; overflow-y: auto; padding: 10px; display: flex; flex-direction: column; gap: 10px; }
|
|
@@ -114,12 +114,12 @@
|
|
|
114
114
|
.obj-del { border: 0; background: #fbe9ec; color: #d0435a; border-radius: 5px; cursor: pointer; padding: 0 6px; }
|
|
115
115
|
.side-card .slice-support { color: #444; font-size: 12px; margin: 5px 0 0; }
|
|
116
116
|
|
|
117
|
-
/*
|
|
117
|
+
/* Process card = embedded settings panel (light, full width) */
|
|
118
118
|
.process-card { padding: 8px; }
|
|
119
|
-
/*
|
|
120
|
-
(:host(.sp-embedded), components/styles.css) —
|
|
119
|
+
/* Width/border overrides for the embedded SettingsPanel now live in the panel's own shadow rules
|
|
120
|
+
(:host(.sp-embedded), components/styles.css) — they are across the boundary and unreachable from here. */
|
|
121
121
|
|
|
122
|
-
/* Preview
|
|
122
|
+
/* Preview control overrides (inside the light card) */
|
|
123
123
|
.side-card .view-type-row { color: #444; }
|
|
124
124
|
.side-card .view-type-row select, .side-card .obj-ext { background: #fff; color: #222; border: 1px solid #ccd0d5; }
|
|
125
125
|
.side-card .slice-layer label { color: #444; font-size: 12px; }
|
|
@@ -128,9 +128,11 @@
|
|
|
128
128
|
.side-card .layer-ctl button { background: #f1f2f4; color: #333; border: 1px solid #d3d6db; }
|
|
129
129
|
.side-card .layer-ctl button.on { background: #00ae42; color: #fff; border-color: #00ae42; }
|
|
130
130
|
|
|
131
|
-
/*
|
|
131
|
+
/* (5) Fixed bottom button bar */
|
|
132
132
|
.side-bottom { flex: 0 0 auto; display: flex; gap: 8px; padding: 10px; border-top: 1px solid #dcdfe3; background: #e6e9ec; }
|
|
133
133
|
.side-bottom .slice-btn { flex: 1.4; margin: 0; }
|
|
134
|
+
.auto-slice { display: flex; align-items: center; gap: 5px; font-size: 12px; color: #444; cursor: pointer; white-space: nowrap; user-select: none; }
|
|
135
|
+
.auto-slice input { margin: 0; }
|
|
134
136
|
.export-btn { flex: 1; text-align: center; padding: 9px; border-radius: 8px; background: #dfe6ea; color: #1f6feb;
|
|
135
137
|
border: 1px solid #c7d2da; text-decoration: none; font-weight: 600; cursor: pointer; font-size: 13px; }
|
|
136
138
|
.export-btn:hover { background: #d3dee4; }
|
|
@@ -143,7 +145,7 @@
|
|
|
143
145
|
.vp-status { position: absolute; bottom: 8px; left: 12px; right: 12px; z-index: 1;
|
|
144
146
|
font-size: 11.5px; color: #9fe3bd; font-family: ui-monospace, monospace;
|
|
145
147
|
text-shadow: 0 1px 2px #000; pointer-events: none; }
|
|
146
|
-
/* ---- Slice
|
|
148
|
+
/* ---- Slice status display (viewport overlay) ---- */
|
|
147
149
|
.slice-warn { color: #f0c060; margin: 4px 0; }
|
|
148
150
|
.slice-btn { width: 100%; margin-top: 6px; padding: 7px; border: 0; border-radius: 7px;
|
|
149
151
|
background: #00ae42; color: #fff; font-weight: 700; cursor: pointer; }
|
|
@@ -155,7 +157,7 @@
|
|
|
155
157
|
.slice-layer input[type=range] { width: 100%; }
|
|
156
158
|
.slice-travel { color: #aebcc6; display: flex; align-items: center; gap: 4px; }
|
|
157
159
|
|
|
158
|
-
/* 25
|
|
160
|
+
/* Stage 25 S6: view type select · dual slider · gradient legend */
|
|
159
161
|
.view-type-row { display: flex; align-items: center; justify-content: space-between; gap: 6px; color: #aebcc6; }
|
|
160
162
|
.view-type-row select { flex: 1; background: #10141a; color: #eee; border: 1px solid #2c353d; border-radius: 4px; padding: 2px 4px; }
|
|
161
163
|
.dual-slider { position: relative; height: 22px; }
|
|
@@ -176,7 +178,7 @@
|
|
|
176
178
|
.role-item i { width: 10px; height: 6px; border-radius: 2px; display: inline-block; }
|
|
177
179
|
.role-item b { color: #cdd6dd; }
|
|
178
180
|
|
|
179
|
-
/* 26
|
|
181
|
+
/* Stage 26: empty scene hint + drag-and-drop overlay */
|
|
180
182
|
.vp-canvas.drag-over { outline: 3px dashed #00ae42; outline-offset: -6px; }
|
|
181
183
|
.empty-hint { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
182
184
|
gap: 8px; pointer-events: none; color: #9fb3c0; text-align: center; }
|
|
@@ -190,12 +192,12 @@
|
|
|
190
192
|
background: rgba(0,174,66,.14); color: #d7f7e3; font-size: 18px; font-weight: 700; pointer-events: none;
|
|
191
193
|
border: 3px dashed #00ae42; box-sizing: border-box; }
|
|
192
194
|
|
|
193
|
-
/*
|
|
195
|
+
/* Split objects button */
|
|
194
196
|
.obj-split { border: 0; background: transparent; cursor: pointer; padding: 0 3px; line-height: 0; }
|
|
195
197
|
.obj-split img { width: 13px; height: 13px; opacity: .6; }
|
|
196
198
|
.obj-split:hover img { opacity: 1; }
|
|
197
199
|
|
|
198
|
-
/*
|
|
200
|
+
/* Right-click context menu */
|
|
199
201
|
.ctx-scrim { position: absolute; inset: 0; z-index: 24; }
|
|
200
202
|
.ctx-menu { position: absolute; z-index: 25; min-width: 168px; padding: 4px;
|
|
201
203
|
background: #1b2027; border: 1px solid #2f3944; border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,.5); }
|
|
@@ -208,7 +210,7 @@
|
|
|
208
210
|
.ctx-menu hr { margin: 4px 6px; border: 0; border-top: 1px solid #2f3944; }
|
|
209
211
|
.ctx-key { color: #7d8b96; font-family: ui-monospace, monospace; font-size: 11px; }
|
|
210
212
|
|
|
211
|
-
/*
|
|
213
|
+
/* Keyboard shortcut help overlay ('?') */
|
|
212
214
|
.help-overlay { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
|
|
213
215
|
background: rgba(8,12,16,.72); z-index: 20; }
|
|
214
216
|
.help-card { background: #1b2027; color: #dfe6ee; border: 1px solid #2f3944; border-radius: 10px;
|
|
@@ -220,12 +222,12 @@
|
|
|
220
222
|
.help-card dt { color: #9fb0c2; font-family: ui-monospace, monospace; white-space: nowrap; }
|
|
221
223
|
.help-card dd { margin: 0; }
|
|
222
224
|
|
|
223
|
-
/*
|
|
225
|
+
/* Multi-object list / support toggle (stage 3) */
|
|
224
226
|
.slice-support { display: flex; align-items: center; gap: 5px; margin: 6px 0; color: #cdd6dd; font-size: 12px; }
|
|
225
227
|
|
|
226
228
|
.slice-support .muted { font-size: 10px; }
|
|
227
229
|
|
|
228
|
-
/*
|
|
230
|
+
/* Printer card — inline editing of bed width x depth */
|
|
229
231
|
.sc-bed { display: inline-flex; align-items: center; gap: 4px; font-weight: 700; color: #222; }
|
|
230
232
|
.sc-bed input { width: 54px; padding: 1px 4px; font-size: 12px; font-weight: 600; text-align: right;
|
|
231
233
|
border: 1px solid #ccd0d5; border-radius: 5px; background: #fff; color: #222; }
|