three-slicer-viewer 0.3.2 → 0.3.4

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/dist/toolpath.js CHANGED
@@ -1,113 +1,133 @@
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 R, b as Bt, p as lt, h as _t, T as wt, r as kt, D as Ot } from "./toolpath_palette-B8xEl-qa.js";
2
+ import { b as Vt, a as jt } from "./viewer_defaults-B7UUZ582.js";
3
+ import { r as At, S as ct, R as ot, t as Tt } from "./toolpath_encoding-BuYs95qZ.js";
4
+ import { T as Ut } from "./theme-2oyfMuvf.js";
5
+ const ft = {};
6
+ for (const t of Object.keys(R)) ft[t] = lt(R[t]);
7
+ function Wt(t) {
8
8
  const e = new Float32Array(t.length);
9
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;
10
+ const o = Number(t[n]?.z) || 0, r = n > 0 && Number(t[n - 1]?.z) || 0, l = n > 0 ? o - r : o;
11
+ e[n] = l > 1e-6 ? l : jt;
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;
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;
15
+ const ut = (t) => t?.paths?.length ? t.paths : null, Lt = (t) => {
16
+ const e = ut(t);
17
+ return e ? Math.floor(e.length / ct) : 0;
18
+ }, xt = (t, e) => {
19
+ const n = e * 8, o = n + 4;
20
+ return Math.atan2(t[o + 1] - t[n + 1], t[o] - t[n]);
21
+ }, Mt = (t, e) => {
22
+ const n = e * 8, o = n + 4;
23
+ return Math.hypot(t[o] - t[n], t[o + 1] - t[n + 1]);
24
+ }, zt = (t, e, n) => t[e] === t[n] && t[e + 1] === t[n + 1] && t[e + 2] === t[n + 2];
25
+ function Dt(t, e, n, o) {
26
+ const r = (a, h) => {
27
+ e[a * 8 + 4 + 2] = xt(t, h), e[h * 8 + 2] = xt(t, a);
28
+ }, l = (a, h) => n[a * 2] === n[h * 2] && zt(t, a * 8 + 4, h * 8) && Mt(t, a) > 0 && Mt(t, h) > 0;
29
+ let m = 0;
30
+ for (let a = 0; a < o; a++) {
31
+ if (a + 1 < o && l(a, a + 1)) {
32
+ r(a, a + 1);
33
+ continue;
34
+ }
35
+ m < a && l(a, m) && r(a, m), m = a + 1;
36
+ }
37
+ }
38
+ function le(t, e) {
39
+ const n = Array.isArray(t) ? t : [], o = n.length, r = Number(e) > 0 ? Number(e) : Vt, l = Wt(n), m = new Uint32Array(o + 1), a = new Uint32Array(o + 1), h = new Uint32Array(o + 1);
40
+ let p = 0, s = 0, d = 0;
41
+ for (let u = 0; u < o; u++) {
42
+ const v = ut(n[u]), g = Lt(n[u]);
43
+ for (let M = 0; M < g; M++)
44
+ At(v[M * ct + 3]) === ot.TRAVEL ? s++ : p++;
45
+ d += g, m[u + 1] = p, a[u + 1] = s, h[u + 1] = d;
27
46
  }
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++;
47
+ const c = p * 2, L = new Float32Array(c * 4), S = new Float32Array(c * 4), W = new Uint32Array(c * 2), b = new Uint8Array(c), H = new Uint8Array(c), B = new Float32Array(c), _ = new Float32Array(c), E = new Int32Array(c), F = new Float32Array(s * 6), I = new Float32Array(d * 3), z = new Uint8Array(d), D = new Float64Array(16);
48
+ let it = !1, K = 0, G = 1 / 0, Z = 1 / 0, N = 1 / 0, q = -1 / 0, k = -1 / 0, O = -1 / 0, x = 0, J = 0, st = 0, i = 0;
49
+ for (let u = 0; u < o; u++) {
50
+ const v = n[u], g = ut(v), M = Lt(v), V = v?.widths, X = l[u], tt = X / 2;
51
+ for (let Y = 0; Y < M; Y++) {
52
+ const w = Y * ct, $ = g[w], P = g[w + 1], y = g[w + 2], A = g[w + 4], j = g[w + 5], T = g[w + 6], mt = g[w + 3] | 0, et = At(mt), It = Tt(mt);
53
+ if (Number.isFinite($ + P + y + A + j + T) || (it = !0), z[i] = et === ot.TRAVEL ? 0 : 1, I[i * 3] = A, I[i * 3 + 1] = j, I[i * 3 + 2] = T, i++, et === ot.TRAVEL) {
54
+ const C = st * 6;
55
+ F[C] = $, F[C + 1] = P, F[C + 2] = y, F[C + 3] = A, F[C + 4] = j, F[C + 5] = T, st++;
37
56
  continue;
38
57
  }
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);
58
+ const at = V ? Number(V[Y]) : NaN, dt = Number.isFinite(at) && at > 0 ? at : r, vt = A - $, yt = j - P, Nt = Math.atan2(yt, vt), pt = Math.hypot(vt, yt, T - y);
59
+ Number.isFinite(pt) && (D[et] += pt);
60
+ const Pt = ft[et] ?? ft[1];
61
+ for (const [C, Q, bt] of [[$, P, y], [A, j, T]]) {
62
+ const U = x * 4;
63
+ L[U] = C, L[U + 1] = Q, L[U + 2] = bt - tt, L[U + 3] = 0, S[U] = X, S[U + 1] = dt, S[U + 2] = Nt, S[U + 3] = Pt, W[x * 2] = J, W[x * 2 + 1] = u, b[x] = et, H[x] = It, B[x] = dt, _[x] = X, E[x] = u, x++;
64
+ const nt = bt - tt;
65
+ C < G && (G = C), C > q && (q = C), Q < Z && (Z = Q), Q > k && (k = Q), nt < N && (N = nt), nt > O && (O = nt);
66
+ const gt = Math.max(Math.abs(C), Math.abs(Q), Math.abs(nt));
67
+ gt > K && (K = gt);
49
68
  }
50
- st++;
69
+ J++;
51
70
  }
52
71
  }
53
- const Lt = i > 0 && Number.isFinite(I) ? { min: [I, T, W], max: [J, Q, $] } : null;
72
+ Dt(L, S, E, p);
73
+ const f = c > 0 && Number.isFinite(G) ? { min: [G, Z, N], max: [q, k, O] } : null;
54
74
  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 }
