three-slicer-viewer 0.3.1 → 0.3.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/VIEWER.md CHANGED
@@ -95,7 +95,8 @@ Every panel can be switched off, and the values the component owns can be seeded
95
95
  resin masks on a filament bed. The one number it cannot supply is the display's PHYSICAL size: millimetres
96
96
  appear nowhere in an SL1, so the preview is scaled by the printer set in the viewer and the import notice says
97
97
  so. Export hands an imported archive back byte-identical rather than re-rasterizing empty geometry.
98
- - **`gcode`** — G-code text drawn on the selected plate instead of a slice result. `parseGcode` recovers roles from
98
+ - **`gcode`** — G-code text drawn on the selected plate instead of a slice result, or a `{ plateIndex: text }` map
99
+ drawn plate by plate (what an opened `.gcode.3mf` becomes; the viewer is preview-only while one is shown). `parseGcode` recovers roles from
99
100
  `;TYPE:` (OrcaSlicer/PrusaSlicer/Cura), from `;_EXTRUSION_ROLE:` tags and from this kernel's own feature comments;
100
101
  bead width comes from `;WIDTH:` or, absent that, from E. What the file never states cannot be recovered: an
101
102
  unmarked run reads as wall, and there is no print-time estimate (that needs the machine's acceleration limits).
@@ -1,6 +1,32 @@
1
- import { D as at, a as rt } from "./viewer_defaults-B7UUZ582.js";
2
- import { R as t, e as B } from "./toolpath_encoding-BuYs95qZ.js";
3
- const F = 1e-6, lt = {
1
+ import { D as Lt, a as Nt } from "./viewer_defaults-B7UUZ582.js";
2
+ import { R as t, e as Z } from "./toolpath_encoding-BuYs95qZ.js";
3
+ import { T as ft } from "./toolpath_palette-B8xEl-qa.js";
4
+ const F = 1e-6, Rt = 254, It = /^(filament|extruder)_colour\s*=\s*(.*)$/i, ut = (i) => i.split(/[;,]/).map((r) => {
5
+ const s = /^"?#?([0-9a-f]{6})(?:[0-9a-f]{2})?"?$/i.exec(r.trim());
6
+ return s ? "#" + s[1].toUpperCase() : null;
7
+ }), At = (i) => "#" + ft[i % ft.length].map((r) => Math.round(r * 255).toString(16).padStart(2, "0")).join("");
8
+ function gt(i, r) {
9
+ let s = [];
10
+ Array.isArray(i?.colors) && (s = i.colors);
11
+ const g = r ?? [], u = Math.max(s.length, g.length, i?.filament_mm_by_tool?.length ?? 0);
12
+ return Array.from({ length: u }, (m, c) => s[c] || g[c] || At(c));
13
+ }
14
+ function wt(i, r) {
15
+ return dt(i.gcode, gt(i.stats, r));
16
+ }
17
+ function dt(i, r) {
18
+ const s = String(i ?? ""), g = [r].flat().filter(Boolean);
19
+ if (!g.length || /^;\s*filament_colour\s*=/mi.test(s)) return s;
20
+ const u = "; filament_colour = " + g.join(";") + `
21
+ `, m = s.lastIndexOf(`
22
+ ; CONFIG_BLOCK_END`);
23
+ if (m >= 0) return s.slice(0, m + 1) + u + s.slice(m + 1);
24
+ let c = `
25
+ `;
26
+ return (!s || s.endsWith(`
27
+ `)) && (c = ""), s + c + u;
28
+ }
29
+ const St = {
4
30
  // OrcaSlicer / PrusaSlicer ;TYPE: names
5
31
  "outer wall": t.WALL,
6
32
  "external perimeter": t.WALL,
@@ -43,7 +69,7 @@ const F = 1e-6, lt = {
43
69
  skin: t.SOLID,
44
70
  "support-interface": t.SUPPORT,
45
71
  "prime-tower": t.PRIME
46
- }, ot = [
72
+ }, Pt = [
47
73
  ["skirt/brim", t.SKIRT],
48
74
  ["skirt", t.SKIRT],
49
75
  ["walls", t.WALL],
@@ -54,7 +80,7 @@ const F = 1e-6, lt = {
54
80
  ["support", t.SUPPORT],
55
81
  ["prime tower", t.PRIME],
56
82
  ["wipe_tower_real", t.PRIME]
57
- ], ct = (I, f) => I === f || f.length < I.length && " (:/".includes(I[f.length]) && I.startsWith(f), ft = {
83
+ ], Et = (i, r) => i === r || r.length < i.length && " (:/".includes(i[r.length]) && i.startsWith(r), Ot = {
58
84
  1: t.WALL,
59
85
  2: t.WALL,
60
86
  3: t.WALL,
@@ -73,120 +99,136 @@ const F = 1e-6, lt = {
73
99
  16: t.SUPPORT,
74
100
  17: t.PRIME
75
101
  };
76
- function Lt(I, f = {}) {
77
- const it = Math.PI / 4 * (f.filamentDiameter > 0 ? f.filamentDiameter : at) ** 2, nt = f.defaultLayerHeight > 0 ? f.defaultLayerHeight : rt;
78
- let p = 0, u = 0, h = 0, G = 0, d = !0, O = !0, w = 0, T = t.WALL, W = 0, L = null;
79
- const P = [];
80
- let b = !1, D = !0, K = NaN, z = 0, H = 0, k = 0;
81
- const Y = /* @__PURE__ */ new Set([0]), y = (a) => {
82
- L = { z: a, p: [], w: [] }, P.push(L), D = !1, K = NaN, T = t.WALL, W = 0;
83
- }, st = () => P.length > 1 ? P[P.length - 2].z : 0, Z = (a, c, R, A, m, i, e) => {
84
- const r = Math.hypot(A - a, m - c, i - R);
85
- if (!(r < F))
102
+ function Gt(i, r = {}) {
103
+ const s = Math.PI / 4 * (r.filamentDiameter > 0 ? r.filamentDiameter : Lt) ** 2, g = r.defaultLayerHeight > 0 ? r.defaultLayerHeight : Nt;
104
+ let u = 0, m = 0, c = 0, b = 0, _ = !0, W = !0, d = 0, w = t.WALL, y = 0, R = null;
105
+ const E = [];
106
+ let D = !1, x = !0, K = NaN, q = 0, X = 0, $ = 0;
107
+ const v = /* @__PURE__ */ new Set([0]), H = [];
108
+ let z = [], k = [], j = !1;
109
+ const V = () => {
110
+ w = t.WALL, y = 0;
111
+ }, U = (o, a = !1) => {
112
+ R = { z: o, p: [], w: [] }, E.push(R), x = !1, K = NaN, (a || !j) && V();
113
+ }, mt = () => E.length > 1 ? E[E.length - 2].z : 0, J = (o, a, S, P, A, n, e) => {
114
+ const p = Math.hypot(P - o, A - a, n - S);
115
+ if (!(p < F))
86
116
  if (e > F) {
87
- k += e, D ? y(Number.isNaN(K) ? i : K) : !b && i > L.z + 1e-3 && y(i);
88
- const l = B(T, w);
89
- L.p.push(a, c, R, l, A, m, i, l);
90
- const n = Math.max(0.02, L.z - st() || nt), _ = W > 0 ? W : e * it / (r * n) + n * (1 - Math.PI / 4);
91
- L.w.push(Math.min(3, Math.max(0.05, _))), z++;
92
- } else L && (L.p.push(a, c, R, B(t.TRAVEL, w), A, m, i, B(t.TRAVEL, w)), L.w.push(0), H++);
117
+ $ += e, H[d] = (H[d] ?? 0) + e, x ? U(Number.isNaN(K) ? n : K) : !D && n > R.z + 1e-3 && U(n);
118
+ const h = Z(w, d);
119
+ R.p.push(o, a, S, h, P, A, n, h);
120
+ const f = Math.max(0.02, R.z - mt() || g), L = y > 0 ? y : e * s / (p * f) + f * (1 - Math.PI / 4);
121
+ R.w.push(Math.min(3, Math.max(0.05, L))), q++;
122
+ } else R && (R.p.push(o, a, S, Z(t.TRAVEL, d), P, A, n, Z(t.TRAVEL, d)), R.w.push(0), X++);
93
123
  };
94
- for (const a of I.split(`
124
+ for (const o of i.split(`
95
125
  `)) {
96
- const c = a.indexOf(";"), R = (c < 0 ? a : a.slice(0, c)).trim(), A = c < 0 ? "" : a.slice(c + 1).trim();
97
- if (A && !R) {
98
- const e = A.toLowerCase();
126
+ const a = o.indexOf(";"), S = (a < 0 ? o : o.slice(0, a)).trim(), P = a < 0 ? "" : o.slice(a + 1).trim();
127
+ if (P && !S) {
128
+ const e = P.toLowerCase(), p = It.exec(P);
129
+ if (p) {
130
+ p[1].toLowerCase() === "filament" ? z = ut(p[2]) : k = ut(p[2]);
131
+ continue;
132
+ }
99
133
  if (e.startsWith("type:")) {
100
- T = lt[e.slice(5).trim()] ?? t.WALL;
134
+ w = St[e.slice(5).trim()] ?? t.WALL, j = !0;
101
135
  continue;
102
136
  }
103
137
  if (e.startsWith("_extrusion_role:")) {
104
- T = ft[parseInt(e.slice(16), 10)] ?? t.WALL;
138
+ w = Ot[parseInt(e.slice(16), 10)] ?? t.WALL, j = !0;
105
139
  continue;
106
140
  }
107
141
  if (e.startsWith("width:")) {
108
- const n = parseFloat(e.slice(6));
109
- W = n > 0 ? n : 0;
142
+ const L = parseFloat(e.slice(6));
143
+ y = L > 0 ? L : 0;
110
144
  continue;
111
145
  }
112
146
  if (e.startsWith("layer_change") || e.startsWith("layer:")) {
113
- b = !0, D = !0;
147
+ D = !0, x = !0, V();
114
148
  continue;
115
149
  }
116
150
  if (e.startsWith("z:")) {
117
- const n = parseFloat(e.slice(2));
118
- D && n > 0 && (b = !0, y(n));
151
+ const L = parseFloat(e.slice(2));
152
+ x && L > 0 && (D = !0, U(L));
119
153
  continue;
120
154
  }
121
- const r = /^layer \d+ z([-\d.]+)/.exec(e);
122
- if (r) {
123
- b = !0, y(parseFloat(r[1]));
155
+ const h = /^layer \d+ z([-\d.]+)/.exec(e);
156
+ if (h) {
157
+ D = !0, U(parseFloat(h[1]), !0);
124
158
  continue;
125
159
  }
126
- const l = ot.find(([n]) => ct(e, n));
127
- l && (T = l[1]);
160
+ const f = Pt.find(([L]) => Et(e, L));
161
+ f && (w = f[1]);
128
162
  continue;
129
163
  }
130
- if (!R) continue;
131
- const m = R.split(/\s+/), i = m[0].toUpperCase();
132
- if (i === "G90") {
133
- d = !0;
164
+ if (!S) continue;
165
+ const A = S.split(/\s+/), n = A[0].toUpperCase();
166
+ if (n === "G90") {
167
+ _ = !0;
134
168
  continue;
135
169
  }
136
- if (i === "G91") {
137
- d = !1;
170
+ if (n === "G91") {
171
+ _ = !1;
138
172
  continue;
139
173
  }
140
- if (i === "M82") {
141
- O = !0;
174
+ if (n === "M82") {
175
+ W = !0;
142
176
  continue;
143
177
  }
144
- if (i === "M83") {
145
- O = !1;
178
+ if (n === "M83") {
179
+ W = !1;
146
180
  continue;
147
181
  }
148
- if (/^T\d+$/.test(i)) {
149
- w = parseInt(i.slice(1), 10), Y.add(w);
182
+ if (/^T\d+$/.test(n)) {
183
+ const e = parseInt(n.slice(1), 10);
184
+ e <= Rt && (d = e, v.add(d));
150
185
  continue;
151
186
  }
152
- if (i === "G92" || i === "G0" || i === "G1" || i === "G2" || i === "G3") {
153
- let e = NaN, r = NaN, l = NaN, n = NaN, _ = 0, q = 0;
154
- for (let N = 1; N < m.length; N++) {
155
- const s = m[N][0], o = parseFloat(m[N].slice(1));
156
- Number.isNaN(o) || (s === "X" || s === "x" ? e = o : s === "Y" || s === "y" ? r = o : s === "Z" || s === "z" ? l = o : s === "E" || s === "e" ? n = o : s === "I" || s === "i" ? _ = o : (s === "J" || s === "j") && (q = o));
187
+ if (n === "G92" || n === "G0" || n === "G1" || n === "G2" || n === "G3") {
188
+ let e = NaN, p = NaN, h = NaN, f = NaN, L = 0, tt = 0;
189
+ for (let I = 1; I < A.length; I++) {
190
+ const l = A[I][0], N = parseFloat(A[I].slice(1));
191
+ Number.isNaN(N) || (l === "X" || l === "x" ? e = N : l === "Y" || l === "y" ? p = N : l === "Z" || l === "z" ? h = N : l === "E" || l === "e" ? f = N : l === "I" || l === "i" ? L = N : (l === "J" || l === "j") && (tt = N));
157
192
  }
158
- if (i === "G92") {
159
- Number.isNaN(e) || (p = e), Number.isNaN(r) || (u = r), Number.isNaN(l) || (h = l), Number.isNaN(n) || (G = n);
193
+ if (n === "G92") {
194
+ Number.isNaN(e) || (u = e), Number.isNaN(p) || (m = p), Number.isNaN(h) || (c = h), Number.isNaN(f) || (b = f);
160
195
  continue;
161
196
  }
162
- const U = Number.isNaN(e) ? p : d ? e : p + e, x = Number.isNaN(r) ? u : d ? r : u + r, v = Number.isNaN(l) ? h : d ? l : h + l, j = Number.isNaN(n) ? 0 : O ? n - G : n;
163
- if (i === "G2" || i === "G3") {
164
- const N = p + _, s = u + q, o = Math.hypot(p - N, u - s), g = Math.atan2(u - s, p - N);
165
- let S = Math.atan2(x - s, U - N);
166
- const C = i === "G3";
167
- C && S <= g + F && (S += 2 * Math.PI), !C && S >= g - F && (S -= 2 * Math.PI);
168
- const E = Math.max(1, Math.min(360, Math.ceil(Math.abs(S - g) * o / 0.3)));
169
- let V = p, X = u, J = h;
170
- for (let M = 1; M <= E; M++) {
171
- const $ = g + (S - g) * M / E, Q = M === E ? U : N + o * Math.cos($), tt = M === E ? x : s + o * Math.sin($), et = h + (v - h) * M / E;
172
- Z(V, X, J, Q, tt, et, j / E), V = Q, X = tt, J = et;
197
+ const C = Number.isNaN(e) ? u : _ ? e : u + e, B = Number.isNaN(p) ? m : _ ? p : m + p, Y = Number.isNaN(h) ? c : _ ? h : c + h, et = Number.isNaN(f) ? 0 : W ? f - b : f;
198
+ if (n === "G2" || n === "G3") {
199
+ const I = u + L, l = m + tt, N = Math.hypot(u - I, m - l), G = Math.atan2(m - l, u - I);
200
+ let O = Math.atan2(B - l, C - I);
201
+ const nt = n === "G3";
202
+ nt && O <= G + F && (O += 2 * Math.PI), !nt && O >= G - F && (O -= 2 * Math.PI);
203
+ const M = Math.max(1, Math.min(360, Math.ceil(Math.abs(O - G) * N / 0.3)));
204
+ let it = u, rt = m, ot = c;
205
+ for (let T = 1; T <= M; T++) {
206
+ const st = G + (O - G) * T / M, at = T === M ? C : I + N * Math.cos(st), lt = T === M ? B : l + N * Math.sin(st), ct = c + (Y - c) * T / M;
207
+ J(it, rt, ot, at, lt, ct, et / M), it = at, rt = lt, ot = ct;
173
208
  }
174
209
  } else
175
- Z(p, u, h, U, x, v, j);
176
- p = U, u = x, h = v, Number.isNaN(n) || (G = O ? n : G + n);
210
+ J(u, m, c, C, B, Y, et);
211
+ u = C, m = B, c = Y, Number.isNaN(f) || (b = W ? f : b + f);
177
212
  }
178
213
  }
214
+ const pt = Math.max(z.length, k.length), Q = Array.from({ length: pt }, (o, a) => k[a] || z[a] || null), ht = Array.from({ length: Math.max(...v) + 1 }, (o, a) => H[a] || 0);
179
215
  return {
180
- layers: P.map((a) => ({ z: a.z, paths: Float32Array.from(a.p), widths: Float32Array.from(a.w) })),
216
+ layers: E.map((o) => ({ z: o.z, paths: Float32Array.from(o.p), widths: Float32Array.from(o.w) })),
181
217
  stats: {
182
- layers: P.length,
183
- path_segments: z,
184
- travel_segments: H,
185
- filament_mm: k,
186
- tools: [...Y].sort((a, c) => a - c)
218
+ layers: E.length,
219
+ path_segments: q,
220
+ travel_segments: X,
221
+ filament_mm: $,
222
+ tools: [...v].sort((o, a) => o - a),
223
+ // The kernel's own stat name, so the Filament-view switch and the stats card's per-tool split work unchanged.
224
+ filament_mm_by_tool: ht,
225
+ ...Q.some(Boolean) && { colors: Q }
187
226
  }
188
227
  };
189
228
  }
190
229
  export {
191
- Lt as parseGcode
230
+ wt as exportedGcode,
231
+ Gt as parseGcode,
232
+ gt as resultToolColors,
233
+ dt as withFilamentColours
192
234
  };