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.
- package/VIEWER.md +24 -0
- package/dist/components.js +47 -43
- package/dist/gcode_parse.js +99 -95
- package/dist/index.js +3855 -3758
- package/dist/{model_loaders-DxlFNFOu.js → model_loaders-Dk9rqXFb.js} +27 -27
- package/dist/model_loaders.js +2 -2
- package/dist/parse_3mf-CpbA-6Iq.js +666 -0
- package/dist/parse_3mf.worker.js +67 -5
- package/dist/toolpath.js +248 -176
- package/package.json +6 -1
- package/src/core/paint_tools.js +8 -0
- package/src/settings/kernel_setting_keys.js +28 -0
- package/src/settings/settings_core.js +55 -5
- package/types/paint.d.ts +7 -0
- package/types/viewer.d.ts +1 -1
- package/dist/parse_3mf-BZISF3eW.js +0 -327
package/dist/parse_3mf.worker.js
CHANGED
|
@@ -1,9 +1,71 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
6
|
-
|
|
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
|
|
2
|
-
import { b as
|
|
3
|
-
import { r as
|
|
4
|
-
import { T as
|
|
5
|
-
const
|
|
6
|
-
for (const t of Object.keys(
|
|
7
|
-
function
|
|
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
|
|
10
|
-
const
|
|
11
|
-
e[
|
|
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
|
|
16
|
-
const e =
|
|
17
|
-
return e ? Math.floor(e.length /
|
|
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
|
|
20
|
-
const
|
|
21
|
-
let
|
|
22
|
-
for (let
|
|
23
|
-
const
|
|
24
|
-
for (let
|
|
25
|
-
|
|
26
|
-
|
|
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
|
|
29
|
-
let
|
|
30
|
-
for (let
|
|
31
|
-
const
|
|
32
|
-
for (let
|
|
33
|
-
const
|
|
34
|
-
if (Number.isFinite(
|
|
35
|
-
const
|
|
36
|
-
|
|
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
|
|
40
|
-
Number.isFinite(vt) && (
|
|
41
|
-
const Ft =
|
|
42
|
-
for (const [
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
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
|
-
|
|
50
|
+
b++;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
const
|
|
53
|
+
const N = l > 0 && Number.isFinite(z) ? { min: [z, k, X], max: [W, D, i] } : null;
|
|
54
54
|
return {
|
|
55
|
-
position:
|
|
56
|
-
hwa:
|
|
57
|
-
segIndex:
|
|
58
|
-
nV:
|
|
59
|
-
nSeg:
|
|
60
|
-
layerSegPrefix:
|
|
61
|
-
travelPos:
|
|
62
|
-
travelPrefix:
|
|
63
|
-
nTrav:
|
|
64
|
-
movePos:
|
|
65
|
-
moveKind:
|
|
66
|
-
movePrefix:
|
|
67
|
-
layerCount:
|
|
68
|
-
maxAbs:
|
|
69
|
-
hasNaN:
|
|
70
|
-
typeLengths:
|
|
71
|
-
bbox:
|
|
72
|
-
meta: { vType:
|
|
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
|
|
75
|
+
function Rt(t) {
|
|
76
76
|
const e = t ?? [];
|
|
77
|
-
let
|
|
78
|
-
for (let
|
|
79
|
-
if (
|
|
80
|
-
const
|
|
81
|
-
for (let
|
|
82
|
-
const
|
|
83
|
-
|
|
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
|
|
85
|
+
return n.sort((r, c) => c.pct - r.pct);
|
|
86
86
|
}
|
|
87
|
-
const
|
|
88
|
-
function
|
|
89
|
-
return
|
|
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
|
|
92
|
-
const
|
|
93
|
-
for (let
|
|
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
|
|
97
|
-
const
|
|
98
|
-
let
|
|
99
|
-
for (let
|
|
100
|
-
t.moveKind[
|
|
101
|
-
if (
|
|
102
|
-
const
|
|
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[
|
|
105
|
-
segCount:
|
|
106
|
-
travCount:
|
|
107
|
-
onTravel: t.moveKind[
|
|
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
|
|
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,
|
|
123
|
-
const
|
|
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[
|
|
126
|
+
return e.vHeight[o];
|
|
127
127
|
case "width":
|
|
128
|
-
return e.vWidth[
|
|
128
|
+
return e.vWidth[o];
|
|
129
129
|
case "speed":
|
|
130
|
-
return
|
|
130
|
+
return h ? n.firstLayerSpeed : n.speedByType[r] ?? n.speedByType[1];
|
|
131
131
|
case "fan":
|
|
132
|
-
return
|
|
132
|
+
return c < n.closeFanLayers ? 0 : r === 9 ? 100 : n.fanNormal;
|
|
133
133
|
case "temp":
|
|
134
|
-
return
|
|
134
|
+
return h ? n.tempFirst : n.tempNormal;
|
|
135
135
|
default:
|
|
136
136
|
return 0;
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
-
function
|
|
140
|
-
const { meta:
|
|
141
|
-
if (!
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
return
|
|
145
|
-
} : (
|
|
146
|
-
for (let
|
|
147
|
-
return { color:
|
|
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
|
|
150
|
-
const
|
|
151
|
-
for (let
|
|
152
|
-
const
|
|
153
|
-
|
|
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(
|
|
156
|
-
for (let
|
|
157
|
-
const
|
|
158
|
-
s
|
|
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:
|
|
160
|
+
return { color: c, min: d, max: u, viewType: e, label: h.label, unit: h.unit, cont: !0 };
|
|
161
161
|
}
|
|
162
|
-
const
|
|
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
|
-
`,
|
|
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
|
-
//
|
|
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
|
-
`,
|
|
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
|
-
]),
|
|
290
|
+
]), Zt = (() => {
|
|
258
291
|
const t = [];
|
|
259
292
|
for (let e = 0; e < 4; e++) {
|
|
260
|
-
const
|
|
261
|
-
t.push(n, r, o,
|
|
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
|
|
266
|
-
const { nSeg:
|
|
267
|
-
for (let
|
|
268
|
-
const
|
|
269
|
-
|
|
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
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
const
|
|
276
|
-
vertexShader:
|
|
277
|
-
fragmentShader:
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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
|
|
294
|
-
mesh:
|
|
295
|
-
travLines:
|
|
296
|
-
setLayerRange:
|
|
297
|
-
setVisibleLayers: (
|
|
298
|
-
setTravelVisible: (
|
|
299
|
-
|
|
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: (
|
|
304
|
-
if (!(!
|
|
305
|
-
for (let
|
|
306
|
-
|
|
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
|
-
|
|
381
|
+
for (const i of T) i.mesh.geometry.dispose();
|
|
382
|
+
v.dispose(), B.dispose(), k.dispose(), X.dispose();
|
|
311
383
|
},
|
|
312
|
-
nSeg:
|
|
313
|
-
layerCount:
|
|
384
|
+
nSeg: o,
|
|
385
|
+
layerCount: u
|
|
314
386
|
};
|
|
315
387
|
}
|
|
316
388
|
export {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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.
|
|
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",
|