75
+ position: L,
76
+ hwa: S,
77
+ segIndex: W,
78
+ nV: c,
79
+ nSeg: p,
80
+ layerSegPrefix: m,
81
+ travelPos: F,
82
+ travelPrefix: a,
83
+ nTrav: s,
84
+ movePos: I,
85
+ moveKind: z,
86
+ movePrefix: h,
87
+ layerCount: o,
88
+ maxAbs: K,
89
+ hasNaN: it,
90
+ typeLengths: D,
91
+ bbox: f,
92
+ meta: { vType: b, vTool: H, vWidth: B, vHeight: _, vLayer: E }
73
93
  };
74
94
  }
75
- function Kt(t) {
95
+ function ce(t) {
76
96
  const e = t ?? [];
77
97
  let n = 0;
78
- for (let o = 0; o < 16; o++) n += Number(e[o]) || 0;
98
+ for (let r = 0; r < 16; r++) n += Number(e[r]) || 0;
79
99
  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] });
100
+ const o = [];
101
+ for (let r = 0; r < 16; r++) {
102
+ const l = Number(e[r]) || 0;
103
+ l <= 0 || o.push({ type: r, label: Bt[r] ?? String(r), pct: l / n * 100, color: R[r] ?? R[1] });
84
104
  }
85
- return r.sort((o, s) => s.pct - o.pct);
105
+ return o.sort((r, l) => l.pct - r.pct);
86
106
  }
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);
107
+ const ht = (t, e) => e >= 0 && e < t.layerCount ? t.movePrefix[e + 1] - t.movePrefix[e] : 0;
108
+ function fe(t, e) {
109
+ return ht(t, e);
90
110
  }
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;
111
+ function Gt(t, e, n) {
112
+ const o = Math.min(n, t.layerCount - 1);
113
+ for (let r = o; r >= e; r--) if (ht(t, r) > 0) return r;
94
114
  return e;
95
115
  }
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;
116
+ function Jt(t, e, n) {
117
+ const o = ht(t, e), r = Math.max(0, Math.min(Number(n) || 0, o)), l = e >= 0 && e < t.layerCount ? t.movePrefix[e] : 0;
118
+ let m = 0, a = 0;
119
+ for (let p = 0; p < r; p++)
120
+ t.moveKind[l + p] === 0 ? a++ : m++;
121
+ if (r === 0) return { point: null, segCount: 0, travCount: 0, onTravel: !1 };
122
+ const h = l + r - 1;
103
123
  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
124
+ point: [t.movePos[h * 3], t.movePos[h * 3 + 1], t.movePos[h * 3 + 2]],
125
+ segCount: m,
126
+ travCount: a,
127
+ onTravel: t.moveKind[h] === 0
108
128
  };
