three-slicer-viewer 0.3.2 → 0.3.3

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.
@@ -1,9 +1,71 @@
1
- import { p as f } from "./parse_3mf-BZISF3eW.js";
2
- self.onmessage = async (a) => {
3
- const { id: s, buffer: r, baseName: t } = a.data || {};
1
+ import { r as u, p } from "./parse_3mf-CpbA-6Iq.js";
2
+ function b(r) {
3
+ if (!r) return [];
4
+ const t = [r.tris.buffer, ...r.modifiers.map((s) => s.tris.buffer)];
5
+ return r.baked && t.push(r.baked.localPos.buffer, r.baked.normals.buffer), t;
6
+ }
7
+ const g = 8;
8
+ let i = null, h = 0;
9
+ const c = /* @__PURE__ */ new Map();
10
+ function w() {
11
+ if (i) return i;
12
+ i = [];
13
+ const r = Math.min(g, Math.max(1, (self.navigator?.hardwareConcurrency || 2) - 1));
4
14
  try {
5
- const { objects: e, project: o } = await f(r, t);
6
- self.postMessage({ id: s, objects: e, project: o }, e.map((c) => c.tris.buffer));
15
+ for (let t = 0; t < r; t++) {
16
+ const s = new Worker(self.location.href, { type: "module" }), n = { worker: s, failed: !1 };
17
+ s.onmessage = (o) => {
18
+ const { id: e, result: f, error: a } = o.data || {}, l = c.get(e);
19
+ l && (c.delete(e), a ? l.reject(new Error(a)) : l.resolve(f));
20
+ }, s.onerror = () => {
21
+ n.failed = !0;
22
+ for (const [o, e] of c) e.helper === n && (c.delete(o), e.reject(new Error("3MF helper failed")));
23
+ }, i.push(n);
24
+ }
25
+ } catch {
26
+ for (const t of i) t.worker.terminate();
27
+ i = [];
28
+ }
29
+ return i;
30
+ }
31
+ function M(r, t) {
32
+ const s = ++h;
33
+ return new Promise((n, o) => {
34
+ c.set(s, { resolve: n, reject: o, helper: r }), r.worker.postMessage({ type: "item-job", id: s, job: t }, t.members.map((e) => e.data.buffer));
35
+ });
36
+ }
37
+ async function k(r) {
38
+ const t = w().filter((e) => !e.failed);
39
+ if (!t.length) return Promise.all(r.map(u));
40
+ const s = new Array(r.length);
41
+ let n = 0;
42
+ const o = async (e) => {
43
+ for (; n < r.length; ) {
44
+ const f = n++, a = r[f], l = a.members.map((m) => m.data.slice());
45
+ try {
46
+ s[f] = await M(e, a);
47
+ } catch {
48
+ s[f] = await u({ ...a, members: a.members.map((m, d) => ({ ...m, data: l[d] })) });
49
+ }
50
+ }
51
+ };
52
+ return await Promise.all(t.slice(0, r.length).map(o)), s;
53
+ }
54
+ self.onmessage = async (r) => {
55
+ const t = r.data || {};
56
+ if (t.type === "item-job") {
57
+ try {
58
+ const e = await u(t.job);
59
+ self.postMessage({ id: t.id, result: e }, e.items.flatMap((f) => b(f.built)));
60
+ } catch (e) {
61
+ self.postMessage({ id: t.id, error: e && e.message || String(e) });
62
+ }
63
+ return;
64
+ }
65
+ const { id: s, buffer: n, baseName: o } = t;
66
+ try {
67
+ const { objects: e, project: f } = await p(n, o, { runJobs: k, bake: !0 });
68
+ self.postMessage({ id: s, objects: e, project: f }, e.flatMap((a) => [a.tris.buffer, a.baked.localPos.buffer, a.baked.normals.buffer]));
7
69
  } catch (e) {
8
70
  self.postMessage({ id: s, error: e && e.message || String(e) });
9
71
  }
package/dist/toolpath.js CHANGED
@@ -1,113 +1,113 @@
1
- import { a as V, b as Mt, p as ot, h as Nt, T as bt, r as St, D as It } from "./toolpath_palette-B8xEl-qa.js";
2
- import { b as kt, a as Tt } from "./viewer_defaults-B7UUZ582.js";
3
- import { r as gt, S as nt, R as et, t as Pt } from "./toolpath_encoding-BuYs95qZ.js";
4
- import { T as Vt } from "./theme-2oyfMuvf.js";
5
- const rt = {};
6
- for (const t of Object.keys(V)) rt[t] = ot(V[t]);
7
- function _t(t) {
1
+ import { a as Z, b as It, p as at, h as St, T as wt, r as Nt, D as Pt } from "./toolpath_palette-B8xEl-qa.js";
2
+ import { b as Bt, a as Vt } from "./viewer_defaults-B7UUZ582.js";
3
+ import { r as At, S as lt, R as et, t as _t } from "./toolpath_encoding-BuYs95qZ.js";
4
+ import { T as kt } from "./theme-2oyfMuvf.js";
5
+ const ct = {};
6
+ for (const t of Object.keys(Z)) ct[t] = at(Z[t]);
7
+ function Wt(t) {
8
8
  const e = new Float32Array(t.length);
9
- for (let n = 0; n < t.length; n++) {
10
- const r = Number(t[n]?.z) || 0, o = n > 0 && Number(t[n - 1]?.z) || 0, s = n > 0 ? r - o : r;
11
- e[n] = s > 1e-6 ? s : Tt;
9
+ for (let o = 0; o < t.length; o++) {
10
+ const n = Number(t[o]?.z) || 0, r = o > 0 && Number(t[o - 1]?.z) || 0, c = o > 0 ? n - r : n;
11
+ e[o] = c > 1e-6 ? c : Vt;
12
12
  }
13
13
  return e;
14
14
  }
15
- const it = (t) => t?.paths?.length ? t.paths : null, wt = (t) => {
16
- const e = it(t);
17
- return e ? Math.floor(e.length / nt) : 0;
15
+ const ft = (t) => t?.paths?.length ? t.paths : null, gt = (t) => {
16
+ const e = ft(t);
17
+ return e ? Math.floor(e.length / lt) : 0;
18
18
  };
19
- function jt(t, e) {
20
- const n = Array.isArray(t) ? t : [], r = n.length, o = Number(e) > 0 ? Number(e) : kt, s = _t(n), f = new Uint32Array(r + 1), h = new Uint32Array(r + 1), c = new Uint32Array(r + 1);
21
- let y = 0, l = 0, u = 0;
22
- for (let v = 0; v < r; v++) {
23
- const U = it(n[v]), w = wt(n[v]);
24
- for (let D = 0; D < w; D++)
25
- gt(U[D * nt + 3]) === et.TRAVEL ? l++ : y++;
26
- u += w, f[v + 1] = y, h[v + 1] = l, c[v + 1] = u;
19
+ function Ht(t, e) {
20
+ const o = Array.isArray(t) ? t : [], n = o.length, r = Number(e) > 0 ? Number(e) : Bt, c = Wt(o), h = new Uint32Array(n + 1), d = new Uint32Array(n + 1), u = new Uint32Array(n + 1);
21
+ let m = 0, s = 0, f = 0;
22
+ for (let p = 0; p < n; p++) {
23
+ const P = ft(o[p]), C = gt(o[p]);
24
+ for (let A = 0; A < C; A++)
25
+ At(P[A * lt + 3]) === et.TRAVEL ? s++ : m++;
26
+ f += C, h[p + 1] = m, d[p + 1] = s, u[p + 1] = f;
27
27
  }
28
- const i = y * 2, b = new Float32Array(i * 4), x = new Float32Array(i * 4), p = new Uint32Array(i * 2), _ = new Uint8Array(i), M = new Uint8Array(i), O = new Float32Array(i), N = new Float32Array(i), z = new Int32Array(i), g = new Float32Array(l * 6), C = new Float32Array(u * 3), a = new Uint8Array(u), m = new Float64Array(16);
29
- let A = !1, S = 0, I = 1 / 0, T = 1 / 0, W = 1 / 0, J = -1 / 0, Q = -1 / 0, $ = -1 / 0, L = 0, st = 0, lt = 0, B = 0;
30
- for (let v = 0; v < r; v++) {
31
- const U = n[v], w = it(U), D = wt(U), ct = U?.widths, E = s[v], ft = E / 2;
32
- for (let R = 0; R < D; R++) {
33
- const k = R * nt, X = w[k], Z = w[k + 1], q = w[k + 2], G = w[k + 4], Y = w[k + 5], H = w[k + 6], ut = w[k + 3] | 0, j = gt(ut), xt = Pt(ut);
34
- if (Number.isFinite(X + Z + q + G + Y + H) || (A = !0), a[B] = j === et.TRAVEL ? 0 : 1, C[B * 3] = G, C[B * 3 + 1] = Y, C[B * 3 + 2] = H, B++, j === et.TRAVEL) {
35
- const d = lt * 6;
36
- g[d] = X, g[d + 1] = Z, g[d + 2] = q, g[d + 3] = G, g[d + 4] = Y, g[d + 5] = H, lt++;
28
+ const l = m * 2, L = new Float32Array(l * 4), I = new Float32Array(l * 4), v = new Uint32Array(l * 2), q = new Uint8Array(l), B = new Uint8Array(l), V = new Float32Array(l), ot = new Float32Array(l), T = new Int32Array(l), F = new Float32Array(s * 6), _ = new Float32Array(f * 3), j = new Uint8Array(f), nt = new Float64Array(16);
29
+ let J = !1, Y = 0, z = 1 / 0, k = 1 / 0, X = 1 / 0, W = -1 / 0, D = -1 / 0, i = -1 / 0, a = 0, b = 0, w = 0, x = 0;
30
+ for (let p = 0; p < n; p++) {
31
+ const P = o[p], C = ft(P), A = gt(P), Q = P?.widths, O = c[p], y = O / 2;
32
+ for (let g = 0; g < A; g++) {
33
+ const S = g * lt, G = C[S], rt = C[S + 1], it = C[S + 2], $ = C[S + 4], H = C[S + 5], R = C[S + 6], ht = C[S + 3] | 0, E = At(ht), Ct = _t(ht);
34
+ if (Number.isFinite(G + rt + it + $ + H + R) || (J = !0), j[x] = E === et.TRAVEL ? 0 : 1, _[x * 3] = $, _[x * 3 + 1] = H, _[x * 3 + 2] = R, x++, E === et.TRAVEL) {
35
+ const M = w * 6;
36
+ F[M] = G, F[M + 1] = rt, F[M + 2] = it, F[M + 3] = $, F[M + 4] = H, F[M + 5] = R, w++;
37
37
  continue;
38
38
  }
39
- const tt = ct ? Number(ct[R]) : NaN, mt = Number.isFinite(tt) && tt > 0 ? tt : o, ht = G - X, pt = Y - Z, Ct = Math.atan2(pt, ht), vt = Math.hypot(ht, pt, H - q);
40
- Number.isFinite(vt) && (m[j] += vt);
41
- const Ft = rt[j] ?? rt[1];
42
- for (const [d, P, yt] of [[X, Z, q], [G, Y, H]]) {
43
- const F = L * 4;
44
- b[F] = d, b[F + 1] = P, b[F + 2] = yt - ft, b[F + 3] = 0, x[F] = E, x[F + 1] = mt, x[F + 2] = Ct, x[F + 3] = Ft, p[L * 2] = st, p[L * 2 + 1] = v, _[L] = j, M[L] = xt, O[L] = mt, N[L] = E, z[L] = v, L++;
45
- const K = yt - ft;
46
- d < I && (I = d), d > J && (J = d), P < T && (T = P), P > Q && (Q = P), K < W && (W = K), K > $ && ($ = K);
47
- const dt = Math.max(Math.abs(d), Math.abs(P), Math.abs(K));
48
- dt > S && (S = dt);
39
+ const st = Q ? Number(Q[g]) : NaN, mt = Number.isFinite(st) && st > 0 ? st : r, pt = $ - G, yt = H - rt, Mt = Math.atan2(yt, pt), vt = Math.hypot(pt, yt, R - it);
40
+ Number.isFinite(vt) && (nt[E] += vt);
41
+ const Ft = ct[E] ?? ct[1];
42
+ for (const [M, K, dt] of [[G, rt, it], [$, H, R]]) {
43
+ const U = a * 4;
44
+ L[U] = M, L[U + 1] = K, L[U + 2] = dt - y, L[U + 3] = 0, I[U] = O, I[U + 1] = mt, I[U + 2] = Mt, I[U + 3] = Ft, v[a * 2] = b, v[a * 2 + 1] = p, q[a] = E, B[a] = Ct, V[a] = mt, ot[a] = O, T[a] = p, a++;
45
+ const tt = dt - y;
46
+ M < z && (z = M), M > W && (W = M), K < k && (k = K), K > D && (D = K), tt < X && (X = tt), tt > i && (i = tt);
47
+ const bt = Math.max(Math.abs(M), Math.abs(K), Math.abs(tt));
48
+ bt > Y && (Y = bt);
49
49
  }
50
- st++;
50
+ b++;
51
51
  }
52
52
  }
53
- const Lt = i > 0 && Number.isFinite(I) ? { min: [I, T, W], max: [J, Q, $] } : null;
53
+ const N = l > 0 && Number.isFinite(z) ? { min: [z, k, X], max: [W, D, i] } : null;
54
54
  return {
55
- position: b,
56
- hwa: x,
57
- segIndex: p,
58
- nV: i,
59
- nSeg: y,
60
- layerSegPrefix: f,
61
- travelPos: g,
62
- travelPrefix: h,
63
- nTrav: l,
64
- movePos: C,
65
- moveKind: a,
66
- movePrefix: c,
67
- layerCount: r,
68
- maxAbs: S,
69
- hasNaN: A,
70
- typeLengths: m,
71
- bbox: Lt,
72
- meta: { vType: _, vTool: M, vWidth: O, vHeight: N, vLayer: z }
55
+ position: L,
56
+ hwa: I,
57
+ segIndex: v,
58
+ nV: l,
59
+ nSeg: m,
60
+ layerSegPrefix: h,
61
+ travelPos: F,
62
+ travelPrefix: d,
63
+ nTrav: s,
64
+ movePos: _,
65
+ moveKind: j,
66
+ movePrefix: u,
67
+ layerCount: n,
68
+ maxAbs: Y,
69
+ hasNaN: J,
70
+ typeLengths: nt,
71
+ bbox: N,
72
+ meta: { vType: q, vTool: B, vWidth: V, vHeight: ot, vLayer: T }
73
73
  };
74
74
  }
75
- function Kt(t) {
75
+ function Rt(t) {
76
76
  const e = t ?? [];
77
- let n = 0;
78
- for (let o = 0; o < 16; o++) n += Number(e[o]) || 0;
79
- if (n <= 0) return [];
80
- const r = [];
81
- for (let o = 0; o < 16; o++) {
82
- const s = Number(e[o]) || 0;
83
- s <= 0 || r.push({ type: o, label: Mt[o] ?? String(o), pct: s / n * 100, color: V[o] ?? V[1] });
77
+ let o = 0;
78
+ for (let r = 0; r < 16; r++) o += Number(e[r]) || 0;
79
+ if (o <= 0) return [];
80
+ const n = [];
81
+ for (let r = 0; r < 16; r++) {
82
+ const c = Number(e[r]) || 0;
83
+ c <= 0 || n.push({ type: r, label: It[r] ?? String(r), pct: c / o * 100, color: Z[r] ?? Z[1] });
84
84
  }
85
- return r.sort((o, s) => s.pct - o.pct);
85
+ return n.sort((r, c) => c.pct - r.pct);
86
86
  }
87
- const at = (t, e) => e >= 0 && e < t.layerCount ? t.movePrefix[e + 1] - t.movePrefix[e] : 0;
88
- function Rt(t, e) {
89
- return at(t, e);
87
+ const ut = (t, e) => e >= 0 && e < t.layerCount ? t.movePrefix[e + 1] - t.movePrefix[e] : 0;
88
+ function Et(t, e) {
89
+ return ut(t, e);
90
90
  }
91
- function Xt(t, e, n) {
92
- const r = Math.min(n, t.layerCount - 1);
93
- for (let o = r; o >= e; o--) if (at(t, o) > 0) return o;
91
+ function te(t, e, o) {
92
+ const n = Math.min(o, t.layerCount - 1);
93
+ for (let r = n; r >= e; r--) if (ut(t, r) > 0) return r;
94
94
  return e;
95
95
  }
96
- function Zt(t, e, n) {
97
- const r = at(t, e), o = Math.max(0, Math.min(Number(n) || 0, r)), s = e >= 0 && e < t.layerCount ? t.movePrefix[e] : 0;
98
- let f = 0, h = 0;
99
- for (let y = 0; y < o; y++)
100
- t.moveKind[s + y] === 0 ? h++ : f++;
101
- if (o === 0) return { point: null, segCount: 0, travCount: 0, onTravel: !1 };
102
- const c = s + o - 1;
96
+ function ee(t, e, o) {
97
+ const n = ut(t, e), r = Math.max(0, Math.min(Number(o) || 0, n)), c = e >= 0 && e < t.layerCount ? t.movePrefix[e] : 0;
98
+ let h = 0, d = 0;
99
+ for (let m = 0; m < r; m++)
100
+ t.moveKind[c + m] === 0 ? d++ : h++;
101
+ if (r === 0) return { point: null, segCount: 0, travCount: 0, onTravel: !1 };
102
+ const u = c + r - 1;
103
103
  return {
104
- point: [t.movePos[c * 3], t.movePos[c * 3 + 1], t.movePos[c * 3 + 2]],
105
- segCount: f,
106
- travCount: h,
107
- onTravel: t.moveKind[c] === 0
104
+ point: [t.movePos[u * 3], t.movePos[u * 3 + 1], t.movePos[u * 3 + 2]],
105
+ segCount: h,
106
+ travCount: d,
107
+ onTravel: t.moveKind[u] === 0
108
108
  };
109
109
  }
110
- const At = [
110
+ const Lt = [
111
111
  { key: "feature", label: "Feature type", cont: !1, unit: "" },
112
112
  { key: "speed", label: "Speed", cont: !0, unit: "mm/s" },
113
113
  { key: "height", label: "Layer Height", cont: !0, unit: "mm" },
@@ -119,47 +119,47 @@ const At = [
119
119
  // extruder index is a label, and a heatmap over it would imply tool 2 sits "between" tools 1 and 3.
120
120
  { key: "filament", label: "Filament", cont: !1, unit: "" }
121
121
  ];
122
- function Ot(t, e, n, r) {
123
- const o = e.vType[n], s = e.vLayer[n], f = s === 0;
122
+ function Ot(t, e, o, n) {
123
+ const r = e.vType[o], c = e.vLayer[o], h = c === 0;
124
124
  switch (t) {
125
125
  case "height":
126
- return e.vHeight[n];
126
+ return e.vHeight[o];
127
127
  case "width":
128
- return e.vWidth[n];
128
+ return e.vWidth[o];
129
129
  case "speed":
130
- return f ? r.firstLayerSpeed : r.speedByType[o] ?? r.speedByType[1];
130
+ return h ? n.firstLayerSpeed : n.speedByType[r] ?? n.speedByType[1];
131
131
  case "fan":
132
- return s < r.closeFanLayers ? 0 : o === 9 ? 100 : r.fanNormal;
132
+ return c < n.closeFanLayers ? 0 : r === 9 ? 100 : n.fanNormal;
133
133
  case "temp":
134
- return f ? r.tempFirst : r.tempNormal;
134
+ return h ? n.tempFirst : n.tempNormal;
135
135
  default:
136
136
  return 0;
137
137
  }
138
138
  }
139
- function qt(t, e, n) {
140
- const { meta: r, nV: o } = t, s = new Float32Array(o * 4), f = At.find((l) => l.key === e) || At[0];
141
- if (!f.cont) {
142
- const l = (n?.toolColors ?? []).map((i) => i && Nt(i)), u = f.key === "filament" ? (i) => {
143
- const b = r.vTool ? r.vTool[i] : 0;
144
- return l[b] || bt[b % bt.length];
145
- } : (i) => V[r.vType[i]] || V[1];
146
- for (let i = 0; i < o; i++) s[i * 4] = ot(u(i));
147
- return { color: s, min: 0, max: 0, viewType: e, label: f.label, unit: f.unit, cont: !1 };
139
+ function oe(t, e, o) {
140
+ const { meta: n, nV: r } = t, c = new Float32Array(r * 4), h = Lt.find((s) => s.key === e) || Lt[0];
141
+ if (!h.cont) {
142
+ const s = (o?.toolColors ?? []).map((l) => l && St(l)), f = h.key === "filament" ? (l) => {
143
+ const L = n.vTool ? n.vTool[l] : 0;
144
+ return s[L] || wt[L % wt.length];
145
+ } : (l) => Z[n.vType[l]] || Z[1];
146
+ for (let l = 0; l < r; l++) c[l * 4] = at(f(l));
147
+ return { color: c, min: 0, max: 0, viewType: e, label: h.label, unit: h.unit, cont: !1 };
148
148
  }
149
- let h = 1 / 0, c = -1 / 0;
150
- const y = new Float32Array(o);
151
- for (let l = 0; l < o; l++) {
152
- const u = Ot(e, r, l, n), i = Number.isFinite(u) ? u : 0;
153
- y[l] = i, i < h && (h = i), i > c && (c = i);
149
+ let d = 1 / 0, u = -1 / 0;
150
+ const m = new Float32Array(r);
151
+ for (let s = 0; s < r; s++) {
152
+ const f = Ot(e, n, s, o), l = Number.isFinite(f) ? f : 0;
153
+ m[s] = l, l < d && (d = l), l > u && (u = l);
154
154
  }
155
- Number.isFinite(h) || (h = 0, c = 1);
156
- for (let l = 0; l < o; l++) {
157
- const u = St(y[l], h, c, It);
158
- s[l * 4] = ot(u);
155
+ Number.isFinite(d) || (d = 0, u = 1);
156
+ for (let s = 0; s < r; s++) {
157
+ const f = Nt(m[s], d, u, Pt);
158
+ c[s * 4] = at(f);
159
159
  }
160
- return { color: s, min: h, max: c, viewType: e, label: f.label, unit: f.unit, cont: !0 };
160
+ return { color: c, min: d, max: u, viewType: e, label: h.label, unit: h.unit, cont: !0 };
161
161
  }
162
- const zt = `
162
+ const Ut = `
163
163
  precision highp float;
164
164
 
165
165
  uniform mat4 projectionMatrix;
@@ -219,7 +219,7 @@ void main() {
219
219
  vColor = unpackColor(iColor);
220
220
  gl_Position = projectionMatrix * modelViewMatrix * vec4(world, 1.0);
221
221
  }
222
- `, Wt = `
222
+ `, zt = `
223
223
  precision highp float;
224
224
 
225
225
  in vec3 vColor;
@@ -227,15 +227,48 @@ in vec3 vNormal;
227
227
  out vec4 fragColor;
228
228
 
229
229
  void main() {
230
- // Two-sided: the layer slider cuts the plate open, so back faces are seen and must not go black.
230
+ // Front faces only (the material culls the rest), so the normal never needs flipping.
231
231
  vec3 n = normalize(vNormal);
232
- if (!gl_FrontFacing) n = -n;
233
232
  // A single head-on light plus a generous ambient. The point is to read the bead's ROUNDING — which
234
233
  // face is up, which is the side — not to look lit.
235
234
  float lambert = max(dot(n, normalize(vec3(0.35, 0.35, 1.0))), 0.0);
236
235
  fragColor = vec4(vColor * (0.55 + 0.45 * lambert), 1.0);
237
236
  }
238
- `, Bt = new Float32Array([
237
+ `, xt = [2, 4], Dt = 1.5;
238
+ function Gt(t, e) {
239
+ let o = 0;
240
+ for (let n = 0; n < t.length; n += 2)
241
+ (t[n] === et.RAFT || t[n] === et.SKIRT) && e[n] > o && (o = e[n]);
242
+ return o;
243
+ }
244
+ function Tt(t, e, o, n) {
245
+ let r = 0;
246
+ for (let s = 0; s < e; s++) t(s) > r && (r = t(s));
247
+ const c = (s) => s <= n || (r - s) % o === 0;
248
+ let h = 0;
249
+ for (let s = 0; s < e; s++) c(t(s)) && h++;
250
+ const d = new Uint32Array(h), u = new Uint8Array(h);
251
+ let m = 0;
252
+ for (let s = 0; s < e; s++) {
253
+ const f = t(s);
254
+ c(f) && (d[m] = s, u[m] = 1, f > n && (u[m] = Math.min(o, f - n)), m++);
255
+ }
256
+ return { source: d, layers: u };
257
+ }
258
+ function jt(t, e) {
259
+ const o = Math.max(1, Math.floor(e / 4096)), n = [];
260
+ for (let r = 0; r < e; r += o) n.push(t(r));
261
+ return n.length ? (n.sort((r, c) => r - c), n[n.length >> 1]) : 0;
262
+ }
263
+ function Yt(t, e, o, n) {
264
+ return e > 0 ? t * (n / 2) / (e * Math.tan(o * Math.PI / 360)) : 1 / 0;
265
+ }
266
+ function Xt(t, e = xt) {
267
+ let o = 1;
268
+ for (const n of e) n * t <= Dt && n > o && (o = n);
269
+ return o;
270
+ }
271
+ const Kt = new Float32Array([
239
272
  0,
240
273
  0,
241
274
  0,
@@ -254,80 +287,119 @@ void main() {
254
287
  1,
255
288
  3
256
289
  // end ring
257
- ]), Ut = (() => {
290
+ ]), Zt = (() => {
258
291
  const t = [];
259
292
  for (let e = 0; e < 4; e++) {
260
- const n = e, r = (e + 1) % 4, o = 4 + (e + 1) % 4, s = 4 + e;
261
- t.push(n, r, o, n, o, s);
293
+ const o = e, n = (e + 1) % 4, r = 4 + (e + 1) % 4, c = 4 + e;
294
+ t.push(o, n, r, o, r, c);
262
295
  }
263
296
  return t;
264
297
  })();
265
- function Jt(t, e) {
266
- const { nSeg: n, nV: r, position: o, hwa: s, travelPos: f, travelPrefix: h, layerCount: c, meta: y } = e, l = new Float32Array(n * 3), u = new Float32Array(n * 3), i = new Float32Array(n * 2), b = new Float32Array(n), x = new Float32Array(n);
267
- for (let a = 0; a < n; a++) {
268
- const m = a * 2 * 4, A = (a * 2 + 1) * 4;
269
- l[a * 3] = o[m], l[a * 3 + 1] = o[m + 1], l[a * 3 + 2] = o[m + 2], u[a * 3] = o[A], u[a * 3 + 1] = o[A + 1], u[a * 3 + 2] = o[A + 2], i[a * 2] = s[m], i[a * 2 + 1] = s[m + 1], b[a] = s[m + 3], x[a] = y.vLayer[a * 2];
298
+ function ne(t, e) {
299
+ const { nSeg: o, nV: n, position: r, hwa: c, travelPos: h, travelPrefix: d, layerCount: u, meta: m } = e, s = new Float32Array(o * 3), f = new Float32Array(o * 3), l = new Float32Array(o * 2), L = new Float32Array(o), I = new Float32Array(o);
300
+ for (let i = 0; i < o; i++) {
301
+ const a = i * 2 * 4, b = (i * 2 + 1) * 4;
302
+ s[i * 3] = r[a], s[i * 3 + 1] = r[a + 1], s[i * 3 + 2] = r[a + 2], f[i * 3] = r[b], f[i * 3 + 1] = r[b + 1], f[i * 3 + 2] = r[b + 2], l[i * 2] = c[a], l[i * 2 + 1] = c[a + 1], L[i] = c[a + 3], I[i] = m.vLayer[i * 2];
270
303
  }
271
- const p = new t.InstancedBufferGeometry();
272
- p.setAttribute("tpl", new t.BufferAttribute(Bt, 2)), p.setIndex(Ut), p.setAttribute("iStart", new t.InstancedBufferAttribute(l, 3)), p.setAttribute("iEnd", new t.InstancedBufferAttribute(u, 3)), p.setAttribute("iHW", new t.InstancedBufferAttribute(i, 2));
273
- const _ = new t.InstancedBufferAttribute(b, 1);
274
- p.setAttribute("iColor", _), p.setAttribute("iLayer", new t.InstancedBufferAttribute(x, 1)), p.instanceCount = n, p.boundingSphere = new t.Sphere(new t.Vector3(0, 0, 0), (e.maxAbs || 1) * 2);
275
- const M = new t.RawShaderMaterial({
276
- vertexShader: zt,
277
- fragmentShader: Wt,
304
+ const v = new t.InstancedBufferGeometry();
305
+ v.setAttribute("tpl", new t.BufferAttribute(Kt, 2)), v.setIndex(Zt), v.setAttribute("iStart", new t.InstancedBufferAttribute(s, 3)), v.setAttribute("iEnd", new t.InstancedBufferAttribute(f, 3)), v.setAttribute("iHW", new t.InstancedBufferAttribute(l, 2));
306
+ const q = new t.InstancedBufferAttribute(L, 1);
307
+ v.setAttribute("iColor", q), v.setAttribute("iLayer", new t.InstancedBufferAttribute(I, 1)), v.instanceCount = o, v.boundingSphere = new t.Sphere(new t.Vector3(0, 0, 0), (e.maxAbs || 1) * 2);
308
+ const B = new t.RawShaderMaterial({
309
+ vertexShader: Ut,
310
+ fragmentShader: zt,
278
311
  glslVersion: t.GLSL3,
279
- side: t.DoubleSide,
280
- uniforms: { uLayerLo: { value: 0 }, uLayerHi: { value: Math.max(0, c - 1) } }
281
- }), O = new t.Mesh(p, M);
282
- O.frustumCulled = !1;
283
- const N = new t.BufferGeometry();
284
- N.setAttribute("position", new t.BufferAttribute(f, 3));
285
- const z = new t.LineBasicMaterial({ color: Vt.travel, transparent: !0, opacity: 0.6 }), g = new t.LineSegments(N, z);
286
- g.visible = !1, g.frustumCulled = !1;
287
- const C = (a, m) => {
288
- const A = Math.max(0, c - 1), S = Math.max(0, Math.min(a | 0, A)), I = Math.max(S, Math.min(m | 0, A));
289
- M.uniforms.uLayerLo.value = S, M.uniforms.uLayerHi.value = I;
290
- const T = h[S] * 2, W = h[I + 1] * 2;
291
- N.setDrawRange(T, Math.max(0, W - T));
312
+ // Every face of the template winds outward (test_toolpath_contract.mjs), so a back face is only ever the
313
+ // inside of a bead seen through its open end. Drawing those doubled the GPU time of a frame: measured on a
314
+ // 14.6M-segment scene (6 plates, M5 Pro, DPR 2), 53.6 -> 29.4 ms with back faces culled.
315
+ side: t.FrontSide,
316
+ uniforms: { uLayerLo: { value: 0 }, uLayerHi: { value: Math.max(0, u - 1) } }
317
+ }), V = new t.Mesh(v, B);
318
+ V.frustumCulled = !1;
319
+ const ot = Gt(m.vType, m.vLayer), T = xt.map((i) => {
320
+ const { source: a, layers: b } = Tt((y) => I[y], o, i, ot), w = a.length, x = new Float32Array(w * 3), N = new Float32Array(w * 3), p = new Float32Array(w * 2), P = new Float32Array(w), C = new Float32Array(w);
321
+ for (let y = 0; y < w; y++) {
322
+ const g = a[y], S = l[g * 2], G = (b[y] - 1) * S / 2;
323
+ x[y * 3] = s[g * 3], x[y * 3 + 1] = s[g * 3 + 1], x[y * 3 + 2] = s[g * 3 + 2] - G, N[y * 3] = f[g * 3], N[y * 3 + 1] = f[g * 3 + 1], N[y * 3 + 2] = f[g * 3 + 2] - G, p[y * 2] = S * b[y], p[y * 2 + 1] = l[g * 2 + 1], P[y] = L[g], C[y] = I[g];
324
+ }
325
+ const A = new t.InstancedBufferGeometry();
326
+ A.setAttribute("tpl", v.attributes.tpl), A.setIndex(v.index), A.setAttribute("iStart", new t.InstancedBufferAttribute(x, 3)), A.setAttribute("iEnd", new t.InstancedBufferAttribute(N, 3)), A.setAttribute("iHW", new t.InstancedBufferAttribute(p, 2));
327
+ const Q = new t.InstancedBufferAttribute(P, 1);
328
+ A.setAttribute("iColor", Q), A.setAttribute("iLayer", new t.InstancedBufferAttribute(C, 1)), A.instanceCount = w;
329
+ const O = new t.Mesh(A, B);
330
+ return O.frustumCulled = !1, O.visible = !1, V.add(O), { k: i, mesh: O, source: a, colors: P, colorAttr: Q };
331
+ });
332
+ let F = 1, _ = !0;
333
+ const j = (i) => {
334
+ if (i !== F) {
335
+ F = i;
336
+ for (const a of T) a.mesh.visible = a.k === i;
337
+ v.instanceCount = 0, i === 1 && (v.instanceCount = o);
338
+ }
339
+ }, nt = jt((i) => l[i * 2], o), J = e.bbox && new t.Box3(new t.Vector3(...e.bbox.min), new t.Vector3(...e.bbox.max)), Y = new t.Box3(), z = (i, a) => {
340
+ if (!_ || !J || !i?.isPerspectiveCamera) {
341
+ j(1);
342
+ return;
343
+ }
344
+ Y.copy(J).applyMatrix4(V.matrixWorld), j(Xt(Yt(nt, Y.distanceToPoint(i.position), i.fov, a)));
345
+ };
346
+ V.userData.updateLod = z;
347
+ const k = new t.BufferGeometry();
348
+ k.setAttribute("position", new t.BufferAttribute(h, 3));
349
+ const X = new t.LineBasicMaterial({ color: kt.travel, transparent: !0, opacity: 0.6 }), W = new t.LineSegments(k, X);
350
+ W.visible = !1, W.frustumCulled = !1;
351
+ const D = (i, a) => {
352
+ const b = Math.max(0, u - 1), w = Math.max(0, Math.min(i | 0, b)), x = Math.max(w, Math.min(a | 0, b));
353
+ B.uniforms.uLayerLo.value = w, B.uniforms.uLayerHi.value = x, _ = w === 0 && x === b, _ || j(1);
354
+ const N = d[w] * 2, p = d[x + 1] * 2;
355
+ k.setDrawRange(N, Math.max(0, p - N));
292
356
  };
293
- return C(0, c - 1), {
294
- mesh: O,
295
- travLines: g,
296
- setLayerRange: C,
297
- setVisibleLayers: (a) => C(0, (a | 0) - 1),
298
- setTravelVisible: (a) => {
299
- g.visible = !!a;
357
+ return D(0, u - 1), {
358
+ mesh: V,
359
+ travLines: W,
360
+ setLayerRange: D,
361
+ setVisibleLayers: (i) => D(0, (i | 0) - 1),
362
+ setTravelVisible: (i) => {
363
+ W.visible = !!i;
300
364
  },
301
365
  /** color is Float32Array(nV*4) with the packed value in .r — computeColors' output shape. One instance
302
366
  * takes the colour of its first vertex; the two agree, since a segment is one colour. */
303
- setColors: (a) => {
304
- if (!(!a || a.length < r * 4)) {
305
- for (let m = 0; m < n; m++) b[m] = a[m * 2 * 4];
306
- _.needsUpdate = !0;
367
+ setColors: (i) => {
368
+ if (!(!i || i.length < n * 4)) {
369
+ for (let a = 0; a < o; a++) L[a] = i[a * 2 * 4];
370
+ q.needsUpdate = !0;
371
+ for (const a of T) {
372
+ for (let b = 0; b < a.source.length; b++) a.colors[b] = L[a.source[b]];
373
+ a.colorAttr.needsUpdate = !0;
374
+ }
307
375
  }
308
376
  },
377
+ /** Call once per frame before rendering; viewportPixels is the drawing buffer's height. */
378
+ updateLod: z,
379
+ lodLevel: () => F,
309
380
  dispose: () => {
310
- p.dispose(), M.dispose(), N.dispose(), z.dispose();
381
+ for (const i of T) i.mesh.geometry.dispose();
382
+ v.dispose(), B.dispose(), k.dispose(), X.dispose();
311
383
  },
312
- nSeg: n,
313
- layerCount: c
384
+ nSeg: o,
385
+ layerCount: u
314
386
  };
315
387
  }
316
388
  export {
317
- It as DEFAULT_RANGES_COLORS,
318
- bt as TOOL_COLOR,
319
- V as TYPE_COLOR,
320
- Mt as TYPE_LABEL,
321
- Ut as VERTEX_DATA,
322
- At as VIEW_TYPES,
323
- jt as buildSegmentData,
324
- qt as computeColors,
325
- Nt as hexToRgb,
326
- Rt as layerMoveCount,
327
- Jt as makeToolpath,
328
- Zt as moveCursor,
329
- ot as packColor,
330
- St as rangeColorAt,
331
- Kt as roleRatios,
332
- Xt as topMoveLayer
389
+ Pt as DEFAULT_RANGES_COLORS,
390
+ wt as TOOL_COLOR,
391
+ Z as TYPE_COLOR,
392
+ It as TYPE_LABEL,
393
+ Zt as VERTEX_DATA,
394
+ Lt as VIEW_TYPES,
395
+ Ht as buildSegmentData,
396
+ oe as computeColors,
397
+ St as hexToRgb,
398
+ Et as layerMoveCount,
399
+ ne as makeToolpath,
400
+ ee as moveCursor,
401
+ at as packColor,
402
+ Nt as rangeColorAt,
403
+ Rt as roleRatios,
404
+ te as topMoveLayer
333
405
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-slicer-viewer",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "The three-slicer viewer without the slicer — model loading, G-code parsing, GPU toolpath rendering and the settings transforms, under MIT. Plug a slicer in through the `slicer` prop.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,6 +35,10 @@
35
35
  "types": "./types/toggle.d.ts",
36
36
  "default": "./src/settings/toggle_eval.js"
37
37
  },
38
+ "./paint": {
39
+ "types": "./types/paint.d.ts",
40
+ "default": "./src/core/paint_tools.js"
41
+ },
38
42
  "./components": {
39
43
  "types": "./types/components.d.ts",
40
44
  "default": "./dist/components.js"
@@ -49,6 +53,7 @@
49
53
  "VIEWER.md",
50
54
  "data",
51
55
  "dist",
56
+ "src/core/paint_tools.js",
52
57
  "src/data.js",
53
58
  "src/settings",
54
59
  "types",