109
129
  }
110
- const At = [
130
+ const Ct = [
111
131
  { key: "feature", label: "Feature type", cont: !1, unit: "" },
112
132
  { key: "speed", label: "Speed", cont: !0, unit: "mm/s" },
113
133
  { key: "height", label: "Layer Height", cont: !0, unit: "mm" },
@@ -119,47 +139,51 @@ const At = [
119
139
  // extruder index is a label, and a heatmap over it would imply tool 2 sits "between" tools 1 and 3.
120
140
  { key: "filament", label: "Filament", cont: !1, unit: "" }
121
141
  ];
122
- function Ot(t, e, n, r) {
123
- const o = e.vType[n], s = e.vLayer[n], f = s === 0;
142
+ function Xt(t, e, n, o) {
143
+ const r = e.vType[n], l = e.vLayer[n], m = l === 0;
124
144
  switch (t) {
125
145
  case "height":
126
146
  return e.vHeight[n];
127
147
  case "width":
128
148
  return e.vWidth[n];
129
149
  case "speed":
130
- return f ? r.firstLayerSpeed : r.speedByType[o] ?? r.speedByType[1];
150
+ return m ? o.firstLayerSpeed : o.speedByType[r] ?? o.speedByType[1];
131
151
  case "fan":
132
- return s < r.closeFanLayers ? 0 : o === 9 ? 100 : r.fanNormal;
152
+ return l < o.closeFanLayers ? 0 : r === 9 ? 100 : o.fanNormal;
133
153
  case "temp":
134
- return f ? r.tempFirst : r.tempNormal;
154
+ return m ? o.tempFirst : o.tempNormal;
135
155
  default:
136
156
  return 0;
137
157
  }
138
158
  }
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 };
159
+ function ue(t, e, n) {
160
+ const { meta: o, nV: r } = t, l = new Float32Array(r * 4), m = Ct.find((s) => s.key === e) || Ct[0];
161
+ if (!m.cont) {
162
+ const s = (n?.toolColors ?? []).map((c) => c && _t(c)), d = m.key === "filament" ? (c) => {
163
+ const L = o.vTool ? o.vTool[c] : 0;
164
+ return s[L] || wt[L % wt.length];
165
+ } : (c) => R[o.vType[c]] || R[1];
166
+ for (let c = 0; c < r; c++) l[c * 4] = lt(d(c));
167
+ return { color: l, min: 0, max: 0, viewType: e, label: m.label, unit: m.unit, cont: !1 };
148
168
  }
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);
169
+ let a = 1 / 0, h = -1 / 0;
170
+ const p = new Float32Array(r);
171
+ for (let s = 0; s < r; s++) {
172
+ const d = Xt(e, o, s, n), c = Number.isFinite(d) ? d : 0;
173
+ p[s] = c, c < a && (a = c), c > h && (h = c);
154
174
  }
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);
175
+ Number.isFinite(a) || (a = 0, h = 1);
176
+ for (let s = 0; s < r; s++) {
177
+ const d = kt(p[s], a, h, Ot);
178
+ l[s * 4] = lt(d);
159
179
  }
160
- return { color: s, min: h, max: c, viewType: e, label: f.label, unit: f.unit, cont: !0 };
180
+ return { color: l, min: a, max: h, viewType: e, label: m.label, unit: m.unit, cont: !0 };
181
+ }
182
+ const rt = 4096, Yt = 140 * Math.PI / 180, $t = 45 * Math.PI / 180, St = (t) => Math.round((t + Math.PI) / (2 * Math.PI) * (rt - 1));
183
+ function Kt(t, e) {
184
+ return St(t) * rt + St(e);
161
185
  }
162
- const zt = `
186
+ const Zt = `
163
187
  precision highp float;
164
188
 
165
189
  uniform mat4 projectionMatrix;
@@ -173,6 +197,7 @@ in vec3 iEnd;
173
197
  in vec2 iHW; // [height, width]
174
198
  in float iColor; // r<<16 | g<<8 | b
175
199
  in float iLayer;
200
+ in float iJoin; // packJoin(start heading, end heading)
176
201
 
177
202
  out vec3 vColor;
178
203
  out vec3 vNormal;
@@ -199,8 +224,26 @@ void main() {
199
224
  vec3 axis = iEnd - iStart;
200
225
  // A zero-length segment has no direction to orient against; pick one rather than emitting NaN.
201
226
  vec2 flat2 = axis.xy;
202
- vec2 dir = length(flat2) > 1e-9 ? normalize(flat2) : vec2(1.0, 0.0);
203
- vec3 side = vec3(-dir.y, dir.x, 0.0);
227
+ vec2 dir = vec2(1.0, 0.0);
228
+ if (length(flat2) > 1e-9) dir = normalize(flat2);
229
+ vec2 ownSide = vec2(-dir.y, dir.x);
230
+
231
+ float joinStart = floor(iJoin / ${rt}.0);
232
+ float joined = joinStart;
233
+ if (tpl.x > 0.5) joined = iJoin - joinStart * ${rt}.0;
234
+ joined = joined * (6.283185307179586 / ${rt - 1}.0) - 3.141592653589793;
235
+ vec2 bisector = dir + vec2(cos(joined), sin(joined));
236
+ vec2 side2 = ownSide;
237
+ vec2 facing2 = ownSide;
238
+ if (length(bisector) > 1e-6) {
239
+ vec2 tangent = normalize(bisector);
240
+ vec2 miterSide = vec2(-tangent.y, tangent.x);
241
+ float halfTurnCos = dot(miterSide, ownSide);
242
+ if (halfTurnCos > ${Math.cos(Yt / 2)}) side2 = miterSide / halfTurnCos;
243
+ if (halfTurnCos > ${Math.cos($t / 2)}) facing2 = miterSide;
244
+ }
245
+ vec3 side = vec3(side2, 0.0);
246
+ vec3 facing = vec3(facing2, 0.0);
204
247
  vec3 up = vec3(0.0, 0.0, 1.0);
205
248
 
206
249
  float halfHeight = iHW.x * 0.5;
@@ -208,18 +251,19 @@ void main() {
208
251
 
209
252
  float ring = tpl.y;
210
253
  vec3 offset;
211
- if (ring < 0.5) offset = side * halfWidth;
212
- else if (ring < 1.5) offset = up * halfHeight;
213
- else if (ring < 2.5) offset = -side * halfWidth;
214
- else offset = -up * halfHeight;
254
+ vec3 normal;
255
+ if (ring < 0.5) { offset = side * halfWidth; normal = facing; }
256
+ else if (ring < 1.5) { offset = up * halfHeight; normal = up; }
257
+ else if (ring < 2.5) { offset = -side * halfWidth; normal = -facing; }
258
+ else { offset = -up * halfHeight; normal = -up; }
215
259
 
216
260
  vec3 world = mix(iStart, iEnd, tpl.x) + offset;
217
261
 
218
- vNormal = normalize(mat3(modelViewMatrix) * normalize(offset));
262
+ vNormal = normalize(mat3(modelViewMatrix) * normal);
219
263
  vColor = unpackColor(iColor);
220
264
  gl_Position = projectionMatrix * modelViewMatrix * vec4(world, 1.0);
221
265
  }
222
- `, Wt = `
266
+ `, qt = `
223
267
  precision highp float;
224
268
 
225
269
  in vec3 vColor;
@@ -227,15 +271,48 @@ in vec3 vNormal;
227
271
  out vec4 fragColor;
228
272
 
229
273
  void main() {
230
- // Two-sided: the layer slider cuts the plate open, so back faces are seen and must not go black.
274
+ // Front faces only (the material culls the rest), so the normal never needs flipping.
231
275
  vec3 n = normalize(vNormal);
232
- if (!gl_FrontFacing) n = -n;
233
276
  // A single head-on light plus a generous ambient. The point is to read the bead's ROUNDING — which
234
277
  // face is up, which is the side — not to look lit.
235
278
  float lambert = max(dot(n, normalize(vec3(0.35, 0.35, 1.0))), 0.0);
236
279
  fragColor = vec4(vColor * (0.55 + 0.45 * lambert), 1.0);
237
280
  }
238
- `, Bt = new Float32Array([
281
+ `, Ft = [2, 4], Qt = 1.5;
282
+ function Rt(t, e) {
283
+ let n = 0;
284
+ for (let o = 0; o < t.length; o += 2)
285
+ (t[o] === ot.RAFT || t[o] === ot.SKIRT) && e[o] > n && (n = e[o]);
286
+ return n;
287
+ }
288
+ function Ht(t, e, n, o) {
289
+ let r = 0;
290
+ for (let s = 0; s < e; s++) t(s) > r && (r = t(s));
291
+ const l = (s) => s <= o || (r - s) % n === 0;
292
+ let m = 0;
293
+ for (let s = 0; s < e; s++) l(t(s)) && m++;
294
+ const a = new Uint32Array(m), h = new Uint8Array(m);
295
+ let p = 0;
296
+ for (let s = 0; s < e; s++) {
297
+ const d = t(s);
298
+ l(d) && (a[p] = s, h[p] = 1, d > o && (h[p] = Math.min(n, d - o)), p++);
299
+ }
300
+ return { source: a, layers: h };
301
+ }
302
+ function Et(t, e) {
303
+ const n = Math.max(1, Math.floor(e / 4096)), o = [];
304
+ for (let r = 0; r < e; r += n) o.push(t(r));
305
+ return o.length ? (o.sort((r, l) => r - l), o[o.length >> 1]) : 0;
306
+ }
307
+ function te(t, e, n, o) {
308
+ return e > 0 ? t * (o / 2) / (e * Math.tan(n * Math.PI / 360)) : 1 / 0;
309
+ }
310
+ function ee(t, e = Ft) {
311
+ let n = 1;
312
+ for (const o of e) o * t <= Qt && o > n && (n = o);
313
+ return n;
314
+ }
315
+ const ne = new Float32Array([
239
316
  0,
240
317
  0,
241
318
  0,
@@ -254,80 +331,129 @@ void main() {
254
331
  1,
255
332
  3
256
333
  // end ring
257
- ]), Ut = (() => {
334
+ ]), oe = (() => {
258
335
  const t = [];
259
336
  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);
337
+ const n = e, o = (e + 1) % 4, r = 4 + (e + 1) % 4, l = 4 + e;
338
+ t.push(n, o, r, n, r, l);
262
339
  }
263
340
  return t;
264
341
  })();
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];
342
+ function he(t, e) {
343
+ const { nSeg: n, nV: o, position: r, hwa: l, travelPos: m, travelPrefix: a, layerCount: h, meta: p } = e, s = new Float32Array(n * 3), d = new Float32Array(n * 3), c = new Float32Array(n * 2), L = new Float32Array(n), S = new Float32Array(n), W = new Float32Array(n);
344
+ for (let i = 0; i < n; i++) {
345
+ const f = i * 2 * 4, u = (i * 2 + 1) * 4;
346
+ s[i * 3] = r[f], s[i * 3 + 1] = r[f + 1], s[i * 3 + 2] = r[f + 2], d[i * 3] = r[u], d[i * 3 + 1] = r[u + 1], d[i * 3 + 2] = r[u + 2], c[i * 2] = l[f], c[i * 2 + 1] = l[f + 1], L[i] = l[f + 3], S[i] = p.vLayer[i * 2], W[i] = Kt(l[f + 2], l[u + 2]);
270
347
  }
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,
348
+ const b = new t.InstancedBufferGeometry();
349
+ b.setAttribute("tpl", new t.BufferAttribute(ne, 2)), b.setIndex(oe), b.setAttribute("iStart", new t.InstancedBufferAttribute(s, 3)), b.setAttribute("iEnd", new t.InstancedBufferAttribute(d, 3)), b.setAttribute("iHW", new t.InstancedBufferAttribute(c, 2));
350
+ const H = new t.InstancedBufferAttribute(L, 1);
351
+ b.setAttribute("iColor", H), b.setAttribute("iLayer", new t.InstancedBufferAttribute(S, 1)), b.setAttribute("iJoin", new t.InstancedBufferAttribute(W, 1)), b.instanceCount = n, b.boundingSphere = new t.Sphere(new t.Vector3(0, 0, 0), (e.maxAbs || 1) * 2);
352
+ const B = new t.RawShaderMaterial({
353
+ vertexShader: Zt,
354
+ fragmentShader: qt,
278
355
  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;
356
+ // Every face of the template winds outward (test_toolpath_contract.mjs), so a back face is only ever the
357
+ // inside of a bead seen through its open end. Drawing those doubled the GPU time of a frame: measured on a
358
+ // 14.6M-segment scene (6 plates, M5 Pro, DPR 2), 53.6 -> 29.4 ms with back faces culled.
359
+ side: t.FrontSide,
360
+ uniforms: { uLayerLo: { value: 0 }, uLayerHi: { value: Math.max(0, h - 1) } }
361
+ }), _ = new t.Mesh(b, B);
362
+ _.frustumCulled = !1;
363
+ const E = Rt(p.vType, p.vLayer), F = Ft.map((i) => {
364
+ const { source: f, layers: u } = Ht((y) => S[y], n, i, E), v = f.length, g = new Float32Array(v * 3), M = new Float32Array(v * 3), V = new Float32Array(v * 2), X = new Float32Array(v), tt = new Float32Array(v), Y = new Float32Array(v);
365
+ for (let y = 0; y < v; y++) {
366
+ const A = f[y], j = c[A * 2], T = (u[y] - 1) * j / 2;
367
+ g[y * 3] = s[A * 3], g[y * 3 + 1] = s[A * 3 + 1], g[y * 3 + 2] = s[A * 3 + 2] - T, M[y * 3] = d[A * 3], M[y * 3 + 1] = d[A * 3 + 1], M[y * 3 + 2] = d[A * 3 + 2] - T, V[y * 2] = j * u[y], V[y * 2 + 1] = c[A * 2 + 1], X[y] = L[A], tt[y] = S[A], Y[y] = W[A];
368
+ }
369
+ const w = new t.InstancedBufferGeometry();
370
+ w.setAttribute("tpl", b.attributes.tpl), w.setIndex(b.index), w.setAttribute("iStart", new t.InstancedBufferAttribute(g, 3)), w.setAttribute("iEnd", new t.InstancedBufferAttribute(M, 3)), w.setAttribute("iHW", new t.InstancedBufferAttribute(V, 2));
371
+ const $ = new t.InstancedBufferAttribute(X, 1);
372
+ w.setAttribute("iColor", $), w.setAttribute("iLayer", new t.InstancedBufferAttribute(tt, 1)), w.setAttribute("iJoin", new t.InstancedBufferAttribute(Y, 1)), w.instanceCount = v;
373
+ const P = new t.Mesh(w, B);
374
+ return P.frustumCulled = !1, P.visible = !1, _.add(P), { k: i, mesh: P, source: f, colors: X, colorAttr: $ };
375
+ });
376
+ let I = 1, z = !0;
377
+ const D = (i) => {
378
+ if (i !== I) {
379
+ I = i;
380
+ for (const f of F) f.mesh.visible = f.k === i;
381
+ b.instanceCount = 0, i === 1 && (b.instanceCount = n);
382
+ }
383
+ }, it = Et((i) => c[i * 2], n), K = e.bbox && new t.Box3(new t.Vector3(...e.bbox.min), new t.Vector3(...e.bbox.max)), G = new t.Box3(), Z = (i, f) => {
384
+ if (!z || !K || !i?.isPerspectiveCamera) {
385
+ D(1);
386
+ return;
387
+ }
388
+ G.copy(K).applyMatrix4(_.matrixWorld), D(ee(te(it, G.distanceToPoint(i.position), i.fov, f)));
389
+ };
390
+ _.userData.updateLod = Z;
283
391
  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));
392
+ N.setAttribute("position", new t.BufferAttribute(m, 3));
393
+ const q = new t.LineBasicMaterial({ color: Ut.travel, transparent: !0, opacity: 0.6 }), k = new t.LineSegments(N, q);
394
+ k.visible = !1, k.frustumCulled = !1;
395
+ let O = 0, x = Math.max(0, h - 1);
396
+ const J = (i, f) => {
397
+ const u = Math.max(0, h - 1), v = Math.max(0, Math.min(i | 0, u)), g = Math.max(v, Math.min(f | 0, u));
398
+ O = v, x = g, I === 1 && (b.instanceCount = n), B.uniforms.uLayerLo.value = v, B.uniforms.uLayerHi.value = g, z = v === 0 && g === u, z || D(1);
399
+ const M = a[v] * 2, V = a[g + 1] * 2;
400
+ N.setDrawRange(M, Math.max(0, V - M));
292
401
  };
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;
402
+ return J(0, h - 1), {
403
+ mesh: _,
404
+ travLines: k,
405
+ setLayerRange: J,
406
+ setMoveRange: (i) => {
407
+ if (i == null)
408
+ return J(O, x), null;
409
+ const f = Gt(e, O, x), u = Jt(e, f, i);
410
+ z = !1, D(1), b.instanceCount = e.layerSegPrefix[f] + u.segCount;
411
+ const v = a[O] * 2;
412
+ return N.setDrawRange(v, Math.max(0, (a[f] + u.travCount) * 2 - v)), { ...u, layer: f };
413
+ },
414
+ data: e,
415
+ setVisibleLayers: (i) => J(0, (i | 0) - 1),
416
+ setTravelVisible: (i) => {
417
+ k.visible = !!i;
300
418
  },
301
419
  /** color is Float32Array(nV*4) with the packed value in .r — computeColors' output shape. One instance
302
420
  * 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;
421
+ setColors: (i) => {
422
+ if (!(!i || i.length < o * 4)) {
423
+ for (let f = 0; f < n; f++) L[f] = i[f * 2 * 4];
424
+ H.needsUpdate = !0;
425
+ for (const f of F) {
426
+ for (let u = 0; u < f.source.length; u++) f.colors[u] = L[f.source[u]];
427
+ f.colorAttr.needsUpdate = !0;
428
+ }
307
429
  }
308
430
  },
431
+ /** Call once per frame before rendering; viewportPixels is the drawing buffer's height. */
432
+ updateLod: Z,
433
+ lodLevel: () => I,
309
434
  dispose: () => {
310
- p.dispose(), M.dispose(), N.dispose(), z.dispose();
435
+ for (const i of F) i.mesh.geometry.dispose();
436
+ b.dispose(), B.dispose(), N.dispose(), q.dispose();
311
437
  },
312
438
  nSeg: n,
313
- layerCount: c
439
+ layerCount: h
314
440
  };
315
441
  }
316
442
  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
443
+ Ot as DEFAULT_RANGES_COLORS,
444
+ wt as TOOL_COLOR,
445
+ R as TYPE_COLOR,
446
+ Bt as TYPE_LABEL,
447
+ oe as VERTEX_DATA,
448
+ Ct as VIEW_TYPES,
449
+ le as buildSegmentData,
450
+ ue as computeColors,
451
+ _t as hexToRgb,
452
+ fe as layerMoveCount,
453
+ he as makeToolpath,
454
+ Jt as moveCursor,
455
+ lt as packColor,
456
+ kt as rangeColorAt,
457
+ ce as roleRatios,
458
+ Gt as topMoveLayer
333
459
  };
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.4",
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",